@aerostack/sdk-web 0.8.7 → 0.8.9

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 (106) hide show
  1. package/package.json +10 -3
  2. package/FUNCTIONS.md +0 -95
  3. package/RUNTIMES.md +0 -48
  4. package/examples/aiAIChat.example.ts +0 -31
  5. package/examples/databaseDbQuery.example.ts +0 -34
  6. package/examples/e2e/__tests__/e2e.test.ts +0 -69
  7. package/examples/e2e/package.json +0 -15
  8. package/examples/e2e/vitest.config.ts +0 -8
  9. package/examples/package.json +0 -18
  10. package/jsr.json +0 -27
  11. package/src/__tests__/realtime.test.ts +0 -388
  12. package/src/__tests__/sdk.test.ts +0 -181
  13. package/src/_generated/apis/AIApi.ts +0 -477
  14. package/src/_generated/apis/AuthenticationApi.ts +0 -121
  15. package/src/_generated/apis/CacheApi.ts +0 -551
  16. package/src/_generated/apis/DatabaseApi.ts +0 -138
  17. package/src/_generated/apis/GatewayApi.ts +0 -204
  18. package/src/_generated/apis/QueueApi.ts +0 -218
  19. package/src/_generated/apis/ServicesApi.ts +0 -74
  20. package/src/_generated/apis/StorageApi.ts +0 -476
  21. package/src/_generated/apis/index.ts +0 -10
  22. package/src/_generated/index.ts +0 -5
  23. package/src/_generated/models/AuthResponse.ts +0 -88
  24. package/src/_generated/models/AuthSigninRequest.ts +0 -75
  25. package/src/_generated/models/AuthSignupRequest.ts +0 -91
  26. package/src/_generated/models/CacheDeleteMany200Response.ts +0 -81
  27. package/src/_generated/models/CacheDeleteManyRequest.ts +0 -66
  28. package/src/_generated/models/CacheExpireRequest.ts +0 -75
  29. package/src/_generated/models/CacheFlush200Response.ts +0 -73
  30. package/src/_generated/models/CacheFlushRequest.ts +0 -65
  31. package/src/_generated/models/CacheGet200Response.ts +0 -73
  32. package/src/_generated/models/CacheGetMany200Response.ts +0 -72
  33. package/src/_generated/models/CacheGetManyEntry.ts +0 -81
  34. package/src/_generated/models/CacheGetManyRequest.ts +0 -66
  35. package/src/_generated/models/CacheGetRequest.ts +0 -66
  36. package/src/_generated/models/CacheIncrement200Response.ts +0 -65
  37. package/src/_generated/models/CacheIncrementRequest.ts +0 -90
  38. package/src/_generated/models/CacheKeyEntry.ts +0 -73
  39. package/src/_generated/models/CacheKeys200Response.ts +0 -73
  40. package/src/_generated/models/CacheKeysRequest.ts +0 -65
  41. package/src/_generated/models/CacheListRequest.ts +0 -81
  42. package/src/_generated/models/CacheListResult.ts +0 -88
  43. package/src/_generated/models/CacheSet200Response.ts +0 -65
  44. package/src/_generated/models/CacheSetEntry.ts +0 -83
  45. package/src/_generated/models/CacheSetMany200Response.ts +0 -73
  46. package/src/_generated/models/CacheSetManyRequest.ts +0 -73
  47. package/src/_generated/models/CacheSetRequest.ts +0 -83
  48. package/src/_generated/models/ChatCompletionRequest.ts +0 -130
  49. package/src/_generated/models/ChatCompletionRequestStreamOptions.ts +0 -67
  50. package/src/_generated/models/ChatCompletionResponse.ts +0 -128
  51. package/src/_generated/models/ChatCompletionResponseChoicesInner.ts +0 -100
  52. package/src/_generated/models/ChatMessage.ts +0 -87
  53. package/src/_generated/models/ConfigureRequest.ts +0 -77
  54. package/src/_generated/models/DbBatchRequest.ts +0 -73
  55. package/src/_generated/models/DbBatchRequestQueriesInner.ts +0 -74
  56. package/src/_generated/models/DbBatchResult.ts +0 -80
  57. package/src/_generated/models/DbBatchResultResultsInner.ts +0 -81
  58. package/src/_generated/models/DbQueryRequest.ts +0 -74
  59. package/src/_generated/models/DbQueryResult.ts +0 -73
  60. package/src/_generated/models/DeleteByTypeRequest.ts +0 -66
  61. package/src/_generated/models/DeleteRequest.ts +0 -66
  62. package/src/_generated/models/ErrorResponse.ts +0 -99
  63. package/src/_generated/models/GatewayBillingLog200Response.ts +0 -73
  64. package/src/_generated/models/GatewayBillingLogRequest.ts +0 -92
  65. package/src/_generated/models/GatewayGetWallet200Response.ts +0 -72
  66. package/src/_generated/models/IngestRequest.ts +0 -91
  67. package/src/_generated/models/JobRecord.ts +0 -119
  68. package/src/_generated/models/ListTypes200Response.ts +0 -72
  69. package/src/_generated/models/Query200Response.ts +0 -72
  70. package/src/_generated/models/QueryRequest.ts +0 -90
  71. package/src/_generated/models/QueueCancelJob200Response.ts +0 -73
  72. package/src/_generated/models/QueueEnqueue201Response.ts +0 -73
  73. package/src/_generated/models/QueueEnqueueRequest.ts +0 -83
  74. package/src/_generated/models/QueueGetJob200Response.ts +0 -80
  75. package/src/_generated/models/QueueGetJobRequest.ts +0 -66
  76. package/src/_generated/models/QueueListJobs200Response.ts +0 -88
  77. package/src/_generated/models/QueueListJobsRequest.ts +0 -103
  78. package/src/_generated/models/SearchCount200Response.ts +0 -65
  79. package/src/_generated/models/SearchCountRequest.ts +0 -65
  80. package/src/_generated/models/SearchGet200Response.ts +0 -80
  81. package/src/_generated/models/SearchGetRequest.ts +0 -66
  82. package/src/_generated/models/SearchResult.ts +0 -97
  83. package/src/_generated/models/SearchUpdateRequest.ts +0 -91
  84. package/src/_generated/models/ServicesInvoke200Response.ts +0 -73
  85. package/src/_generated/models/ServicesInvokeRequest.ts +0 -75
  86. package/src/_generated/models/StorageCopy200Response.ts +0 -73
  87. package/src/_generated/models/StorageCopyRequest.ts +0 -75
  88. package/src/_generated/models/StorageExists200Response.ts +0 -65
  89. package/src/_generated/models/StorageGetRequest.ts +0 -66
  90. package/src/_generated/models/StorageListRequest.ts +0 -81
  91. package/src/_generated/models/StorageListResult.ts +0 -88
  92. package/src/_generated/models/StorageMetadata.ts +0 -97
  93. package/src/_generated/models/StorageMove200Response.ts +0 -73
  94. package/src/_generated/models/StorageMoveRequest.ts +0 -75
  95. package/src/_generated/models/StorageObject.ts +0 -97
  96. package/src/_generated/models/StorageUpload200Response.ts +0 -65
  97. package/src/_generated/models/TokenUsage.ts +0 -81
  98. package/src/_generated/models/TokenWallet.ts +0 -73
  99. package/src/_generated/models/TypeStats.ts +0 -73
  100. package/src/_generated/models/User.ts +0 -97
  101. package/src/_generated/models/index.ts +0 -80
  102. package/src/_generated/runtime.ts +0 -431
  103. package/src/index.ts +0 -3
  104. package/src/realtime.ts +0 -456
  105. package/src/sdk.ts +0 -197
  106. package/tsconfig.json +0 -41
package/src/realtime.ts DELETED
@@ -1,456 +0,0 @@
1
- /**
2
- * Aerostack Realtime Client for Web/Browser SDK
3
- */
4
- export type RealtimeEvent = 'INSERT' | 'UPDATE' | 'DELETE' | '*' | string;
5
-
6
- export interface RealtimeMessage {
7
- type: string;
8
- topic: string;
9
- [key: string]: any;
10
- }
11
-
12
- export interface RealtimeSubscriptionOptions {
13
- event?: RealtimeEvent;
14
- filter?: Record<string, any>;
15
- }
16
-
17
- export type RealtimeCallback<T = any> = (payload: RealtimePayload<T>) => void;
18
-
19
- /** Typed payload for realtime events */
20
- export interface RealtimePayload<T = any> {
21
- type: 'db_change' | 'chat_message' | 'event';
22
- topic: string;
23
- operation?: RealtimeEvent;
24
- event?: string;
25
- data: T;
26
- old?: T;
27
- userId?: string;
28
- timestamp?: number | string;
29
- [key: string]: any;
30
- }
31
-
32
- /** Chat history message returned from REST API */
33
- export interface HistoryMessage {
34
- id: string;
35
- room_id: string;
36
- user_id: string;
37
- event: string;
38
- data: any;
39
- created_at: number;
40
- }
41
-
42
- export class RealtimeSubscription<T = any> {
43
- private client: RealtimeClient;
44
- topic: string;
45
- private options: RealtimeSubscriptionOptions;
46
- private callbacks: Map<string, Set<RealtimeCallback<T>>> = new Map();
47
- private isSubscribed: boolean = false;
48
-
49
- constructor(client: RealtimeClient, topic: string, options: RealtimeSubscriptionOptions = {}) {
50
- this.client = client;
51
- this.topic = topic;
52
- this.options = options;
53
- }
54
-
55
- /** Listen for DB change events (INSERT/UPDATE/DELETE/*) or custom named events */
56
- on(event: RealtimeEvent | string, callback: RealtimeCallback<T>): this {
57
- if (!this.callbacks.has(event)) {
58
- this.callbacks.set(event, new Set());
59
- }
60
- this.callbacks.get(event)!.add(callback);
61
- return this;
62
- }
63
-
64
- /** Remove a specific callback for an event */
65
- off(event: RealtimeEvent | string, callback: RealtimeCallback<T>): this {
66
- this.callbacks.get(event)?.delete(callback);
67
- return this;
68
- }
69
-
70
- subscribe(): this {
71
- if (this.isSubscribed) return this;
72
- this.client._send({
73
- type: 'subscribe',
74
- topic: this.topic,
75
- filter: this.options.filter
76
- });
77
- this.isSubscribed = true;
78
- return this;
79
- }
80
-
81
- unsubscribe(): void {
82
- if (!this.isSubscribed) return;
83
- this.client._send({
84
- type: 'unsubscribe',
85
- topic: this.topic
86
- });
87
- this.isSubscribed = false;
88
- this.callbacks.clear();
89
- this.client._removeSubscription(this.topic);
90
- }
91
-
92
- // ─── Phase 1: Pub/Sub — Publish custom events ─────────────────────────
93
- /** Publish a custom event to all subscribers on this channel */
94
- publish(event: string, data: any, options?: { persist?: boolean }): void {
95
- this.client._send({
96
- type: 'publish',
97
- topic: this.topic,
98
- event,
99
- data,
100
- persist: options?.persist,
101
- id: this.client._generateId(),
102
- });
103
- }
104
-
105
- // ─── Phase 2: Chat History ────────────────────────────────────────────
106
- /** Fetch persisted message history for this channel (requires persist: true on publish) */
107
- async getHistory(limit: number = 50, before?: number): Promise<HistoryMessage[]> {
108
- return this.client._fetchHistory(this.topic, limit, before);
109
- }
110
-
111
- // ─── Phase 3: Presence ────────────────────────────────────────────────
112
- /** Track this user's presence state on this channel (auto-synced to subscribers) */
113
- track(state: Record<string, any>): void {
114
- this.client._send({
115
- type: 'track',
116
- topic: this.topic,
117
- state,
118
- });
119
- }
120
-
121
- /** Stop tracking presence on this channel */
122
- untrack(): void {
123
- this.client._send({
124
- type: 'untrack',
125
- topic: this.topic,
126
- });
127
- }
128
-
129
- /** @internal */
130
- _emit(payload: RealtimePayload<T>): void {
131
- // DB change events (INSERT/UPDATE/DELETE)
132
- if (payload.operation) {
133
- const event = payload.operation as string;
134
- this.callbacks.get(event)?.forEach(cb => cb(payload));
135
- }
136
- // Custom named events ('player-moved', 'presence:join', etc.)
137
- if (payload.event) {
138
- this.callbacks.get(payload.event)?.forEach(cb => cb(payload));
139
- }
140
- // Catch-all
141
- this.callbacks.get('*')?.forEach(cb => cb(payload));
142
- }
143
- }
144
-
145
- export type RealtimeStatus = 'idle' | 'connecting' | 'connected' | 'reconnecting' | 'disconnected';
146
-
147
- export interface RealtimeClientOptions {
148
- baseUrl: string;
149
- projectId: string;
150
- token?: string;
151
- userId?: string;
152
- apiKey?: string;
153
- /** Max reconnect attempts before giving up (default: Infinity) */
154
- maxReconnectAttempts?: number;
155
- }
156
-
157
- export class RealtimeClient {
158
- private baseUrl: string;
159
- private projectId: string;
160
- private token?: string;
161
- private userId?: string;
162
- private apiKey?: string;
163
- private ws: WebSocket | null = null;
164
- private subscriptions: Map<string, RealtimeSubscription> = new Map();
165
- private reconnectTimer: any = null;
166
- private heartbeatTimer: any = null;
167
- private reconnectAttempts: number = 0;
168
- private _sendQueue: any[] = [];
169
- private _connectingPromise: Promise<void> | null = null;
170
- private _status: RealtimeStatus = 'idle';
171
- private _statusListeners: Set<(s: RealtimeStatus) => void> = new Set();
172
- // HTTP base URL for REST endpoints (history, etc.)
173
- private _httpBaseUrl: string;
174
- // Pong tracking
175
- private _lastPong: number = 0;
176
- // Max reconnect attempts
177
- private _maxReconnectAttempts: number;
178
- private _maxRetriesListeners: Set<() => void> = new Set();
179
-
180
- constructor(options: RealtimeClientOptions) {
181
- const wsBase = options.baseUrl.replace(/\/v1\/?$/, '').replace(/^http/, 'ws');
182
- this.baseUrl = `${wsBase}/api/realtime`;
183
- this._httpBaseUrl = options.baseUrl.replace(/\/v1\/?$/, '');
184
- this.projectId = options.projectId;
185
- this.token = options.token;
186
- this.userId = options.userId;
187
- this.apiKey = options.apiKey;
188
- this._maxReconnectAttempts = options.maxReconnectAttempts ?? Infinity;
189
- }
190
-
191
- get status(): RealtimeStatus { return this._status; }
192
- get connected(): boolean { return this._status === 'connected'; }
193
-
194
- /** Subscribe to connection status changes. Returns unsubscribe fn. */
195
- onStatusChange(cb: (status: RealtimeStatus) => void): () => void {
196
- this._statusListeners.add(cb);
197
- return () => this._statusListeners.delete(cb);
198
- }
199
-
200
- /** Called when max reconnect attempts exceeded. Returns unsubscribe fn. */
201
- onMaxRetriesExceeded(cb: () => void): () => void {
202
- this._maxRetriesListeners.add(cb);
203
- return () => this._maxRetriesListeners.delete(cb);
204
- }
205
-
206
- private _setStatus(s: RealtimeStatus) {
207
- this._status = s;
208
- this._statusListeners.forEach(cb => cb(s));
209
- }
210
-
211
- /** Update the auth token on a live connection */
212
- setToken(newToken: string): void {
213
- this.token = newToken;
214
- this._send({ type: 'auth', token: newToken });
215
- }
216
-
217
- async connect(): Promise<void> {
218
- if (this.ws && this.ws.readyState === WebSocket.OPEN) return Promise.resolve();
219
- if (this._connectingPromise) return this._connectingPromise;
220
- this._connectingPromise = this._doConnect().finally(() => {
221
- this._connectingPromise = null;
222
- });
223
- return this._connectingPromise;
224
- }
225
-
226
- private _doConnect(): Promise<void> {
227
- this._setStatus('connecting');
228
- return new Promise((resolve, reject) => {
229
- const url = new URL(this.baseUrl);
230
- url.searchParams.set('projectId', this.projectId);
231
- if (this.userId) url.searchParams.set('userId', this.userId);
232
-
233
- // SECURITY: Pass credentials via Sec-WebSocket-Protocol header — never as URL query params
234
- // (URL params appear in CDN logs, browser history, and Referer headers).
235
- const protocols: string[] = [];
236
- if (this.apiKey) protocols.push(`aerostack-key.${this.apiKey}`);
237
- if (this.token) protocols.push(`aerostack-token.${this.token}`);
238
- if (protocols.length > 0) protocols.push('aerostack-v1');
239
-
240
- this.ws = protocols.length > 0
241
- ? new WebSocket(url.toString(), protocols)
242
- : new WebSocket(url.toString());
243
-
244
- this.ws.onopen = () => {
245
- this._setStatus('connected');
246
- this.reconnectAttempts = 0;
247
- this._lastPong = Date.now();
248
- this.startHeartbeat();
249
- this._setupOfflineDetection();
250
- // Flush queued messages
251
- while (this._sendQueue.length > 0) {
252
- this.ws!.send(JSON.stringify(this._sendQueue.shift()));
253
- }
254
- for (const sub of this.subscriptions.values()) {
255
- sub.subscribe();
256
- }
257
- resolve();
258
- };
259
-
260
- this.ws.onmessage = (event) => {
261
- try {
262
- const data = JSON.parse(event.data);
263
- this.handleMessage(data);
264
- } catch (e) {
265
- console.error('Realtime message parse error:', e);
266
- }
267
- };
268
-
269
- this.ws.onclose = () => {
270
- this._setStatus('reconnecting');
271
- this.stopHeartbeat();
272
- this.ws = null;
273
- this.scheduleReconnect();
274
- };
275
-
276
- this.ws.onerror = (err) => {
277
- console.error('Realtime connection error:', err);
278
- this._setStatus('disconnected');
279
- reject(err);
280
- };
281
- });
282
- }
283
-
284
- disconnect() {
285
- this._setStatus('disconnected');
286
- this.stopReconnect();
287
- this.stopHeartbeat();
288
- this._teardownOfflineDetection();
289
- if (this.ws) {
290
- this.ws.close();
291
- this.ws = null;
292
- }
293
- this._sendQueue = [];
294
- }
295
-
296
- channel<T = any>(topic: string, options: RealtimeSubscriptionOptions = {}): RealtimeSubscription<T> {
297
- let fullTopic: string;
298
- if (!topic.includes('/')) {
299
- fullTopic = `table/${topic}/${this.projectId}`;
300
- } else if (this.projectId && topic.endsWith(`/${this.projectId}`)) {
301
- fullTopic = topic; // already fully qualified
302
- } else {
303
- fullTopic = `${topic}/${this.projectId}`; // e.g. 'table/orders' → 'table/orders/<projectId>'
304
- }
305
- let sub = this.subscriptions.get(fullTopic);
306
- if (!sub) {
307
- sub = new RealtimeSubscription<T>(this, fullTopic, options);
308
- this.subscriptions.set(fullTopic, sub);
309
- }
310
- return sub as RealtimeSubscription<T>;
311
- }
312
-
313
- /** Legacy: send a chat message (now persisted to DB) */
314
- sendChat(roomId: string, text: string, metadata?: Record<string, any>): void {
315
- this._send({ type: 'chat', roomId, text, metadata });
316
- }
317
-
318
- /** Legacy: get a chat room subscription */
319
- chatRoom(roomId: string): RealtimeSubscription {
320
- return this.channel(`chat/${roomId}/${this.projectId}`);
321
- }
322
-
323
- /** @internal — Generate unique message ID for ack tracking */
324
- _generateId(): string {
325
- return Math.random().toString(36).slice(2) + Date.now().toString(36);
326
- }
327
-
328
- /** @internal — Remove a subscription from the map (called on unsubscribe) */
329
- _removeSubscription(topic: string): void {
330
- this.subscriptions.delete(topic);
331
- }
332
-
333
- /** @internal */
334
- _send(data: any) {
335
- if (this.ws && this.ws.readyState === WebSocket.OPEN) {
336
- this.ws.send(JSON.stringify(data));
337
- } else {
338
- this._sendQueue.push(data);
339
- }
340
- }
341
-
342
- /** @internal — Fetch chat/event history via REST API */
343
- async _fetchHistory(room: string, limit: number = 50, before?: number): Promise<HistoryMessage[]> {
344
- const url = new URL(`${this._httpBaseUrl}/api/v1/public/realtime/history`);
345
- url.searchParams.set('room', room);
346
- url.searchParams.set('limit', String(limit));
347
- if (before) url.searchParams.set('before', String(before));
348
-
349
- const headers: Record<string, string> = {};
350
- if (this.apiKey) headers['X-Aerostack-Key'] = this.apiKey;
351
- if (this.token) headers['Authorization'] = `Bearer ${this.token}`;
352
-
353
- const res = await fetch(url.toString(), { headers });
354
- const json = await res.json() as any;
355
- return json.messages || [];
356
- }
357
-
358
- private handleMessage(data: RealtimeMessage) {
359
- // Track pong for liveness
360
- if (data.type === 'pong') {
361
- this._lastPong = Date.now();
362
- return;
363
- }
364
-
365
- // Ack (fire-and-forget acknowledgment from server)
366
- if (data.type === 'ack') {
367
- return;
368
- }
369
-
370
- // Route to subscription: db_change, chat_message, event, presence:*
371
- if (data.type === 'db_change' || data.type === 'chat_message' || data.type === 'event') {
372
- const sub = this.subscriptions.get(data.topic);
373
- if (sub) {
374
- sub._emit(data as any);
375
- }
376
- }
377
-
378
- // Re-key subscription on server-confirmed topic (for non-TS SDKs compatibility)
379
- if (data.type === 'subscribed' && data.topic) {
380
- for (const [origTopic, sub] of this.subscriptions.entries()) {
381
- if (data.topic !== origTopic && data.topic.startsWith(origTopic)) {
382
- this.subscriptions.delete(origTopic);
383
- sub.topic = data.topic;
384
- this.subscriptions.set(data.topic, sub);
385
- break;
386
- }
387
- }
388
- }
389
- }
390
-
391
- private startHeartbeat() {
392
- this.heartbeatTimer = setInterval(() => {
393
- this._send({ type: 'ping' });
394
- if (this._lastPong > 0 && Date.now() - this._lastPong > 70000) {
395
- console.warn('Realtime: no pong received, forcing reconnect');
396
- this.ws?.close();
397
- }
398
- }, 30000);
399
- }
400
-
401
- private stopHeartbeat() {
402
- if (this.heartbeatTimer) {
403
- clearInterval(this.heartbeatTimer);
404
- this.heartbeatTimer = null;
405
- }
406
- }
407
-
408
- private scheduleReconnect() {
409
- this.stopReconnect();
410
- if (this.reconnectAttempts >= this._maxReconnectAttempts) {
411
- this._setStatus('disconnected');
412
- this._maxRetriesListeners.forEach(cb => cb());
413
- return;
414
- }
415
- const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts), 30000);
416
- const jitter = delay * 0.3 * Math.random();
417
- this.reconnectAttempts++;
418
- this.reconnectTimer = setTimeout(() => {
419
- this.connect().catch(() => { });
420
- }, delay + jitter);
421
- }
422
-
423
- private stopReconnect() {
424
- if (this.reconnectTimer) {
425
- clearTimeout(this.reconnectTimer);
426
- this.reconnectTimer = null;
427
- }
428
- }
429
-
430
- // Offline/online detection (browser only)
431
- private _handleOnline = () => {
432
- if (this._status !== 'connected') {
433
- this.reconnectAttempts = 0;
434
- this.connect().catch(() => { });
435
- }
436
- };
437
-
438
- private _handleOffline = () => {
439
- this.stopReconnect();
440
- this._setStatus('disconnected');
441
- };
442
-
443
- private _setupOfflineDetection() {
444
- if (typeof window !== 'undefined') {
445
- window.addEventListener('online', this._handleOnline);
446
- window.addEventListener('offline', this._handleOffline);
447
- }
448
- }
449
-
450
- private _teardownOfflineDetection() {
451
- if (typeof window !== 'undefined') {
452
- window.removeEventListener('online', this._handleOnline);
453
- window.removeEventListener('offline', this._handleOffline);
454
- }
455
- }
456
- }
package/src/sdk.ts DELETED
@@ -1,197 +0,0 @@
1
- import * as gen from './_generated/index.js';
2
- import { RealtimeClient } from './realtime.js';
3
-
4
- export interface SDKOptions {
5
- /**
6
- * Aerostack API Key.
7
- * Use a Public Key for client-side environments.
8
- */
9
- apiKey?: string;
10
- /** Alias for apiKey for backward compatibility */
11
- apiKeyAuth?: string;
12
- serverUrl?: string;
13
- /** Alias for serverUrl for backward compatibility */
14
- serverURL?: string;
15
- maxReconnectAttempts?: number;
16
- projectId?: string;
17
- }
18
-
19
- /**
20
- * Compatibility wrapper for Database API
21
- */
22
- class DatabaseFacade {
23
- constructor(private api: gen.DatabaseApi) { }
24
-
25
- /**
26
- * Run a SQL query against your project database
27
- */
28
- async dbQuery(params: {
29
- dbQueryRequest?: gen.DbQueryRequest,
30
- requestBody?: gen.DbQueryRequest,
31
- xSDKVersion?: string,
32
- xRequestID?: string
33
- }) {
34
- return this.api.dbQuery({
35
- dbQueryRequest: params.dbQueryRequest || params.requestBody!,
36
- xSDKVersion: params.xSDKVersion,
37
- xRequestID: params.xRequestID
38
- });
39
- }
40
- }
41
-
42
- /**
43
- * Aerostack SDK Facade for Web/Browser.
44
- * Provides a clean, ergonomic API for client-safe Aerostack services.
45
- */
46
- export class SDK {
47
- public readonly auth: gen.AuthenticationApi;
48
- public readonly ai: gen.AIApi;
49
- public readonly storage: gen.StorageApi;
50
- public readonly realtime: RealtimeClient;
51
- public readonly database: DatabaseFacade;
52
-
53
- private config: gen.Configuration;
54
-
55
- constructor(options: SDKOptions = {}) {
56
- const serverUrl = options.serverUrl || options.serverURL || 'https://api.aerostack.dev/v1';
57
- const apiKey = options.apiKey || options.apiKeyAuth;
58
-
59
- this.config = new gen.Configuration({
60
- basePath: serverUrl,
61
- headers: apiKey ? { 'X-Aerostack-Key': apiKey } : {},
62
- apiKey: apiKey,
63
- });
64
-
65
- this.auth = new gen.AuthenticationApi(this.config);
66
- this.ai = new gen.AIApi(this.config);
67
- this.storage = new gen.StorageApi(this.config);
68
- this.database = new DatabaseFacade(new gen.DatabaseApi(this.config));
69
-
70
- this.realtime = new RealtimeClient({
71
- baseUrl: serverUrl,
72
- apiKey: apiKey,
73
- projectId: options.projectId || '',
74
- maxReconnectAttempts: options.maxReconnectAttempts
75
- });
76
- }
77
-
78
- /**
79
- * Stream a gateway chat completion with token-by-token callbacks.
80
- *
81
- * @example
82
- * await sdk.streamGateway({
83
- * apiSlug: 'my-chatbot',
84
- * messages: [{ role: 'user', content: 'Hello' }],
85
- * consumerKey: 'ask_live_...',
86
- * onToken: (delta) => process.stdout.write(delta),
87
- * });
88
- */
89
- async streamGateway(opts: {
90
- apiSlug: string;
91
- messages: Array<{ role: 'user' | 'assistant' | 'system'; content: string }>;
92
- consumerKey?: string;
93
- token?: string;
94
- systemPrompt?: string;
95
- onToken?: (delta: string) => void;
96
- onDone?: (usage: { tokensUsed: number }) => void;
97
- onError?: (error: Error) => void;
98
- signal?: AbortSignal;
99
- }): Promise<{ text: string; tokensUsed: number }> {
100
- const baseUrl = this.config.basePath.replace(/\/v1\/?$/, '');
101
- const endpoint = `${baseUrl}/api/gateway/${opts.apiSlug}/v1/chat/completions`;
102
-
103
- const headers: Record<string, string> = { 'Content-Type': 'application/json' };
104
- if (opts.consumerKey) {
105
- headers['Authorization'] = `Bearer ${opts.consumerKey}`;
106
- } else if (opts.token) {
107
- headers['Authorization'] = `Bearer ${opts.token}`;
108
- }
109
-
110
- const messages = opts.systemPrompt
111
- ? [{ role: 'system' as const, content: opts.systemPrompt }, ...opts.messages]
112
- : opts.messages;
113
-
114
- let text = '';
115
- let totalTokens = 0;
116
- let estimatedTokens = 0;
117
-
118
- try {
119
- const response = await fetch(endpoint, {
120
- method: 'POST',
121
- headers,
122
- body: JSON.stringify({ messages, stream: true, stream_options: { include_usage: true } }),
123
- signal: opts.signal,
124
- });
125
-
126
- if (!response.ok) {
127
- const err = await response.json().catch(() => ({ error: 'Request failed' }));
128
- throw new Error((err as any).error || `HTTP ${response.status}`);
129
- }
130
- if (!response.body) throw new Error('No response body');
131
-
132
- const reader = response.body.getReader();
133
- const decoder = new TextDecoder();
134
- let buffer = '';
135
-
136
- while (true) {
137
- const { done, value } = await reader.read();
138
- if (done) break;
139
- buffer += decoder.decode(value, { stream: true });
140
- const lines = buffer.split('\n');
141
- buffer = lines.pop() || '';
142
-
143
- for (const line of lines) {
144
- if (!line.startsWith('data: ')) continue;
145
- const payload = line.slice(6).trim();
146
- if (payload === '[DONE]') {
147
- reader.cancel();
148
- const result = { text, tokensUsed: totalTokens || estimatedTokens };
149
- opts.onDone?.(result);
150
- return result;
151
- }
152
- try {
153
- const parsed = JSON.parse(payload);
154
- const delta = parsed.choices?.[0]?.delta?.content;
155
- if (delta) {
156
- text += delta;
157
- opts.onToken?.(delta);
158
- estimatedTokens += Math.ceil(delta.length / 4);
159
- }
160
- if (parsed.usage?.total_tokens) totalTokens = parsed.usage.total_tokens;
161
- else if (parsed.usage?.completion_tokens) totalTokens = parsed.usage.completion_tokens;
162
- } catch { /* skip malformed frames */ }
163
- }
164
- }
165
-
166
- const result = { text, tokensUsed: totalTokens || estimatedTokens };
167
- opts.onDone?.(result);
168
- return result;
169
- } catch (err: any) {
170
- if (err.name === 'AbortError') return { text, tokensUsed: totalTokens || estimatedTokens };
171
- const error = err instanceof Error ? err : new Error(String(err));
172
- opts.onError?.(error);
173
- throw error;
174
- }
175
- }
176
-
177
- /**
178
- * Update the API key for subsequent requests.
179
- */
180
- setApiKey(apiKey: string): void {
181
- this.config = new gen.Configuration({
182
- ...this.config,
183
- headers: { ...this.config.headers, 'X-Aerostack-Key': apiKey },
184
- apiKey,
185
- });
186
- (this as any).auth = new gen.AuthenticationApi(this.config);
187
- (this as any).ai = new gen.AIApi(this.config);
188
- (this as any).storage = new gen.StorageApi(this.config);
189
- (this as any).database = new DatabaseFacade(new gen.DatabaseApi(this.config));
190
- }
191
- }
192
-
193
- /** @deprecated Use SDK instead */
194
- export const Aerostack = SDK;
195
-
196
- // Export a default instance factory or just the class
197
- export const createClient = (options: SDKOptions) => new SDK(options);
package/tsconfig.json DELETED
@@ -1,41 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "incremental": false,
4
- "target": "ES2020",
5
- "lib": [
6
- "ES2022",
7
- "DOM",
8
- "DOM.Iterable"
9
- ],
10
- "jsx": "react-jsx",
11
- "module": "Node16",
12
- "moduleResolution": "Node16",
13
- "allowJs": true,
14
- "declaration": true,
15
- "declarationMap": true,
16
- "sourceMap": true,
17
- "outDir": ".",
18
- // https://github.com/tsconfig/bases/blob/a1bf7c0fa2e094b068ca3e1448ca2ece4157977e/bases/strictest.json
19
- "strict": true,
20
- "allowUnusedLabels": false,
21
- "allowUnreachableCode": false,
22
- "noImplicitOverride": false,
23
- "noImplicitReturns": true,
24
- "noPropertyAccessFromIndexSignature": true,
25
- "noUncheckedIndexedAccess": true,
26
- "noUnusedLocals": false,
27
- "noUnusedParameters": false,
28
- "exactOptionalPropertyTypes": false,
29
- "isolatedModules": true,
30
- "checkJs": true,
31
- "esModuleInterop": true,
32
- "skipLibCheck": true,
33
- "forceConsistentCasingInFileNames": true
34
- },
35
- "include": [
36
- "src"
37
- ],
38
- "exclude": [
39
- "node_modules"
40
- ]
41
- }