@qorejs/qore 0.7.1 → 0.7.2

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 (86) hide show
  1. package/README.md +120 -3
  2. package/dist/src/core/iterable.d.ts +1 -0
  3. package/dist/src/core/iterable.js +17 -0
  4. package/dist/src/core/response-runtime.d.ts +2 -0
  5. package/dist/src/core/response-runtime.js +233 -0
  6. package/dist/src/core/response-state.d.ts +3 -0
  7. package/dist/src/core/response-state.js +37 -0
  8. package/dist/src/core/response-types.d.ts +73 -0
  9. package/dist/src/core/response-types.js +1 -0
  10. package/dist/src/core/response.d.ts +4 -0
  11. package/dist/src/core/response.js +26 -0
  12. package/dist/src/core/signal-context.d.ts +10 -0
  13. package/dist/src/core/signal-context.js +69 -0
  14. package/dist/src/core/signal-nodes.d.ts +45 -0
  15. package/dist/src/core/signal-nodes.js +197 -0
  16. package/dist/src/core/signal-scheduler.d.ts +2 -0
  17. package/dist/src/core/signal-scheduler.js +19 -0
  18. package/dist/src/core/signal-types.d.ts +19 -0
  19. package/dist/src/core/signal-types.js +1 -0
  20. package/dist/src/core/signal.d.ts +19 -0
  21. package/dist/src/core/signal.js +41 -0
  22. package/dist/src/core/stream-backpressure.d.ts +3 -0
  23. package/dist/src/core/stream-backpressure.js +36 -0
  24. package/dist/src/core/stream-buffer.d.ts +17 -0
  25. package/dist/src/core/stream-buffer.js +162 -0
  26. package/dist/src/core/stream-iterator.d.ts +6 -0
  27. package/dist/src/core/stream-iterator.js +14 -0
  28. package/dist/src/core/stream-lifecycle.d.ts +10 -0
  29. package/dist/src/core/stream-lifecycle.js +28 -0
  30. package/dist/src/core/stream-queue.d.ts +17 -0
  31. package/dist/src/core/stream-queue.js +62 -0
  32. package/dist/src/core/stream-runtime.d.ts +2 -0
  33. package/dist/src/core/stream-runtime.js +127 -0
  34. package/dist/src/core/stream-source.d.ts +2 -0
  35. package/dist/src/core/stream-source.js +28 -0
  36. package/dist/src/core/stream-state.d.ts +4 -0
  37. package/dist/src/core/stream-state.js +20 -0
  38. package/dist/src/core/stream-types.d.ts +61 -0
  39. package/dist/src/core/stream-types.js +1 -0
  40. package/dist/src/core/stream.d.ts +11 -0
  41. package/dist/src/core/stream.js +90 -0
  42. package/dist/src/dom/app.d.ts +38 -0
  43. package/dist/src/dom/app.js +102 -0
  44. package/dist/src/dom/dom.d.ts +13 -0
  45. package/dist/src/dom/dom.js +197 -0
  46. package/dist/src/dom/properties.d.ts +3 -0
  47. package/dist/src/dom/properties.js +147 -0
  48. package/dist/src/dom/reactive.d.ts +6 -0
  49. package/dist/src/dom/reactive.js +14 -0
  50. package/dist/src/dom/response-view.d.ts +4 -0
  51. package/dist/src/dom/response-view.js +37 -0
  52. package/dist/src/dom/scope.d.ts +10 -0
  53. package/dist/src/dom/scope.js +49 -0
  54. package/dist/src/dom/types.d.ts +34 -0
  55. package/dist/src/dom/types.js +1 -0
  56. package/dist/src/index.d.ts +16 -0
  57. package/dist/src/index.js +10 -0
  58. package/dist/src/providers/anthropic.d.ts +2 -0
  59. package/dist/src/providers/anthropic.js +102 -0
  60. package/dist/src/providers/openai.d.ts +2 -0
  61. package/dist/src/providers/openai.js +96 -0
  62. package/dist/src/providers/sse-adapter.d.ts +2 -0
  63. package/dist/src/providers/sse-adapter.js +83 -0
  64. package/dist/src/providers/sse-env.d.ts +4 -0
  65. package/dist/src/providers/sse-env.js +33 -0
  66. package/dist/src/providers/sse-parser.d.ts +5 -0
  67. package/dist/src/providers/sse-parser.js +99 -0
  68. package/dist/src/providers/sse.d.ts +4 -0
  69. package/dist/src/providers/sse.js +3 -0
  70. package/dist/src/providers/types.d.ts +94 -0
  71. package/dist/src/providers/types.js +1 -0
  72. package/dist/src/shared/utils.d.ts +2 -0
  73. package/dist/src/shared/utils.js +32 -0
  74. package/package.json +25 -11
  75. package/src/anthropic.js +0 -122
  76. package/src/app.js +0 -123
  77. package/src/dom.js +0 -527
  78. package/src/index.d.ts +0 -405
  79. package/src/index.js +0 -10
  80. package/src/iterable.js +0 -20
  81. package/src/openai.js +0 -112
  82. package/src/response.js +0 -312
  83. package/src/signal.js +0 -328
  84. package/src/sse.js +0 -264
  85. package/src/stream.js +0 -582
  86. package/src/utils.js +0 -39
package/src/stream.js DELETED
@@ -1,582 +0,0 @@
1
- import { createResponse } from './response.js';
2
- import { signal } from './signal.js';
3
- import { toAsyncIterable } from './iterable.js';
4
- import { normalizeError, sleep } from './utils.js';
5
-
6
- // Bridge producer pushes and async iteration with a minimal internal queue.
7
- class AsyncQueue {
8
- constructor() {
9
- this.values = [];
10
- this.waiters = [];
11
- this.closed = false;
12
- this.error = null;
13
- }
14
-
15
- push(value) {
16
- if (this.closed) {
17
- return;
18
- }
19
-
20
- const waiter = this.waiters.shift();
21
-
22
- if (waiter) {
23
- waiter.resolve({ value, done: false });
24
- return;
25
- }
26
-
27
- this.values.push(value);
28
- }
29
-
30
- close() {
31
- if (this.closed) {
32
- return;
33
- }
34
-
35
- this.closed = true;
36
-
37
- while (this.waiters.length > 0) {
38
- const waiter = this.waiters.shift();
39
- waiter.resolve({ value: undefined, done: true });
40
- }
41
- }
42
-
43
- fail(error) {
44
- if (this.closed) {
45
- return;
46
- }
47
-
48
- this.closed = true;
49
- this.error = normalizeError(error);
50
-
51
- while (this.waiters.length > 0) {
52
- const waiter = this.waiters.shift();
53
- waiter.reject(this.error);
54
- }
55
- }
56
-
57
- next() {
58
- if (this.values.length > 0) {
59
- return Promise.resolve({ value: this.values.shift(), done: false });
60
- }
61
-
62
- if (this.closed) {
63
- if (this.error) {
64
- return Promise.reject(this.error);
65
- }
66
-
67
- return Promise.resolve({ value: undefined, done: true });
68
- }
69
-
70
- return new Promise((resolve, reject) => {
71
- this.waiters.push({ resolve, reject });
72
- });
73
- }
74
-
75
- return() {
76
- this.close();
77
- return Promise.resolve({ value: undefined, done: true });
78
- }
79
-
80
- [Symbol.asyncIterator]() {
81
- return this;
82
- }
83
- }
84
-
85
- // Expose a response value as a read-only signal surface.
86
- function createReadableSignal(sourceSignal) {
87
- const read = () => sourceSignal();
88
-
89
- read.peek = () => sourceSignal.peek();
90
- read.subscribe = (listener, options) => sourceSignal.subscribe(listener, options);
91
-
92
- return read;
93
- }
94
-
95
- // Text streams concatenate chunks by default so they can drive text nodes directly.
96
- function reduceText(currentValue, chunk) {
97
- return currentValue + String(chunk ?? '');
98
- }
99
-
100
- // Normalize backpressure into one consistent shape the runtime can enforce.
101
- function normalizeBackpressure(backpressure) {
102
- if (backpressure == null) {
103
- return {
104
- interval: 0,
105
- buffer: Infinity,
106
- overflow: 'wait'
107
- };
108
- }
109
-
110
- const options = typeof backpressure === 'number'
111
- ? { interval: backpressure }
112
- : backpressure;
113
- const interval = options.interval ?? 0;
114
- const buffer = options.buffer ?? Infinity;
115
- const overflow = options.overflow ?? 'wait';
116
-
117
- if (!Number.isFinite(interval) || interval < 0) {
118
- throw new TypeError('Qore stream backpressure.interval must be a non-negative finite number');
119
- }
120
-
121
- if (buffer !== Infinity && (!Number.isInteger(buffer) || buffer < 1)) {
122
- throw new TypeError('Qore stream backpressure.buffer must be a positive integer or Infinity');
123
- }
124
-
125
- if (!['wait', 'drop-oldest', 'drop-newest', 'error'].includes(overflow)) {
126
- throw new TypeError(
127
- 'Qore stream backpressure.overflow must be one of "wait", "drop-oldest", "drop-newest", or "error"'
128
- );
129
- }
130
-
131
- return { interval, buffer, overflow };
132
- }
133
-
134
- // Build a deferred promise so queue operations can wait for capacity or completion.
135
- function createDeferred() {
136
- let resolve = null;
137
- let reject = null;
138
- const promise = new Promise((nextResolve, nextReject) => {
139
- resolve = nextResolve;
140
- reject = nextReject;
141
- });
142
-
143
- return { promise, resolve, reject };
144
- }
145
-
146
- // Distinguish a setup callback from callable stream or signal-like values.
147
- function isSetupFunction(sourceOrSetup) {
148
- return typeof sourceOrSetup === 'function'
149
- && typeof sourceOrSetup[Symbol.asyncIterator] !== 'function'
150
- && typeof sourceOrSetup.peek !== 'function';
151
- }
152
-
153
- // Pipe any async iterable-like source into the controller, honoring aborts and pacing.
154
- async function pipeSource(source, controller) {
155
- for await (const chunk of toAsyncIterable(source)) {
156
- if (controller.signal.aborted) {
157
- break;
158
- }
159
-
160
- await controller.push(chunk);
161
- }
162
- }
163
-
164
- // Accept either a setup callback or a pre-existing iterable source.
165
- async function startSource(sourceOrSetup, controller) {
166
- if (isSetupFunction(sourceOrSetup)) {
167
- const maybeSource = await sourceOrSetup(controller);
168
-
169
- if (maybeSource !== undefined) {
170
- await pipeSource(maybeSource, controller);
171
- }
172
-
173
- return;
174
- }
175
-
176
- await pipeSource(sourceOrSetup, controller);
177
- }
178
-
179
- // Create the core stream primitive: a read-only signal plus async iterable plus lifecycle state.
180
- export function createStream(sourceOrSetup, options = {}) {
181
- const {
182
- seed = '',
183
- reduce = reduceText,
184
- backpressure = null
185
- } = options;
186
- const pressure = normalizeBackpressure(backpressure);
187
-
188
- const state = createResponse({ seed, reduce });
189
- const queue = new AsyncQueue();
190
- const readable = createReadableSignal(state.value);
191
- const buffered = signal(0);
192
- const dropped = signal(0);
193
-
194
- let activeSignal = null;
195
- let terminated = false;
196
- let flushActiveWrites = () => readable.peek();
197
-
198
- // Close queue delivery and flush any buffered chunks before the final lifecycle transition.
199
- const stopStream = (finalizer, cleanup = flushActiveWrites) => {
200
- if (terminated) {
201
- return readable.peek();
202
- }
203
-
204
- terminated = true;
205
- cleanup?.();
206
- queue.close();
207
- return finalizer();
208
- };
209
-
210
- const run = state.run(async ({ signal, push, complete, fail, abort }) => {
211
- activeSignal = signal;
212
- const pendingWrites = [];
213
- const spaceWaiters = [];
214
- const scheduledPushes = new Set();
215
- let drainPromise = null;
216
- let lastPushAt = 0;
217
-
218
- // Wake producers waiting on queue space once the buffer has room again.
219
- function releaseSpaceWaiters() {
220
- if (pressure.buffer === Infinity) {
221
- while (spaceWaiters.length > 0) {
222
- spaceWaiters.shift().resolve();
223
- }
224
-
225
- return;
226
- }
227
-
228
- while (spaceWaiters.length > 0 && pendingWrites.length < pressure.buffer) {
229
- spaceWaiters.shift().resolve();
230
- }
231
- }
232
-
233
- // Resolve buffered writes when the stream finishes so late chunks do not leak through.
234
- function flushBufferedWrites(result = readable.peek()) {
235
- while (pendingWrites.length > 0) {
236
- pendingWrites.shift().resolve(result);
237
- }
238
-
239
- buffered(0);
240
- releaseSpaceWaiters();
241
- return result;
242
- }
243
-
244
- flushActiveWrites = flushBufferedWrites;
245
-
246
- // Allow setup functions that ignore await push(...) to still drain in order before completion.
247
- async function flushScheduledPushes() {
248
- while (scheduledPushes.size > 0) {
249
- await Promise.all(Array.from(scheduledPushes));
250
- }
251
-
252
- while (drainPromise) {
253
- await drainPromise;
254
- }
255
- }
256
-
257
- // Maintain a minimum delay between chunks entering signal/UI state.
258
- async function waitForNextWindow() {
259
- if (pressure.interval <= 0 || lastPushAt === 0) {
260
- return;
261
- }
262
-
263
- const remaining = pressure.interval - (Date.now() - lastPushAt);
264
-
265
- if (remaining > 0) {
266
- try {
267
- await sleep(remaining, signal);
268
- } catch (error) {
269
- if (!signal.aborted) {
270
- throw error;
271
- }
272
- }
273
- }
274
- }
275
-
276
- // Serialize writes so buffered or unawaited producers still update the UI one chunk at a time.
277
- function scheduleDrain() {
278
- if (drainPromise || terminated) {
279
- return drainPromise;
280
- }
281
-
282
- drainPromise = (async () => {
283
- try {
284
- while (pendingWrites.length > 0 && !terminated && !signal.aborted) {
285
- const entry = pendingWrites.shift();
286
- buffered(pendingWrites.length);
287
- releaseSpaceWaiters();
288
-
289
- await waitForNextWindow();
290
-
291
- if (terminated || signal.aborted) {
292
- entry.resolve(readable.peek());
293
- continue;
294
- }
295
-
296
- queue.push(entry.chunk);
297
- const nextValue = push(entry.chunk);
298
- lastPushAt = Date.now();
299
- entry.resolve(nextValue);
300
- }
301
- } finally {
302
- drainPromise = null;
303
-
304
- if (pendingWrites.length > 0 && !terminated && !signal.aborted) {
305
- scheduleDrain();
306
- }
307
- }
308
- })();
309
-
310
- return drainPromise;
311
- }
312
-
313
- // Wait until buffered chunks can fit into the configured queue capacity.
314
- async function waitForBufferSpace() {
315
- if (pressure.buffer === Infinity) {
316
- return true;
317
- }
318
-
319
- while (!terminated && !signal.aborted && pendingWrites.length >= pressure.buffer) {
320
- const gate = createDeferred();
321
- spaceWaiters.push(gate);
322
- await gate.promise;
323
- }
324
-
325
- return !terminated && !signal.aborted;
326
- }
327
-
328
- // Wrap the response lifecycle so streams can push, fail, or abort through one surface.
329
- const controller = {
330
- get signal() {
331
- return signal;
332
- },
333
-
334
- // Queue chunks first, then let the serialized drain loop move them into state/UI.
335
- async push(chunk) {
336
- if (terminated || signal.aborted) {
337
- return readable.peek();
338
- }
339
-
340
- const writeTask = (async () => {
341
- if (pressure.overflow === 'wait') {
342
- const hasSpace = await waitForBufferSpace();
343
-
344
- if (!hasSpace) {
345
- return readable.peek();
346
- }
347
- } else if (pressure.buffer !== Infinity && pendingWrites.length >= pressure.buffer) {
348
- if (pressure.overflow === 'drop-oldest' && pendingWrites.length > 0) {
349
- const droppedWrite = pendingWrites.shift();
350
- dropped(dropped.peek() + 1);
351
- droppedWrite.resolve(readable.peek());
352
- } else if (pressure.overflow === 'drop-newest' || pressure.overflow === 'drop-oldest') {
353
- dropped(dropped.peek() + 1);
354
- return readable.peek();
355
- } else if (pressure.overflow === 'error') {
356
- controller.fail(new Error('Qore stream backpressure buffer overflow'));
357
- return readable.peek();
358
- }
359
- }
360
-
361
- if (terminated || signal.aborted) {
362
- return readable.peek();
363
- }
364
-
365
- const entry = createDeferred();
366
- entry.chunk = chunk;
367
- pendingWrites.push(entry);
368
- buffered(pendingWrites.length);
369
- scheduleDrain();
370
- return entry.promise;
371
- })();
372
-
373
- scheduledPushes.add(writeTask);
374
-
375
- try {
376
- return await writeTask;
377
- } finally {
378
- scheduledPushes.delete(writeTask);
379
- }
380
- },
381
-
382
- // Mark the stream as gracefully finished.
383
- done() {
384
- return stopStream(() => complete());
385
- },
386
-
387
- // Surface producer failures to both async consumers and signal readers.
388
- fail(error) {
389
- if (terminated) {
390
- return state.error.peek();
391
- }
392
-
393
- terminated = true;
394
- flushBufferedWrites();
395
- queue.fail(error);
396
- return fail(error);
397
- },
398
-
399
- // Abort the stream and preserve the partial value already accumulated.
400
- abort(reason = 'Stream aborted') {
401
- return stopStream(() => abort(reason));
402
- }
403
- };
404
-
405
- try {
406
- await startSource(sourceOrSetup, controller);
407
- await flushScheduledPushes();
408
-
409
- if (!terminated && signal.aborted) {
410
- controller.abort(signal.reason ?? 'Stream aborted');
411
- return readable.peek();
412
- }
413
-
414
- if (!terminated) {
415
- controller.done();
416
- }
417
-
418
- return readable.peek();
419
- } catch (error) {
420
- if (terminated || signal.aborted) {
421
- return readable.peek();
422
- }
423
-
424
- throw error;
425
- }
426
- });
427
-
428
- // Keep async consumers in sync with failures that surface after startup.
429
- run.catch((error) => {
430
- if (!queue.closed) {
431
- queue.fail(error);
432
- }
433
- });
434
-
435
- readable.status = state.status;
436
- readable.error = state.error;
437
- readable.chunks = state.chunks;
438
- readable.startedAt = state.startedAt;
439
- readable.finishedAt = state.finishedAt;
440
- readable.pending = state.pending;
441
- readable.streaming = state.streaming;
442
- readable.completed = state.completed;
443
- readable.failed = state.failed;
444
- readable.aborted = state.aborted;
445
- readable.chunkCount = state.chunkCount;
446
- readable.snapshot = state.snapshot;
447
- readable.buffered = createReadableSignal(buffered);
448
- readable.dropped = createReadableSignal(dropped);
449
- readable.ready = run;
450
- readable.abort = (reason) => stopStream(() => state.abort(reason));
451
-
452
- // Expose the current AbortSignal so advanced integrations can observe cancellation.
453
- Object.defineProperty(readable, 'signal', {
454
- enumerable: true,
455
- get() {
456
- return activeSignal;
457
- }
458
- });
459
-
460
- // Preserve async iteration so streams can still compose with for-await and adapters.
461
- readable[Symbol.asyncIterator] = async function*() {
462
- try {
463
- for await (const chunk of queue) {
464
- yield chunk;
465
- }
466
- } finally {
467
- if (!terminated && !state.aborted()) {
468
- readable.abort('Stream consumer disposed');
469
- }
470
- }
471
- };
472
-
473
- return readable;
474
- }
475
-
476
- // Create a text-accumulating stream by default.
477
- export function stream(sourceOrSetup, options = {}) {
478
- return createStream(sourceOrSetup, {
479
- seed: '',
480
- reduce: reduceText,
481
- ...options
482
- });
483
- }
484
-
485
- // Alias the generic constructor for advanced callers that provide custom reducers.
486
- stream.create = createStream;
487
-
488
- // Convenience constructor for explicit text streams.
489
- stream.text = (sourceOrSetup, options = {}) => createStream(sourceOrSetup, {
490
- seed: '',
491
- reduce: reduceText,
492
- ...options
493
- });
494
-
495
- // Convenience constructor for streams that accumulate every chunk into an array.
496
- stream.list = (sourceOrSetup, options = {}) => createStream(sourceOrSetup, {
497
- seed: [],
498
- reduce: (currentValue, chunk) => [...currentValue, chunk],
499
- ...options
500
- });
501
-
502
- // Convenience constructor for streams that only expose the latest chunk as current value.
503
- stream.latest = (sourceOrSetup, options = {}) => createStream(sourceOrSetup, {
504
- seed: null,
505
- reduce: (_, chunk) => chunk,
506
- ...options
507
- });
508
-
509
- // Attach backpressure behavior without changing the reducer semantics.
510
- stream.withBackpressure = (sourceOrSetup, backpressure, options = {}) => createStream(sourceOrSetup, {
511
- ...options,
512
- backpressure: typeof options.backpressure === 'object' && typeof backpressure === 'object'
513
- ? { ...options.backpressure, ...backpressure }
514
- : backpressure
515
- });
516
-
517
- // Shorthand for the first backpressure primitive: minimum interval between chunks.
518
- stream.paced = (sourceOrSetup, interval, options = {}) => stream.withBackpressure(
519
- sourceOrSetup,
520
- { interval },
521
- options
522
- );
523
-
524
- // Turn any iterable or async iterable into a stream, optionally adding source delay.
525
- export function from(source, options = {}) {
526
- const { delay = 0, ...streamOptions } = options;
527
-
528
- return createStream(async (controller) => {
529
- for await (const chunk of toAsyncIterable(source)) {
530
- if (controller.signal.aborted) {
531
- break;
532
- }
533
-
534
- if (delay > 0) {
535
- await sleep(delay, controller.signal);
536
- }
537
-
538
- await controller.push(chunk);
539
- }
540
- }, streamOptions);
541
- }
542
-
543
- // Map source chunks into a new stream while preserving stream semantics.
544
- export function mapStream(source, mapper, options = {}) {
545
- return createStream(async (controller) => {
546
- let index = 0;
547
-
548
- for await (const chunk of toAsyncIterable(source)) {
549
- if (controller.signal.aborted) {
550
- break;
551
- }
552
-
553
- await controller.push(await mapper(chunk, index));
554
- index += 1;
555
- }
556
- }, options);
557
- }
558
-
559
- // Emit a running reduction so each chunk sees the accumulated state so far.
560
- export function scanStream(source, reducer, seed, options = {}) {
561
- return createStream(async (controller) => {
562
- let index = 0;
563
- let current = seed;
564
-
565
- for await (const chunk of toAsyncIterable(source)) {
566
- if (controller.signal.aborted) {
567
- break;
568
- }
569
-
570
- current = await reducer(current, chunk, index);
571
- await controller.push(current);
572
- index += 1;
573
- }
574
- }, {
575
- seed,
576
- reduce: (_, chunk) => chunk,
577
- ...options
578
- });
579
- }
580
-
581
- // Re-export the iterable helper so integrations can normalize external sources.
582
- export { toAsyncIterable } from './iterable.js';
package/src/utils.js DELETED
@@ -1,39 +0,0 @@
1
- // Convert unknown thrown values into Error instances the runtime can reason about.
2
- export function normalizeError(error) {
3
- if (error instanceof Error) {
4
- return error;
5
- }
6
-
7
- if (typeof error === 'string') {
8
- return new Error(error);
9
- }
10
-
11
- return new Error('Unknown Qore error');
12
- }
13
-
14
- // Sleep for a fixed time and reject early if the surrounding operation is aborted.
15
- export function sleep(ms, signal) {
16
- return new Promise((resolve, reject) => {
17
- const timer = setTimeout(() => {
18
- cleanup();
19
- resolve();
20
- }, ms);
21
-
22
- const onAbort = () => {
23
- cleanup();
24
- reject(normalizeError(signal?.reason ?? 'Operation aborted'));
25
- };
26
-
27
- const cleanup = () => {
28
- clearTimeout(timer);
29
- signal?.removeEventListener('abort', onAbort);
30
- };
31
-
32
- if (signal?.aborted) {
33
- onAbort();
34
- return;
35
- }
36
-
37
- signal?.addEventListener('abort', onAbort, { once: true });
38
- });
39
- }