@qorejs/qore 0.7.0 → 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 +170 -52
  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/response.js DELETED
@@ -1,312 +0,0 @@
1
- import { batch, computed, signal } from './signal.js';
2
- import { toAsyncIterable } from './iterable.js';
3
- import { normalizeError } from './utils.js';
4
-
5
- // Treat these states as closed so late writes cannot mutate a finished response.
6
- function isTerminalStatus(currentStatus) {
7
- return currentStatus === 'completed' || currentStatus === 'error' || currentStatus === 'aborted';
8
- }
9
-
10
- // Build a response state machine that accumulates chunks into a reactive value.
11
- export function createResponse(options) {
12
- const { seed, reduce } = options;
13
-
14
- const status = signal('idle');
15
- const value = signal(seed);
16
- const error = signal(null);
17
- const chunks = signal([]);
18
- const startedAt = signal(null);
19
- const finishedAt = signal(null);
20
-
21
- const pending = computed(() => {
22
- const currentStatus = status();
23
- return currentStatus === 'pending' || currentStatus === 'streaming';
24
- });
25
-
26
- const streaming = computed(() => status() === 'streaming');
27
- const completed = computed(() => status() === 'completed');
28
- const failed = computed(() => status() === 'error');
29
- const aborted = computed(() => status() === 'aborted');
30
- const chunkCount = computed(() => chunks().length);
31
-
32
- let activeController = null;
33
- let runId = 0;
34
-
35
- // Abort the active executor when a new run supersedes it.
36
- function supersedeActiveRun(reason = 'Response superseded by a new run') {
37
- if (!activeController) {
38
- return;
39
- }
40
-
41
- activeController.abort(reason);
42
- activeController = null;
43
- }
44
-
45
- // Reset the response to its initial seed and clear all lifecycle markers.
46
- function reset(nextSeed = seed) {
47
- supersedeActiveRun('Response reset');
48
-
49
- batch(() => {
50
- status('idle');
51
- value(nextSeed);
52
- error(null);
53
- chunks([]);
54
- startedAt(null);
55
- finishedAt(null);
56
- });
57
-
58
- return nextSeed;
59
- }
60
-
61
- // Push a chunk through the reducer and advance the response into streaming state.
62
- function push(chunk) {
63
- const currentStatus = status.peek();
64
-
65
- if (isTerminalStatus(currentStatus)) {
66
- return value.peek();
67
- }
68
-
69
- const index = chunks.peek().length;
70
- const nextValue = reduce(value.peek(), chunk, index);
71
-
72
- batch(() => {
73
- if (status.peek() === 'idle' || status.peek() === 'pending') {
74
- status('streaming');
75
- }
76
-
77
- chunks([...chunks.peek(), chunk]);
78
- value(nextValue);
79
- });
80
-
81
- return nextValue;
82
- }
83
-
84
- // Mark the response as completed and freeze the current accumulated value.
85
- function complete() {
86
- const currentStatus = status.peek();
87
-
88
- if (isTerminalStatus(currentStatus)) {
89
- return value.peek();
90
- }
91
-
92
- activeController = null;
93
-
94
- batch(() => {
95
- status('completed');
96
- finishedAt(Date.now());
97
- });
98
-
99
- return value.peek();
100
- }
101
-
102
- // Capture an error unless the response is already closed.
103
- function fail(reason) {
104
- const currentStatus = status.peek();
105
- const normalizedError = normalizeError(reason);
106
-
107
- if (isTerminalStatus(currentStatus)) {
108
- return currentStatus === 'error' ? error.peek() : value.peek();
109
- }
110
-
111
- activeController = null;
112
-
113
- batch(() => {
114
- status('error');
115
- error(normalizedError);
116
- finishedAt(Date.now());
117
- });
118
-
119
- return normalizedError;
120
- }
121
-
122
- // Abort an in-flight response while keeping the value accumulated so far.
123
- function abort(reason = 'Response aborted') {
124
- const currentStatus = status.peek();
125
-
126
- if (currentStatus !== 'pending' && currentStatus !== 'streaming') {
127
- return value.peek();
128
- }
129
-
130
- activeController?.abort(reason);
131
- activeController = null;
132
-
133
- batch(() => {
134
- status('aborted');
135
- finishedAt(Date.now());
136
- });
137
-
138
- return value.peek();
139
- }
140
-
141
- // Run an async executor and guard every lifecycle method to the active run only.
142
- async function run(executor, options = {}) {
143
- const { resetValue = true, nextSeed = seed } = options;
144
-
145
- supersedeActiveRun();
146
-
147
- runId += 1;
148
- const currentRunId = runId;
149
-
150
- const controller = new AbortController();
151
- activeController = controller;
152
-
153
- // A response may outlive older executors, so every write must prove it still owns the run.
154
- const isCurrentRun = () => (
155
- currentRunId === runId
156
- && activeController === controller
157
- && !controller.signal.aborted
158
- );
159
-
160
- batch(() => {
161
- if (resetValue) {
162
- value(nextSeed);
163
- chunks([]);
164
- }
165
-
166
- error(null);
167
- status('pending');
168
- startedAt(Date.now());
169
- finishedAt(null);
170
- });
171
-
172
- // Expose guarded lifecycle helpers so stale executors cannot leak writes into the latest run.
173
- const context = {
174
- get signal() {
175
- return controller.signal;
176
- },
177
-
178
- response: api,
179
- push(chunk) {
180
- if (!isCurrentRun()) {
181
- return value.peek();
182
- }
183
-
184
- return push(chunk);
185
- },
186
- complete() {
187
- if (!isCurrentRun()) {
188
- return value.peek();
189
- }
190
-
191
- return complete();
192
- },
193
- fail(reason) {
194
- if (!isCurrentRun()) {
195
- return status.peek() === 'error' ? error.peek() : value.peek();
196
- }
197
-
198
- return fail(reason);
199
- },
200
- abort(reason) {
201
- if (!isCurrentRun()) {
202
- return value.peek();
203
- }
204
-
205
- return abort(reason);
206
- }
207
- };
208
-
209
- try {
210
- await executor(context);
211
-
212
- if (!isCurrentRun()) {
213
- return value.peek();
214
- }
215
-
216
- return complete();
217
- } catch (reason) {
218
- if (!isCurrentRun()) {
219
- return value.peek();
220
- }
221
-
222
- throw fail(reason);
223
- } finally {
224
- if (currentRunId === runId && activeController === controller) {
225
- activeController = null;
226
- }
227
- }
228
- }
229
-
230
- // Consume any async iterable-like source and route each chunk through the guarded writer.
231
- async function consume(source, options = {}) {
232
- return run(async ({ signal: abortSignal, push: write }) => {
233
- const resolvedSource = typeof source === 'function'
234
- && typeof source[Symbol.asyncIterator] !== 'function'
235
- && typeof source.peek !== 'function'
236
- ? await source({ signal: abortSignal, response: api })
237
- : await source;
238
-
239
- for await (const chunk of toAsyncIterable(resolvedSource)) {
240
- if (abortSignal.aborted) {
241
- break;
242
- }
243
-
244
- write(chunk);
245
- }
246
- }, options);
247
- }
248
-
249
- // Return a plain snapshot suitable for inspection without exposing mutable internals.
250
- function snapshot() {
251
- return {
252
- status: status.peek(),
253
- value: value.peek(),
254
- error: error.peek(),
255
- chunks: [...chunks.peek()],
256
- startedAt: startedAt.peek(),
257
- finishedAt: finishedAt.peek(),
258
- chunkCount: chunks.peek().length
259
- };
260
- }
261
-
262
- const api = {
263
- status,
264
- value,
265
- error,
266
- chunks,
267
- startedAt,
268
- finishedAt,
269
- pending,
270
- streaming,
271
- completed,
272
- failed,
273
- aborted,
274
- chunkCount,
275
- reset,
276
- push,
277
- complete,
278
- fail,
279
- abort,
280
- run,
281
- consume,
282
- snapshot
283
- };
284
-
285
- return api;
286
- }
287
-
288
- // Ship a few common reducers as convenience constructors on top of createResponse.
289
- export const response = {
290
- create: createResponse,
291
-
292
- text(seed = '') {
293
- return createResponse({
294
- seed,
295
- reduce: (currentValue, chunk) => currentValue + String(chunk)
296
- });
297
- },
298
-
299
- list(seed = []) {
300
- return createResponse({
301
- seed,
302
- reduce: (currentValue, chunk) => [...currentValue, chunk]
303
- });
304
- },
305
-
306
- latest(seed = null) {
307
- return createResponse({
308
- seed,
309
- reduce: (_, chunk) => chunk
310
- });
311
- }
312
- };
package/src/signal.js DELETED
@@ -1,328 +0,0 @@
1
- // Use a sentinel so signals can still store undefined as a real value.
2
- const READ = Symbol('qore.signal.read');
3
-
4
- let activeObserver = null;
5
- let batchDepth = 0;
6
- const pendingObservers = new Set();
7
-
8
- // Remove this observer from every dependency it tracked during the last run.
9
- function cleanupObserver(observer) {
10
- for (const dep of observer.deps) {
11
- dep.subscribers.delete(observer);
12
- }
13
-
14
- observer.deps.clear();
15
- }
16
-
17
- // Queue observer work during batching, otherwise notify immediately.
18
- function scheduleObserver(observer) {
19
- if (!observer.active) {
20
- return;
21
- }
22
-
23
- if (batchDepth > 0) {
24
- pendingObservers.add(observer);
25
- return;
26
- }
27
-
28
- observer.notify();
29
- }
30
-
31
- // Flush batched observer work in FIFO-like waves until the queue is empty.
32
- function flushObservers() {
33
- while (pendingObservers.size > 0) {
34
- const queue = Array.from(pendingObservers);
35
- pendingObservers.clear();
36
-
37
- for (const observer of queue) {
38
- observer.notify();
39
- }
40
- }
41
- }
42
-
43
- // A mutable signal node stores a value and fan-outs updates to listeners and observers.
44
- class SignalNode {
45
- constructor(initialValue) {
46
- this.value = initialValue;
47
- this.subscribers = new Set();
48
- this.listeners = new Set();
49
- }
50
-
51
- get() {
52
- if (activeObserver) {
53
- this.subscribers.add(activeObserver);
54
- activeObserver.deps.add(this);
55
- }
56
-
57
- return this.value;
58
- }
59
-
60
- peek() {
61
- return this.value;
62
- }
63
-
64
- set(nextValue) {
65
- if (Object.is(this.value, nextValue)) {
66
- return this.value;
67
- }
68
-
69
- this.value = nextValue;
70
- this.emit();
71
- return this.value;
72
- }
73
-
74
- update(updater) {
75
- return this.set(updater(this.value));
76
- }
77
-
78
- subscribe(listener, options = {}) {
79
- const { immediate = true } = options;
80
-
81
- this.listeners.add(listener);
82
-
83
- if (immediate) {
84
- listener(this.value);
85
- }
86
-
87
- return () => {
88
- this.listeners.delete(listener);
89
- };
90
- }
91
-
92
- // Snapshot listeners first so resubscription during notification cannot loop forever.
93
- emit() {
94
- for (const listener of Array.from(this.listeners)) {
95
- listener(this.value);
96
- }
97
-
98
- for (const observer of Array.from(this.subscribers)) {
99
- scheduleObserver(observer);
100
- }
101
- }
102
- }
103
-
104
- // A computed node re-runs its getter whenever one of its dependencies changes.
105
- class ComputedNode {
106
- constructor(getter) {
107
- this.getter = getter;
108
- this.subscribers = new Set();
109
- this.listeners = new Set();
110
- this.deps = new Set();
111
- this.active = true;
112
- this.initialized = false;
113
- this.value = undefined;
114
-
115
- this.recompute();
116
- }
117
-
118
- get() {
119
- if (activeObserver) {
120
- this.subscribers.add(activeObserver);
121
- activeObserver.deps.add(this);
122
- }
123
-
124
- return this.value;
125
- }
126
-
127
- peek() {
128
- return this.value;
129
- }
130
-
131
- notify() {
132
- this.recompute();
133
- }
134
-
135
- subscribe(listener, options = {}) {
136
- const { immediate = true } = options;
137
-
138
- this.listeners.add(listener);
139
-
140
- if (immediate) {
141
- listener(this.value);
142
- }
143
-
144
- return () => {
145
- this.listeners.delete(listener);
146
- };
147
- }
148
-
149
- // Recompute under dependency tracking and notify downstream observers only on change.
150
- recompute() {
151
- if (!this.active) {
152
- return;
153
- }
154
-
155
- const previousValue = this.value;
156
-
157
- cleanupObserver(this);
158
-
159
- const previousObserver = activeObserver;
160
- activeObserver = this;
161
-
162
- try {
163
- const nextValue = this.getter();
164
- const changed = !this.initialized || !Object.is(previousValue, nextValue);
165
-
166
- this.value = nextValue;
167
- this.initialized = true;
168
-
169
- if (!changed) {
170
- return;
171
- }
172
-
173
- for (const listener of Array.from(this.listeners)) {
174
- listener(this.value);
175
- }
176
-
177
- for (const observer of Array.from(this.subscribers)) {
178
- scheduleObserver(observer);
179
- }
180
- } finally {
181
- activeObserver = previousObserver;
182
- }
183
- }
184
-
185
- stop() {
186
- if (!this.active) {
187
- return;
188
- }
189
-
190
- this.active = false;
191
- cleanupObserver(this);
192
- pendingObservers.delete(this);
193
- this.subscribers.clear();
194
- this.listeners.clear();
195
- }
196
- }
197
-
198
- // Effects are observers with optional cleanup that re-run when dependencies change.
199
- class EffectNode {
200
- constructor(fn) {
201
- this.fn = fn;
202
- this.deps = new Set();
203
- this.active = true;
204
- this.cleanup = null;
205
-
206
- this.run();
207
- }
208
-
209
- notify() {
210
- this.run();
211
- }
212
-
213
- // Execute the effect under tracking and remember any returned cleanup callback.
214
- run() {
215
- if (!this.active) {
216
- return;
217
- }
218
-
219
- cleanupObserver(this);
220
-
221
- if (typeof this.cleanup === 'function') {
222
- this.cleanup();
223
- this.cleanup = null;
224
- }
225
-
226
- const previousObserver = activeObserver;
227
- activeObserver = this;
228
-
229
- try {
230
- const maybeCleanup = this.fn();
231
- this.cleanup = typeof maybeCleanup === 'function' ? maybeCleanup : null;
232
- } finally {
233
- activeObserver = previousObserver;
234
- }
235
- }
236
-
237
- stop() {
238
- if (!this.active) {
239
- return;
240
- }
241
-
242
- this.active = false;
243
- cleanupObserver(this);
244
- pendingObservers.delete(this);
245
-
246
- if (typeof this.cleanup === 'function') {
247
- this.cleanup();
248
- this.cleanup = null;
249
- }
250
- }
251
- }
252
-
253
- // Create a mutable signal function with helper methods attached to it.
254
- export function signal(initialValue) {
255
- const node = new SignalNode(initialValue);
256
-
257
- const readWriteSignal = (nextValue = READ) => {
258
- if (nextValue === READ) {
259
- return node.get();
260
- }
261
-
262
- return node.set(nextValue);
263
- };
264
-
265
- readWriteSignal.set = (nextValue) => node.set(nextValue);
266
- readWriteSignal.update = (updater) => node.update(updater);
267
- readWriteSignal.peek = () => node.peek();
268
- readWriteSignal.subscribe = (listener, options) => node.subscribe(listener, options);
269
-
270
- return readWriteSignal;
271
- }
272
-
273
- // Create a read-only computed signal backed by dependency tracking.
274
- export function computed(getter) {
275
- const node = new ComputedNode(getter);
276
-
277
- const readOnlySignal = (nextValue = READ) => {
278
- if (nextValue !== READ) {
279
- throw new Error('Computed signals are read-only');
280
- }
281
-
282
- return node.get();
283
- };
284
-
285
- readOnlySignal.peek = () => node.peek();
286
- readOnlySignal.subscribe = (listener, options) => node.subscribe(listener, options);
287
- readOnlySignal.stop = () => node.stop();
288
-
289
- return readOnlySignal;
290
- }
291
-
292
- // Run a reactive effect and return a disposer for it.
293
- export function effect(fn) {
294
- const node = new EffectNode(fn);
295
- return () => node.stop();
296
- }
297
-
298
- // Batch synchronous updates so dependent observers only re-run once afterward.
299
- export function batch(fn) {
300
- batchDepth += 1;
301
-
302
- try {
303
- return fn();
304
- } finally {
305
- batchDepth -= 1;
306
-
307
- if (batchDepth === 0) {
308
- flushObservers();
309
- }
310
- }
311
- }
312
-
313
- // Read signals without subscribing the current observer to them.
314
- export function untrack(fn) {
315
- const previousObserver = activeObserver;
316
- activeObserver = null;
317
-
318
- try {
319
- return fn();
320
- } finally {
321
- activeObserver = previousObserver;
322
- }
323
- }
324
-
325
- // Detect Qore signal-like values by their callable shape plus peek helper.
326
- export function isSignal(value) {
327
- return typeof value === 'function' && typeof value.peek === 'function';
328
- }