@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
@@ -0,0 +1,197 @@
1
+ import { effect } from '../core/signal.js';
2
+ import { bindProp } from './properties.js';
3
+ import { isReactiveValue, resolveAccessor, resolveTemplate } from './reactive.js';
4
+ import { pickResponseTemplate, readResponseState } from './response-view.js';
5
+ import { ROOT_CLEANUP, assertDocument, createScope, disposeScope, registerCleanup, withScope } from './scope.js';
6
+ function isDomNode(value) {
7
+ return typeof Node !== 'undefined' && value instanceof Node;
8
+ }
9
+ // Convert supported child types into concrete nodes that can be inserted into the DOM.
10
+ function materializeChild(buffer, child) {
11
+ if (Array.isArray(child)) {
12
+ for (const entry of child) {
13
+ materializeChild(buffer, entry);
14
+ }
15
+ return;
16
+ }
17
+ if (child == null || child === false || child === true) {
18
+ return;
19
+ }
20
+ if (isReactiveValue(child)) {
21
+ buffer.push(dynamic(child));
22
+ return;
23
+ }
24
+ if (isDomNode(child)) {
25
+ buffer.push(child);
26
+ return;
27
+ }
28
+ if (typeof child === 'string' || typeof child === 'number' || typeof child === 'bigint') {
29
+ buffer.push(document.createTextNode(String(child)));
30
+ return;
31
+ }
32
+ throw new TypeError(`Unsupported Qore child: ${typeof child}. Use strings, numbers, DOM nodes, arrays, or reactive getters.`);
33
+ }
34
+ // Flatten any child payload into a linear list of nodes.
35
+ function materialize(value) {
36
+ const nodes = [];
37
+ materializeChild(nodes, value);
38
+ return nodes;
39
+ }
40
+ // Append normalized child content to a parent node or fragment.
41
+ function appendChild(parent, child) {
42
+ for (const node of materialize(child)) {
43
+ parent.appendChild(node);
44
+ }
45
+ }
46
+ // Remove every node between the two markers of a dynamic region.
47
+ function clearRange(start, end) {
48
+ let current = start.nextSibling;
49
+ while (current && current !== end) {
50
+ const next = current.nextSibling;
51
+ current.remove();
52
+ current = next;
53
+ }
54
+ }
55
+ // Replace a dynamic region without recreating its boundary markers.
56
+ function replaceRange(start, end, nextValue) {
57
+ const parent = end.parentNode;
58
+ if (!parent) {
59
+ return;
60
+ }
61
+ clearRange(start, end);
62
+ for (const node of materialize(nextValue)) {
63
+ parent.insertBefore(node, end);
64
+ }
65
+ }
66
+ // Allow mount targets to be passed as selectors or direct nodes.
67
+ function resolveRoot(root) {
68
+ if (typeof root === 'string') {
69
+ const element = document.querySelector(root);
70
+ if (!element) {
71
+ throw new Error(`Qore could not find a mount target for selector: ${root}`);
72
+ }
73
+ return element;
74
+ }
75
+ return root;
76
+ }
77
+ // Build a fragment from a variadic list of children.
78
+ export function fragment(...children) {
79
+ assertDocument();
80
+ const node = document.createDocumentFragment();
81
+ for (const child of children) {
82
+ appendChild(node, child);
83
+ }
84
+ return node;
85
+ }
86
+ // Render a live region between comment markers and refresh it when the source changes.
87
+ export function dynamic(source, render = (value) => value) {
88
+ assertDocument();
89
+ const start = document.createComment('qore-dynamic-start');
90
+ const end = document.createComment('qore-dynamic-end');
91
+ const node = document.createDocumentFragment();
92
+ node.append(start, end);
93
+ let childScope = null;
94
+ const stop = effect(() => {
95
+ const nextValue = resolveAccessor(source);
96
+ disposeScope(childScope);
97
+ childScope = createScope();
98
+ const renderedValue = withScope(childScope, () => resolveTemplate(render, nextValue));
99
+ replaceRange(start, end, renderedValue);
100
+ });
101
+ registerCleanup(() => {
102
+ stop();
103
+ disposeScope(childScope);
104
+ });
105
+ return node;
106
+ }
107
+ // Conditionally render one branch or a fallback from a truthy source.
108
+ export function show(source, render, fallback = null) {
109
+ const truthyView = render === undefined
110
+ ? (value) => value
111
+ : render;
112
+ return dynamic(source, (value) => value
113
+ ? resolveTemplate(truthyView, value)
114
+ : resolveTemplate(fallback, value));
115
+ }
116
+ // Render a list reactively, or a fallback when the collection is empty.
117
+ export function list(source, render, options = {}) {
118
+ const { fallback = null } = options;
119
+ return dynamic(source, (value) => {
120
+ const items = value == null
121
+ ? []
122
+ : Array.isArray(value)
123
+ ? value
124
+ : Array.from(value);
125
+ if (items.length === 0) {
126
+ return resolveTemplate(fallback, items);
127
+ }
128
+ return items.map((item, index) => render(item, index));
129
+ });
130
+ }
131
+ // Render response state through status-aware template overrides.
132
+ export function renderResponse(responseState, views = {}) {
133
+ return dynamic(() => readResponseState(responseState), (state) => {
134
+ const template = pickResponseTemplate(state.status, views);
135
+ if (template !== undefined) {
136
+ return resolveTemplate(template, state);
137
+ }
138
+ if (state.status === 'error') {
139
+ return state.error?.message ?? 'Qore response failed.';
140
+ }
141
+ return state.value;
142
+ });
143
+ }
144
+ export function h(tag, props = null, ...children) {
145
+ assertDocument();
146
+ if (typeof tag === 'function') {
147
+ return tag({
148
+ ...(props ?? {}),
149
+ children
150
+ });
151
+ }
152
+ const element = document.createElement(tag);
153
+ if (props) {
154
+ for (const [key, value] of Object.entries(props)) {
155
+ bindProp(element, key, value);
156
+ }
157
+ }
158
+ for (const child of children) {
159
+ appendChild(element, child);
160
+ }
161
+ return element;
162
+ }
163
+ // Create a text node and keep it in sync with a reactive getter when necessary.
164
+ export function text(valueOrGetter) {
165
+ assertDocument();
166
+ const node = document.createTextNode('');
167
+ if (isReactiveValue(valueOrGetter)) {
168
+ const stop = effect(() => {
169
+ const nextValue = resolveAccessor(valueOrGetter);
170
+ node.textContent = nextValue == null ? '' : String(nextValue);
171
+ });
172
+ registerCleanup(stop);
173
+ return node;
174
+ }
175
+ node.textContent = valueOrGetter == null ? '' : String(valueOrGetter);
176
+ return node;
177
+ }
178
+ // Mount a view into a root element and return a disposer for its reactive scope.
179
+ export function mount(root, view) {
180
+ assertDocument();
181
+ const target = resolveRoot(root);
182
+ target[ROOT_CLEANUP]?.();
183
+ const scope = createScope();
184
+ const content = withScope(scope, () => typeof view === 'function' ? view() : view);
185
+ target.replaceChildren();
186
+ appendChild(target, content);
187
+ const dispose = () => {
188
+ if (target[ROOT_CLEANUP] === dispose) {
189
+ delete target[ROOT_CLEANUP];
190
+ }
191
+ disposeScope(scope);
192
+ target.replaceChildren();
193
+ return target;
194
+ };
195
+ target[ROOT_CLEANUP] = dispose;
196
+ return dispose;
197
+ }
@@ -0,0 +1,3 @@
1
+ type DomPropertyTarget = HTMLElement;
2
+ export declare function bindProp(element: DomPropertyTarget, key: string, value: unknown): void;
3
+ export {};
@@ -0,0 +1,147 @@
1
+ import { effect, isSignal } from '../core/signal.js';
2
+ import { isReactiveValue, resolveAccessor } from './reactive.js';
3
+ import { registerCleanup } from './scope.js';
4
+ // Normalize class payloads so callers can pass strings, arrays, or object maps.
5
+ function normalizeClassName(value) {
6
+ if (Array.isArray(value)) {
7
+ return value
8
+ .map((entry) => normalizeClassName(entry))
9
+ .filter(Boolean)
10
+ .join(' ');
11
+ }
12
+ if (value && typeof value === 'object') {
13
+ return Object.entries(value)
14
+ .filter(([, active]) => Boolean(active))
15
+ .map(([className]) => className)
16
+ .join(' ');
17
+ }
18
+ if (value == null || value === false) {
19
+ return '';
20
+ }
21
+ return String(value);
22
+ }
23
+ // Apply styles from either a raw string or a property map.
24
+ function setStyleValue(element, value) {
25
+ element.style.cssText = '';
26
+ if (typeof value === 'string') {
27
+ element.style.cssText = value;
28
+ return;
29
+ }
30
+ if (!value || typeof value !== 'object') {
31
+ if (value == null || value === false) {
32
+ element.removeAttribute('style');
33
+ }
34
+ return;
35
+ }
36
+ const styleRecord = element.style;
37
+ for (const [property, propertyValue] of Object.entries(value)) {
38
+ styleRecord[property] = propertyValue == null || propertyValue === false
39
+ ? ''
40
+ : String(propertyValue);
41
+ }
42
+ }
43
+ // Centralize DOM property and attribute writes behind one compatibility layer.
44
+ function setDomProperty(element, key, value) {
45
+ const attributeName = key === 'className' ? 'class' : key;
46
+ const domRecord = element;
47
+ if (key === 'className' || key === 'class') {
48
+ element.className = normalizeClassName(value);
49
+ return;
50
+ }
51
+ if (key === 'style') {
52
+ setStyleValue(element, value);
53
+ return;
54
+ }
55
+ if (value == null || value === false) {
56
+ if (key in element && key !== 'list' && key !== 'form') {
57
+ try {
58
+ if (typeof domRecord[key] === 'boolean') {
59
+ domRecord[key] = false;
60
+ }
61
+ else if (key === 'value') {
62
+ domRecord[key] = '';
63
+ }
64
+ else {
65
+ domRecord[key] = '';
66
+ }
67
+ }
68
+ catch {
69
+ // Ignore readonly DOM properties and fall back to attribute cleanup.
70
+ }
71
+ }
72
+ element.removeAttribute(attributeName);
73
+ return;
74
+ }
75
+ if (value === true) {
76
+ if (key in element && key !== 'list' && key !== 'form') {
77
+ try {
78
+ domRecord[key] = true;
79
+ }
80
+ catch {
81
+ // Fall through to attribute mode.
82
+ }
83
+ }
84
+ element.setAttribute(attributeName, '');
85
+ return;
86
+ }
87
+ if (key in element && key !== 'list' && key !== 'form') {
88
+ try {
89
+ domRecord[key] = value;
90
+ return;
91
+ }
92
+ catch {
93
+ // Fall back to setAttribute for readonly DOM properties.
94
+ }
95
+ }
96
+ element.setAttribute(attributeName, String(value));
97
+ }
98
+ // Bind events and only treat signal-like values as reactive handler containers.
99
+ function bindEvent(element, key, handler) {
100
+ const eventName = key.slice(2).toLowerCase();
101
+ if (isSignal(handler)) {
102
+ let activeHandler = null;
103
+ const stop = effect(() => {
104
+ const nextHandler = handler();
105
+ if (activeHandler) {
106
+ element.removeEventListener(eventName, activeHandler);
107
+ }
108
+ activeHandler = typeof nextHandler === 'function' ? nextHandler : null;
109
+ if (activeHandler) {
110
+ element.addEventListener(eventName, activeHandler);
111
+ }
112
+ });
113
+ registerCleanup(() => {
114
+ stop();
115
+ if (activeHandler) {
116
+ element.removeEventListener(eventName, activeHandler);
117
+ }
118
+ });
119
+ return;
120
+ }
121
+ if (typeof handler === 'function') {
122
+ const listener = handler;
123
+ element.addEventListener(eventName, listener);
124
+ registerCleanup(() => element.removeEventListener(eventName, listener));
125
+ }
126
+ }
127
+ // Bind a prop key, upgrading reactive values into tracked effects when needed.
128
+ export function bindProp(element, key, value) {
129
+ if (key === 'ref') {
130
+ if (typeof value === 'function') {
131
+ value(element);
132
+ }
133
+ return;
134
+ }
135
+ if (key.startsWith('on')) {
136
+ bindEvent(element, key, value);
137
+ return;
138
+ }
139
+ if (isReactiveValue(value)) {
140
+ const stop = effect(() => {
141
+ setDomProperty(element, key, resolveAccessor(value));
142
+ });
143
+ registerCleanup(stop);
144
+ return;
145
+ }
146
+ setDomProperty(element, key, value);
147
+ }
@@ -0,0 +1,6 @@
1
+ import type { ReactiveValue, QoreTemplate } from './types.js';
2
+ export declare function isReactiveValue<T>(value: ReactiveValue<T> | unknown): value is ReactiveValue<T>;
3
+ export declare function resolveAccessor<T>(value: ReactiveValue<T>): T;
4
+ export declare function resolveAccessor<T>(value: T): T;
5
+ export declare function resolveTemplate<T>(template: QoreTemplate<T>, value: T): QoreTemplate<T>;
6
+ export declare function resolveTemplate<T>(template: QoreTemplate<T> | undefined, value: T): QoreTemplate<T> | undefined;
@@ -0,0 +1,14 @@
1
+ import { isSignal } from '../core/signal.js';
2
+ // Treat signals and getters as reactive values the DOM layer should subscribe to.
3
+ export function isReactiveValue(value) {
4
+ return isSignal(value) || typeof value === 'function';
5
+ }
6
+ export function resolveAccessor(value) {
7
+ if (isSignal(value) || typeof value === 'function') {
8
+ return value();
9
+ }
10
+ return value;
11
+ }
12
+ export function resolveTemplate(template, value) {
13
+ return typeof template === 'function' ? template(value) : template;
14
+ }
@@ -0,0 +1,4 @@
1
+ import type { ResponseState, ResponseStatus } from '../core/response.js';
2
+ import type { ResponseRenderState, ResponseViews } from './types.js';
3
+ export declare function readResponseState<TChunk, TValue>(responseState: ResponseState<TChunk, TValue>): ResponseRenderState<TChunk, TValue>;
4
+ export declare function pickResponseTemplate<TChunk, TValue>(status: ResponseStatus, views: ResponseViews<TChunk, TValue>): unknown;
@@ -0,0 +1,37 @@
1
+ // Read a response into one plain object so templates can branch on status cleanly.
2
+ export function readResponseState(responseState) {
3
+ return {
4
+ response: responseState,
5
+ status: responseState.status(),
6
+ value: responseState.value(),
7
+ error: responseState.error(),
8
+ chunks: responseState.chunks(),
9
+ startedAt: responseState.startedAt(),
10
+ finishedAt: responseState.finishedAt(),
11
+ pending: responseState.pending(),
12
+ streaming: responseState.streaming(),
13
+ completed: responseState.completed(),
14
+ failed: responseState.failed(),
15
+ aborted: responseState.aborted(),
16
+ chunkCount: responseState.chunkCount()
17
+ };
18
+ }
19
+ // Pick the best matching view override for the current response lifecycle state.
20
+ export function pickResponseTemplate(status, views) {
21
+ switch (status) {
22
+ case 'idle':
23
+ return views.idle ?? views.pending ?? views.default;
24
+ case 'pending':
25
+ return views.pending ?? views.default;
26
+ case 'streaming':
27
+ return views.streaming ?? views.pending ?? views.default;
28
+ case 'completed':
29
+ return views.completed ?? views.default;
30
+ case 'error':
31
+ return views.error ?? views.default;
32
+ case 'aborted':
33
+ return views.aborted ?? views.default;
34
+ default:
35
+ return views.default;
36
+ }
37
+ }
@@ -0,0 +1,10 @@
1
+ import type { Cleanup } from '../core/signal-types.js';
2
+ export declare const ROOT_CLEANUP: unique symbol;
3
+ export interface Scope {
4
+ cleanups: Cleanup[];
5
+ }
6
+ export declare function assertDocument(): void;
7
+ export declare function createScope(): Scope;
8
+ export declare function withScope<T>(scope: Scope, fn: () => T): T;
9
+ export declare function registerCleanup<T extends Cleanup | null | undefined>(cleanup: T): T;
10
+ export declare function disposeScope(scope: Scope | null | undefined): void;
@@ -0,0 +1,49 @@
1
+ // Store mount cleanup directly on the root node so remounts can tear down old scopes.
2
+ export const ROOT_CLEANUP = Symbol('qore.dom.cleanup');
3
+ let activeScope = null;
4
+ // Guard DOM helpers so they only run in browser-like environments.
5
+ export function assertDocument() {
6
+ if (typeof document === 'undefined') {
7
+ throw new Error('Qore DOM APIs require a browser-like environment');
8
+ }
9
+ }
10
+ // A scope collects effect disposers created while rendering a subtree.
11
+ export function createScope() {
12
+ return { cleanups: [] };
13
+ }
14
+ // Temporarily switch the active scope while a subtree is being materialized.
15
+ export function withScope(scope, fn) {
16
+ const previousScope = activeScope;
17
+ activeScope = scope;
18
+ try {
19
+ return fn();
20
+ }
21
+ finally {
22
+ activeScope = previousScope;
23
+ }
24
+ }
25
+ // Register a cleanup callback on the currently active scope, if one exists.
26
+ export function registerCleanup(cleanup) {
27
+ if (typeof cleanup === 'function' && activeScope) {
28
+ activeScope.cleanups.push(cleanup);
29
+ }
30
+ return cleanup;
31
+ }
32
+ // Dispose nested resources in reverse order so teardown mirrors setup.
33
+ export function disposeScope(scope) {
34
+ if (!scope) {
35
+ return;
36
+ }
37
+ for (let index = scope.cleanups.length - 1; index >= 0; index -= 1) {
38
+ try {
39
+ const cleanup = scope.cleanups[index];
40
+ if (cleanup) {
41
+ cleanup();
42
+ }
43
+ }
44
+ catch {
45
+ // Ignore cleanup errors during teardown so the rest of the scope can unwind.
46
+ }
47
+ }
48
+ scope.cleanups.length = 0;
49
+ }
@@ -0,0 +1,34 @@
1
+ import type { ResponseState, ResponseStatus } from '../core/response.js';
2
+ import type { ReadonlySignal } from '../core/signal.js';
3
+ export type QoreNode = Node;
4
+ export type QoreElement = Element;
5
+ export type QoreText = Text;
6
+ export type QoreDocumentFragment = DocumentFragment;
7
+ export type GlobalNode = QoreNode;
8
+ export type GlobalElement = QoreElement;
9
+ export type GlobalText = QoreText;
10
+ export type GlobalDocumentFragment = QoreDocumentFragment;
11
+ export type ReactiveValue<T> = T | ReadonlySignal<T> | (() => T);
12
+ export type QoreChild = QoreNode | string | number | bigint | boolean | null | undefined | ReactiveValue<unknown> | QoreChild[];
13
+ export type QoreTemplate<T> = QoreChild | ((value: T) => QoreChild);
14
+ export interface ResponseRenderState<TChunk = unknown, TValue = unknown> {
15
+ response: ResponseState<TChunk, TValue>;
16
+ status: ResponseStatus;
17
+ value: TValue;
18
+ error: Error | null;
19
+ chunks: TChunk[];
20
+ startedAt: number | null;
21
+ finishedAt: number | null;
22
+ pending: boolean;
23
+ streaming: boolean;
24
+ completed: boolean;
25
+ failed: boolean;
26
+ aborted: boolean;
27
+ chunkCount: number;
28
+ }
29
+ export type ResponseViews<TChunk = unknown, TValue = unknown> = Partial<Record<ResponseStatus | 'default', QoreTemplate<ResponseRenderState<TChunk, TValue>>>>;
30
+ export type QoreComponent<Props extends Record<string, unknown> = Record<string, unknown>> = (props: Props & {
31
+ children: QoreChild[];
32
+ }) => QoreChild;
33
+ export type MountTarget = string | QoreElement;
34
+ export type MountView = QoreChild | (() => QoreChild);
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,16 @@
1
+ export { signal, computed, effect, batch, untrack, isSignal } from './core/signal.js';
2
+ export type { ComputedSignal, ReadonlySignal, Signal } from './core/signal.js';
3
+ export type { EffectOptions, EffectScheduler, SubscribeOptions } from './core/signal-types.js';
4
+ export { stream, createStream, from, mapStream, scanStream, toAsyncIterable } from './core/stream.js';
5
+ export type { BackpressureOptions, QoreStream, StreamController, StreamFactory, StreamInput, StreamOptions, StreamSetup } from './core/stream.js';
6
+ export { createResponse, response } from './core/response.js';
7
+ export type { CreateResponseOptions, GlobalAbortSignal, MaybePromise, ResponseConsumeContext, ResponseExecutorContext, ResponseFactory, ResponseReactiveState, ResponseRunOptions, ResponseSnapshot, ResponseSource, ResponseSourceFactory, ResponseState, ResponseStatus, SourceLike } from './core/response.js';
8
+ export { createApp } from './dom/app.js';
9
+ export type { AppContext, AppSetupResult, QoreApp } from './dom/app.js';
10
+ export { dynamic, fragment, h, list, mount, renderResponse, show, text } from './dom/dom.js';
11
+ export type { GlobalDocumentFragment, GlobalElement, GlobalNode, GlobalText, MountTarget, MountView, QoreChild, QoreComponent, QoreDocumentFragment, QoreElement, QoreNode, QoreTemplate, QoreText, ReactiveValue, ResponseRenderState, ResponseViews } from './dom/types.js';
12
+ export { createAnthropic } from './providers/anthropic.js';
13
+ export { createOpenAI } from './providers/openai.js';
14
+ export { createSSEAdapter } from './providers/sse.js';
15
+ export type { AnthropicAdapter, AnthropicChatInput, AnthropicEvent, AnthropicMessage, AnthropicOptions, AnthropicRequest, FetchLike, OpenAIAdapter, OpenAIChatInput, OpenAIEvent, OpenAIMessage, OpenAIOptions, OpenAIRequest, ProviderHeaders, ProviderRequestOptions, SSEAdapter, SSEAdapterOptions, SSEEvent, SSERequestConfig } from './providers/sse.js';
16
+ export { normalizeError, sleep } from './shared/utils.js';
@@ -0,0 +1,10 @@
1
+ // Re-export the public runtime surface from a single module entrypoint.
2
+ export { signal, computed, effect, batch, untrack, isSignal } from './core/signal.js';
3
+ export { stream, createStream, from, mapStream, scanStream, toAsyncIterable } from './core/stream.js';
4
+ export { createResponse, response } from './core/response.js';
5
+ export { createApp } from './dom/app.js';
6
+ export { dynamic, fragment, h, list, mount, renderResponse, show, text } from './dom/dom.js';
7
+ export { createAnthropic } from './providers/anthropic.js';
8
+ export { createOpenAI } from './providers/openai.js';
9
+ export { createSSEAdapter } from './providers/sse.js';
10
+ export { normalizeError, sleep } from './shared/utils.js';
@@ -0,0 +1,2 @@
1
+ import type { AnthropicAdapter, AnthropicOptions } from './types.js';
2
+ export declare function createAnthropic(options?: AnthropicOptions): AnthropicAdapter;
@@ -0,0 +1,102 @@
1
+ import { createSSEAdapter, readEnv } from './sse.js';
2
+ const DEFAULT_BASE_URL = 'https://api.anthropic.com/v1';
3
+ const DEFAULT_MODEL = 'claude-sonnet-4-20250514';
4
+ const DEFAULT_VERSION = '2023-06-01';
5
+ const DEFAULT_MAX_TOKENS = 1024;
6
+ // Normalize single-string prompts into Anthropic's Messages API shape.
7
+ function normalizeMessages(input) {
8
+ if (typeof input === 'string') {
9
+ return [{ role: 'user', content: input }];
10
+ }
11
+ if (Array.isArray(input)) {
12
+ return input;
13
+ }
14
+ if (input && typeof input === 'object' && 'role' in input) {
15
+ return [input];
16
+ }
17
+ return input;
18
+ }
19
+ // Keep provider setup explicit because real API keys should stay off the client.
20
+ export function createAnthropic(options = {}) {
21
+ const { apiKey, baseURL = DEFAULT_BASE_URL, model = DEFAULT_MODEL, version = DEFAULT_VERSION, maxTokens = DEFAULT_MAX_TOKENS, headers: defaultHeaders = {}, fetch: fetchImpl = globalThis.fetch } = options;
22
+ const resolvedApiKey = apiKey ?? readEnv('ANTHROPIC_API_KEY');
23
+ if (!resolvedApiKey) {
24
+ throw new Error('Qore Anthropic adapter requires an API key. Pass apiKey or set ANTHROPIC_API_KEY.');
25
+ }
26
+ const transport = createSSEAdapter({
27
+ name: 'Anthropic',
28
+ url: `${baseURL}/messages`,
29
+ headers: {
30
+ 'content-type': 'application/json',
31
+ 'anthropic-version': version,
32
+ 'x-api-key': resolvedApiKey,
33
+ ...defaultHeaders
34
+ },
35
+ fetch: fetchImpl,
36
+ buildRequest(request, requestOptions = {}) {
37
+ const { signal, headers = {}, ...overrides } = requestOptions;
38
+ const config = {
39
+ method: 'POST',
40
+ headers,
41
+ body: JSON.stringify({
42
+ model,
43
+ max_tokens: maxTokens,
44
+ stream: true,
45
+ ...request,
46
+ ...overrides
47
+ })
48
+ };
49
+ if (signal) {
50
+ config.signal = signal;
51
+ }
52
+ return config;
53
+ },
54
+ parse: (data) => JSON.parse(data),
55
+ isError: (event) => event.data?.type === 'error',
56
+ getError: (event) => {
57
+ const errorEvent = event.data;
58
+ return errorEvent.error?.message ?? 'Anthropic streaming error';
59
+ },
60
+ eventToText: (event) => (event.data?.type === 'content_block_delta'
61
+ && typeof event.data.delta?.type === 'string'
62
+ && event.data.delta?.type === 'text_delta'
63
+ && typeof event.data.delta?.text === 'string')
64
+ ? event.data.delta.text
65
+ : undefined
66
+ });
67
+ async function* streamEvents(request, requestOptions = {}) {
68
+ for await (const event of transport.stream(request, requestOptions)) {
69
+ yield event.data;
70
+ }
71
+ }
72
+ async function* streamText(messages, requestOptions = {}) {
73
+ const request = messages && typeof messages === 'object' && 'messages' in messages
74
+ ? messages
75
+ : { messages };
76
+ for await (const chunk of transport.streamText(request, requestOptions)) {
77
+ yield chunk;
78
+ }
79
+ }
80
+ return {
81
+ // Stream typed semantic events from the Messages API.
82
+ messages: {
83
+ stream: streamEvents
84
+ },
85
+ // Stream only text delta chunks from assistant content blocks.
86
+ streamText(messages, requestOptions = {}) {
87
+ return streamText(messages, requestOptions);
88
+ },
89
+ // Match the Qore narrative directly: stream(anthropic.chat(prompt)).
90
+ chat(input, requestOptions = {}) {
91
+ const { signal, headers, ...rest } = requestOptions;
92
+ const request = { ...rest };
93
+ if (!('messages' in request)) {
94
+ request.messages = normalizeMessages(input);
95
+ }
96
+ return streamText(request, {
97
+ ...(signal ? { signal } : {}),
98
+ ...(headers ? { headers } : {})
99
+ });
100
+ }
101
+ };
102
+ }
@@ -0,0 +1,2 @@
1
+ import type { OpenAIAdapter, OpenAIOptions } from './types.js';
2
+ export declare function createOpenAI(options?: OpenAIOptions): OpenAIAdapter;