@qorejs/qore 0.7.2 → 0.9.0
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/README.md +294 -5
- package/dist/src/core/owner.d.ts +14 -0
- package/dist/src/core/owner.js +66 -0
- package/dist/src/core/response-runtime.js +5 -5
- package/dist/src/core/response-state.d.ts +4 -0
- package/dist/src/core/response-state.js +67 -2
- package/dist/src/core/signal-context.js +19 -9
- package/dist/src/core/signal-nodes.d.ts +5 -0
- package/dist/src/core/signal-nodes.js +51 -21
- package/dist/src/core/signal-types.d.ts +2 -0
- package/dist/src/core/signal.d.ts +1 -0
- package/dist/src/core/signal.js +2 -0
- package/dist/src/core/stream-types.d.ts +12 -0
- package/dist/src/core/stream.d.ts +1 -1
- package/dist/src/core/stream.js +144 -0
- package/dist/src/dom/app.js +2 -3
- package/dist/src/dom/dom.d.ts +1 -0
- package/dist/src/dom/dom.js +96 -9
- package/dist/src/dom/scope.d.ts +3 -1
- package/dist/src/dom/scope.js +10 -3
- package/dist/src/index.d.ts +10 -4
- package/dist/src/index.js +7 -2
- package/dist/src/providers/anthropic.js +6 -4
- package/dist/src/providers/deepseek.d.ts +2 -0
- package/dist/src/providers/deepseek.js +90 -0
- package/dist/src/providers/line-adapter.d.ts +2 -0
- package/dist/src/providers/line-adapter.js +83 -0
- package/dist/src/providers/line-parser.d.ts +5 -0
- package/dist/src/providers/line-parser.js +103 -0
- package/dist/src/providers/metadata.d.ts +8 -0
- package/dist/src/providers/metadata.js +193 -0
- package/dist/src/providers/ollama.d.ts +2 -0
- package/dist/src/providers/ollama.js +82 -0
- package/dist/src/providers/openai.js +6 -4
- package/dist/src/providers/openrouter.d.ts +2 -0
- package/dist/src/providers/openrouter.js +90 -0
- package/dist/src/providers/sse-adapter.js +129 -44
- package/dist/src/providers/sse-parser.d.ts +1 -1
- package/dist/src/providers/sse-parser.js +74 -38
- package/dist/src/providers/sse.d.ts +7 -1
- package/dist/src/providers/sse.js +6 -0
- package/dist/src/providers/types.d.ts +145 -0
- package/dist/src/server/sse-response.d.ts +16 -0
- package/dist/src/server/sse-response.js +102 -0
- package/dist/src/shared/utils.d.ts +1 -0
- package/dist/src/shared/utils.js +8 -1
- package/package.json +9 -2
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { toAsyncIterable } from '../core/iterable.js';
|
|
2
|
+
import { normalizeAbortReason, normalizeError } from '../shared/utils.js';
|
|
3
|
+
const encoder = new TextEncoder();
|
|
4
|
+
function normalizeFrame(chunk, index, options) {
|
|
5
|
+
if (typeof options.encode === 'function') {
|
|
6
|
+
return Promise.resolve(options.encode(chunk, index));
|
|
7
|
+
}
|
|
8
|
+
return Promise.resolve({
|
|
9
|
+
...(options.event ? { event: options.event } : {}),
|
|
10
|
+
data: typeof chunk === 'string' ? chunk : JSON.stringify(chunk)
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
function formatSSEFrame(frame) {
|
|
14
|
+
if (typeof frame === 'string') {
|
|
15
|
+
return frame.endsWith('\n\n') ? frame : `${frame}\n\n`;
|
|
16
|
+
}
|
|
17
|
+
const lines = [];
|
|
18
|
+
if (frame.event) {
|
|
19
|
+
lines.push(`event: ${frame.event}`);
|
|
20
|
+
}
|
|
21
|
+
if (frame.id) {
|
|
22
|
+
lines.push(`id: ${frame.id}`);
|
|
23
|
+
}
|
|
24
|
+
if (typeof frame.retry === 'number') {
|
|
25
|
+
lines.push(`retry: ${frame.retry}`);
|
|
26
|
+
}
|
|
27
|
+
const payloadLines = String(frame.data).split('\n');
|
|
28
|
+
for (const line of payloadLines) {
|
|
29
|
+
lines.push(`data: ${line}`);
|
|
30
|
+
}
|
|
31
|
+
return `${lines.join('\n')}\n\n`;
|
|
32
|
+
}
|
|
33
|
+
function mergeResponseHeaders(headers = {}) {
|
|
34
|
+
const merged = new Headers({
|
|
35
|
+
'cache-control': 'no-cache, no-transform',
|
|
36
|
+
connection: 'keep-alive',
|
|
37
|
+
'content-type': 'text/event-stream; charset=utf-8',
|
|
38
|
+
...headers
|
|
39
|
+
});
|
|
40
|
+
return merged;
|
|
41
|
+
}
|
|
42
|
+
export function createSSEResponse(source, options = {}) {
|
|
43
|
+
const { signal, headers, doneFrame = 'data: [DONE]\n\n', onError = (error) => ({
|
|
44
|
+
event: 'error',
|
|
45
|
+
data: error.message
|
|
46
|
+
}) } = options;
|
|
47
|
+
const body = new ReadableStream({
|
|
48
|
+
async start(controller) {
|
|
49
|
+
let index = 0;
|
|
50
|
+
const close = () => {
|
|
51
|
+
if (doneFrame) {
|
|
52
|
+
controller.enqueue(encoder.encode(typeof doneFrame === 'string' ? doneFrame : 'data: [DONE]\n\n'));
|
|
53
|
+
}
|
|
54
|
+
controller.close();
|
|
55
|
+
};
|
|
56
|
+
if (signal?.aborted) {
|
|
57
|
+
controller.error(normalizeAbortReason(signal.reason, 'SSE response aborted'));
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const abortHandler = () => {
|
|
61
|
+
try {
|
|
62
|
+
controller.close();
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
// Ignore close races after the stream has already settled.
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
signal?.addEventListener('abort', abortHandler, { once: true });
|
|
69
|
+
try {
|
|
70
|
+
for await (const chunk of toAsyncIterable(source)) {
|
|
71
|
+
if (signal?.aborted) {
|
|
72
|
+
close();
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
const frame = await normalizeFrame(chunk, index, options);
|
|
76
|
+
controller.enqueue(encoder.encode(formatSSEFrame(frame)));
|
|
77
|
+
index += 1;
|
|
78
|
+
}
|
|
79
|
+
close();
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
if (signal?.aborted) {
|
|
83
|
+
abortHandler();
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const normalizedError = normalizeError(error);
|
|
87
|
+
const errorFrame = await onError(normalizedError);
|
|
88
|
+
if (errorFrame !== false) {
|
|
89
|
+
controller.enqueue(encoder.encode(formatSSEFrame(errorFrame)));
|
|
90
|
+
}
|
|
91
|
+
controller.close();
|
|
92
|
+
}
|
|
93
|
+
finally {
|
|
94
|
+
signal?.removeEventListener('abort', abortHandler);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
return new Response(body, {
|
|
99
|
+
status: 200,
|
|
100
|
+
headers: mergeResponseHeaders(headers)
|
|
101
|
+
});
|
|
102
|
+
}
|
package/dist/src/shared/utils.js
CHANGED
|
@@ -8,6 +8,13 @@ export function normalizeError(error) {
|
|
|
8
8
|
}
|
|
9
9
|
return new Error('Unknown Qore error');
|
|
10
10
|
}
|
|
11
|
+
// Convert abort reasons into stable Error instances for transport and runtime code.
|
|
12
|
+
export function normalizeAbortReason(reason, fallbackMessage = 'Operation aborted') {
|
|
13
|
+
if (reason == null) {
|
|
14
|
+
return new Error(fallbackMessage);
|
|
15
|
+
}
|
|
16
|
+
return normalizeError(reason);
|
|
17
|
+
}
|
|
11
18
|
// Sleep for a fixed time and reject early if the surrounding operation is aborted.
|
|
12
19
|
export function sleep(ms, signal) {
|
|
13
20
|
return new Promise((resolve, reject) => {
|
|
@@ -17,7 +24,7 @@ export function sleep(ms, signal) {
|
|
|
17
24
|
}, ms);
|
|
18
25
|
const onAbort = () => {
|
|
19
26
|
cleanup();
|
|
20
|
-
reject(
|
|
27
|
+
reject(normalizeAbortReason(signal?.reason, 'Operation aborted'));
|
|
21
28
|
};
|
|
22
29
|
const cleanup = () => {
|
|
23
30
|
clearTimeout(timer);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qorejs/qore",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Qore is a streaming-response framework where stream becomes signal.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/src/index.js",
|
|
@@ -23,13 +23,17 @@
|
|
|
23
23
|
"browsers:install": "playwright install chromium",
|
|
24
24
|
"typecheck": "node ./scripts/typecheck.mjs",
|
|
25
25
|
"check:dist": "node ./scripts/check-dist-sync.mjs",
|
|
26
|
+
"check:api-surface": "node ./scripts/check-public-api.mjs",
|
|
27
|
+
"check:release-docs": "node ./scripts/check-release-docs.mjs",
|
|
26
28
|
"test:browser": "node ./scripts/browser-smoke.mjs",
|
|
29
|
+
"test:benchmark": "node ./scripts/benchmark-gate.mjs",
|
|
27
30
|
"smoke:package-types": "node ./scripts/package-type-smoke.mjs",
|
|
28
31
|
"smoke:package-runtime": "node ./scripts/package-runtime-smoke.mjs",
|
|
29
32
|
"test": "node ./scripts/test.mjs",
|
|
30
33
|
"release:check": "node ./scripts/release-check.mjs",
|
|
34
|
+
"publish:preflight": "node ./scripts/publish-preflight.mjs",
|
|
31
35
|
"publish:github": "npm publish --registry=https://npm.pkg.github.com",
|
|
32
|
-
"publish:npm": "
|
|
36
|
+
"publish:npm": "node ./scripts/publish-npm.mjs",
|
|
33
37
|
"prepublishOnly": "node ./scripts/release-check.mjs"
|
|
34
38
|
},
|
|
35
39
|
"engines": {
|
|
@@ -42,9 +46,12 @@
|
|
|
42
46
|
"signal",
|
|
43
47
|
"reactive",
|
|
44
48
|
"sse",
|
|
49
|
+
"ndjson",
|
|
45
50
|
"ai",
|
|
46
51
|
"openai",
|
|
47
52
|
"anthropic",
|
|
53
|
+
"deepseek",
|
|
54
|
+
"ollama",
|
|
48
55
|
"framework",
|
|
49
56
|
"async-iterable"
|
|
50
57
|
],
|