@suveren/gateway 0.7.3 → 0.7.4

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 (49) hide show
  1. package/content/integrations/gmail.json +3 -6
  2. package/dist/control-plane/index.mjs +46 -4
  3. package/dist/mcp-server/http.mjs +59 -8
  4. package/dist/ui/assets/{index-DdJeSfV9.js → index-0Q2eNytX.js} +10 -10
  5. package/dist/ui/index.html +1 -1
  6. package/node_modules/@hono/node-server/dist/index.cjs +151 -9
  7. package/node_modules/@hono/node-server/dist/index.mjs +151 -9
  8. package/node_modules/@hono/node-server/package.json +1 -1
  9. package/node_modules/@modelcontextprotocol/sdk/node_modules/body-parser/node_modules/content-type/README.md +2 -0
  10. package/node_modules/@modelcontextprotocol/sdk/node_modules/body-parser/node_modules/content-type/dist/index.d.ts +20 -0
  11. package/node_modules/@modelcontextprotocol/sdk/node_modules/body-parser/node_modules/content-type/dist/index.js +20 -14
  12. package/node_modules/@modelcontextprotocol/sdk/node_modules/body-parser/node_modules/content-type/dist/index.js.map +1 -1
  13. package/node_modules/@modelcontextprotocol/sdk/node_modules/body-parser/node_modules/content-type/package.json +1 -1
  14. package/node_modules/@modelcontextprotocol/sdk/node_modules/type-is/node_modules/content-type/README.md +2 -0
  15. package/node_modules/@modelcontextprotocol/sdk/node_modules/type-is/node_modules/content-type/dist/index.d.ts +20 -0
  16. package/node_modules/@modelcontextprotocol/sdk/node_modules/type-is/node_modules/content-type/dist/index.js +20 -14
  17. package/node_modules/@modelcontextprotocol/sdk/node_modules/type-is/node_modules/content-type/dist/index.js.map +1 -1
  18. package/node_modules/@modelcontextprotocol/sdk/node_modules/type-is/node_modules/content-type/package.json +1 -1
  19. package/node_modules/eventsource-parser/dist/index.cjs +2 -2
  20. package/node_modules/eventsource-parser/dist/index.cjs.map +1 -1
  21. package/node_modules/eventsource-parser/dist/index.js +2 -2
  22. package/node_modules/eventsource-parser/dist/index.js.map +1 -1
  23. package/node_modules/eventsource-parser/package.json +1 -1
  24. package/node_modules/eventsource-parser/src/parse.ts +4 -2
  25. package/node_modules/hono/dist/cjs/client/client.js +3 -3
  26. package/node_modules/hono/dist/cjs/jsx/intrinsic-element/components.js +1 -1
  27. package/node_modules/hono/dist/cjs/middleware/cors/index.js +15 -12
  28. package/node_modules/hono/dist/cjs/middleware/etag/digest.js +47 -1
  29. package/node_modules/hono/dist/cjs/middleware/secure-headers/secure-headers.js +6 -3
  30. package/node_modules/hono/dist/cjs/utils/url.js +2 -2
  31. package/node_modules/hono/dist/client/client.js +3 -3
  32. package/node_modules/hono/dist/jsx/intrinsic-element/components.js +1 -1
  33. package/node_modules/hono/dist/middleware/cors/index.js +15 -12
  34. package/node_modules/hono/dist/middleware/etag/digest.js +47 -1
  35. package/node_modules/hono/dist/middleware/secure-headers/secure-headers.js +6 -3
  36. package/node_modules/hono/dist/types/middleware/secure-headers/permissions-policy.d.ts +3 -3
  37. package/node_modules/hono/dist/utils/url.js +2 -2
  38. package/node_modules/hono/package.json +1 -1
  39. package/node_modules/ip-address/README.md +134 -134
  40. package/node_modules/ip-address/dist/address-error.d.ts +11 -0
  41. package/node_modules/ip-address/dist/address-error.js.map +1 -1
  42. package/node_modules/ip-address/dist/ipv4.d.ts +22 -6
  43. package/node_modules/ip-address/dist/ipv4.js +22 -6
  44. package/node_modules/ip-address/dist/ipv4.js.map +1 -1
  45. package/node_modules/ip-address/dist/ipv6.d.ts +10 -3
  46. package/node_modules/ip-address/dist/ipv6.js +26 -17
  47. package/node_modules/ip-address/dist/ipv6.js.map +1 -1
  48. package/node_modules/ip-address/package.json +1 -1
  49. package/package.json +2 -2
@@ -8,7 +8,7 @@
8
8
  because tab chrome does. -->
9
9
  <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
10
10
  <title>Suveren</title>
11
- <script type="module" crossorigin src="/assets/index-DdJeSfV9.js"></script>
11
+ <script type="module" crossorigin src="/assets/index-0Q2eNytX.js"></script>
12
12
  <link rel="stylesheet" crossorigin href="/assets/index-CkWaRck1.css">
13
13
  </head>
14
14
  <body>
@@ -13,6 +13,157 @@ var RequestError = class extends Error {
13
13
  }
14
14
  };
15
15
 
16
+ //#endregion
17
+ //#region src/headers.ts
18
+ const nonJoinedHeaders = new Set([
19
+ "age",
20
+ "authorization",
21
+ "content-length",
22
+ "content-type",
23
+ "etag",
24
+ "expires",
25
+ "from",
26
+ "host",
27
+ "if-modified-since",
28
+ "if-unmodified-since",
29
+ "last-modified",
30
+ "location",
31
+ "max-forwards",
32
+ "proxy-authorization",
33
+ "referer",
34
+ "retry-after",
35
+ "server",
36
+ "user-agent"
37
+ ]);
38
+ const validHeaderName = /^[!#$%&'*+\-.^_`|~\dA-Za-z]+$/;
39
+ const isHttpWhitespace = (code) => code === 9 || code === 10 || code === 13 || code === 32;
40
+ const normalizeHeaderValue = (value) => {
41
+ if (!isHttpWhitespace(value.charCodeAt(0)) && !isHttpWhitespace(value.charCodeAt(value.length - 1))) return value;
42
+ let start = 0;
43
+ let end = value.length;
44
+ while (start < end && isHttpWhitespace(value.charCodeAt(start))) start++;
45
+ while (end > start && isHttpWhitespace(value.charCodeAt(end - 1))) end--;
46
+ return value.slice(start, end);
47
+ };
48
+ const forbiddenHeaderValue = /[\0\r\n]/;
49
+ const GlobalHeaders = globalThis.Headers;
50
+ const materializeHeaders = (rawHeaders, HeadersCtor = GlobalHeaders) => {
51
+ const headers = new HeadersCtor();
52
+ for (let i = 0; i < rawHeaders.length; i += 2) {
53
+ const name = rawHeaders[i];
54
+ if (!name.startsWith(":")) headers.append(name, rawHeaders[i + 1]);
55
+ }
56
+ return headers;
57
+ };
58
+ var RequestHeaders = class {
59
+ #incoming;
60
+ #rawHeaders;
61
+ #headers;
62
+ #invalidValue;
63
+ constructor(incoming) {
64
+ this.#incoming = incoming;
65
+ if (incoming instanceof node_http2.Http2ServerRequest) this.#rawHeaders = incoming.rawHeaders.slice();
66
+ }
67
+ get #lazyRawHeaders() {
68
+ return this.#rawHeaders ??= this.#incoming.rawHeaders.slice();
69
+ }
70
+ get #native() {
71
+ if (!this.#headers) {
72
+ this.#headers = materializeHeaders(this.#lazyRawHeaders);
73
+ this.#rawHeaders = void 0;
74
+ }
75
+ return this.#headers;
76
+ }
77
+ #normalizedName(name) {
78
+ if (typeof name !== "string") return;
79
+ if (!validHeaderName.test(name)) throw new TypeError(`Invalid header name: ${name}`);
80
+ return name.toLowerCase();
81
+ }
82
+ #lookupHttp1(lowerName) {
83
+ const headers = this.#incoming instanceof node_http2.Http2ServerRequest ? void 0 : this.#incoming.headers;
84
+ if (!headers || nonJoinedHeaders.has(lowerName) || lowerName === "set-cookie" || lowerName === "__proto__") return;
85
+ if (!Object.hasOwn(headers, lowerName)) return null;
86
+ const rawValue = headers[lowerName];
87
+ if (typeof rawValue === "string") {
88
+ const value = normalizeHeaderValue(rawValue);
89
+ return forbiddenHeaderValue.test(value) ? void 0 : value;
90
+ }
91
+ }
92
+ #lookup(rawHeaders, lowerName) {
93
+ const separator = lowerName === "cookie" ? "; " : ", ";
94
+ let value = null;
95
+ for (let i = 0; i < rawHeaders.length; i += 2) {
96
+ const rawName = rawHeaders[i];
97
+ if (rawName.length === lowerName.length && rawName.toLowerCase() === lowerName) {
98
+ const rawValue = normalizeHeaderValue(rawHeaders[i + 1]);
99
+ if (forbiddenHeaderValue.test(rawValue)) {
100
+ this.#invalidValue = true;
101
+ return;
102
+ }
103
+ value = value === null ? rawValue : value + separator + rawValue;
104
+ }
105
+ }
106
+ return value;
107
+ }
108
+ append(name, value) {
109
+ this.#native.append(name, value);
110
+ }
111
+ delete(name) {
112
+ this.#native.delete(name);
113
+ }
114
+ get(name) {
115
+ const lowerName = this.#normalizedName(name);
116
+ if (lowerName && !this.#headers && !this.#invalidValue) {
117
+ const http1Value = this.#lookupHttp1(lowerName);
118
+ if (http1Value !== void 0) return http1Value;
119
+ const value = this.#lookup(this.#lazyRawHeaders, lowerName);
120
+ if (value !== void 0) return value;
121
+ }
122
+ return this.#native.get(name);
123
+ }
124
+ has(name) {
125
+ const lowerName = this.#normalizedName(name);
126
+ if (lowerName && !this.#headers && !this.#invalidValue) {
127
+ const http1Value = this.#lookupHttp1(lowerName);
128
+ if (http1Value !== void 0) return http1Value !== null;
129
+ const value = this.#lookup(this.#lazyRawHeaders, lowerName);
130
+ if (value !== void 0) return value !== null;
131
+ }
132
+ return this.#native.has(name);
133
+ }
134
+ set(name, value) {
135
+ this.#native.set(name, value);
136
+ }
137
+ getSetCookie() {
138
+ return this.#native.getSetCookie();
139
+ }
140
+ keys() {
141
+ return this.#native.keys();
142
+ }
143
+ values() {
144
+ return this.#native.values();
145
+ }
146
+ entries() {
147
+ return this.#native.entries();
148
+ }
149
+ forEach(callback, thisArg) {
150
+ this.#native.forEach((value, key) => {
151
+ callback.call(thisArg, value, key, this);
152
+ });
153
+ }
154
+ [Symbol.iterator]() {
155
+ return this.entries();
156
+ }
157
+ };
158
+ Object.defineProperty(RequestHeaders.prototype, Symbol.for("nodejs.util.inspect.custom"), { value: function(depth, options, inspectFn) {
159
+ return `Headers (lightweight) ${inspectFn(Object.fromEntries(this), {
160
+ ...options,
161
+ depth: depth == null ? null : depth - 1
162
+ })}`;
163
+ } });
164
+ Object.setPrototypeOf(RequestHeaders.prototype, GlobalHeaders.prototype);
165
+ const newHeadersFromIncoming = (incoming) => globalThis.Headers === GlobalHeaders ? new RequestHeaders(incoming) : materializeHeaders(incoming.rawHeaders, globalThis.Headers);
166
+
16
167
  //#endregion
17
168
  //#region src/url.ts
18
169
  const reValidRequestUrl = /^\/[!#$&-;=?-\[\]_a-z~]*$/;
@@ -50,15 +201,6 @@ var Request$1 = class extends GlobalRequest {
50
201
  super(input, options);
51
202
  }
52
203
  };
53
- const newHeadersFromIncoming = (incoming) => {
54
- const headerRecord = [];
55
- const rawHeaders = incoming.rawHeaders;
56
- for (let i = 0, len = rawHeaders.length; i < len; i += 2) {
57
- const key = rawHeaders[i];
58
- if (key.charCodeAt(0) !== 58) headerRecord.push([key, rawHeaders[i + 1]]);
59
- }
60
- return new Headers(headerRecord);
61
- };
62
204
  const wrapBodyStream = Symbol("wrapBodyStream");
63
205
  const byteExactEncodings = new Set([
64
206
  "latin1",
@@ -12,6 +12,157 @@ var RequestError = class extends Error {
12
12
  }
13
13
  };
14
14
 
15
+ //#endregion
16
+ //#region src/headers.ts
17
+ const nonJoinedHeaders = new Set([
18
+ "age",
19
+ "authorization",
20
+ "content-length",
21
+ "content-type",
22
+ "etag",
23
+ "expires",
24
+ "from",
25
+ "host",
26
+ "if-modified-since",
27
+ "if-unmodified-since",
28
+ "last-modified",
29
+ "location",
30
+ "max-forwards",
31
+ "proxy-authorization",
32
+ "referer",
33
+ "retry-after",
34
+ "server",
35
+ "user-agent"
36
+ ]);
37
+ const validHeaderName = /^[!#$%&'*+\-.^_`|~\dA-Za-z]+$/;
38
+ const isHttpWhitespace = (code) => code === 9 || code === 10 || code === 13 || code === 32;
39
+ const normalizeHeaderValue = (value) => {
40
+ if (!isHttpWhitespace(value.charCodeAt(0)) && !isHttpWhitespace(value.charCodeAt(value.length - 1))) return value;
41
+ let start = 0;
42
+ let end = value.length;
43
+ while (start < end && isHttpWhitespace(value.charCodeAt(start))) start++;
44
+ while (end > start && isHttpWhitespace(value.charCodeAt(end - 1))) end--;
45
+ return value.slice(start, end);
46
+ };
47
+ const forbiddenHeaderValue = /[\0\r\n]/;
48
+ const GlobalHeaders = globalThis.Headers;
49
+ const materializeHeaders = (rawHeaders, HeadersCtor = GlobalHeaders) => {
50
+ const headers = new HeadersCtor();
51
+ for (let i = 0; i < rawHeaders.length; i += 2) {
52
+ const name = rawHeaders[i];
53
+ if (!name.startsWith(":")) headers.append(name, rawHeaders[i + 1]);
54
+ }
55
+ return headers;
56
+ };
57
+ var RequestHeaders = class {
58
+ #incoming;
59
+ #rawHeaders;
60
+ #headers;
61
+ #invalidValue;
62
+ constructor(incoming) {
63
+ this.#incoming = incoming;
64
+ if (incoming instanceof Http2ServerRequest) this.#rawHeaders = incoming.rawHeaders.slice();
65
+ }
66
+ get #lazyRawHeaders() {
67
+ return this.#rawHeaders ??= this.#incoming.rawHeaders.slice();
68
+ }
69
+ get #native() {
70
+ if (!this.#headers) {
71
+ this.#headers = materializeHeaders(this.#lazyRawHeaders);
72
+ this.#rawHeaders = void 0;
73
+ }
74
+ return this.#headers;
75
+ }
76
+ #normalizedName(name) {
77
+ if (typeof name !== "string") return;
78
+ if (!validHeaderName.test(name)) throw new TypeError(`Invalid header name: ${name}`);
79
+ return name.toLowerCase();
80
+ }
81
+ #lookupHttp1(lowerName) {
82
+ const headers = this.#incoming instanceof Http2ServerRequest ? void 0 : this.#incoming.headers;
83
+ if (!headers || nonJoinedHeaders.has(lowerName) || lowerName === "set-cookie" || lowerName === "__proto__") return;
84
+ if (!Object.hasOwn(headers, lowerName)) return null;
85
+ const rawValue = headers[lowerName];
86
+ if (typeof rawValue === "string") {
87
+ const value = normalizeHeaderValue(rawValue);
88
+ return forbiddenHeaderValue.test(value) ? void 0 : value;
89
+ }
90
+ }
91
+ #lookup(rawHeaders, lowerName) {
92
+ const separator = lowerName === "cookie" ? "; " : ", ";
93
+ let value = null;
94
+ for (let i = 0; i < rawHeaders.length; i += 2) {
95
+ const rawName = rawHeaders[i];
96
+ if (rawName.length === lowerName.length && rawName.toLowerCase() === lowerName) {
97
+ const rawValue = normalizeHeaderValue(rawHeaders[i + 1]);
98
+ if (forbiddenHeaderValue.test(rawValue)) {
99
+ this.#invalidValue = true;
100
+ return;
101
+ }
102
+ value = value === null ? rawValue : value + separator + rawValue;
103
+ }
104
+ }
105
+ return value;
106
+ }
107
+ append(name, value) {
108
+ this.#native.append(name, value);
109
+ }
110
+ delete(name) {
111
+ this.#native.delete(name);
112
+ }
113
+ get(name) {
114
+ const lowerName = this.#normalizedName(name);
115
+ if (lowerName && !this.#headers && !this.#invalidValue) {
116
+ const http1Value = this.#lookupHttp1(lowerName);
117
+ if (http1Value !== void 0) return http1Value;
118
+ const value = this.#lookup(this.#lazyRawHeaders, lowerName);
119
+ if (value !== void 0) return value;
120
+ }
121
+ return this.#native.get(name);
122
+ }
123
+ has(name) {
124
+ const lowerName = this.#normalizedName(name);
125
+ if (lowerName && !this.#headers && !this.#invalidValue) {
126
+ const http1Value = this.#lookupHttp1(lowerName);
127
+ if (http1Value !== void 0) return http1Value !== null;
128
+ const value = this.#lookup(this.#lazyRawHeaders, lowerName);
129
+ if (value !== void 0) return value !== null;
130
+ }
131
+ return this.#native.has(name);
132
+ }
133
+ set(name, value) {
134
+ this.#native.set(name, value);
135
+ }
136
+ getSetCookie() {
137
+ return this.#native.getSetCookie();
138
+ }
139
+ keys() {
140
+ return this.#native.keys();
141
+ }
142
+ values() {
143
+ return this.#native.values();
144
+ }
145
+ entries() {
146
+ return this.#native.entries();
147
+ }
148
+ forEach(callback, thisArg) {
149
+ this.#native.forEach((value, key) => {
150
+ callback.call(thisArg, value, key, this);
151
+ });
152
+ }
153
+ [Symbol.iterator]() {
154
+ return this.entries();
155
+ }
156
+ };
157
+ Object.defineProperty(RequestHeaders.prototype, Symbol.for("nodejs.util.inspect.custom"), { value: function(depth, options, inspectFn) {
158
+ return `Headers (lightweight) ${inspectFn(Object.fromEntries(this), {
159
+ ...options,
160
+ depth: depth == null ? null : depth - 1
161
+ })}`;
162
+ } });
163
+ Object.setPrototypeOf(RequestHeaders.prototype, GlobalHeaders.prototype);
164
+ const newHeadersFromIncoming = (incoming) => globalThis.Headers === GlobalHeaders ? new RequestHeaders(incoming) : materializeHeaders(incoming.rawHeaders, globalThis.Headers);
165
+
15
166
  //#endregion
16
167
  //#region src/url.ts
17
168
  const reValidRequestUrl = /^\/[!#$&-;=?-\[\]_a-z~]*$/;
@@ -49,15 +200,6 @@ var Request$1 = class extends GlobalRequest {
49
200
  super(input, options);
50
201
  }
51
202
  };
52
- const newHeadersFromIncoming = (incoming) => {
53
- const headerRecord = [];
54
- const rawHeaders = incoming.rawHeaders;
55
- for (let i = 0, len = rawHeaders.length; i < len; i += 2) {
56
- const key = rawHeaders[i];
57
- if (key.charCodeAt(0) !== 58) headerRecord.push([key, rawHeaders[i + 1]]);
58
- }
59
- return new Headers(headerRecord);
60
- };
61
203
  const wrapBodyStream = Symbol("wrapBodyStream");
62
204
  const byteExactEncodings = new Set([
63
205
  "latin1",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hono/node-server",
3
- "version": "2.1.0",
3
+ "version": "2.1.1",
4
4
  "description": "Node.js Adapter for Hono",
5
5
  "main": "dist/index.mjs",
6
6
  "type": "module",
@@ -36,6 +36,8 @@ The parser is lenient and does not error. You should validate `type` and `parame
36
36
  #### Options
37
37
 
38
38
  - `parameters` (default: `true`): Set to `false` to skip parameters.
39
+ - `comma` (default: `false`): Set to `true` to stop on a comma. This can be used to parse the media range in an `Accept` header.
40
+ - `start` (default: `0`): Set index to start parsing from.
39
41
 
40
42
  ### contentType.format(obj)
41
43
 
@@ -8,6 +8,7 @@
8
8
  */
9
9
  export interface ContentType {
10
10
  type: string;
11
+ index: number;
11
12
  parameters: Record<string, string>;
12
13
  }
13
14
  /**
@@ -18,7 +19,26 @@ export declare function format(obj: Partial<ContentType>): string;
18
19
  * Options for parsing a `Content-Type` header.
19
20
  */
20
21
  export interface ParseOptions {
22
+ /**
23
+ * Exit early on the first semicolon, returning only the type.
24
+ * This is useful for parsing the MIME from `Content-Type` headers.
25
+ *
26
+ * @default false
27
+ */
21
28
  parameters?: boolean;
29
+ /**
30
+ * Exits early on a comma, returning the first value and parameters.
31
+ * This is useful for parsing `Accept` headers.
32
+ *
33
+ * @default false
34
+ */
35
+ comma?: boolean;
36
+ /**
37
+ * The index to start parsing from.
38
+ *
39
+ * @default 0
40
+ */
41
+ start?: number;
22
42
  }
23
43
  /**
24
44
  * Parse a `Content-Type` header.
@@ -52,16 +52,17 @@ function format(obj) {
52
52
  * Parse a `Content-Type` header.
53
53
  */
54
54
  function parse(header, options) {
55
+ const stopChar = options?.comma === true ? COMMA : 65536; // Sentinel for "no stop char".
55
56
  const len = header.length;
56
- let index = skipOWS(header, 0, len);
57
+ let index = skipOWS(header, options?.start ?? 0, len);
57
58
  const valueStart = index;
58
- index = skipValue(header, index, len);
59
+ index = skipValue(header, index, len, stopChar);
59
60
  const valueEnd = trailingOWS(header, valueStart, index);
60
61
  const type = header.slice(valueStart, valueEnd).toLowerCase();
61
- const parameters = options?.parameters === false
62
- ? new NullObject()
63
- : parseParameters(header, index, len);
64
- return { type, parameters };
62
+ if (options?.parameters === false) {
63
+ return { type, index, parameters: new NullObject() };
64
+ }
65
+ return parseParameters(header, type, index, len, stopChar);
65
66
  }
66
67
  const SP = 32; // " "
67
68
  const HTAB = 9; // "\t"
@@ -69,16 +70,21 @@ const SEMI = 59; // ";"
69
70
  const EQ = 61; // "="
70
71
  const DQUOTE = 34; // '"'
71
72
  const BSLASH = 92; // "\\"
73
+ const COMMA = 44; // ","
72
74
  /**
73
75
  * Parses the parameters of a `Content-Type` header starting at the given index.
74
76
  */
75
- function parseParameters(header, index, len) {
77
+ function parseParameters(header, type, index, len, stopChar) {
76
78
  const parameters = new NullObject();
77
79
  parameter: while (index < len) {
80
+ if (header.charCodeAt(index) === stopChar)
81
+ break;
78
82
  index = skipOWS(header, index + 1 /* Skip over ; */, len);
79
83
  const keyStart = index;
80
84
  while (index < len) {
81
85
  const code = header.charCodeAt(index);
86
+ if (code === stopChar)
87
+ break parameter;
82
88
  if (code === SEMI)
83
89
  continue parameter;
84
90
  if (code === EQ) {
@@ -91,7 +97,7 @@ function parseParameters(header, index, len) {
91
97
  while (index < len) {
92
98
  const code = header.charCodeAt(index++);
93
99
  if (code === DQUOTE) {
94
- index = skipValue(header, index, len);
100
+ index = skipValue(header, index, len, stopChar);
95
101
  if (parameters[key] === undefined)
96
102
  parameters[key] = value;
97
103
  break;
@@ -105,7 +111,7 @@ function parseParameters(header, index, len) {
105
111
  continue parameter;
106
112
  }
107
113
  const valueStart = index;
108
- index = skipValue(header, index, len);
114
+ index = skipValue(header, index, len, stopChar);
109
115
  if (parameters[key] === undefined) {
110
116
  const valueEnd = trailingOWS(header, valueStart, index);
111
117
  parameters[key] = header.slice(valueStart, valueEnd);
@@ -115,15 +121,15 @@ function parseParameters(header, index, len) {
115
121
  index++;
116
122
  }
117
123
  }
118
- return parameters;
124
+ return { type, index, parameters };
119
125
  }
120
126
  /**
121
- * Skip over characters until a semicolon.
127
+ * Skip over characters until a semicolon or other exit character.
122
128
  */
123
- function skipValue(str, index, len) {
129
+ function skipValue(str, index, len, stopChar) {
124
130
  while (index < len) {
125
- const char = str.charCodeAt(index);
126
- if (char === SEMI)
131
+ const code = str.charCodeAt(index);
132
+ if (code === SEMI || code === stopChar)
127
133
  break;
128
134
  index++;
129
135
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * content-type\n * Copyright(c) 2015 Douglas Christopher Wilson\n * MIT Licensed\n */\n\nconst TEXT_REGEXP = /^[\\u0009\\u0020-\\u007e\\u0080-\\u00ff]*$/;\nconst TOKEN_REGEXP = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;\n\n/**\n * RegExp to match chars that must be quoted-pair in RFC 9110 sec 5.6.4\n */\nconst QUOTE_REGEXP = /[\\\\\"]/g;\n\n/**\n * RegExp to match type in RFC 9110 sec 8.3.1\n *\n * media-type = type \"/\" subtype\n * type = token\n * subtype = token\n */\nconst TYPE_REGEXP =\n /^[!#$%&'*+.^_`|~0-9A-Za-z-]+\\/[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;\n\n/**\n * Null object perf optimization. Faster than `Object.create(null)` and `{ __proto__: null }`.\n */\nconst NullObject = /* @__PURE__ */ (() => {\n const C = function () {};\n C.prototype = Object.create(null);\n return C;\n})() as unknown as { new (): any };\n\n/**\n * The content type object contains a type string and optional parameters.\n */\nexport interface ContentType {\n type: string;\n parameters: Record<string, string>;\n}\n\n/**\n * Format an object into a `Content-Type` header.\n */\nexport function format(obj: Partial<ContentType>): string {\n const { type, parameters } = obj;\n\n if (!type || !TYPE_REGEXP.test(type)) {\n throw new TypeError(`Invalid type: ${type}`);\n }\n\n let result = type;\n\n if (parameters) {\n for (const param of Object.keys(parameters)) {\n if (!TOKEN_REGEXP.test(param)) {\n throw new TypeError(`Invalid parameter name: ${param}`);\n }\n\n result += `; ${param}=${qstring(parameters[param])}`;\n }\n }\n\n return result;\n}\n\n/**\n * Options for parsing a `Content-Type` header.\n */\nexport interface ParseOptions {\n parameters?: boolean;\n}\n\n/**\n * Parse a `Content-Type` header.\n */\nexport function parse(header: string, options?: ParseOptions): ContentType {\n const len = header.length;\n let index = skipOWS(header, 0, len);\n\n const valueStart = index;\n index = skipValue(header, index, len);\n const valueEnd = trailingOWS(header, valueStart, index);\n const type = header.slice(valueStart, valueEnd).toLowerCase();\n const parameters =\n options?.parameters === false\n ? new NullObject()\n : parseParameters(header, index, len);\n\n return { type, parameters };\n}\n\nconst SP = 32; // \" \"\nconst HTAB = 9; // \"\\t\"\nconst SEMI = 59; // \";\"\nconst EQ = 61; // \"=\"\nconst DQUOTE = 34; // '\"'\nconst BSLASH = 92; // \"\\\\\"\n\n/**\n * Parses the parameters of a `Content-Type` header starting at the given index.\n */\nfunction parseParameters(\n header: string,\n index: number,\n len: number,\n): Record<string, string> {\n const parameters: Record<string, string> = new NullObject();\n\n parameter: while (index < len) {\n index = skipOWS(header, index + 1 /* Skip over ; */, len);\n\n const keyStart = index;\n\n while (index < len) {\n const code = header.charCodeAt(index);\n if (code === SEMI) continue parameter;\n\n if (code === EQ) {\n const keyEnd = trailingOWS(header, keyStart, index);\n const key = header.slice(keyStart, keyEnd).toLowerCase();\n\n index = skipOWS(header, index + 1, len);\n\n if (index < len && header.charCodeAt(index) === DQUOTE) {\n index++;\n\n let value = \"\";\n while (index < len) {\n const code = header.charCodeAt(index++);\n if (code === DQUOTE) {\n index = skipValue(header, index, len);\n if (parameters[key] === undefined) parameters[key] = value;\n break;\n }\n\n if (code === BSLASH && index < len) {\n value += header[index++];\n continue;\n }\n\n value += String.fromCharCode(code);\n }\n\n continue parameter;\n }\n\n const valueStart = index;\n index = skipValue(header, index, len);\n\n if (parameters[key] === undefined) {\n const valueEnd = trailingOWS(header, valueStart, index);\n parameters[key] = header.slice(valueStart, valueEnd);\n }\n\n continue parameter;\n }\n\n index++;\n }\n }\n\n return parameters;\n}\n\n/**\n * Skip over characters until a semicolon.\n */\nfunction skipValue(str: string, index: number, len: number): number {\n while (index < len) {\n const char = str.charCodeAt(index);\n if (char === SEMI) break;\n index++;\n }\n return index;\n}\n\n/**\n * Skip optional whitespace (OWS) in an HTTP header value.\n *\n * OWS is defined in RFC 9110 sec 5.6.3 as SP (\" \") or HTAB (\"\\t\").\n */\nfunction skipOWS(header: string, index: number, len: number): number {\n while (index < len) {\n const char = header.charCodeAt(index);\n if (char !== SP && char !== HTAB) break;\n index++;\n }\n return index;\n}\n\n/**\n * Trim optional whitespace (OWS) from the end of a substring.\n *\n * OWS is defined in RFC 9110 sec 5.6.3 as SP (\" \") or HTAB (\"\\t\").\n */\nfunction trailingOWS(header: string, start: number, end: number): number {\n while (end > start) {\n const char = header.charCodeAt(end - 1);\n if (char !== SP && char !== HTAB) break;\n end--;\n }\n return end;\n}\n\n/**\n * Serialize a parameter value.\n */\nfunction qstring(str: string): string {\n if (TOKEN_REGEXP.test(str)) return str;\n if (TEXT_REGEXP.test(str)) return `\"${str.replace(QUOTE_REGEXP, \"\\\\$&\")}\"`;\n\n throw new TypeError(`Invalid parameter value: ${str}`);\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * content-type\n * Copyright(c) 2015 Douglas Christopher Wilson\n * MIT Licensed\n */\n\nconst TEXT_REGEXP = /^[\\u0009\\u0020-\\u007e\\u0080-\\u00ff]*$/;\nconst TOKEN_REGEXP = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;\n\n/**\n * RegExp to match chars that must be quoted-pair in RFC 9110 sec 5.6.4\n */\nconst QUOTE_REGEXP = /[\\\\\"]/g;\n\n/**\n * RegExp to match type in RFC 9110 sec 8.3.1\n *\n * media-type = type \"/\" subtype\n * type = token\n * subtype = token\n */\nconst TYPE_REGEXP =\n /^[!#$%&'*+.^_`|~0-9A-Za-z-]+\\/[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;\n\n/**\n * Null object perf optimization. Faster than `Object.create(null)` and `{ __proto__: null }`.\n */\nconst NullObject = /* @__PURE__ */ (() => {\n const C = function () {};\n C.prototype = Object.create(null);\n return C;\n})() as unknown as { new (): any };\n\n/**\n * The content type object contains a type string and optional parameters.\n */\nexport interface ContentType {\n type: string;\n index: number;\n parameters: Record<string, string>;\n}\n\n/**\n * Format an object into a `Content-Type` header.\n */\nexport function format(obj: Partial<ContentType>): string {\n const { type, parameters } = obj;\n\n if (!type || !TYPE_REGEXP.test(type)) {\n throw new TypeError(`Invalid type: ${type}`);\n }\n\n let result = type;\n\n if (parameters) {\n for (const param of Object.keys(parameters)) {\n if (!TOKEN_REGEXP.test(param)) {\n throw new TypeError(`Invalid parameter name: ${param}`);\n }\n\n result += `; ${param}=${qstring(parameters[param])}`;\n }\n }\n\n return result;\n}\n\n/**\n * Options for parsing a `Content-Type` header.\n */\nexport interface ParseOptions {\n /**\n * Exit early on the first semicolon, returning only the type.\n * This is useful for parsing the MIME from `Content-Type` headers.\n *\n * @default false\n */\n parameters?: boolean;\n /**\n * Exits early on a comma, returning the first value and parameters.\n * This is useful for parsing `Accept` headers.\n *\n * @default false\n */\n comma?: boolean;\n /**\n * The index to start parsing from.\n *\n * @default 0\n */\n start?: number;\n}\n\n/**\n * Parse a `Content-Type` header.\n */\nexport function parse(header: string, options?: ParseOptions): ContentType {\n const stopChar = options?.comma === true ? COMMA : 65_536; // Sentinel for \"no stop char\".\n const len = header.length;\n let index = skipOWS(header, options?.start ?? 0, len);\n\n const valueStart = index;\n index = skipValue(header, index, len, stopChar);\n const valueEnd = trailingOWS(header, valueStart, index);\n const type = header.slice(valueStart, valueEnd).toLowerCase();\n\n if (options?.parameters === false) {\n return { type, index, parameters: new NullObject() };\n }\n\n return parseParameters(header, type, index, len, stopChar);\n}\n\nconst SP = 32; // \" \"\nconst HTAB = 9; // \"\\t\"\nconst SEMI = 59; // \";\"\nconst EQ = 61; // \"=\"\nconst DQUOTE = 34; // '\"'\nconst BSLASH = 92; // \"\\\\\"\nconst COMMA = 44; // \",\"\n\n/**\n * Parses the parameters of a `Content-Type` header starting at the given index.\n */\nfunction parseParameters(\n header: string,\n type: string,\n index: number,\n len: number,\n stopChar: number,\n): ContentType {\n const parameters: Record<string, string> = new NullObject();\n\n parameter: while (index < len) {\n if (header.charCodeAt(index) === stopChar) break;\n\n index = skipOWS(header, index + 1 /* Skip over ; */, len);\n\n const keyStart = index;\n\n while (index < len) {\n const code = header.charCodeAt(index);\n if (code === stopChar) break parameter;\n\n if (code === SEMI) continue parameter;\n\n if (code === EQ) {\n const keyEnd = trailingOWS(header, keyStart, index);\n const key = header.slice(keyStart, keyEnd).toLowerCase();\n\n index = skipOWS(header, index + 1, len);\n\n if (index < len && header.charCodeAt(index) === DQUOTE) {\n index++;\n\n let value = \"\";\n while (index < len) {\n const code = header.charCodeAt(index++);\n if (code === DQUOTE) {\n index = skipValue(header, index, len, stopChar);\n if (parameters[key] === undefined) parameters[key] = value;\n break;\n }\n\n if (code === BSLASH && index < len) {\n value += header[index++];\n continue;\n }\n\n value += String.fromCharCode(code);\n }\n\n continue parameter;\n }\n\n const valueStart = index;\n index = skipValue(header, index, len, stopChar);\n\n if (parameters[key] === undefined) {\n const valueEnd = trailingOWS(header, valueStart, index);\n parameters[key] = header.slice(valueStart, valueEnd);\n }\n\n continue parameter;\n }\n\n index++;\n }\n }\n\n return { type, index, parameters };\n}\n\n/**\n * Skip over characters until a semicolon or other exit character.\n */\nfunction skipValue(\n str: string,\n index: number,\n len: number,\n stopChar: number,\n): number {\n while (index < len) {\n const code = str.charCodeAt(index);\n if (code === SEMI || code === stopChar) break;\n index++;\n }\n return index;\n}\n\n/**\n * Skip optional whitespace (OWS) in an HTTP header value.\n *\n * OWS is defined in RFC 9110 sec 5.6.3 as SP (\" \") or HTAB (\"\\t\").\n */\nfunction skipOWS(header: string, index: number, len: number): number {\n while (index < len) {\n const char = header.charCodeAt(index);\n if (char !== SP && char !== HTAB) break;\n index++;\n }\n return index;\n}\n\n/**\n * Trim optional whitespace (OWS) from the end of a substring.\n *\n * OWS is defined in RFC 9110 sec 5.6.3 as SP (\" \") or HTAB (\"\\t\").\n */\nfunction trailingOWS(header: string, start: number, end: number): number {\n while (end > start) {\n const char = header.charCodeAt(end - 1);\n if (char !== SP && char !== HTAB) break;\n end--;\n }\n return end;\n}\n\n/**\n * Serialize a parameter value.\n */\nfunction qstring(str: string): string {\n if (TOKEN_REGEXP.test(str)) return str;\n if (TEXT_REGEXP.test(str)) return `\"${str.replace(QUOTE_REGEXP, \"\\\\$&\")}\"`;\n\n throw new TypeError(`Invalid parameter value: ${str}`);\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "content-type",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "Create and parse HTTP Content-Type header",
5
5
  "keywords": [
6
6
  "content-type",
@@ -36,6 +36,8 @@ The parser is lenient and does not error. You should validate `type` and `parame
36
36
  #### Options
37
37
 
38
38
  - `parameters` (default: `true`): Set to `false` to skip parameters.
39
+ - `comma` (default: `false`): Set to `true` to stop on a comma. This can be used to parse the media range in an `Accept` header.
40
+ - `start` (default: `0`): Set index to start parsing from.
39
41
 
40
42
  ### contentType.format(obj)
41
43
 
@@ -8,6 +8,7 @@
8
8
  */
9
9
  export interface ContentType {
10
10
  type: string;
11
+ index: number;
11
12
  parameters: Record<string, string>;
12
13
  }
13
14
  /**
@@ -18,7 +19,26 @@ export declare function format(obj: Partial<ContentType>): string;
18
19
  * Options for parsing a `Content-Type` header.
19
20
  */
20
21
  export interface ParseOptions {
22
+ /**
23
+ * Exit early on the first semicolon, returning only the type.
24
+ * This is useful for parsing the MIME from `Content-Type` headers.
25
+ *
26
+ * @default false
27
+ */
21
28
  parameters?: boolean;
29
+ /**
30
+ * Exits early on a comma, returning the first value and parameters.
31
+ * This is useful for parsing `Accept` headers.
32
+ *
33
+ * @default false
34
+ */
35
+ comma?: boolean;
36
+ /**
37
+ * The index to start parsing from.
38
+ *
39
+ * @default 0
40
+ */
41
+ start?: number;
22
42
  }
23
43
  /**
24
44
  * Parse a `Content-Type` header.