@ag-ui/encoder 0.0.27

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.
@@ -0,0 +1,23 @@
1
+
2
+ 
3
+ > @ag-ui/encoder@0.0.27 build /Users/mme/Code/ag-ui-protocol/typescript-sdk/packages/encoder
4
+ > tsup
5
+
6
+ CLI Building entry: src/index.ts
7
+ CLI Using tsconfig: tsconfig.json
8
+ CLI tsup v8.4.0
9
+ CLI Using tsup config: /Users/mme/Code/ag-ui-protocol/typescript-sdk/packages/encoder/tsup.config.ts
10
+ CLI Target: es2017
11
+ CLI Cleaning output folder
12
+ CJS Build start
13
+ ESM Build start
14
+ CJS dist/index.js 7.09 KB
15
+ CJS dist/index.js.map 13.37 KB
16
+ CJS ⚡️ Build success in 8ms
17
+ ESM dist/index.mjs 5.49 KB
18
+ ESM dist/index.mjs.map 13.34 KB
19
+ ESM ⚡️ Build success in 8ms
20
+ DTS Build start
21
+ DTS ⚡️ Build success in 652ms
22
+ DTS dist/index.d.ts 540.00 B
23
+ DTS dist/index.d.mts 540.00 B
@@ -0,0 +1,18 @@
1
+ import { BaseEvent } from '@ag-ui/core';
2
+ export { AGUI_MEDIA_TYPE } from '@ag-ui/proto';
3
+
4
+ interface EventEncoderParams {
5
+ accept?: string;
6
+ }
7
+ declare class EventEncoder {
8
+ private acceptsProtobuf;
9
+ constructor(params?: EventEncoderParams);
10
+ getContentType(): string;
11
+ encode(event: BaseEvent): string;
12
+ encodeSSE(event: BaseEvent): string;
13
+ encodeBinary(event: BaseEvent): Uint8Array;
14
+ encodeProtobuf(event: BaseEvent): Uint8Array;
15
+ private isProtobufAccepted;
16
+ }
17
+
18
+ export { EventEncoder, type EventEncoderParams };
@@ -0,0 +1,18 @@
1
+ import { BaseEvent } from '@ag-ui/core';
2
+ export { AGUI_MEDIA_TYPE } from '@ag-ui/proto';
3
+
4
+ interface EventEncoderParams {
5
+ accept?: string;
6
+ }
7
+ declare class EventEncoder {
8
+ private acceptsProtobuf;
9
+ constructor(params?: EventEncoderParams);
10
+ getContentType(): string;
11
+ encode(event: BaseEvent): string;
12
+ encodeSSE(event: BaseEvent): string;
13
+ encodeBinary(event: BaseEvent): Uint8Array;
14
+ encodeProtobuf(event: BaseEvent): Uint8Array;
15
+ private isProtobufAccepted;
16
+ }
17
+
18
+ export { EventEncoder, type EventEncoderParams };
package/dist/index.js ADDED
@@ -0,0 +1,250 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ AGUI_MEDIA_TYPE: () => import_proto.AGUI_MEDIA_TYPE,
34
+ EventEncoder: () => EventEncoder
35
+ });
36
+ module.exports = __toCommonJS(index_exports);
37
+
38
+ // src/encoder.ts
39
+ var proto = __toESM(require("@ag-ui/proto"));
40
+
41
+ // src/media-type.ts
42
+ function preferredMediaTypes(accept, provided) {
43
+ const accepts = parseAccept(accept === void 0 ? "*/*" : accept || "");
44
+ if (!provided) {
45
+ return accepts.filter((spec) => spec.q > 0).sort((a, b) => {
46
+ return b.q - a.q || b.i - a.i || 0;
47
+ }).map(getFullType);
48
+ }
49
+ const priorities = provided.map(function getPriority(type, index) {
50
+ return getMediaTypePriority(type, accepts, index);
51
+ });
52
+ return priorities.filter((spec) => spec.q > 0).sort(compareSpecs).map(function getType(priority) {
53
+ return provided[priorities.indexOf(priority)];
54
+ });
55
+ }
56
+ var simpleMediaTypeRegExp = /^\s*([^\s\/;]+)\/([^;\s]+)\s*(?:;(.*))?$/;
57
+ function parseAccept(accept) {
58
+ const accepts = splitMediaTypes(accept);
59
+ const result = [];
60
+ for (let i = 0, j = 0; i < accepts.length; i++) {
61
+ const mediaType = parseMediaType(accepts[i].trim(), i);
62
+ if (mediaType) {
63
+ result[j++] = mediaType;
64
+ }
65
+ }
66
+ return result;
67
+ }
68
+ function parseMediaType(str, i) {
69
+ const match = simpleMediaTypeRegExp.exec(str);
70
+ if (!match) return null;
71
+ const params = /* @__PURE__ */ Object.create(null);
72
+ let q = 1;
73
+ const subtype = match[2];
74
+ const type = match[1];
75
+ if (match[3]) {
76
+ const kvps = splitParameters(match[3]).map(splitKeyValuePair);
77
+ for (let j = 0; j < kvps.length; j++) {
78
+ const pair = kvps[j];
79
+ const key = pair[0].toLowerCase();
80
+ const val = pair[1];
81
+ const value = val && val[0] === '"' && val[val.length - 1] === '"' ? val.slice(1, -1) : val;
82
+ if (key === "q") {
83
+ q = parseFloat(value);
84
+ break;
85
+ }
86
+ params[key] = value;
87
+ }
88
+ }
89
+ return {
90
+ type,
91
+ subtype,
92
+ params,
93
+ q,
94
+ i
95
+ };
96
+ }
97
+ function getMediaTypePriority(type, accepted, index) {
98
+ const priority = { o: -1, q: 0, s: 0 };
99
+ for (let i = 0; i < accepted.length; i++) {
100
+ const spec = specify(type, accepted[i], index);
101
+ if (spec && (priority.s - spec.s || priority.q - spec.q || priority.o - spec.o) < 0) {
102
+ priority.o = spec.o;
103
+ priority.q = spec.q;
104
+ priority.s = spec.s;
105
+ priority.i = spec.i;
106
+ }
107
+ }
108
+ return priority;
109
+ }
110
+ function specify(type, spec, index) {
111
+ const p = parseMediaType(type, 0);
112
+ let s = 0;
113
+ if (!p) {
114
+ return null;
115
+ }
116
+ if (spec.type.toLowerCase() == p.type.toLowerCase()) {
117
+ s |= 4;
118
+ } else if (spec.type != "*") {
119
+ return null;
120
+ }
121
+ if (spec.subtype.toLowerCase() == p.subtype.toLowerCase()) {
122
+ s |= 2;
123
+ } else if (spec.subtype != "*") {
124
+ return null;
125
+ }
126
+ const keys = Object.keys(spec.params);
127
+ if (keys.length > 0) {
128
+ if (keys.every(function(k) {
129
+ return spec.params[k] == "*" || (spec.params[k] || "").toLowerCase() == (p.params[k] || "").toLowerCase();
130
+ })) {
131
+ s |= 1;
132
+ } else {
133
+ return null;
134
+ }
135
+ }
136
+ return {
137
+ i: index,
138
+ o: spec.i,
139
+ q: spec.q,
140
+ s
141
+ };
142
+ }
143
+ function compareSpecs(a, b) {
144
+ return b.q - a.q || b.s - a.s || (a.o || 0) - (b.o || 0) || (a.i || 0) - (b.i || 0) || 0;
145
+ }
146
+ function getFullType(spec) {
147
+ return spec.type + "/" + spec.subtype;
148
+ }
149
+ function quoteCount(string) {
150
+ let count = 0;
151
+ let index = 0;
152
+ while ((index = string.indexOf('"', index)) !== -1) {
153
+ count++;
154
+ index++;
155
+ }
156
+ return count;
157
+ }
158
+ function splitKeyValuePair(str) {
159
+ const index = str.indexOf("=");
160
+ let key;
161
+ let val = "";
162
+ if (index === -1) {
163
+ key = str;
164
+ } else {
165
+ key = str.slice(0, index);
166
+ val = str.slice(index + 1);
167
+ }
168
+ return [key, val];
169
+ }
170
+ function splitMediaTypes(accept) {
171
+ const accepts = accept.split(",");
172
+ const result = [accepts[0]];
173
+ for (let i = 1, j = 0; i < accepts.length; i++) {
174
+ if (quoteCount(result[j]) % 2 == 0) {
175
+ result[++j] = accepts[i];
176
+ } else {
177
+ result[j] += "," + accepts[i];
178
+ }
179
+ }
180
+ return result;
181
+ }
182
+ function splitParameters(str) {
183
+ const parameters = str.split(";");
184
+ const result = [parameters[0]];
185
+ for (let i = 1, j = 0; i < parameters.length; i++) {
186
+ if (quoteCount(result[j]) % 2 == 0) {
187
+ result[++j] = parameters[i];
188
+ } else {
189
+ result[j] += ";" + parameters[i];
190
+ }
191
+ }
192
+ for (let i = 0; i < result.length; i++) {
193
+ result[i] = result[i].trim();
194
+ }
195
+ return result;
196
+ }
197
+
198
+ // src/encoder.ts
199
+ var EventEncoder = class {
200
+ constructor(params) {
201
+ this.acceptsProtobuf = (params == null ? void 0 : params.accept) ? this.isProtobufAccepted(params.accept) : false;
202
+ }
203
+ getContentType() {
204
+ if (this.acceptsProtobuf) {
205
+ return proto.AGUI_MEDIA_TYPE;
206
+ } else {
207
+ return "text/event-stream";
208
+ }
209
+ }
210
+ encode(event) {
211
+ return this.encodeSSE(event);
212
+ }
213
+ encodeSSE(event) {
214
+ return `data: ${JSON.stringify(event)}
215
+
216
+ `;
217
+ }
218
+ encodeBinary(event) {
219
+ if (this.acceptsProtobuf) {
220
+ return this.encodeProtobuf(event);
221
+ } else {
222
+ const sseString = this.encodeSSE(event);
223
+ const encoder = new TextEncoder();
224
+ return encoder.encode(sseString);
225
+ }
226
+ }
227
+ encodeProtobuf(event) {
228
+ const messageBytes = proto.encode(event);
229
+ const length = messageBytes.length;
230
+ const buffer = new ArrayBuffer(4 + length);
231
+ const dataView = new DataView(buffer);
232
+ dataView.setUint32(0, length, false);
233
+ const result = new Uint8Array(buffer);
234
+ result.set(messageBytes, 4);
235
+ return result;
236
+ }
237
+ isProtobufAccepted(acceptHeader) {
238
+ const preferred = preferredMediaTypes(acceptHeader, [proto.AGUI_MEDIA_TYPE]);
239
+ return preferred.includes(proto.AGUI_MEDIA_TYPE);
240
+ }
241
+ };
242
+
243
+ // src/index.ts
244
+ var import_proto = require("@ag-ui/proto");
245
+ // Annotate the CommonJS export names for ESM import in node:
246
+ 0 && (module.exports = {
247
+ AGUI_MEDIA_TYPE,
248
+ EventEncoder
249
+ });
250
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/encoder.ts","../src/media-type.ts"],"sourcesContent":["export * from \"./encoder\";\nexport { AGUI_MEDIA_TYPE } from \"@ag-ui/proto\";\n","import { BaseEvent } from \"@ag-ui/core\";\nimport * as proto from \"@ag-ui/proto\";\nimport { preferredMediaTypes } from \"./media-type\";\n\nexport interface EventEncoderParams {\n accept?: string;\n}\n\nexport class EventEncoder {\n private acceptsProtobuf: boolean;\n\n constructor(params?: EventEncoderParams) {\n this.acceptsProtobuf = params?.accept ? this.isProtobufAccepted(params.accept) : false;\n }\n\n getContentType(): string {\n if (this.acceptsProtobuf) {\n return proto.AGUI_MEDIA_TYPE;\n } else {\n return \"text/event-stream\";\n }\n }\n\n encode(event: BaseEvent): string {\n return this.encodeSSE(event);\n }\n\n encodeSSE(event: BaseEvent): string {\n return `data: ${JSON.stringify(event)}\\n\\n`;\n }\n\n encodeBinary(event: BaseEvent): Uint8Array {\n if (this.acceptsProtobuf) {\n return this.encodeProtobuf(event);\n } else {\n const sseString = this.encodeSSE(event);\n // Convert string to Uint8Array using TextEncoder\n const encoder = new TextEncoder();\n return encoder.encode(sseString);\n }\n }\n\n encodeProtobuf(event: BaseEvent): Uint8Array {\n const messageBytes = proto.encode(event);\n const length = messageBytes.length;\n\n // Create a buffer for 4 bytes (for the uint32 length) plus the message bytes\n const buffer = new ArrayBuffer(4 + length);\n const dataView = new DataView(buffer);\n\n // Write the length as a uint32\n // Set the third parameter to `false` for big-endian or `true` for little-endian\n dataView.setUint32(0, length, false);\n\n // Create a Uint8Array view and copy in the message bytes after the 4-byte header\n const result = new Uint8Array(buffer);\n result.set(messageBytes, 4);\n\n return result;\n }\n\n private isProtobufAccepted(acceptHeader: string): boolean {\n // Pass the Accept header and an array with your media type\n const preferred = preferredMediaTypes(acceptHeader, [proto.AGUI_MEDIA_TYPE]);\n\n // If the returned array includes your media type, it's acceptable\n return preferred.includes(proto.AGUI_MEDIA_TYPE);\n }\n}\n","/**\n * negotiator\n * Copyright(c) 2012 Isaac Z. Schlueter\n * Copyright(c) 2014 Federico Romero\n * Copyright(c) 2014-2015 Douglas Christopher Wilson\n * MIT Licensed\n */\n\n// modified from https://github.com/jshttp/negotiator/blob/master/lib/mediaType.js\n\n/**\n * Module exports.\n * @public\n */\n\nexport function preferredMediaTypes(accept?: string, provided?: string[]): string[] {\n // RFC 2616 sec 14.2: no header = */*\n const accepts = parseAccept(accept === undefined ? \"*/*\" : accept || \"\");\n\n if (!provided) {\n // sorted list of all types\n return accepts\n .filter((spec): spec is MediaType => spec.q > 0)\n .sort((a, b) => {\n return b.q - a.q || b.i - a.i || 0;\n })\n .map(getFullType);\n }\n\n const priorities = provided.map(function getPriority(type: string, index: number) {\n return getMediaTypePriority(type, accepts, index);\n });\n\n // sorted list of accepted types\n return priorities\n .filter((spec): spec is Priority => spec.q > 0)\n .sort(compareSpecs)\n .map(function getType(priority: Priority) {\n return provided[priorities.indexOf(priority)];\n });\n}\n\n/**\n * Module variables.\n * @private\n */\n\nconst simpleMediaTypeRegExp = /^\\s*([^\\s\\/;]+)\\/([^;\\s]+)\\s*(?:;(.*))?$/;\n\n/**\n * Media type interface\n * @private\n */\ninterface MediaType {\n type: string;\n subtype: string;\n params: Record<string, string>;\n q: number;\n i: number;\n}\n\n/**\n * Priority interface\n * @private\n */\ninterface Priority {\n o: number;\n q: number;\n s: number;\n i?: number;\n}\n\n/**\n * Parse the Accept header.\n * @private\n */\nfunction parseAccept(accept: string): MediaType[] {\n const accepts = splitMediaTypes(accept);\n const result: MediaType[] = [];\n\n for (let i = 0, j = 0; i < accepts.length; i++) {\n const mediaType = parseMediaType(accepts[i].trim(), i);\n\n if (mediaType) {\n result[j++] = mediaType;\n }\n }\n\n return result;\n}\n\n/**\n * Parse a media type from the Accept header.\n * @private\n */\nfunction parseMediaType(str: string, i: number): MediaType | null {\n const match = simpleMediaTypeRegExp.exec(str);\n if (!match) return null;\n\n const params: Record<string, string> = Object.create(null);\n let q = 1;\n const subtype = match[2];\n const type = match[1];\n\n if (match[3]) {\n const kvps = splitParameters(match[3]).map(splitKeyValuePair);\n\n for (let j = 0; j < kvps.length; j++) {\n const pair = kvps[j];\n const key = pair[0].toLowerCase();\n const val = pair[1];\n\n // get the value, unwrapping quotes\n const value = val && val[0] === '\"' && val[val.length - 1] === '\"' ? val.slice(1, -1) : val;\n\n if (key === \"q\") {\n q = parseFloat(value);\n break;\n }\n\n // store parameter\n params[key] = value;\n }\n }\n\n return {\n type: type,\n subtype: subtype,\n params: params,\n q: q,\n i: i,\n };\n}\n\n/**\n * Get the priority of a media type.\n * @private\n */\nfunction getMediaTypePriority(type: string, accepted: MediaType[], index: number): Priority {\n const priority: Priority = { o: -1, q: 0, s: 0 };\n\n for (let i = 0; i < accepted.length; i++) {\n const spec = specify(type, accepted[i], index);\n\n if (spec && (priority.s - spec.s || priority.q - spec.q || priority.o - spec.o) < 0) {\n priority.o = spec.o;\n priority.q = spec.q;\n priority.s = spec.s;\n priority.i = spec.i;\n }\n }\n\n return priority;\n}\n\n/**\n * Get the specificity of the media type.\n * @private\n */\nfunction specify(type: string, spec: MediaType, index: number): Priority | null {\n const p = parseMediaType(type, 0);\n let s = 0;\n\n if (!p) {\n return null;\n }\n\n if (spec.type.toLowerCase() == p.type.toLowerCase()) {\n s |= 4;\n } else if (spec.type != \"*\") {\n return null;\n }\n\n if (spec.subtype.toLowerCase() == p.subtype.toLowerCase()) {\n s |= 2;\n } else if (spec.subtype != \"*\") {\n return null;\n }\n\n const keys = Object.keys(spec.params);\n if (keys.length > 0) {\n if (\n keys.every(function (k) {\n return (\n spec.params[k] == \"*\" ||\n (spec.params[k] || \"\").toLowerCase() == (p.params[k] || \"\").toLowerCase()\n );\n })\n ) {\n s |= 1;\n } else {\n return null;\n }\n }\n\n return {\n i: index,\n o: spec.i,\n q: spec.q,\n s: s,\n };\n}\n\n/**\n * Compare two specs.\n * @private\n */\nfunction compareSpecs(a: Priority, b: Priority): number {\n return b.q - a.q || b.s - a.s || (a.o || 0) - (b.o || 0) || (a.i || 0) - (b.i || 0) || 0;\n}\n\n/**\n * Get full type string.\n * @private\n */\nfunction getFullType(spec: MediaType): string {\n return spec.type + \"/\" + spec.subtype;\n}\n\n/**\n * Check if a spec has any quality.\n * @private\n */\nfunction isQuality(spec: Priority | MediaType): boolean {\n return spec.q > 0;\n}\n\n/**\n * Count the number of quotes in a string.\n * @private\n */\nfunction quoteCount(string: string): number {\n let count = 0;\n let index = 0;\n\n while ((index = string.indexOf('\"', index)) !== -1) {\n count++;\n index++;\n }\n\n return count;\n}\n\n/**\n * Split a key value pair.\n * @private\n */\nfunction splitKeyValuePair(str: string): [string, string] {\n const index = str.indexOf(\"=\");\n let key: string;\n let val: string = \"\";\n\n if (index === -1) {\n key = str;\n } else {\n key = str.slice(0, index);\n val = str.slice(index + 1);\n }\n\n return [key, val];\n}\n\n/**\n * Split an Accept header into media types.\n * @private\n */\nfunction splitMediaTypes(accept: string): string[] {\n const accepts = accept.split(\",\");\n const result: string[] = [accepts[0]];\n\n for (let i = 1, j = 0; i < accepts.length; i++) {\n if (quoteCount(result[j]) % 2 == 0) {\n result[++j] = accepts[i];\n } else {\n result[j] += \",\" + accepts[i];\n }\n }\n\n // trim result\n return result;\n}\n\n/**\n * Split a string of parameters.\n * @private\n */\nfunction splitParameters(str: string): string[] {\n const parameters = str.split(\";\");\n const result: string[] = [parameters[0]];\n\n for (let i = 1, j = 0; i < parameters.length; i++) {\n if (quoteCount(result[j]) % 2 == 0) {\n result[++j] = parameters[i];\n } else {\n result[j] += \";\" + parameters[i];\n }\n }\n\n // trim parameters\n for (let i = 0; i < result.length; i++) {\n result[i] = result[i].trim();\n }\n\n return result;\n}\n"],"mappings":"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","names":[]}
package/dist/index.mjs ADDED
@@ -0,0 +1,212 @@
1
+ // src/encoder.ts
2
+ import * as proto from "@ag-ui/proto";
3
+
4
+ // src/media-type.ts
5
+ function preferredMediaTypes(accept, provided) {
6
+ const accepts = parseAccept(accept === void 0 ? "*/*" : accept || "");
7
+ if (!provided) {
8
+ return accepts.filter((spec) => spec.q > 0).sort((a, b) => {
9
+ return b.q - a.q || b.i - a.i || 0;
10
+ }).map(getFullType);
11
+ }
12
+ const priorities = provided.map(function getPriority(type, index) {
13
+ return getMediaTypePriority(type, accepts, index);
14
+ });
15
+ return priorities.filter((spec) => spec.q > 0).sort(compareSpecs).map(function getType(priority) {
16
+ return provided[priorities.indexOf(priority)];
17
+ });
18
+ }
19
+ var simpleMediaTypeRegExp = /^\s*([^\s\/;]+)\/([^;\s]+)\s*(?:;(.*))?$/;
20
+ function parseAccept(accept) {
21
+ const accepts = splitMediaTypes(accept);
22
+ const result = [];
23
+ for (let i = 0, j = 0; i < accepts.length; i++) {
24
+ const mediaType = parseMediaType(accepts[i].trim(), i);
25
+ if (mediaType) {
26
+ result[j++] = mediaType;
27
+ }
28
+ }
29
+ return result;
30
+ }
31
+ function parseMediaType(str, i) {
32
+ const match = simpleMediaTypeRegExp.exec(str);
33
+ if (!match) return null;
34
+ const params = /* @__PURE__ */ Object.create(null);
35
+ let q = 1;
36
+ const subtype = match[2];
37
+ const type = match[1];
38
+ if (match[3]) {
39
+ const kvps = splitParameters(match[3]).map(splitKeyValuePair);
40
+ for (let j = 0; j < kvps.length; j++) {
41
+ const pair = kvps[j];
42
+ const key = pair[0].toLowerCase();
43
+ const val = pair[1];
44
+ const value = val && val[0] === '"' && val[val.length - 1] === '"' ? val.slice(1, -1) : val;
45
+ if (key === "q") {
46
+ q = parseFloat(value);
47
+ break;
48
+ }
49
+ params[key] = value;
50
+ }
51
+ }
52
+ return {
53
+ type,
54
+ subtype,
55
+ params,
56
+ q,
57
+ i
58
+ };
59
+ }
60
+ function getMediaTypePriority(type, accepted, index) {
61
+ const priority = { o: -1, q: 0, s: 0 };
62
+ for (let i = 0; i < accepted.length; i++) {
63
+ const spec = specify(type, accepted[i], index);
64
+ if (spec && (priority.s - spec.s || priority.q - spec.q || priority.o - spec.o) < 0) {
65
+ priority.o = spec.o;
66
+ priority.q = spec.q;
67
+ priority.s = spec.s;
68
+ priority.i = spec.i;
69
+ }
70
+ }
71
+ return priority;
72
+ }
73
+ function specify(type, spec, index) {
74
+ const p = parseMediaType(type, 0);
75
+ let s = 0;
76
+ if (!p) {
77
+ return null;
78
+ }
79
+ if (spec.type.toLowerCase() == p.type.toLowerCase()) {
80
+ s |= 4;
81
+ } else if (spec.type != "*") {
82
+ return null;
83
+ }
84
+ if (spec.subtype.toLowerCase() == p.subtype.toLowerCase()) {
85
+ s |= 2;
86
+ } else if (spec.subtype != "*") {
87
+ return null;
88
+ }
89
+ const keys = Object.keys(spec.params);
90
+ if (keys.length > 0) {
91
+ if (keys.every(function(k) {
92
+ return spec.params[k] == "*" || (spec.params[k] || "").toLowerCase() == (p.params[k] || "").toLowerCase();
93
+ })) {
94
+ s |= 1;
95
+ } else {
96
+ return null;
97
+ }
98
+ }
99
+ return {
100
+ i: index,
101
+ o: spec.i,
102
+ q: spec.q,
103
+ s
104
+ };
105
+ }
106
+ function compareSpecs(a, b) {
107
+ return b.q - a.q || b.s - a.s || (a.o || 0) - (b.o || 0) || (a.i || 0) - (b.i || 0) || 0;
108
+ }
109
+ function getFullType(spec) {
110
+ return spec.type + "/" + spec.subtype;
111
+ }
112
+ function quoteCount(string) {
113
+ let count = 0;
114
+ let index = 0;
115
+ while ((index = string.indexOf('"', index)) !== -1) {
116
+ count++;
117
+ index++;
118
+ }
119
+ return count;
120
+ }
121
+ function splitKeyValuePair(str) {
122
+ const index = str.indexOf("=");
123
+ let key;
124
+ let val = "";
125
+ if (index === -1) {
126
+ key = str;
127
+ } else {
128
+ key = str.slice(0, index);
129
+ val = str.slice(index + 1);
130
+ }
131
+ return [key, val];
132
+ }
133
+ function splitMediaTypes(accept) {
134
+ const accepts = accept.split(",");
135
+ const result = [accepts[0]];
136
+ for (let i = 1, j = 0; i < accepts.length; i++) {
137
+ if (quoteCount(result[j]) % 2 == 0) {
138
+ result[++j] = accepts[i];
139
+ } else {
140
+ result[j] += "," + accepts[i];
141
+ }
142
+ }
143
+ return result;
144
+ }
145
+ function splitParameters(str) {
146
+ const parameters = str.split(";");
147
+ const result = [parameters[0]];
148
+ for (let i = 1, j = 0; i < parameters.length; i++) {
149
+ if (quoteCount(result[j]) % 2 == 0) {
150
+ result[++j] = parameters[i];
151
+ } else {
152
+ result[j] += ";" + parameters[i];
153
+ }
154
+ }
155
+ for (let i = 0; i < result.length; i++) {
156
+ result[i] = result[i].trim();
157
+ }
158
+ return result;
159
+ }
160
+
161
+ // src/encoder.ts
162
+ var EventEncoder = class {
163
+ constructor(params) {
164
+ this.acceptsProtobuf = (params == null ? void 0 : params.accept) ? this.isProtobufAccepted(params.accept) : false;
165
+ }
166
+ getContentType() {
167
+ if (this.acceptsProtobuf) {
168
+ return proto.AGUI_MEDIA_TYPE;
169
+ } else {
170
+ return "text/event-stream";
171
+ }
172
+ }
173
+ encode(event) {
174
+ return this.encodeSSE(event);
175
+ }
176
+ encodeSSE(event) {
177
+ return `data: ${JSON.stringify(event)}
178
+
179
+ `;
180
+ }
181
+ encodeBinary(event) {
182
+ if (this.acceptsProtobuf) {
183
+ return this.encodeProtobuf(event);
184
+ } else {
185
+ const sseString = this.encodeSSE(event);
186
+ const encoder = new TextEncoder();
187
+ return encoder.encode(sseString);
188
+ }
189
+ }
190
+ encodeProtobuf(event) {
191
+ const messageBytes = proto.encode(event);
192
+ const length = messageBytes.length;
193
+ const buffer = new ArrayBuffer(4 + length);
194
+ const dataView = new DataView(buffer);
195
+ dataView.setUint32(0, length, false);
196
+ const result = new Uint8Array(buffer);
197
+ result.set(messageBytes, 4);
198
+ return result;
199
+ }
200
+ isProtobufAccepted(acceptHeader) {
201
+ const preferred = preferredMediaTypes(acceptHeader, [proto.AGUI_MEDIA_TYPE]);
202
+ return preferred.includes(proto.AGUI_MEDIA_TYPE);
203
+ }
204
+ };
205
+
206
+ // src/index.ts
207
+ import { AGUI_MEDIA_TYPE as AGUI_MEDIA_TYPE2 } from "@ag-ui/proto";
208
+ export {
209
+ AGUI_MEDIA_TYPE2 as AGUI_MEDIA_TYPE,
210
+ EventEncoder
211
+ };
212
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/encoder.ts","../src/media-type.ts","../src/index.ts"],"sourcesContent":["import { BaseEvent } from \"@ag-ui/core\";\nimport * as proto from \"@ag-ui/proto\";\nimport { preferredMediaTypes } from \"./media-type\";\n\nexport interface EventEncoderParams {\n accept?: string;\n}\n\nexport class EventEncoder {\n private acceptsProtobuf: boolean;\n\n constructor(params?: EventEncoderParams) {\n this.acceptsProtobuf = params?.accept ? this.isProtobufAccepted(params.accept) : false;\n }\n\n getContentType(): string {\n if (this.acceptsProtobuf) {\n return proto.AGUI_MEDIA_TYPE;\n } else {\n return \"text/event-stream\";\n }\n }\n\n encode(event: BaseEvent): string {\n return this.encodeSSE(event);\n }\n\n encodeSSE(event: BaseEvent): string {\n return `data: ${JSON.stringify(event)}\\n\\n`;\n }\n\n encodeBinary(event: BaseEvent): Uint8Array {\n if (this.acceptsProtobuf) {\n return this.encodeProtobuf(event);\n } else {\n const sseString = this.encodeSSE(event);\n // Convert string to Uint8Array using TextEncoder\n const encoder = new TextEncoder();\n return encoder.encode(sseString);\n }\n }\n\n encodeProtobuf(event: BaseEvent): Uint8Array {\n const messageBytes = proto.encode(event);\n const length = messageBytes.length;\n\n // Create a buffer for 4 bytes (for the uint32 length) plus the message bytes\n const buffer = new ArrayBuffer(4 + length);\n const dataView = new DataView(buffer);\n\n // Write the length as a uint32\n // Set the third parameter to `false` for big-endian or `true` for little-endian\n dataView.setUint32(0, length, false);\n\n // Create a Uint8Array view and copy in the message bytes after the 4-byte header\n const result = new Uint8Array(buffer);\n result.set(messageBytes, 4);\n\n return result;\n }\n\n private isProtobufAccepted(acceptHeader: string): boolean {\n // Pass the Accept header and an array with your media type\n const preferred = preferredMediaTypes(acceptHeader, [proto.AGUI_MEDIA_TYPE]);\n\n // If the returned array includes your media type, it's acceptable\n return preferred.includes(proto.AGUI_MEDIA_TYPE);\n }\n}\n","/**\n * negotiator\n * Copyright(c) 2012 Isaac Z. Schlueter\n * Copyright(c) 2014 Federico Romero\n * Copyright(c) 2014-2015 Douglas Christopher Wilson\n * MIT Licensed\n */\n\n// modified from https://github.com/jshttp/negotiator/blob/master/lib/mediaType.js\n\n/**\n * Module exports.\n * @public\n */\n\nexport function preferredMediaTypes(accept?: string, provided?: string[]): string[] {\n // RFC 2616 sec 14.2: no header = */*\n const accepts = parseAccept(accept === undefined ? \"*/*\" : accept || \"\");\n\n if (!provided) {\n // sorted list of all types\n return accepts\n .filter((spec): spec is MediaType => spec.q > 0)\n .sort((a, b) => {\n return b.q - a.q || b.i - a.i || 0;\n })\n .map(getFullType);\n }\n\n const priorities = provided.map(function getPriority(type: string, index: number) {\n return getMediaTypePriority(type, accepts, index);\n });\n\n // sorted list of accepted types\n return priorities\n .filter((spec): spec is Priority => spec.q > 0)\n .sort(compareSpecs)\n .map(function getType(priority: Priority) {\n return provided[priorities.indexOf(priority)];\n });\n}\n\n/**\n * Module variables.\n * @private\n */\n\nconst simpleMediaTypeRegExp = /^\\s*([^\\s\\/;]+)\\/([^;\\s]+)\\s*(?:;(.*))?$/;\n\n/**\n * Media type interface\n * @private\n */\ninterface MediaType {\n type: string;\n subtype: string;\n params: Record<string, string>;\n q: number;\n i: number;\n}\n\n/**\n * Priority interface\n * @private\n */\ninterface Priority {\n o: number;\n q: number;\n s: number;\n i?: number;\n}\n\n/**\n * Parse the Accept header.\n * @private\n */\nfunction parseAccept(accept: string): MediaType[] {\n const accepts = splitMediaTypes(accept);\n const result: MediaType[] = [];\n\n for (let i = 0, j = 0; i < accepts.length; i++) {\n const mediaType = parseMediaType(accepts[i].trim(), i);\n\n if (mediaType) {\n result[j++] = mediaType;\n }\n }\n\n return result;\n}\n\n/**\n * Parse a media type from the Accept header.\n * @private\n */\nfunction parseMediaType(str: string, i: number): MediaType | null {\n const match = simpleMediaTypeRegExp.exec(str);\n if (!match) return null;\n\n const params: Record<string, string> = Object.create(null);\n let q = 1;\n const subtype = match[2];\n const type = match[1];\n\n if (match[3]) {\n const kvps = splitParameters(match[3]).map(splitKeyValuePair);\n\n for (let j = 0; j < kvps.length; j++) {\n const pair = kvps[j];\n const key = pair[0].toLowerCase();\n const val = pair[1];\n\n // get the value, unwrapping quotes\n const value = val && val[0] === '\"' && val[val.length - 1] === '\"' ? val.slice(1, -1) : val;\n\n if (key === \"q\") {\n q = parseFloat(value);\n break;\n }\n\n // store parameter\n params[key] = value;\n }\n }\n\n return {\n type: type,\n subtype: subtype,\n params: params,\n q: q,\n i: i,\n };\n}\n\n/**\n * Get the priority of a media type.\n * @private\n */\nfunction getMediaTypePriority(type: string, accepted: MediaType[], index: number): Priority {\n const priority: Priority = { o: -1, q: 0, s: 0 };\n\n for (let i = 0; i < accepted.length; i++) {\n const spec = specify(type, accepted[i], index);\n\n if (spec && (priority.s - spec.s || priority.q - spec.q || priority.o - spec.o) < 0) {\n priority.o = spec.o;\n priority.q = spec.q;\n priority.s = spec.s;\n priority.i = spec.i;\n }\n }\n\n return priority;\n}\n\n/**\n * Get the specificity of the media type.\n * @private\n */\nfunction specify(type: string, spec: MediaType, index: number): Priority | null {\n const p = parseMediaType(type, 0);\n let s = 0;\n\n if (!p) {\n return null;\n }\n\n if (spec.type.toLowerCase() == p.type.toLowerCase()) {\n s |= 4;\n } else if (spec.type != \"*\") {\n return null;\n }\n\n if (spec.subtype.toLowerCase() == p.subtype.toLowerCase()) {\n s |= 2;\n } else if (spec.subtype != \"*\") {\n return null;\n }\n\n const keys = Object.keys(spec.params);\n if (keys.length > 0) {\n if (\n keys.every(function (k) {\n return (\n spec.params[k] == \"*\" ||\n (spec.params[k] || \"\").toLowerCase() == (p.params[k] || \"\").toLowerCase()\n );\n })\n ) {\n s |= 1;\n } else {\n return null;\n }\n }\n\n return {\n i: index,\n o: spec.i,\n q: spec.q,\n s: s,\n };\n}\n\n/**\n * Compare two specs.\n * @private\n */\nfunction compareSpecs(a: Priority, b: Priority): number {\n return b.q - a.q || b.s - a.s || (a.o || 0) - (b.o || 0) || (a.i || 0) - (b.i || 0) || 0;\n}\n\n/**\n * Get full type string.\n * @private\n */\nfunction getFullType(spec: MediaType): string {\n return spec.type + \"/\" + spec.subtype;\n}\n\n/**\n * Check if a spec has any quality.\n * @private\n */\nfunction isQuality(spec: Priority | MediaType): boolean {\n return spec.q > 0;\n}\n\n/**\n * Count the number of quotes in a string.\n * @private\n */\nfunction quoteCount(string: string): number {\n let count = 0;\n let index = 0;\n\n while ((index = string.indexOf('\"', index)) !== -1) {\n count++;\n index++;\n }\n\n return count;\n}\n\n/**\n * Split a key value pair.\n * @private\n */\nfunction splitKeyValuePair(str: string): [string, string] {\n const index = str.indexOf(\"=\");\n let key: string;\n let val: string = \"\";\n\n if (index === -1) {\n key = str;\n } else {\n key = str.slice(0, index);\n val = str.slice(index + 1);\n }\n\n return [key, val];\n}\n\n/**\n * Split an Accept header into media types.\n * @private\n */\nfunction splitMediaTypes(accept: string): string[] {\n const accepts = accept.split(\",\");\n const result: string[] = [accepts[0]];\n\n for (let i = 1, j = 0; i < accepts.length; i++) {\n if (quoteCount(result[j]) % 2 == 0) {\n result[++j] = accepts[i];\n } else {\n result[j] += \",\" + accepts[i];\n }\n }\n\n // trim result\n return result;\n}\n\n/**\n * Split a string of parameters.\n * @private\n */\nfunction splitParameters(str: string): string[] {\n const parameters = str.split(\";\");\n const result: string[] = [parameters[0]];\n\n for (let i = 1, j = 0; i < parameters.length; i++) {\n if (quoteCount(result[j]) % 2 == 0) {\n result[++j] = parameters[i];\n } else {\n result[j] += \";\" + parameters[i];\n }\n }\n\n // trim parameters\n for (let i = 0; i < result.length; i++) {\n result[i] = result[i].trim();\n }\n\n return result;\n}\n","export * from \"./encoder\";\nexport { AGUI_MEDIA_TYPE } from \"@ag-ui/proto\";\n"],"mappings":"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","names":["AGUI_MEDIA_TYPE"]}
package/jest.config.js ADDED
@@ -0,0 +1,6 @@
1
+ /** @type {import('ts-jest').JestConfigWithTsJest} */
2
+ module.exports = {
3
+ preset: "ts-jest",
4
+ testEnvironment: "node",
5
+ testMatch: ["**/*.test.ts"],
6
+ };
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@ag-ui/encoder",
3
+ "author": "Markus Ecker <markus.ecker@gmail.com>",
4
+ "version": "0.0.27",
5
+ "private": false,
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
9
+ "main": "./dist/index.js",
10
+ "module": "./dist/index.mjs",
11
+ "types": "./dist/index.d.ts",
12
+ "dependencies": {
13
+ "@ag-ui/core": "0.0.27",
14
+ "@ag-ui/proto": "0.0.27"
15
+ },
16
+ "devDependencies": {
17
+ "@types/jest": "^29.5.12",
18
+ "jest": "^29.7.0",
19
+ "ts-jest": "^29.1.2",
20
+ "tsup": "^8.0.2",
21
+ "typescript": "^5.8.2"
22
+ },
23
+ "scripts": {
24
+ "build": "tsup",
25
+ "dev": "tsup --watch",
26
+ "lint": "eslint \"src/**/*.ts*\"",
27
+ "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist",
28
+ "test": "jest",
29
+ "link:global": "pnpm link --global",
30
+ "unlink:global": "pnpm unlink --global"
31
+ }
32
+ }
@@ -0,0 +1,101 @@
1
+ import { EventEncoder } from "../encoder";
2
+ import { BaseEvent, EventType, TextMessageStartEvent } from "@ag-ui/core";
3
+ import * as proto from "@ag-ui/proto";
4
+
5
+ describe("Encoder Tests", () => {
6
+ // Create a valid TextMessageStartEvent event
7
+ const testEvent: TextMessageStartEvent = {
8
+ type: EventType.TEXT_MESSAGE_START,
9
+ timestamp: 123456789,
10
+ messageId: "msg123",
11
+ role: "assistant",
12
+ };
13
+
14
+ describe("encodeBinary method", () => {
15
+ it("should return protobuf encoded data when accept header includes protobuf media type", () => {
16
+ // Setup an encoder with protobuf accepted
17
+ const encoder = new EventEncoder({
18
+ accept: `text/event-stream, ${proto.AGUI_MEDIA_TYPE}`,
19
+ });
20
+
21
+ // Get the binary encoding
22
+ const result = encoder.encodeBinary(testEvent);
23
+
24
+ // Verify it's a Uint8Array
25
+ expect(result).toBeInstanceOf(Uint8Array);
26
+
27
+ // A protobuf message should start with 4 bytes for length followed by the message
28
+ // So the length should be greater than 4 at minimum
29
+ expect(result.length).toBeGreaterThan(4);
30
+
31
+ // The first 4 bytes should be a uint32 representing the message length
32
+ const dataView = new DataView(result.buffer);
33
+ const messageLength = dataView.getUint32(0, false); // false for big-endian
34
+
35
+ // The actual message should match the length specified in the header
36
+ expect(result.length - 4).toBe(messageLength);
37
+ });
38
+
39
+ it("should return SSE encoded data when accept header doesn't include protobuf media type", () => {
40
+ // Setup an encoder without protobuf accepted
41
+ const encoder = new EventEncoder({
42
+ accept: "text/event-stream",
43
+ });
44
+
45
+ // Get the binary encoding
46
+ const result = encoder.encodeBinary(testEvent);
47
+
48
+ // Verify it's a Uint8Array
49
+ expect(result).toBeInstanceOf(Uint8Array);
50
+
51
+ // Convert back to string to verify it's SSE format
52
+ const decoder = new TextDecoder();
53
+ const resultString = decoder.decode(result);
54
+
55
+ // Should match the SSE format with the expected JSON
56
+ expect(resultString).toBe(`data: ${JSON.stringify(testEvent)}\n\n`);
57
+ });
58
+
59
+ it("should return SSE encoded data when no accept header is provided", () => {
60
+ // Setup an encoder without any accept header
61
+ const encoder = new EventEncoder();
62
+
63
+ // Get the binary encoding
64
+ const result = encoder.encodeBinary(testEvent);
65
+
66
+ // Verify it's a Uint8Array
67
+ expect(result).toBeInstanceOf(Uint8Array);
68
+
69
+ // Convert back to string to verify it's SSE format
70
+ const decoder = new TextDecoder();
71
+ const resultString = decoder.decode(result);
72
+
73
+ // Should match the SSE format with the expected JSON
74
+ expect(resultString).toBe(`data: ${JSON.stringify(testEvent)}\n\n`);
75
+ });
76
+ });
77
+
78
+ describe("encodeProtobuf method", () => {
79
+ it("should encode event as protobuf with length prefix", () => {
80
+ const encoder = new EventEncoder();
81
+
82
+ const result = encoder.encodeProtobuf(testEvent);
83
+
84
+ // Verify it's a Uint8Array
85
+ expect(result).toBeInstanceOf(Uint8Array);
86
+
87
+ // A protobuf message should start with 4 bytes for length followed by the message
88
+ expect(result.length).toBeGreaterThan(4);
89
+
90
+ // The first 4 bytes should be a uint32 representing the message length
91
+ const dataView = new DataView(result.buffer);
92
+ const messageLength = dataView.getUint32(0, false); // false for big-endian
93
+
94
+ // The actual message should match the length specified in the header
95
+ expect(result.length - 4).toBe(messageLength);
96
+
97
+ // The message length should be greater than zero
98
+ expect(messageLength).toBeGreaterThan(0);
99
+ });
100
+ });
101
+ });
package/src/encoder.ts ADDED
@@ -0,0 +1,69 @@
1
+ import { BaseEvent } from "@ag-ui/core";
2
+ import * as proto from "@ag-ui/proto";
3
+ import { preferredMediaTypes } from "./media-type";
4
+
5
+ export interface EventEncoderParams {
6
+ accept?: string;
7
+ }
8
+
9
+ export class EventEncoder {
10
+ private acceptsProtobuf: boolean;
11
+
12
+ constructor(params?: EventEncoderParams) {
13
+ this.acceptsProtobuf = params?.accept ? this.isProtobufAccepted(params.accept) : false;
14
+ }
15
+
16
+ getContentType(): string {
17
+ if (this.acceptsProtobuf) {
18
+ return proto.AGUI_MEDIA_TYPE;
19
+ } else {
20
+ return "text/event-stream";
21
+ }
22
+ }
23
+
24
+ encode(event: BaseEvent): string {
25
+ return this.encodeSSE(event);
26
+ }
27
+
28
+ encodeSSE(event: BaseEvent): string {
29
+ return `data: ${JSON.stringify(event)}\n\n`;
30
+ }
31
+
32
+ encodeBinary(event: BaseEvent): Uint8Array {
33
+ if (this.acceptsProtobuf) {
34
+ return this.encodeProtobuf(event);
35
+ } else {
36
+ const sseString = this.encodeSSE(event);
37
+ // Convert string to Uint8Array using TextEncoder
38
+ const encoder = new TextEncoder();
39
+ return encoder.encode(sseString);
40
+ }
41
+ }
42
+
43
+ encodeProtobuf(event: BaseEvent): Uint8Array {
44
+ const messageBytes = proto.encode(event);
45
+ const length = messageBytes.length;
46
+
47
+ // Create a buffer for 4 bytes (for the uint32 length) plus the message bytes
48
+ const buffer = new ArrayBuffer(4 + length);
49
+ const dataView = new DataView(buffer);
50
+
51
+ // Write the length as a uint32
52
+ // Set the third parameter to `false` for big-endian or `true` for little-endian
53
+ dataView.setUint32(0, length, false);
54
+
55
+ // Create a Uint8Array view and copy in the message bytes after the 4-byte header
56
+ const result = new Uint8Array(buffer);
57
+ result.set(messageBytes, 4);
58
+
59
+ return result;
60
+ }
61
+
62
+ private isProtobufAccepted(acceptHeader: string): boolean {
63
+ // Pass the Accept header and an array with your media type
64
+ const preferred = preferredMediaTypes(acceptHeader, [proto.AGUI_MEDIA_TYPE]);
65
+
66
+ // If the returned array includes your media type, it's acceptable
67
+ return preferred.includes(proto.AGUI_MEDIA_TYPE);
68
+ }
69
+ }
package/src/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export * from "./encoder";
2
+ export { AGUI_MEDIA_TYPE } from "@ag-ui/proto";
@@ -0,0 +1,305 @@
1
+ /**
2
+ * negotiator
3
+ * Copyright(c) 2012 Isaac Z. Schlueter
4
+ * Copyright(c) 2014 Federico Romero
5
+ * Copyright(c) 2014-2015 Douglas Christopher Wilson
6
+ * MIT Licensed
7
+ */
8
+
9
+ // modified from https://github.com/jshttp/negotiator/blob/master/lib/mediaType.js
10
+
11
+ /**
12
+ * Module exports.
13
+ * @public
14
+ */
15
+
16
+ export function preferredMediaTypes(accept?: string, provided?: string[]): string[] {
17
+ // RFC 2616 sec 14.2: no header = */*
18
+ const accepts = parseAccept(accept === undefined ? "*/*" : accept || "");
19
+
20
+ if (!provided) {
21
+ // sorted list of all types
22
+ return accepts
23
+ .filter((spec): spec is MediaType => spec.q > 0)
24
+ .sort((a, b) => {
25
+ return b.q - a.q || b.i - a.i || 0;
26
+ })
27
+ .map(getFullType);
28
+ }
29
+
30
+ const priorities = provided.map(function getPriority(type: string, index: number) {
31
+ return getMediaTypePriority(type, accepts, index);
32
+ });
33
+
34
+ // sorted list of accepted types
35
+ return priorities
36
+ .filter((spec): spec is Priority => spec.q > 0)
37
+ .sort(compareSpecs)
38
+ .map(function getType(priority: Priority) {
39
+ return provided[priorities.indexOf(priority)];
40
+ });
41
+ }
42
+
43
+ /**
44
+ * Module variables.
45
+ * @private
46
+ */
47
+
48
+ const simpleMediaTypeRegExp = /^\s*([^\s\/;]+)\/([^;\s]+)\s*(?:;(.*))?$/;
49
+
50
+ /**
51
+ * Media type interface
52
+ * @private
53
+ */
54
+ interface MediaType {
55
+ type: string;
56
+ subtype: string;
57
+ params: Record<string, string>;
58
+ q: number;
59
+ i: number;
60
+ }
61
+
62
+ /**
63
+ * Priority interface
64
+ * @private
65
+ */
66
+ interface Priority {
67
+ o: number;
68
+ q: number;
69
+ s: number;
70
+ i?: number;
71
+ }
72
+
73
+ /**
74
+ * Parse the Accept header.
75
+ * @private
76
+ */
77
+ function parseAccept(accept: string): MediaType[] {
78
+ const accepts = splitMediaTypes(accept);
79
+ const result: MediaType[] = [];
80
+
81
+ for (let i = 0, j = 0; i < accepts.length; i++) {
82
+ const mediaType = parseMediaType(accepts[i].trim(), i);
83
+
84
+ if (mediaType) {
85
+ result[j++] = mediaType;
86
+ }
87
+ }
88
+
89
+ return result;
90
+ }
91
+
92
+ /**
93
+ * Parse a media type from the Accept header.
94
+ * @private
95
+ */
96
+ function parseMediaType(str: string, i: number): MediaType | null {
97
+ const match = simpleMediaTypeRegExp.exec(str);
98
+ if (!match) return null;
99
+
100
+ const params: Record<string, string> = Object.create(null);
101
+ let q = 1;
102
+ const subtype = match[2];
103
+ const type = match[1];
104
+
105
+ if (match[3]) {
106
+ const kvps = splitParameters(match[3]).map(splitKeyValuePair);
107
+
108
+ for (let j = 0; j < kvps.length; j++) {
109
+ const pair = kvps[j];
110
+ const key = pair[0].toLowerCase();
111
+ const val = pair[1];
112
+
113
+ // get the value, unwrapping quotes
114
+ const value = val && val[0] === '"' && val[val.length - 1] === '"' ? val.slice(1, -1) : val;
115
+
116
+ if (key === "q") {
117
+ q = parseFloat(value);
118
+ break;
119
+ }
120
+
121
+ // store parameter
122
+ params[key] = value;
123
+ }
124
+ }
125
+
126
+ return {
127
+ type: type,
128
+ subtype: subtype,
129
+ params: params,
130
+ q: q,
131
+ i: i,
132
+ };
133
+ }
134
+
135
+ /**
136
+ * Get the priority of a media type.
137
+ * @private
138
+ */
139
+ function getMediaTypePriority(type: string, accepted: MediaType[], index: number): Priority {
140
+ const priority: Priority = { o: -1, q: 0, s: 0 };
141
+
142
+ for (let i = 0; i < accepted.length; i++) {
143
+ const spec = specify(type, accepted[i], index);
144
+
145
+ if (spec && (priority.s - spec.s || priority.q - spec.q || priority.o - spec.o) < 0) {
146
+ priority.o = spec.o;
147
+ priority.q = spec.q;
148
+ priority.s = spec.s;
149
+ priority.i = spec.i;
150
+ }
151
+ }
152
+
153
+ return priority;
154
+ }
155
+
156
+ /**
157
+ * Get the specificity of the media type.
158
+ * @private
159
+ */
160
+ function specify(type: string, spec: MediaType, index: number): Priority | null {
161
+ const p = parseMediaType(type, 0);
162
+ let s = 0;
163
+
164
+ if (!p) {
165
+ return null;
166
+ }
167
+
168
+ if (spec.type.toLowerCase() == p.type.toLowerCase()) {
169
+ s |= 4;
170
+ } else if (spec.type != "*") {
171
+ return null;
172
+ }
173
+
174
+ if (spec.subtype.toLowerCase() == p.subtype.toLowerCase()) {
175
+ s |= 2;
176
+ } else if (spec.subtype != "*") {
177
+ return null;
178
+ }
179
+
180
+ const keys = Object.keys(spec.params);
181
+ if (keys.length > 0) {
182
+ if (
183
+ keys.every(function (k) {
184
+ return (
185
+ spec.params[k] == "*" ||
186
+ (spec.params[k] || "").toLowerCase() == (p.params[k] || "").toLowerCase()
187
+ );
188
+ })
189
+ ) {
190
+ s |= 1;
191
+ } else {
192
+ return null;
193
+ }
194
+ }
195
+
196
+ return {
197
+ i: index,
198
+ o: spec.i,
199
+ q: spec.q,
200
+ s: s,
201
+ };
202
+ }
203
+
204
+ /**
205
+ * Compare two specs.
206
+ * @private
207
+ */
208
+ function compareSpecs(a: Priority, b: Priority): number {
209
+ return b.q - a.q || b.s - a.s || (a.o || 0) - (b.o || 0) || (a.i || 0) - (b.i || 0) || 0;
210
+ }
211
+
212
+ /**
213
+ * Get full type string.
214
+ * @private
215
+ */
216
+ function getFullType(spec: MediaType): string {
217
+ return spec.type + "/" + spec.subtype;
218
+ }
219
+
220
+ /**
221
+ * Check if a spec has any quality.
222
+ * @private
223
+ */
224
+ function isQuality(spec: Priority | MediaType): boolean {
225
+ return spec.q > 0;
226
+ }
227
+
228
+ /**
229
+ * Count the number of quotes in a string.
230
+ * @private
231
+ */
232
+ function quoteCount(string: string): number {
233
+ let count = 0;
234
+ let index = 0;
235
+
236
+ while ((index = string.indexOf('"', index)) !== -1) {
237
+ count++;
238
+ index++;
239
+ }
240
+
241
+ return count;
242
+ }
243
+
244
+ /**
245
+ * Split a key value pair.
246
+ * @private
247
+ */
248
+ function splitKeyValuePair(str: string): [string, string] {
249
+ const index = str.indexOf("=");
250
+ let key: string;
251
+ let val: string = "";
252
+
253
+ if (index === -1) {
254
+ key = str;
255
+ } else {
256
+ key = str.slice(0, index);
257
+ val = str.slice(index + 1);
258
+ }
259
+
260
+ return [key, val];
261
+ }
262
+
263
+ /**
264
+ * Split an Accept header into media types.
265
+ * @private
266
+ */
267
+ function splitMediaTypes(accept: string): string[] {
268
+ const accepts = accept.split(",");
269
+ const result: string[] = [accepts[0]];
270
+
271
+ for (let i = 1, j = 0; i < accepts.length; i++) {
272
+ if (quoteCount(result[j]) % 2 == 0) {
273
+ result[++j] = accepts[i];
274
+ } else {
275
+ result[j] += "," + accepts[i];
276
+ }
277
+ }
278
+
279
+ // trim result
280
+ return result;
281
+ }
282
+
283
+ /**
284
+ * Split a string of parameters.
285
+ * @private
286
+ */
287
+ function splitParameters(str: string): string[] {
288
+ const parameters = str.split(";");
289
+ const result: string[] = [parameters[0]];
290
+
291
+ for (let i = 1, j = 0; i < parameters.length; i++) {
292
+ if (quoteCount(result[j]) % 2 == 0) {
293
+ result[++j] = parameters[i];
294
+ } else {
295
+ result[j] += ";" + parameters[i];
296
+ }
297
+ }
298
+
299
+ // trim parameters
300
+ for (let i = 0; i < result.length; i++) {
301
+ result[i] = result[i].trim();
302
+ }
303
+
304
+ return result;
305
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "es2017",
4
+ "module": "esnext",
5
+ "lib": ["dom", "dom.iterable", "esnext"],
6
+ "declaration": true,
7
+ "declarationMap": true,
8
+ "sourceMap": true,
9
+ "moduleResolution": "node",
10
+ "skipLibCheck": true,
11
+ "strict": true,
12
+ "jsx": "react-jsx",
13
+ "esModuleInterop": true,
14
+ "resolveJsonModule": true,
15
+ "isolatedModules": true,
16
+ "baseUrl": ".",
17
+ "paths": {
18
+ "@/*": ["./src/*"]
19
+ }
20
+ },
21
+ "include": ["src"],
22
+ "exclude": ["node_modules", "dist"]
23
+ }
package/tsup.config.ts ADDED
@@ -0,0 +1,10 @@
1
+ import { defineConfig } from "tsup";
2
+
3
+ export default defineConfig({
4
+ entry: ["src/index.ts"],
5
+ format: ["cjs", "esm"],
6
+ dts: true,
7
+ splitting: false,
8
+ sourcemap: true,
9
+ clean: true,
10
+ });