@suveren/gateway 0.2.0 → 0.2.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.
- package/dist/control-plane/index.mjs +25 -5
- package/dist/mcp-server/http.mjs +48 -17
- package/dist/ui/assets/{index-CqecIRqd.js → index-CIhRJ6MD.js} +23 -22
- package/dist/ui/index.html +1 -1
- package/dist/ui/mockups/intent-redesign.html +1 -1
- package/node_modules/eventsource-parser/README.md +31 -0
- package/node_modules/eventsource-parser/dist/index.cjs +21 -10
- package/node_modules/eventsource-parser/dist/index.cjs.map +1 -1
- package/node_modules/eventsource-parser/dist/index.d.cts +33 -10
- package/node_modules/eventsource-parser/dist/index.d.ts +33 -10
- package/node_modules/eventsource-parser/dist/index.js +21 -10
- package/node_modules/eventsource-parser/dist/index.js.map +1 -1
- package/node_modules/eventsource-parser/dist/stream.cjs +4 -3
- package/node_modules/eventsource-parser/dist/stream.cjs.map +1 -1
- package/node_modules/eventsource-parser/dist/stream.d.cts +16 -3
- package/node_modules/eventsource-parser/dist/stream.d.ts +16 -3
- package/node_modules/eventsource-parser/dist/stream.js +4 -3
- package/node_modules/eventsource-parser/dist/stream.js.map +1 -1
- package/node_modules/eventsource-parser/package.json +8 -8
- package/node_modules/eventsource-parser/src/errors.ts +1 -1
- package/node_modules/eventsource-parser/src/index.ts +6 -1
- package/node_modules/eventsource-parser/src/parse.ts +55 -13
- package/node_modules/eventsource-parser/src/stream.ts +24 -5
- package/node_modules/eventsource-parser/src/types.ts +25 -0
- package/node_modules/hasown/CHANGELOG.md +7 -0
- package/node_modules/hasown/index.d.ts +0 -1
- package/node_modules/hasown/package.json +4 -5
- package/node_modules/hono/dist/cjs/index.js +3 -0
- package/node_modules/hono/dist/cjs/middleware/compress/index.js +10 -4
- package/node_modules/hono/dist/cjs/utils/filepath.js +1 -1
- package/node_modules/hono/dist/cjs/utils/ipaddr.js +1 -1
- package/node_modules/hono/dist/index.js +2 -0
- package/node_modules/hono/dist/middleware/compress/index.js +9 -4
- package/node_modules/hono/dist/tsconfig.build.tsbuildinfo +1 -1
- package/node_modules/hono/dist/types/index.d.ts +2 -1
- package/node_modules/hono/dist/types/middleware/compress/index.d.ts +11 -1
- package/node_modules/hono/dist/utils/filepath.js +1 -1
- package/node_modules/hono/dist/utils/ipaddr.js +1 -1
- package/node_modules/hono/package.json +1 -1
- package/package.json +1 -1
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
* The type of error that occurred.
|
|
3
3
|
* @public
|
|
4
4
|
*/
|
|
5
|
-
export declare type ErrorType =
|
|
5
|
+
export declare type ErrorType =
|
|
6
|
+
| "invalid-retry"
|
|
7
|
+
| "unknown-field"
|
|
8
|
+
| "max-buffer-size-exceeded";
|
|
6
9
|
|
|
7
10
|
/**
|
|
8
11
|
* A parsed EventSource message event
|
|
@@ -43,7 +46,7 @@ export declare interface EventSourceMessage {
|
|
|
43
46
|
* const eventStream =
|
|
44
47
|
* response.body
|
|
45
48
|
* .pipeThrough(new TextDecoderStream())
|
|
46
|
-
* .pipeThrough(new EventSourceParserStream({
|
|
49
|
+
* .pipeThrough(new EventSourceParserStream({onError: 'terminate'}))
|
|
47
50
|
* ```
|
|
48
51
|
*
|
|
49
52
|
* @public
|
|
@@ -52,7 +55,7 @@ export declare class EventSourceParserStream extends TransformStream<
|
|
|
52
55
|
string,
|
|
53
56
|
EventSourceMessage
|
|
54
57
|
> {
|
|
55
|
-
constructor({ onError, onRetry, onComment }?: StreamOptions);
|
|
58
|
+
constructor({ onError, onRetry, onComment, maxBufferSize }?: StreamOptions);
|
|
56
59
|
}
|
|
57
60
|
|
|
58
61
|
/**
|
|
@@ -116,6 +119,16 @@ export declare interface StreamOptions {
|
|
|
116
119
|
* @param comment - The comment encountered in the stream.
|
|
117
120
|
*/
|
|
118
121
|
onComment?: ((comment: string) => void) | undefined;
|
|
122
|
+
/**
|
|
123
|
+
* Maximum number of characters the parser is allowed to buffer across calls to `feed()`.
|
|
124
|
+
* See {@link ParserConfig.maxBufferSize} for details.
|
|
125
|
+
*
|
|
126
|
+
* When the limit is exceeded, the stream is always errored (regardless of the `onError`
|
|
127
|
+
* setting) since the underlying parser is unrecoverable without a `reset()`.
|
|
128
|
+
*
|
|
129
|
+
* @defaultValue `undefined` (unbounded)
|
|
130
|
+
*/
|
|
131
|
+
maxBufferSize?: number | undefined;
|
|
119
132
|
}
|
|
120
133
|
|
|
121
134
|
export {};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createParser } from "./index.js";
|
|
2
2
|
import { ParseError } from "./index.js";
|
|
3
3
|
class EventSourceParserStream extends TransformStream {
|
|
4
|
-
constructor({ onError, onRetry, onComment } = {}) {
|
|
4
|
+
constructor({ onError, onRetry, onComment, maxBufferSize } = {}) {
|
|
5
5
|
let parser;
|
|
6
6
|
super({
|
|
7
7
|
start(controller) {
|
|
@@ -10,10 +10,11 @@ class EventSourceParserStream extends TransformStream {
|
|
|
10
10
|
controller.enqueue(event);
|
|
11
11
|
},
|
|
12
12
|
onError(error) {
|
|
13
|
-
onError
|
|
13
|
+
typeof onError == "function" && onError(error), (onError === "terminate" || error.type === "max-buffer-size-exceeded") && controller.error(error);
|
|
14
14
|
},
|
|
15
15
|
onRetry,
|
|
16
|
-
onComment
|
|
16
|
+
onComment,
|
|
17
|
+
maxBufferSize
|
|
17
18
|
});
|
|
18
19
|
},
|
|
19
20
|
transform(chunk) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stream.js","sources":["../src/stream.ts"],"sourcesContent":["import {createParser} from './parse.ts'\nimport type {EventSourceMessage, EventSourceParser} from './types.ts'\n\n/**\n * Options for the EventSourceParserStream.\n *\n * @public\n */\nexport interface StreamOptions {\n /**\n * Behavior when a parsing error occurs.\n *\n * - A custom function can be provided to handle the error.\n * - `'terminate'` will error the stream and stop parsing.\n * - Any other value will ignore the error and continue parsing.\n *\n * @defaultValue `undefined`\n */\n onError?: ('terminate' | ((error: Error) => void)) | undefined\n\n /**\n * Callback for when a reconnection interval is sent from the server.\n *\n * @param retry - The number of milliseconds to wait before reconnecting.\n */\n onRetry?: ((retry: number) => void) | undefined\n\n /**\n * Callback for when a comment is encountered in the stream.\n *\n * @param comment - The comment encountered in the stream.\n */\n onComment?: ((comment: string) => void) | undefined\n}\n\n/**\n * A TransformStream that ingests a stream of strings and produces a stream of `EventSourceMessage`.\n *\n * @example Basic usage\n * ```\n * const eventStream =\n * response.body\n * .pipeThrough(new TextDecoderStream())\n * .pipeThrough(new EventSourceParserStream())\n * ```\n *\n * @example Terminate stream on parsing errors\n * ```\n * const eventStream =\n * response.body\n * .pipeThrough(new TextDecoderStream())\n * .pipeThrough(new EventSourceParserStream({
|
|
1
|
+
{"version":3,"file":"stream.js","sources":["../src/stream.ts"],"sourcesContent":["import {createParser} from './parse.ts'\nimport type {EventSourceMessage, EventSourceParser} from './types.ts'\n\n/**\n * Options for the EventSourceParserStream.\n *\n * @public\n */\nexport interface StreamOptions {\n /**\n * Behavior when a parsing error occurs.\n *\n * - A custom function can be provided to handle the error.\n * - `'terminate'` will error the stream and stop parsing.\n * - Any other value will ignore the error and continue parsing.\n *\n * @defaultValue `undefined`\n */\n onError?: ('terminate' | ((error: Error) => void)) | undefined\n\n /**\n * Callback for when a reconnection interval is sent from the server.\n *\n * @param retry - The number of milliseconds to wait before reconnecting.\n */\n onRetry?: ((retry: number) => void) | undefined\n\n /**\n * Callback for when a comment is encountered in the stream.\n *\n * @param comment - The comment encountered in the stream.\n */\n onComment?: ((comment: string) => void) | undefined\n\n /**\n * Maximum number of characters the parser is allowed to buffer across calls to `feed()`.\n * See {@link ParserConfig.maxBufferSize} for details.\n *\n * When the limit is exceeded, the stream is always errored (regardless of the `onError`\n * setting) since the underlying parser is unrecoverable without a `reset()`.\n *\n * @defaultValue `undefined` (unbounded)\n */\n maxBufferSize?: number | undefined\n}\n\n/**\n * A TransformStream that ingests a stream of strings and produces a stream of `EventSourceMessage`.\n *\n * @example Basic usage\n * ```\n * const eventStream =\n * response.body\n * .pipeThrough(new TextDecoderStream())\n * .pipeThrough(new EventSourceParserStream())\n * ```\n *\n * @example Terminate stream on parsing errors\n * ```\n * const eventStream =\n * response.body\n * .pipeThrough(new TextDecoderStream())\n * .pipeThrough(new EventSourceParserStream({onError: 'terminate'}))\n * ```\n *\n * @public\n */\nexport class EventSourceParserStream extends TransformStream<string, EventSourceMessage> {\n constructor({onError, onRetry, onComment, maxBufferSize}: StreamOptions = {}) {\n let parser!: EventSourceParser\n\n super({\n start(controller) {\n parser = createParser({\n onEvent: (event) => {\n controller.enqueue(event)\n },\n onError(error) {\n if (typeof onError === 'function') {\n onError(error)\n }\n\n // `max-buffer-size-exceeded` is fatal — the parser is unusable until\n // `reset()`, which the stream wrapper has no way to call. Always\n // terminate the stream in that case so consumers see the meaningful\n // `ParseError` instead of an opaque \"cannot feed terminated parser\"\n // throw from the next chunk.\n if (onError === 'terminate' || error.type === 'max-buffer-size-exceeded') {\n controller.error(error)\n }\n\n // Ignore by default\n },\n onRetry,\n onComment,\n maxBufferSize,\n })\n },\n transform(chunk) {\n parser.feed(chunk)\n },\n })\n }\n}\n\nexport {type ErrorType, ParseError} from './errors.ts'\nexport type {EventSourceMessage} from './types.ts'\n"],"names":[],"mappings":";;AAmEO,MAAM,gCAAgC,gBAA4C;AAAA,EACvF,YAAY,EAAC,SAAS,SAAS,WAAW,cAAA,IAAgC,IAAI;AAC5E,QAAI;AAEJ,UAAM;AAAA,MACJ,MAAM,YAAY;AAChB,iBAAS,aAAa;AAAA,UACpB,SAAS,CAAC,UAAU;AAClB,uBAAW,QAAQ,KAAK;AAAA,UAC1B;AAAA,UACA,QAAQ,OAAO;AACT,mBAAO,WAAY,cACrB,QAAQ,KAAK,IAQX,YAAY,eAAe,MAAM,SAAS,+BAC5C,WAAW,MAAM,KAAK;AAAA,UAI1B;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QAAA,CACD;AAAA,MACH;AAAA,MACA,UAAU,OAAO;AACf,eAAO,KAAK,KAAK;AAAA,MACnB;AAAA,IAAA,CACD;AAAA,EACH;AACF;"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eventsource-parser",
|
|
3
|
-
"version": "3.0
|
|
3
|
+
"version": "3.1.0",
|
|
4
4
|
"description": "Streaming, source-agnostic EventSource/Server-Sent Events parser",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"eventsource",
|
|
@@ -63,21 +63,21 @@
|
|
|
63
63
|
"test:node": "vitest --reporter=verbose"
|
|
64
64
|
},
|
|
65
65
|
"devDependencies": {
|
|
66
|
-
"@sanity/pkg-utils": "^10.4.
|
|
66
|
+
"@sanity/pkg-utils": "^10.4.18",
|
|
67
67
|
"@sanity/semantic-release-preset": "^6.0.0",
|
|
68
68
|
"@sanity/tsconfig": "^2.1.0",
|
|
69
69
|
"@types/node": "^20.19.0",
|
|
70
|
-
"eventsource-encoder": "^1.0.
|
|
71
|
-
"knip": "^6.
|
|
70
|
+
"eventsource-encoder": "^1.0.2",
|
|
71
|
+
"knip": "^6.7.0",
|
|
72
72
|
"mitata": "^1.0.34",
|
|
73
|
-
"oxfmt": "^0.
|
|
74
|
-
"oxlint": "^1.
|
|
73
|
+
"oxfmt": "^0.47.0",
|
|
74
|
+
"oxlint": "^1.62.0",
|
|
75
75
|
"rimraf": "^6.1.3",
|
|
76
76
|
"rollup-plugin-visualizer": "^6.0.3",
|
|
77
77
|
"semantic-release": "^25.0.3",
|
|
78
|
-
"terser": "^5.46.
|
|
78
|
+
"terser": "^5.46.2",
|
|
79
79
|
"typescript": "^5.9.3",
|
|
80
|
-
"vitest": "^4.1.
|
|
80
|
+
"vitest": "^4.1.5"
|
|
81
81
|
},
|
|
82
82
|
"browserslist": [
|
|
83
83
|
"node >= 18",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* The type of error that occurred.
|
|
3
3
|
* @public
|
|
4
4
|
*/
|
|
5
|
-
export type ErrorType = 'invalid-retry' | 'unknown-field'
|
|
5
|
+
export type ErrorType = 'invalid-retry' | 'unknown-field' | 'max-buffer-size-exceeded'
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Error thrown when encountering an issue during parsing.
|
|
@@ -1,3 +1,8 @@
|
|
|
1
1
|
export {type ErrorType, ParseError} from './errors.ts'
|
|
2
2
|
export {createParser} from './parse.ts'
|
|
3
|
-
export type {
|
|
3
|
+
export type {
|
|
4
|
+
EventSourceMessage,
|
|
5
|
+
EventSourceParser,
|
|
6
|
+
ParserCallbacks,
|
|
7
|
+
ParserConfig,
|
|
8
|
+
} from './types.ts'
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* @see https://html.spec.whatwg.org/multipage/server-sent-events.html
|
|
4
4
|
*/
|
|
5
5
|
import {ParseError} from './errors.ts'
|
|
6
|
-
import type {EventSourceParser,
|
|
6
|
+
import type {EventSourceParser, ParserConfig} from './types.ts'
|
|
7
7
|
|
|
8
8
|
// ASCII codes used in the hot parsing paths.
|
|
9
9
|
const LF = 10
|
|
@@ -18,23 +18,20 @@ function noop(_arg: unknown) {
|
|
|
18
18
|
/**
|
|
19
19
|
* Creates a new EventSource parser.
|
|
20
20
|
*
|
|
21
|
-
* @param
|
|
22
|
-
*
|
|
23
|
-
* - `onError` when an error occurs
|
|
24
|
-
* - `onRetry` when a new reconnection interval has been sent from the server
|
|
25
|
-
* - `onComment` when a comment is encountered in the stream
|
|
21
|
+
* @param config - Parser configuration. Accepts callbacks (see {@link ParserCallbacks})
|
|
22
|
+
* and options like `maxBufferSize` (see {@link ParserConfig}).
|
|
26
23
|
*
|
|
27
|
-
* @returns A new EventSource parser, with `
|
|
24
|
+
* @returns A new EventSource parser, with `feed` and `reset` methods.
|
|
28
25
|
* @public
|
|
29
26
|
*/
|
|
30
|
-
export function createParser(
|
|
31
|
-
if (typeof
|
|
27
|
+
export function createParser(config: ParserConfig): EventSourceParser {
|
|
28
|
+
if (typeof config === 'function') {
|
|
32
29
|
throw new TypeError(
|
|
33
|
-
'`
|
|
30
|
+
'`config` must be an object, got a function instead. Did you mean `createParser({onEvent: fn})`?',
|
|
34
31
|
)
|
|
35
32
|
}
|
|
36
33
|
|
|
37
|
-
const {onEvent = noop, onError = noop, onRetry = noop, onComment} =
|
|
34
|
+
const {onEvent = noop, onError = noop, onRetry = noop, onComment, maxBufferSize} = config
|
|
38
35
|
|
|
39
36
|
// Trailing bytes from prior `feed()` calls that did not yet form a complete line.
|
|
40
37
|
// Stored as an array of fragments and only joined when a line terminator arrives.
|
|
@@ -44,12 +41,20 @@ export function createParser(callbacks: ParserCallbacks): EventSourceParser {
|
|
|
44
41
|
// makes the same workload linear.
|
|
45
42
|
const pendingFragments: string[] = []
|
|
46
43
|
|
|
44
|
+
// Running total of `pendingFragments` lengths, kept in sync with the array so the
|
|
45
|
+
// `maxBufferSize` check doesn't have to walk the fragment list on every feed.
|
|
46
|
+
let pendingFragmentsLength = 0
|
|
47
|
+
|
|
47
48
|
let isFirstChunk = true
|
|
48
49
|
let id: string | undefined
|
|
49
50
|
let data = ''
|
|
50
51
|
let dataLines = 0
|
|
51
52
|
let eventType: string | undefined
|
|
52
53
|
|
|
54
|
+
// Set after a `maxBufferSize` overflow. Once tripped, `feed()` throws until
|
|
55
|
+
// `reset()` is called — see the comment on `maxBufferSize` in `ParserConfig`.
|
|
56
|
+
let terminated = false
|
|
57
|
+
|
|
53
58
|
/**
|
|
54
59
|
* Feeds a chunk of the SSE stream to the parser. Any trailing bytes that do
|
|
55
60
|
* not yet form a complete line are held back and prepended to the next chunk,
|
|
@@ -62,6 +67,12 @@ export function createParser(callbacks: ParserCallbacks): EventSourceParser {
|
|
|
62
67
|
* @see https://html.spec.whatwg.org/multipage/server-sent-events.html#parsing-an-event-stream
|
|
63
68
|
*/
|
|
64
69
|
function feed(chunk: string) {
|
|
70
|
+
if (terminated) {
|
|
71
|
+
throw new Error(
|
|
72
|
+
'Cannot feed parser: it was terminated after exceeding the configured max buffer size. Call `reset()` to resume parsing.',
|
|
73
|
+
)
|
|
74
|
+
}
|
|
75
|
+
|
|
65
76
|
if (isFirstChunk) {
|
|
66
77
|
isFirstChunk = false
|
|
67
78
|
// Match and strip UTF-8 BOM from the start of the stream, if present.
|
|
@@ -80,7 +91,11 @@ export function createParser(callbacks: ParserCallbacks): EventSourceParser {
|
|
|
80
91
|
// Zero new work in the common case (every chunk ends with `\n\n`).
|
|
81
92
|
if (pendingFragments.length === 0) {
|
|
82
93
|
const trailing = processLines(chunk)
|
|
83
|
-
if (trailing !== '')
|
|
94
|
+
if (trailing !== '') {
|
|
95
|
+
pendingFragments.push(trailing)
|
|
96
|
+
pendingFragmentsLength = trailing.length
|
|
97
|
+
}
|
|
98
|
+
checkBufferSize()
|
|
84
99
|
return
|
|
85
100
|
}
|
|
86
101
|
|
|
@@ -89,6 +104,8 @@ export function createParser(callbacks: ParserCallbacks): EventSourceParser {
|
|
|
89
104
|
// avoiding (large single `data:` payload split across many tiny chunks).
|
|
90
105
|
if (chunk.indexOf('\n') === -1 && chunk.indexOf('\r') === -1) {
|
|
91
106
|
pendingFragments.push(chunk)
|
|
107
|
+
pendingFragmentsLength += chunk.length
|
|
108
|
+
checkBufferSize()
|
|
92
109
|
return
|
|
93
110
|
}
|
|
94
111
|
|
|
@@ -97,8 +114,31 @@ export function createParser(callbacks: ParserCallbacks): EventSourceParser {
|
|
|
97
114
|
pendingFragments.push(chunk)
|
|
98
115
|
const input = pendingFragments.join('')
|
|
99
116
|
pendingFragments.length = 0
|
|
117
|
+
pendingFragmentsLength = 0
|
|
100
118
|
const trailing = processLines(input)
|
|
101
|
-
if (trailing !== '')
|
|
119
|
+
if (trailing !== '') {
|
|
120
|
+
pendingFragments.push(trailing)
|
|
121
|
+
pendingFragmentsLength = trailing.length
|
|
122
|
+
}
|
|
123
|
+
checkBufferSize()
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function checkBufferSize() {
|
|
127
|
+
if (maxBufferSize === undefined) return
|
|
128
|
+
if (pendingFragmentsLength + data.length <= maxBufferSize) return
|
|
129
|
+
|
|
130
|
+
terminated = true
|
|
131
|
+
pendingFragments.length = 0
|
|
132
|
+
pendingFragmentsLength = 0
|
|
133
|
+
id = undefined
|
|
134
|
+
data = ''
|
|
135
|
+
dataLines = 0
|
|
136
|
+
eventType = undefined
|
|
137
|
+
onError(
|
|
138
|
+
new ParseError(`Buffered data exceeded max buffer size of ${maxBufferSize} characters`, {
|
|
139
|
+
type: 'max-buffer-size-exceeded',
|
|
140
|
+
}),
|
|
141
|
+
)
|
|
102
142
|
}
|
|
103
143
|
|
|
104
144
|
/**
|
|
@@ -350,6 +390,8 @@ export function createParser(callbacks: ParserCallbacks): EventSourceParser {
|
|
|
350
390
|
dataLines = 0
|
|
351
391
|
eventType = undefined
|
|
352
392
|
pendingFragments.length = 0
|
|
393
|
+
pendingFragmentsLength = 0
|
|
394
|
+
terminated = false
|
|
353
395
|
}
|
|
354
396
|
|
|
355
397
|
return {feed, reset}
|
|
@@ -31,6 +31,17 @@ export interface StreamOptions {
|
|
|
31
31
|
* @param comment - The comment encountered in the stream.
|
|
32
32
|
*/
|
|
33
33
|
onComment?: ((comment: string) => void) | undefined
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Maximum number of characters the parser is allowed to buffer across calls to `feed()`.
|
|
37
|
+
* See {@link ParserConfig.maxBufferSize} for details.
|
|
38
|
+
*
|
|
39
|
+
* When the limit is exceeded, the stream is always errored (regardless of the `onError`
|
|
40
|
+
* setting) since the underlying parser is unrecoverable without a `reset()`.
|
|
41
|
+
*
|
|
42
|
+
* @defaultValue `undefined` (unbounded)
|
|
43
|
+
*/
|
|
44
|
+
maxBufferSize?: number | undefined
|
|
34
45
|
}
|
|
35
46
|
|
|
36
47
|
/**
|
|
@@ -49,13 +60,13 @@ export interface StreamOptions {
|
|
|
49
60
|
* const eventStream =
|
|
50
61
|
* response.body
|
|
51
62
|
* .pipeThrough(new TextDecoderStream())
|
|
52
|
-
* .pipeThrough(new EventSourceParserStream({
|
|
63
|
+
* .pipeThrough(new EventSourceParserStream({onError: 'terminate'}))
|
|
53
64
|
* ```
|
|
54
65
|
*
|
|
55
66
|
* @public
|
|
56
67
|
*/
|
|
57
68
|
export class EventSourceParserStream extends TransformStream<string, EventSourceMessage> {
|
|
58
|
-
constructor({onError, onRetry, onComment}: StreamOptions = {}) {
|
|
69
|
+
constructor({onError, onRetry, onComment, maxBufferSize}: StreamOptions = {}) {
|
|
59
70
|
let parser!: EventSourceParser
|
|
60
71
|
|
|
61
72
|
super({
|
|
@@ -65,16 +76,24 @@ export class EventSourceParserStream extends TransformStream<string, EventSource
|
|
|
65
76
|
controller.enqueue(event)
|
|
66
77
|
},
|
|
67
78
|
onError(error) {
|
|
68
|
-
if (onError === '
|
|
69
|
-
controller.error(error)
|
|
70
|
-
} else if (typeof onError === 'function') {
|
|
79
|
+
if (typeof onError === 'function') {
|
|
71
80
|
onError(error)
|
|
72
81
|
}
|
|
73
82
|
|
|
83
|
+
// `max-buffer-size-exceeded` is fatal — the parser is unusable until
|
|
84
|
+
// `reset()`, which the stream wrapper has no way to call. Always
|
|
85
|
+
// terminate the stream in that case so consumers see the meaningful
|
|
86
|
+
// `ParseError` instead of an opaque "cannot feed terminated parser"
|
|
87
|
+
// throw from the next chunk.
|
|
88
|
+
if (onError === 'terminate' || error.type === 'max-buffer-size-exceeded') {
|
|
89
|
+
controller.error(error)
|
|
90
|
+
}
|
|
91
|
+
|
|
74
92
|
// Ignore by default
|
|
75
93
|
},
|
|
76
94
|
onRetry,
|
|
77
95
|
onComment,
|
|
96
|
+
maxBufferSize,
|
|
78
97
|
})
|
|
79
98
|
},
|
|
80
99
|
transform(chunk) {
|
|
@@ -95,3 +95,28 @@ export interface ParserCallbacks {
|
|
|
95
95
|
*/
|
|
96
96
|
onError?: ((error: ParseError) => void) | undefined
|
|
97
97
|
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Configuration accepted by {@link createParser}. Extends {@link ParserCallbacks} with
|
|
101
|
+
* additional options that control parser behavior.
|
|
102
|
+
*
|
|
103
|
+
* @public
|
|
104
|
+
*/
|
|
105
|
+
export interface ParserConfig extends ParserCallbacks {
|
|
106
|
+
/**
|
|
107
|
+
* Maximum number of characters the parser is allowed to buffer across calls to `feed()`.
|
|
108
|
+
*
|
|
109
|
+
* Two unbounded surfaces exist in a streaming SSE parser:
|
|
110
|
+
* - A partial line that has not yet been terminated by `\n`, `\r`, or `\r\n`.
|
|
111
|
+
* - A multi-line event whose terminating blank line has not yet arrived (each `data:`
|
|
112
|
+
* field gets appended to the buffered event).
|
|
113
|
+
*
|
|
114
|
+
* When the combined size of these buffers exceeds `maxBufferSize`, the parser emits a
|
|
115
|
+
* `ParseError` with `type: 'max-buffer-size-exceeded'` to `onError` and becomes
|
|
116
|
+
* terminated — subsequent calls to `feed()` will throw until `reset()` is called.
|
|
117
|
+
* This protects against unbounded memory growth from malformed or malicious streams.
|
|
118
|
+
*
|
|
119
|
+
* @defaultValue `undefined` (unbounded)
|
|
120
|
+
*/
|
|
121
|
+
maxBufferSize?: number | undefined
|
|
122
|
+
}
|
|
@@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [v2.0.4](https://github.com/inspect-js/hasOwn/compare/v2.0.3...v2.0.4) - 2026-05-28
|
|
9
|
+
|
|
10
|
+
### Commits
|
|
11
|
+
|
|
12
|
+
- [types] drop the dead key-narrowing overload [`fdab00e`](https://github.com/inspect-js/hasOwn/commit/fdab00e2703e65411424e19bf86a7e72a8f10da9)
|
|
13
|
+
- [Dev Deps] update `@ljharb/eslint-config`, `auto-changelog`, `eslint` [`91f6247`](https://github.com/inspect-js/hasOwn/commit/91f624768dd0f7db0d019b89d4d86bd66e20ec30)
|
|
14
|
+
|
|
8
15
|
## [v2.0.3](https://github.com/inspect-js/hasOwn/compare/v2.0.2...v2.0.3) - 2026-04-17
|
|
9
16
|
|
|
10
17
|
### Commits
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hasown",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.4",
|
|
4
4
|
"description": "A robust, ES3 compatible, \"has own property\" predicate.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"exports": {
|
|
@@ -52,13 +52,12 @@
|
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@arethetypeswrong/cli": "^0.18.2",
|
|
55
|
-
"@ljharb/eslint-config": "^22.2.
|
|
55
|
+
"@ljharb/eslint-config": "^22.2.3",
|
|
56
56
|
"@ljharb/tsconfig": "^0.3.2",
|
|
57
57
|
"@types/function-bind": "^1.1.10",
|
|
58
58
|
"@types/tape": "^5.8.1",
|
|
59
|
-
"auto-changelog": "^2.5.
|
|
60
|
-
"
|
|
61
|
-
"eslint": "^10.2.0",
|
|
59
|
+
"auto-changelog": "^2.5.1",
|
|
60
|
+
"eslint": "^10.4.0",
|
|
62
61
|
"evalmd": "^0.0.19",
|
|
63
62
|
"in-publish": "^2.0.1",
|
|
64
63
|
"jiti": "^0.0.0",
|
|
@@ -17,11 +17,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
17
17
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
18
|
var index_exports = {};
|
|
19
19
|
__export(index_exports, {
|
|
20
|
+
Context: () => import_context.Context,
|
|
20
21
|
Hono: () => import_hono.Hono
|
|
21
22
|
});
|
|
22
23
|
module.exports = __toCommonJS(index_exports);
|
|
23
24
|
var import_hono = require("./hono");
|
|
25
|
+
var import_context = require("./context");
|
|
24
26
|
// Annotate the CommonJS export names for ESM import in node:
|
|
25
27
|
0 && (module.exports = {
|
|
28
|
+
Context,
|
|
26
29
|
Hono
|
|
27
30
|
});
|
|
@@ -17,6 +17,7 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
17
17
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
18
|
var compress_exports = {};
|
|
19
19
|
__export(compress_exports, {
|
|
20
|
+
COMPRESSIBLE_CONTENT_TYPE_REGEX: () => import_compress.COMPRESSIBLE_CONTENT_TYPE_REGEX,
|
|
20
21
|
compress: () => compress
|
|
21
22
|
});
|
|
22
23
|
module.exports = __toCommonJS(compress_exports);
|
|
@@ -45,6 +46,14 @@ const selectEncoding = (header, candidates) => {
|
|
|
45
46
|
const compress = (options) => {
|
|
46
47
|
const threshold = options?.threshold ?? 1024;
|
|
47
48
|
const candidates = options?.encoding ? [options.encoding] : ENCODING_TYPES;
|
|
49
|
+
const contentTypeFilter = options?.contentTypeFilter ?? import_compress.COMPRESSIBLE_CONTENT_TYPE_REGEX;
|
|
50
|
+
const shouldCompress = typeof contentTypeFilter === "function" ? (res) => {
|
|
51
|
+
const type = res.headers.get("Content-Type");
|
|
52
|
+
return type && contentTypeFilter(type);
|
|
53
|
+
} : (res) => {
|
|
54
|
+
const type = res.headers.get("Content-Type");
|
|
55
|
+
return type && contentTypeFilter.test(type);
|
|
56
|
+
};
|
|
48
57
|
return async function compress2(ctx, next) {
|
|
49
58
|
await next();
|
|
50
59
|
const contentLength = ctx.res.headers.get("Content-Length");
|
|
@@ -71,15 +80,12 @@ const compress = (options) => {
|
|
|
71
80
|
}
|
|
72
81
|
};
|
|
73
82
|
};
|
|
74
|
-
const shouldCompress = (res) => {
|
|
75
|
-
const type = res.headers.get("Content-Type");
|
|
76
|
-
return type && import_compress.COMPRESSIBLE_CONTENT_TYPE_REGEX.test(type);
|
|
77
|
-
};
|
|
78
83
|
const shouldTransform = (res) => {
|
|
79
84
|
const cacheControl = res.headers.get("Cache-Control");
|
|
80
85
|
return !cacheControl || !cacheControlNoTransformRegExp.test(cacheControl);
|
|
81
86
|
};
|
|
82
87
|
// Annotate the CommonJS export names for ESM import in node:
|
|
83
88
|
0 && (module.exports = {
|
|
89
|
+
COMPRESSIBLE_CONTENT_TYPE_REGEX,
|
|
84
90
|
compress
|
|
85
91
|
});
|
|
@@ -42,7 +42,7 @@ const getFilePathWithoutDefaultDocument = (options) => {
|
|
|
42
42
|
return;
|
|
43
43
|
}
|
|
44
44
|
filename = filename.replace(/^\.?[\/\\]/, "");
|
|
45
|
-
filename = filename.replace(
|
|
45
|
+
filename = filename.replace(/\\/g, "/");
|
|
46
46
|
root = root.replace(/\/$/, "");
|
|
47
47
|
let path = root ? root + "/" + filename : filename;
|
|
48
48
|
path = path.replace(/^\.?\//, "");
|
|
@@ -294,7 +294,7 @@ const convertIPv6BinaryToString = (ipV6) => {
|
|
|
294
294
|
maxZeroEnd = 8;
|
|
295
295
|
}
|
|
296
296
|
}
|
|
297
|
-
if (maxZeroStart !== -1) {
|
|
297
|
+
if (maxZeroStart !== -1 && maxZeroEnd - maxZeroStart > 1) {
|
|
298
298
|
sections.splice(maxZeroStart, maxZeroEnd - maxZeroStart, ":");
|
|
299
299
|
}
|
|
300
300
|
return sections.join(":").replace(/:{2,}/g, "::");
|
|
@@ -24,6 +24,14 @@ var selectEncoding = (header, candidates) => {
|
|
|
24
24
|
var compress = (options) => {
|
|
25
25
|
const threshold = options?.threshold ?? 1024;
|
|
26
26
|
const candidates = options?.encoding ? [options.encoding] : ENCODING_TYPES;
|
|
27
|
+
const contentTypeFilter = options?.contentTypeFilter ?? COMPRESSIBLE_CONTENT_TYPE_REGEX;
|
|
28
|
+
const shouldCompress = typeof contentTypeFilter === "function" ? (res) => {
|
|
29
|
+
const type = res.headers.get("Content-Type");
|
|
30
|
+
return type && contentTypeFilter(type);
|
|
31
|
+
} : (res) => {
|
|
32
|
+
const type = res.headers.get("Content-Type");
|
|
33
|
+
return type && contentTypeFilter.test(type);
|
|
34
|
+
};
|
|
27
35
|
return async function compress2(ctx, next) {
|
|
28
36
|
await next();
|
|
29
37
|
const contentLength = ctx.res.headers.get("Content-Length");
|
|
@@ -50,14 +58,11 @@ var compress = (options) => {
|
|
|
50
58
|
}
|
|
51
59
|
};
|
|
52
60
|
};
|
|
53
|
-
var shouldCompress = (res) => {
|
|
54
|
-
const type = res.headers.get("Content-Type");
|
|
55
|
-
return type && COMPRESSIBLE_CONTENT_TYPE_REGEX.test(type);
|
|
56
|
-
};
|
|
57
61
|
var shouldTransform = (res) => {
|
|
58
62
|
const cacheControl = res.headers.get("Cache-Control");
|
|
59
63
|
return !cacheControl || !cacheControlNoTransformRegExp.test(cacheControl);
|
|
60
64
|
};
|
|
61
65
|
export {
|
|
66
|
+
COMPRESSIBLE_CONTENT_TYPE_REGEX,
|
|
62
67
|
compress
|
|
63
68
|
};
|