@anvia/server 0.2.0 → 0.3.1
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/index.d.ts +4 -1
- package/dist/index.js +51 -43
- package/dist/index.js.map +1 -1
- package/package.json +3 -1
package/dist/index.d.ts
CHANGED
|
@@ -19,8 +19,11 @@ type SseStreamOptions<TEvent> = {
|
|
|
19
19
|
serialize?: (event: TEvent | EventStreamErrorEvent) => string;
|
|
20
20
|
retry?: number;
|
|
21
21
|
};
|
|
22
|
-
|
|
22
|
+
|
|
23
23
|
declare function createJsonlStream<TEvent>(events: AsyncIterable<TEvent>, options?: JsonlStreamOptions<TEvent>): ReadableStream<Uint8Array>;
|
|
24
|
+
|
|
25
|
+
declare function createEventStream<TEvent>(events: AsyncIterable<TEvent>, options?: CreateEventStreamOptions<TEvent>): Response;
|
|
26
|
+
|
|
24
27
|
declare function createSseStream<TEvent>(events: AsyncIterable<TEvent>, options?: SseStreamOptions<TEvent>): ReadableStream<Uint8Array>;
|
|
25
28
|
|
|
26
29
|
export { type CreateEventStreamOptions, type EventStreamErrorEvent, type EventStreamFormat, type JsonlStreamOptions, type SseStreamOptions, createEventStream, createJsonlStream, createSseStream };
|
package/dist/index.js
CHANGED
|
@@ -1,32 +1,21 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
function
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const body = format === "sse" ? createSseStream(events, options.sse) : createJsonlStream(events, options.jsonl);
|
|
15
|
-
if (!headers.has("content-type")) {
|
|
16
|
-
headers.set(
|
|
17
|
-
"content-type",
|
|
18
|
-
format === "sse" ? "text/event-stream; charset=utf-8" : "application/x-ndjson; charset=utf-8"
|
|
19
|
-
);
|
|
20
|
-
}
|
|
21
|
-
const responseInit = { headers };
|
|
22
|
-
if (options.status !== void 0) {
|
|
23
|
-
responseInit.status = options.status;
|
|
24
|
-
}
|
|
25
|
-
if (options.statusText !== void 0) {
|
|
26
|
-
responseInit.statusText = options.statusText;
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
function errorEvent(error) {
|
|
3
|
+
return {
|
|
4
|
+
type: "error",
|
|
5
|
+
error: serializeError(error)
|
|
6
|
+
};
|
|
7
|
+
}
|
|
8
|
+
function serializeError(error) {
|
|
9
|
+
if (error instanceof Error) {
|
|
10
|
+
return {
|
|
11
|
+
name: error.name,
|
|
12
|
+
message: error.message
|
|
13
|
+
};
|
|
27
14
|
}
|
|
28
|
-
return
|
|
15
|
+
return error;
|
|
29
16
|
}
|
|
17
|
+
|
|
18
|
+
// src/jsonl.ts
|
|
30
19
|
function createJsonlStream(events, options = {}) {
|
|
31
20
|
const encoder = new TextEncoder();
|
|
32
21
|
const iterator = events[Symbol.asyncIterator]();
|
|
@@ -52,10 +41,15 @@ function createJsonlStream(events, options = {}) {
|
|
|
52
41
|
}
|
|
53
42
|
});
|
|
54
43
|
}
|
|
44
|
+
function serializeJson(value) {
|
|
45
|
+
return JSON.stringify(value);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// src/sse.ts
|
|
55
49
|
function createSseStream(events, options = {}) {
|
|
56
50
|
const encoder = new TextEncoder();
|
|
57
51
|
const iterator = events[Symbol.asyncIterator]();
|
|
58
|
-
const serialize = options.serialize ??
|
|
52
|
+
const serialize = options.serialize ?? serializeJson2;
|
|
59
53
|
return new ReadableStream({
|
|
60
54
|
start(controller) {
|
|
61
55
|
if (options.retry !== void 0) {
|
|
@@ -97,24 +91,38 @@ function formatSseEvent(event, serialize, eventName) {
|
|
|
97
91
|
lines.push("", "");
|
|
98
92
|
return lines.join("\n");
|
|
99
93
|
}
|
|
100
|
-
function
|
|
94
|
+
function serializeJson2(value) {
|
|
101
95
|
return JSON.stringify(value);
|
|
102
96
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
if (error instanceof Error) {
|
|
111
|
-
return {
|
|
112
|
-
name: error.name,
|
|
113
|
-
message: error.message,
|
|
114
|
-
stack: error.stack
|
|
115
|
-
};
|
|
97
|
+
|
|
98
|
+
// src/response.ts
|
|
99
|
+
function createEventStream(events, options = {}) {
|
|
100
|
+
const format = options.format ?? "jsonl";
|
|
101
|
+
const headers = new Headers(options.headers);
|
|
102
|
+
if (!headers.has("cache-control")) {
|
|
103
|
+
headers.set("cache-control", "no-cache, no-transform");
|
|
116
104
|
}
|
|
117
|
-
|
|
105
|
+
if (!headers.has("connection")) {
|
|
106
|
+
headers.set("connection", "keep-alive");
|
|
107
|
+
}
|
|
108
|
+
if (!headers.has("x-accel-buffering")) {
|
|
109
|
+
headers.set("x-accel-buffering", "no");
|
|
110
|
+
}
|
|
111
|
+
const body = format === "sse" ? createSseStream(events, options.sse) : createJsonlStream(events, options.jsonl);
|
|
112
|
+
if (!headers.has("content-type")) {
|
|
113
|
+
headers.set(
|
|
114
|
+
"content-type",
|
|
115
|
+
format === "sse" ? "text/event-stream; charset=utf-8" : "application/x-ndjson; charset=utf-8"
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
const responseInit = { headers };
|
|
119
|
+
if (options.status !== void 0) {
|
|
120
|
+
responseInit.status = options.status;
|
|
121
|
+
}
|
|
122
|
+
if (options.statusText !== void 0) {
|
|
123
|
+
responseInit.statusText = options.statusText;
|
|
124
|
+
}
|
|
125
|
+
return new Response(body, responseInit);
|
|
118
126
|
}
|
|
119
127
|
export {
|
|
120
128
|
createEventStream,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/jsonl.ts","../src/sse.ts","../src/response.ts"],"sourcesContent":["import type { EventStreamErrorEvent } from \"./types\";\n\nexport function errorEvent(error: unknown): EventStreamErrorEvent {\n return {\n type: \"error\",\n error: serializeError(error),\n };\n}\n\nfunction serializeError(error: unknown): unknown {\n if (error instanceof Error) {\n return {\n name: error.name,\n message: error.message,\n };\n }\n\n return error;\n}\n","import { errorEvent } from \"./errors\";\nimport type { JsonlStreamOptions } from \"./types\";\n\nexport function createJsonlStream<TEvent>(\n events: AsyncIterable<TEvent>,\n options: JsonlStreamOptions<TEvent> = {},\n): ReadableStream<Uint8Array> {\n const encoder = new TextEncoder();\n const iterator = events[Symbol.asyncIterator]();\n const serialize = options.serialize ?? serializeJson;\n\n return new ReadableStream<Uint8Array>({\n async pull(controller) {\n try {\n const next = await iterator.next();\n if (next.done === true) {\n controller.close();\n return;\n }\n\n controller.enqueue(encoder.encode(`${serialize(next.value)}\\n`));\n } catch (error) {\n controller.enqueue(encoder.encode(`${serialize(errorEvent(error))}\\n`));\n controller.close();\n }\n },\n async cancel() {\n await iterator.return?.();\n },\n });\n}\n\nfunction serializeJson(value: unknown): string {\n return JSON.stringify(value);\n}\n","import { errorEvent } from \"./errors\";\nimport type { EventStreamErrorEvent, SseStreamOptions } from \"./types\";\n\nexport function createSseStream<TEvent>(\n events: AsyncIterable<TEvent>,\n options: SseStreamOptions<TEvent> = {},\n): ReadableStream<Uint8Array> {\n const encoder = new TextEncoder();\n const iterator = events[Symbol.asyncIterator]();\n const serialize = options.serialize ?? serializeJson;\n\n return new ReadableStream<Uint8Array>({\n start(controller) {\n if (options.retry !== undefined) {\n controller.enqueue(encoder.encode(`retry: ${options.retry}\\n\\n`));\n }\n },\n async pull(controller) {\n try {\n const next = await iterator.next();\n if (next.done === true) {\n controller.close();\n return;\n }\n\n controller.enqueue(\n encoder.encode(formatSseEvent(next.value, serialize, options.eventName)),\n );\n } catch (error) {\n const event = errorEvent(error);\n controller.enqueue(encoder.encode(formatSseEvent(event, serialize, options.eventName)));\n controller.close();\n }\n },\n async cancel() {\n await iterator.return?.();\n },\n });\n}\n\nfunction formatSseEvent<TEvent>(\n event: TEvent | EventStreamErrorEvent,\n serialize: (event: TEvent | EventStreamErrorEvent) => string,\n eventName: SseStreamOptions<TEvent>[\"eventName\"],\n): string {\n const name = typeof eventName === \"function\" ? eventName(event) : eventName;\n const lines: string[] = [];\n\n if (name !== undefined && name.length > 0) {\n lines.push(`event: ${name}`);\n }\n\n for (const line of serialize(event).split(/\\r?\\n/)) {\n lines.push(`data: ${line}`);\n }\n\n lines.push(\"\", \"\");\n return lines.join(\"\\n\");\n}\n\nfunction serializeJson(value: unknown): string {\n return JSON.stringify(value);\n}\n","import { createJsonlStream } from \"./jsonl\";\nimport { createSseStream } from \"./sse\";\nimport type { CreateEventStreamOptions } from \"./types\";\n\nexport function createEventStream<TEvent>(\n events: AsyncIterable<TEvent>,\n options: CreateEventStreamOptions<TEvent> = {},\n): Response {\n const format = options.format ?? \"jsonl\";\n const headers = new Headers(options.headers);\n\n if (!headers.has(\"cache-control\")) {\n headers.set(\"cache-control\", \"no-cache, no-transform\");\n }\n if (!headers.has(\"connection\")) {\n headers.set(\"connection\", \"keep-alive\");\n }\n if (!headers.has(\"x-accel-buffering\")) {\n headers.set(\"x-accel-buffering\", \"no\");\n }\n\n const body =\n format === \"sse\"\n ? createSseStream(events, options.sse)\n : createJsonlStream(events, options.jsonl);\n\n if (!headers.has(\"content-type\")) {\n headers.set(\n \"content-type\",\n format === \"sse\" ? \"text/event-stream; charset=utf-8\" : \"application/x-ndjson; charset=utf-8\",\n );\n }\n\n const responseInit: ResponseInit = { headers };\n if (options.status !== undefined) {\n responseInit.status = options.status;\n }\n if (options.statusText !== undefined) {\n responseInit.statusText = options.statusText;\n }\n\n return new Response(body, responseInit);\n}\n"],"mappings":";AAEO,SAAS,WAAW,OAAuC;AAChE,SAAO;AAAA,IACL,MAAM;AAAA,IACN,OAAO,eAAe,KAAK;AAAA,EAC7B;AACF;AAEA,SAAS,eAAe,OAAyB;AAC/C,MAAI,iBAAiB,OAAO;AAC1B,WAAO;AAAA,MACL,MAAM,MAAM;AAAA,MACZ,SAAS,MAAM;AAAA,IACjB;AAAA,EACF;AAEA,SAAO;AACT;;;ACfO,SAAS,kBACd,QACA,UAAsC,CAAC,GACX;AAC5B,QAAM,UAAU,IAAI,YAAY;AAChC,QAAM,WAAW,OAAO,OAAO,aAAa,EAAE;AAC9C,QAAM,YAAY,QAAQ,aAAa;AAEvC,SAAO,IAAI,eAA2B;AAAA,IACpC,MAAM,KAAK,YAAY;AACrB,UAAI;AACF,cAAM,OAAO,MAAM,SAAS,KAAK;AACjC,YAAI,KAAK,SAAS,MAAM;AACtB,qBAAW,MAAM;AACjB;AAAA,QACF;AAEA,mBAAW,QAAQ,QAAQ,OAAO,GAAG,UAAU,KAAK,KAAK,CAAC;AAAA,CAAI,CAAC;AAAA,MACjE,SAAS,OAAO;AACd,mBAAW,QAAQ,QAAQ,OAAO,GAAG,UAAU,WAAW,KAAK,CAAC,CAAC;AAAA,CAAI,CAAC;AACtE,mBAAW,MAAM;AAAA,MACnB;AAAA,IACF;AAAA,IACA,MAAM,SAAS;AACb,YAAM,SAAS,SAAS;AAAA,IAC1B;AAAA,EACF,CAAC;AACH;AAEA,SAAS,cAAc,OAAwB;AAC7C,SAAO,KAAK,UAAU,KAAK;AAC7B;;;AC/BO,SAAS,gBACd,QACA,UAAoC,CAAC,GACT;AAC5B,QAAM,UAAU,IAAI,YAAY;AAChC,QAAM,WAAW,OAAO,OAAO,aAAa,EAAE;AAC9C,QAAM,YAAY,QAAQ,aAAaA;AAEvC,SAAO,IAAI,eAA2B;AAAA,IACpC,MAAM,YAAY;AAChB,UAAI,QAAQ,UAAU,QAAW;AAC/B,mBAAW,QAAQ,QAAQ,OAAO,UAAU,QAAQ,KAAK;AAAA;AAAA,CAAM,CAAC;AAAA,MAClE;AAAA,IACF;AAAA,IACA,MAAM,KAAK,YAAY;AACrB,UAAI;AACF,cAAM,OAAO,MAAM,SAAS,KAAK;AACjC,YAAI,KAAK,SAAS,MAAM;AACtB,qBAAW,MAAM;AACjB;AAAA,QACF;AAEA,mBAAW;AAAA,UACT,QAAQ,OAAO,eAAe,KAAK,OAAO,WAAW,QAAQ,SAAS,CAAC;AAAA,QACzE;AAAA,MACF,SAAS,OAAO;AACd,cAAM,QAAQ,WAAW,KAAK;AAC9B,mBAAW,QAAQ,QAAQ,OAAO,eAAe,OAAO,WAAW,QAAQ,SAAS,CAAC,CAAC;AACtF,mBAAW,MAAM;AAAA,MACnB;AAAA,IACF;AAAA,IACA,MAAM,SAAS;AACb,YAAM,SAAS,SAAS;AAAA,IAC1B;AAAA,EACF,CAAC;AACH;AAEA,SAAS,eACP,OACA,WACA,WACQ;AACR,QAAM,OAAO,OAAO,cAAc,aAAa,UAAU,KAAK,IAAI;AAClE,QAAM,QAAkB,CAAC;AAEzB,MAAI,SAAS,UAAa,KAAK,SAAS,GAAG;AACzC,UAAM,KAAK,UAAU,IAAI,EAAE;AAAA,EAC7B;AAEA,aAAW,QAAQ,UAAU,KAAK,EAAE,MAAM,OAAO,GAAG;AAClD,UAAM,KAAK,SAAS,IAAI,EAAE;AAAA,EAC5B;AAEA,QAAM,KAAK,IAAI,EAAE;AACjB,SAAO,MAAM,KAAK,IAAI;AACxB;AAEA,SAASA,eAAc,OAAwB;AAC7C,SAAO,KAAK,UAAU,KAAK;AAC7B;;;AC1DO,SAAS,kBACd,QACA,UAA4C,CAAC,GACnC;AACV,QAAM,SAAS,QAAQ,UAAU;AACjC,QAAM,UAAU,IAAI,QAAQ,QAAQ,OAAO;AAE3C,MAAI,CAAC,QAAQ,IAAI,eAAe,GAAG;AACjC,YAAQ,IAAI,iBAAiB,wBAAwB;AAAA,EACvD;AACA,MAAI,CAAC,QAAQ,IAAI,YAAY,GAAG;AAC9B,YAAQ,IAAI,cAAc,YAAY;AAAA,EACxC;AACA,MAAI,CAAC,QAAQ,IAAI,mBAAmB,GAAG;AACrC,YAAQ,IAAI,qBAAqB,IAAI;AAAA,EACvC;AAEA,QAAM,OACJ,WAAW,QACP,gBAAgB,QAAQ,QAAQ,GAAG,IACnC,kBAAkB,QAAQ,QAAQ,KAAK;AAE7C,MAAI,CAAC,QAAQ,IAAI,cAAc,GAAG;AAChC,YAAQ;AAAA,MACN;AAAA,MACA,WAAW,QAAQ,qCAAqC;AAAA,IAC1D;AAAA,EACF;AAEA,QAAM,eAA6B,EAAE,QAAQ;AAC7C,MAAI,QAAQ,WAAW,QAAW;AAChC,iBAAa,SAAS,QAAQ;AAAA,EAChC;AACA,MAAI,QAAQ,eAAe,QAAW;AACpC,iBAAa,aAAa,QAAQ;AAAA,EACpC;AAEA,SAAO,IAAI,SAAS,MAAM,YAAY;AACxC;","names":["serializeJson"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@anvia/server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Server-side event stream helpers for Anvia applications.",
|
|
5
5
|
"author": "anvia",
|
|
6
6
|
"maintainer": "Indra Zulfi",
|
|
@@ -27,12 +27,14 @@
|
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@types/node": "^24.9.1",
|
|
30
|
+
"@vitest/coverage-v8": "4.1.5",
|
|
30
31
|
"tsup": "^8.5.0",
|
|
31
32
|
"typescript": "^5.9.3",
|
|
32
33
|
"vitest": "^4.0.8"
|
|
33
34
|
},
|
|
34
35
|
"scripts": {
|
|
35
36
|
"build": "tsup src/index.ts --format esm --dts --sourcemap --clean",
|
|
37
|
+
"coverage": "vitest run --coverage",
|
|
36
38
|
"test": "vitest run",
|
|
37
39
|
"typecheck": "tsc --noEmit"
|
|
38
40
|
}
|