@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.
- package/package.json +10 -3
- package/FUNCTIONS.md +0 -95
- package/RUNTIMES.md +0 -48
- package/examples/aiAIChat.example.ts +0 -31
- package/examples/databaseDbQuery.example.ts +0 -34
- package/examples/e2e/__tests__/e2e.test.ts +0 -69
- package/examples/e2e/package.json +0 -15
- package/examples/e2e/vitest.config.ts +0 -8
- package/examples/package.json +0 -18
- package/jsr.json +0 -27
- package/src/__tests__/realtime.test.ts +0 -388
- package/src/__tests__/sdk.test.ts +0 -181
- package/src/_generated/apis/AIApi.ts +0 -477
- package/src/_generated/apis/AuthenticationApi.ts +0 -121
- package/src/_generated/apis/CacheApi.ts +0 -551
- package/src/_generated/apis/DatabaseApi.ts +0 -138
- package/src/_generated/apis/GatewayApi.ts +0 -204
- package/src/_generated/apis/QueueApi.ts +0 -218
- package/src/_generated/apis/ServicesApi.ts +0 -74
- package/src/_generated/apis/StorageApi.ts +0 -476
- package/src/_generated/apis/index.ts +0 -10
- package/src/_generated/index.ts +0 -5
- package/src/_generated/models/AuthResponse.ts +0 -88
- package/src/_generated/models/AuthSigninRequest.ts +0 -75
- package/src/_generated/models/AuthSignupRequest.ts +0 -91
- package/src/_generated/models/CacheDeleteMany200Response.ts +0 -81
- package/src/_generated/models/CacheDeleteManyRequest.ts +0 -66
- package/src/_generated/models/CacheExpireRequest.ts +0 -75
- package/src/_generated/models/CacheFlush200Response.ts +0 -73
- package/src/_generated/models/CacheFlushRequest.ts +0 -65
- package/src/_generated/models/CacheGet200Response.ts +0 -73
- package/src/_generated/models/CacheGetMany200Response.ts +0 -72
- package/src/_generated/models/CacheGetManyEntry.ts +0 -81
- package/src/_generated/models/CacheGetManyRequest.ts +0 -66
- package/src/_generated/models/CacheGetRequest.ts +0 -66
- package/src/_generated/models/CacheIncrement200Response.ts +0 -65
- package/src/_generated/models/CacheIncrementRequest.ts +0 -90
- package/src/_generated/models/CacheKeyEntry.ts +0 -73
- package/src/_generated/models/CacheKeys200Response.ts +0 -73
- package/src/_generated/models/CacheKeysRequest.ts +0 -65
- package/src/_generated/models/CacheListRequest.ts +0 -81
- package/src/_generated/models/CacheListResult.ts +0 -88
- package/src/_generated/models/CacheSet200Response.ts +0 -65
- package/src/_generated/models/CacheSetEntry.ts +0 -83
- package/src/_generated/models/CacheSetMany200Response.ts +0 -73
- package/src/_generated/models/CacheSetManyRequest.ts +0 -73
- package/src/_generated/models/CacheSetRequest.ts +0 -83
- package/src/_generated/models/ChatCompletionRequest.ts +0 -130
- package/src/_generated/models/ChatCompletionRequestStreamOptions.ts +0 -67
- package/src/_generated/models/ChatCompletionResponse.ts +0 -128
- package/src/_generated/models/ChatCompletionResponseChoicesInner.ts +0 -100
- package/src/_generated/models/ChatMessage.ts +0 -87
- package/src/_generated/models/ConfigureRequest.ts +0 -77
- package/src/_generated/models/DbBatchRequest.ts +0 -73
- package/src/_generated/models/DbBatchRequestQueriesInner.ts +0 -74
- package/src/_generated/models/DbBatchResult.ts +0 -80
- package/src/_generated/models/DbBatchResultResultsInner.ts +0 -81
- package/src/_generated/models/DbQueryRequest.ts +0 -74
- package/src/_generated/models/DbQueryResult.ts +0 -73
- package/src/_generated/models/DeleteByTypeRequest.ts +0 -66
- package/src/_generated/models/DeleteRequest.ts +0 -66
- package/src/_generated/models/ErrorResponse.ts +0 -99
- package/src/_generated/models/GatewayBillingLog200Response.ts +0 -73
- package/src/_generated/models/GatewayBillingLogRequest.ts +0 -92
- package/src/_generated/models/GatewayGetWallet200Response.ts +0 -72
- package/src/_generated/models/IngestRequest.ts +0 -91
- package/src/_generated/models/JobRecord.ts +0 -119
- package/src/_generated/models/ListTypes200Response.ts +0 -72
- package/src/_generated/models/Query200Response.ts +0 -72
- package/src/_generated/models/QueryRequest.ts +0 -90
- package/src/_generated/models/QueueCancelJob200Response.ts +0 -73
- package/src/_generated/models/QueueEnqueue201Response.ts +0 -73
- package/src/_generated/models/QueueEnqueueRequest.ts +0 -83
- package/src/_generated/models/QueueGetJob200Response.ts +0 -80
- package/src/_generated/models/QueueGetJobRequest.ts +0 -66
- package/src/_generated/models/QueueListJobs200Response.ts +0 -88
- package/src/_generated/models/QueueListJobsRequest.ts +0 -103
- package/src/_generated/models/SearchCount200Response.ts +0 -65
- package/src/_generated/models/SearchCountRequest.ts +0 -65
- package/src/_generated/models/SearchGet200Response.ts +0 -80
- package/src/_generated/models/SearchGetRequest.ts +0 -66
- package/src/_generated/models/SearchResult.ts +0 -97
- package/src/_generated/models/SearchUpdateRequest.ts +0 -91
- package/src/_generated/models/ServicesInvoke200Response.ts +0 -73
- package/src/_generated/models/ServicesInvokeRequest.ts +0 -75
- package/src/_generated/models/StorageCopy200Response.ts +0 -73
- package/src/_generated/models/StorageCopyRequest.ts +0 -75
- package/src/_generated/models/StorageExists200Response.ts +0 -65
- package/src/_generated/models/StorageGetRequest.ts +0 -66
- package/src/_generated/models/StorageListRequest.ts +0 -81
- package/src/_generated/models/StorageListResult.ts +0 -88
- package/src/_generated/models/StorageMetadata.ts +0 -97
- package/src/_generated/models/StorageMove200Response.ts +0 -73
- package/src/_generated/models/StorageMoveRequest.ts +0 -75
- package/src/_generated/models/StorageObject.ts +0 -97
- package/src/_generated/models/StorageUpload200Response.ts +0 -65
- package/src/_generated/models/TokenUsage.ts +0 -81
- package/src/_generated/models/TokenWallet.ts +0 -73
- package/src/_generated/models/TypeStats.ts +0 -73
- package/src/_generated/models/User.ts +0 -97
- package/src/_generated/models/index.ts +0 -80
- package/src/_generated/runtime.ts +0 -431
- package/src/index.ts +0 -3
- package/src/realtime.ts +0 -456
- package/src/sdk.ts +0 -197
- package/tsconfig.json +0 -41
|
@@ -1,388 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
-
import { RealtimeClient, RealtimeSubscription } from '../realtime.js';
|
|
3
|
-
|
|
4
|
-
// ─── Mock WebSocket ───────────────────────────────────────────
|
|
5
|
-
|
|
6
|
-
class MockWebSocket {
|
|
7
|
-
static OPEN = 1;
|
|
8
|
-
static CLOSED = 3;
|
|
9
|
-
|
|
10
|
-
url: string;
|
|
11
|
-
protocols?: string[];
|
|
12
|
-
readyState = MockWebSocket.OPEN;
|
|
13
|
-
onopen: (() => void) | null = null;
|
|
14
|
-
onmessage: ((event: { data: string }) => void) | null = null;
|
|
15
|
-
onclose: (() => void) | null = null;
|
|
16
|
-
onerror: ((err: any) => void) | null = null;
|
|
17
|
-
sent: any[] = [];
|
|
18
|
-
|
|
19
|
-
constructor(url: string, protocols?: string[]) {
|
|
20
|
-
this.url = url;
|
|
21
|
-
this.protocols = protocols;
|
|
22
|
-
setTimeout(() => this.onopen?.(), 0);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
send(data: string) {
|
|
26
|
-
this.sent.push(JSON.parse(data));
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
close() {
|
|
30
|
-
this.readyState = MockWebSocket.CLOSED;
|
|
31
|
-
setTimeout(() => this.onclose?.(), 0);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
beforeEach(() => {
|
|
36
|
-
vi.stubGlobal('WebSocket', MockWebSocket);
|
|
37
|
-
vi.stubGlobal('fetch', vi.fn());
|
|
38
|
-
vi.useFakeTimers();
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
afterEach(() => {
|
|
42
|
-
vi.restoreAllMocks();
|
|
43
|
-
vi.useRealTimers();
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
// ─── RealtimeSubscription ─────────────────────────────────────
|
|
47
|
-
|
|
48
|
-
describe('RealtimeSubscription', () => {
|
|
49
|
-
function createSub() {
|
|
50
|
-
const client = new RealtimeClient({
|
|
51
|
-
baseUrl: 'https://api.test.com/v1',
|
|
52
|
-
projectId: 'proj-1',
|
|
53
|
-
});
|
|
54
|
-
const sub = client.channel('users');
|
|
55
|
-
return { client, sub };
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
it('should register and fire INSERT callbacks', () => {
|
|
59
|
-
const { sub } = createSub();
|
|
60
|
-
const cb = vi.fn();
|
|
61
|
-
sub.on('INSERT', cb);
|
|
62
|
-
|
|
63
|
-
sub._emit({
|
|
64
|
-
type: 'db_change',
|
|
65
|
-
topic: sub.topic,
|
|
66
|
-
operation: 'INSERT',
|
|
67
|
-
data: { id: 1 },
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
expect(cb).toHaveBeenCalledOnce();
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
it('should fire wildcard callbacks', () => {
|
|
74
|
-
const { sub } = createSub();
|
|
75
|
-
const cb = vi.fn();
|
|
76
|
-
sub.on('*', cb);
|
|
77
|
-
|
|
78
|
-
sub._emit({
|
|
79
|
-
type: 'event',
|
|
80
|
-
topic: sub.topic,
|
|
81
|
-
event: 'custom',
|
|
82
|
-
data: {},
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
expect(cb).toHaveBeenCalledOnce();
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
it('should remove callbacks with off()', () => {
|
|
89
|
-
const { sub } = createSub();
|
|
90
|
-
const cb = vi.fn();
|
|
91
|
-
sub.on('INSERT', cb);
|
|
92
|
-
sub.off('INSERT', cb);
|
|
93
|
-
|
|
94
|
-
sub._emit({
|
|
95
|
-
type: 'db_change',
|
|
96
|
-
topic: sub.topic,
|
|
97
|
-
operation: 'INSERT',
|
|
98
|
-
data: {},
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
expect(cb).not.toHaveBeenCalled();
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
it('should be chainable', () => {
|
|
105
|
-
const { sub } = createSub();
|
|
106
|
-
expect(sub.on('INSERT', vi.fn())).toBe(sub);
|
|
107
|
-
expect(sub.off('INSERT', vi.fn())).toBe(sub);
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
it('should clear callbacks on unsubscribe', () => {
|
|
111
|
-
const { sub } = createSub();
|
|
112
|
-
const cb = vi.fn();
|
|
113
|
-
sub.on('INSERT', cb);
|
|
114
|
-
sub.subscribe();
|
|
115
|
-
sub.unsubscribe();
|
|
116
|
-
|
|
117
|
-
sub._emit({
|
|
118
|
-
type: 'db_change',
|
|
119
|
-
topic: sub.topic,
|
|
120
|
-
operation: 'INSERT',
|
|
121
|
-
data: {},
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
expect(cb).not.toHaveBeenCalled();
|
|
125
|
-
});
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
// ─── RealtimeClient ───────────────────────────────────────────
|
|
129
|
-
|
|
130
|
-
describe('RealtimeClient', () => {
|
|
131
|
-
describe('constructor', () => {
|
|
132
|
-
it('should start as idle', () => {
|
|
133
|
-
const client = new RealtimeClient({
|
|
134
|
-
baseUrl: 'https://api.test.com/v1',
|
|
135
|
-
projectId: 'proj-1',
|
|
136
|
-
});
|
|
137
|
-
expect(client.status).toBe('idle');
|
|
138
|
-
});
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
describe('connect', () => {
|
|
142
|
-
it('should connect successfully', async () => {
|
|
143
|
-
const client = new RealtimeClient({
|
|
144
|
-
baseUrl: 'https://api.test.com/v1',
|
|
145
|
-
projectId: 'proj-1',
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
const connectPromise = client.connect();
|
|
149
|
-
await vi.advanceTimersByTimeAsync(10);
|
|
150
|
-
await connectPromise;
|
|
151
|
-
|
|
152
|
-
expect(client.status).toBe('connected');
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
it('should pass apiKey via Sec-WebSocket-Protocol', async () => {
|
|
156
|
-
const client = new RealtimeClient({
|
|
157
|
-
baseUrl: 'https://api.test.com/v1',
|
|
158
|
-
projectId: 'proj-1',
|
|
159
|
-
apiKey: 'my-api-key',
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
const connectPromise = client.connect();
|
|
163
|
-
await vi.advanceTimersByTimeAsync(10);
|
|
164
|
-
await connectPromise;
|
|
165
|
-
|
|
166
|
-
expect(client.status).toBe('connected');
|
|
167
|
-
// apiKey should NOT be in URL query params (security)
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
it('should not duplicate connections', async () => {
|
|
171
|
-
const client = new RealtimeClient({
|
|
172
|
-
baseUrl: 'https://api.test.com/v1',
|
|
173
|
-
projectId: 'proj-1',
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
const p1 = client.connect();
|
|
177
|
-
const p2 = client.connect();
|
|
178
|
-
await vi.advanceTimersByTimeAsync(10);
|
|
179
|
-
await Promise.all([p1, p2]);
|
|
180
|
-
|
|
181
|
-
expect(client.status).toBe('connected');
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
it('should return immediately if already connected', async () => {
|
|
185
|
-
const client = new RealtimeClient({
|
|
186
|
-
baseUrl: 'https://api.test.com/v1',
|
|
187
|
-
projectId: 'proj-1',
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
const p1 = client.connect();
|
|
191
|
-
await vi.advanceTimersByTimeAsync(10);
|
|
192
|
-
await p1;
|
|
193
|
-
|
|
194
|
-
await client.connect(); // Should resolve immediately
|
|
195
|
-
expect(client.status).toBe('connected');
|
|
196
|
-
});
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
describe('disconnect', () => {
|
|
200
|
-
it('should set status to disconnected', async () => {
|
|
201
|
-
const client = new RealtimeClient({
|
|
202
|
-
baseUrl: 'https://api.test.com/v1',
|
|
203
|
-
projectId: 'proj-1',
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
const connectPromise = client.connect();
|
|
207
|
-
await vi.advanceTimersByTimeAsync(10);
|
|
208
|
-
await connectPromise;
|
|
209
|
-
|
|
210
|
-
client.disconnect();
|
|
211
|
-
expect(client.status).toBe('disconnected');
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
it('should be safe when not connected', () => {
|
|
215
|
-
const client = new RealtimeClient({
|
|
216
|
-
baseUrl: 'https://api.test.com/v1',
|
|
217
|
-
projectId: 'proj-1',
|
|
218
|
-
});
|
|
219
|
-
client.disconnect();
|
|
220
|
-
expect(client.status).toBe('disconnected');
|
|
221
|
-
});
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
describe('channel', () => {
|
|
225
|
-
it('should qualify topic with projectId', () => {
|
|
226
|
-
const client = new RealtimeClient({
|
|
227
|
-
baseUrl: 'https://api.test.com/v1',
|
|
228
|
-
projectId: 'proj-1',
|
|
229
|
-
});
|
|
230
|
-
const sub = client.channel('users');
|
|
231
|
-
expect(sub.topic).toBe('table/users/proj-1');
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
it('should reuse subscriptions', () => {
|
|
235
|
-
const client = new RealtimeClient({
|
|
236
|
-
baseUrl: 'https://api.test.com/v1',
|
|
237
|
-
projectId: 'proj-1',
|
|
238
|
-
});
|
|
239
|
-
const sub1 = client.channel('users');
|
|
240
|
-
const sub2 = client.channel('users');
|
|
241
|
-
expect(sub1).toBe(sub2);
|
|
242
|
-
});
|
|
243
|
-
|
|
244
|
-
it('should not double-qualify', () => {
|
|
245
|
-
const client = new RealtimeClient({
|
|
246
|
-
baseUrl: 'https://api.test.com/v1',
|
|
247
|
-
projectId: 'proj-1',
|
|
248
|
-
});
|
|
249
|
-
const sub = client.channel('table/users/proj-1');
|
|
250
|
-
expect(sub.topic).toBe('table/users/proj-1');
|
|
251
|
-
});
|
|
252
|
-
});
|
|
253
|
-
|
|
254
|
-
describe('status listeners', () => {
|
|
255
|
-
it('should notify on status change', async () => {
|
|
256
|
-
const client = new RealtimeClient({
|
|
257
|
-
baseUrl: 'https://api.test.com/v1',
|
|
258
|
-
projectId: 'proj-1',
|
|
259
|
-
});
|
|
260
|
-
const statuses: string[] = [];
|
|
261
|
-
client.onStatusChange((s: string) => statuses.push(s));
|
|
262
|
-
|
|
263
|
-
const connectPromise = client.connect();
|
|
264
|
-
await vi.advanceTimersByTimeAsync(10);
|
|
265
|
-
await connectPromise;
|
|
266
|
-
|
|
267
|
-
expect(statuses).toContain('connecting');
|
|
268
|
-
expect(statuses).toContain('connected');
|
|
269
|
-
});
|
|
270
|
-
|
|
271
|
-
it('should allow unsubscribing', () => {
|
|
272
|
-
const client = new RealtimeClient({
|
|
273
|
-
baseUrl: 'https://api.test.com/v1',
|
|
274
|
-
projectId: 'proj-1',
|
|
275
|
-
});
|
|
276
|
-
const cb = vi.fn();
|
|
277
|
-
const unsub = client.onStatusChange(cb);
|
|
278
|
-
unsub();
|
|
279
|
-
client.disconnect();
|
|
280
|
-
expect(cb).not.toHaveBeenCalled();
|
|
281
|
-
});
|
|
282
|
-
});
|
|
283
|
-
|
|
284
|
-
describe('setToken', () => {
|
|
285
|
-
it('should send auth message', async () => {
|
|
286
|
-
const client = new RealtimeClient({
|
|
287
|
-
baseUrl: 'https://api.test.com/v1',
|
|
288
|
-
projectId: 'proj-1',
|
|
289
|
-
});
|
|
290
|
-
|
|
291
|
-
const connectPromise = client.connect();
|
|
292
|
-
await vi.advanceTimersByTimeAsync(10);
|
|
293
|
-
await connectPromise;
|
|
294
|
-
|
|
295
|
-
client.setToken('new-jwt');
|
|
296
|
-
});
|
|
297
|
-
});
|
|
298
|
-
|
|
299
|
-
describe('sendChat + chatRoom', () => {
|
|
300
|
-
it('should queue chat message', () => {
|
|
301
|
-
const client = new RealtimeClient({
|
|
302
|
-
baseUrl: 'https://api.test.com/v1',
|
|
303
|
-
projectId: 'proj-1',
|
|
304
|
-
});
|
|
305
|
-
client.sendChat('room-1', 'Hello');
|
|
306
|
-
});
|
|
307
|
-
|
|
308
|
-
it('should return chat room subscription', () => {
|
|
309
|
-
const client = new RealtimeClient({
|
|
310
|
-
baseUrl: 'https://api.test.com/v1',
|
|
311
|
-
projectId: 'proj-1',
|
|
312
|
-
});
|
|
313
|
-
const sub = client.chatRoom('room-1');
|
|
314
|
-
expect(sub.topic).toBe('chat/room-1/proj-1');
|
|
315
|
-
});
|
|
316
|
-
});
|
|
317
|
-
|
|
318
|
-
describe('_generateId', () => {
|
|
319
|
-
it('should return unique IDs', () => {
|
|
320
|
-
const client = new RealtimeClient({
|
|
321
|
-
baseUrl: 'https://api.test.com/v1',
|
|
322
|
-
projectId: 'proj-1',
|
|
323
|
-
});
|
|
324
|
-
const ids = new Set(Array.from({ length: 50 }, () => client._generateId()));
|
|
325
|
-
expect(ids.size).toBe(50);
|
|
326
|
-
});
|
|
327
|
-
});
|
|
328
|
-
|
|
329
|
-
describe('_fetchHistory', () => {
|
|
330
|
-
it('should fetch history with auth headers', async () => {
|
|
331
|
-
const mockFetch = vi.fn().mockResolvedValue({
|
|
332
|
-
json: async () => ({ messages: [{ id: '1' }] }),
|
|
333
|
-
});
|
|
334
|
-
vi.stubGlobal('fetch', mockFetch);
|
|
335
|
-
|
|
336
|
-
const client = new RealtimeClient({
|
|
337
|
-
baseUrl: 'https://api.test.com/v1',
|
|
338
|
-
projectId: 'proj-1',
|
|
339
|
-
apiKey: 'my-key',
|
|
340
|
-
token: 'my-jwt',
|
|
341
|
-
});
|
|
342
|
-
|
|
343
|
-
const result = await client._fetchHistory('chat/room', 10);
|
|
344
|
-
expect(result).toEqual([{ id: '1' }]);
|
|
345
|
-
|
|
346
|
-
const headers = mockFetch.mock.calls[0][1].headers;
|
|
347
|
-
expect(headers['X-Aerostack-Key']).toBe('my-key');
|
|
348
|
-
expect(headers['Authorization']).toBe('Bearer my-jwt');
|
|
349
|
-
});
|
|
350
|
-
|
|
351
|
-
it('should return empty array when no messages', async () => {
|
|
352
|
-
vi.stubGlobal('fetch', vi.fn().mockResolvedValue({
|
|
353
|
-
json: async () => ({}),
|
|
354
|
-
}));
|
|
355
|
-
|
|
356
|
-
const client = new RealtimeClient({
|
|
357
|
-
baseUrl: 'https://api.test.com/v1',
|
|
358
|
-
projectId: 'proj-1',
|
|
359
|
-
});
|
|
360
|
-
|
|
361
|
-
const result = await client._fetchHistory('room', 10);
|
|
362
|
-
expect(result).toEqual([]);
|
|
363
|
-
});
|
|
364
|
-
});
|
|
365
|
-
|
|
366
|
-
describe('maxReconnectAttempts', () => {
|
|
367
|
-
it('should accept maxReconnectAttempts', () => {
|
|
368
|
-
const client = new RealtimeClient({
|
|
369
|
-
baseUrl: 'https://api.test.com/v1',
|
|
370
|
-
projectId: 'proj-1',
|
|
371
|
-
maxReconnectAttempts: 5,
|
|
372
|
-
});
|
|
373
|
-
expect(client.status).toBe('idle');
|
|
374
|
-
});
|
|
375
|
-
|
|
376
|
-
it('should support onMaxRetriesExceeded', () => {
|
|
377
|
-
const client = new RealtimeClient({
|
|
378
|
-
baseUrl: 'https://api.test.com/v1',
|
|
379
|
-
projectId: 'proj-1',
|
|
380
|
-
maxReconnectAttempts: 0,
|
|
381
|
-
});
|
|
382
|
-
const cb = vi.fn();
|
|
383
|
-
const unsub = client.onMaxRetriesExceeded(cb);
|
|
384
|
-
expect(typeof unsub).toBe('function');
|
|
385
|
-
unsub();
|
|
386
|
-
});
|
|
387
|
-
});
|
|
388
|
-
});
|
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
-
|
|
3
|
-
// Mock the generated APIs and realtime
|
|
4
|
-
vi.mock('../_generated/index.js', () => {
|
|
5
|
-
class MockConfiguration {
|
|
6
|
-
basePath: string;
|
|
7
|
-
headers: Record<string, string>;
|
|
8
|
-
apiKey?: string;
|
|
9
|
-
constructor(opts: any = {}) {
|
|
10
|
-
this.basePath = opts.basePath || '';
|
|
11
|
-
this.headers = opts.headers || {};
|
|
12
|
-
this.apiKey = opts.apiKey;
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
return {
|
|
16
|
-
Configuration: MockConfiguration,
|
|
17
|
-
AuthenticationApi: vi.fn().mockImplementation(() => ({ auth: true })),
|
|
18
|
-
AIApi: vi.fn().mockImplementation(() => ({ ai: true })),
|
|
19
|
-
StorageApi: vi.fn().mockImplementation(() => ({ storage: true })),
|
|
20
|
-
DatabaseApi: vi.fn().mockImplementation(() => ({
|
|
21
|
-
dbQuery: vi.fn().mockResolvedValue({ results: [] }),
|
|
22
|
-
})),
|
|
23
|
-
};
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
vi.mock('../realtime.js', () => {
|
|
27
|
-
return {
|
|
28
|
-
RealtimeClient: vi.fn().mockImplementation(() => ({
|
|
29
|
-
connect: vi.fn(),
|
|
30
|
-
disconnect: vi.fn(),
|
|
31
|
-
channel: vi.fn(),
|
|
32
|
-
})),
|
|
33
|
-
};
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
import { SDK, Aerostack, createClient } from '../sdk.js';
|
|
37
|
-
|
|
38
|
-
describe('Web SDK', () => {
|
|
39
|
-
describe('constructor', () => {
|
|
40
|
-
it('should initialize with default options', () => {
|
|
41
|
-
const sdk = new SDK();
|
|
42
|
-
expect(sdk).toBeDefined();
|
|
43
|
-
expect(sdk.auth).toBeDefined();
|
|
44
|
-
expect(sdk.ai).toBeDefined();
|
|
45
|
-
expect(sdk.storage).toBeDefined();
|
|
46
|
-
expect(sdk.database).toBeDefined();
|
|
47
|
-
expect(sdk.realtime).toBeDefined();
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it('should accept apiKey option', () => {
|
|
51
|
-
const sdk = new SDK({ apiKey: 'my-key' });
|
|
52
|
-
expect(sdk).toBeDefined();
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it('should accept apiKeyAuth alias', () => {
|
|
56
|
-
const sdk = new SDK({ apiKeyAuth: 'my-key' });
|
|
57
|
-
expect(sdk).toBeDefined();
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
it('should accept serverUrl option', () => {
|
|
61
|
-
const sdk = new SDK({ serverUrl: 'https://custom.com/v1' });
|
|
62
|
-
expect(sdk).toBeDefined();
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it('should accept serverURL alias', () => {
|
|
66
|
-
const sdk = new SDK({ serverURL: 'https://custom.com/v1' });
|
|
67
|
-
expect(sdk).toBeDefined();
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
it('should not expose queue, services, gateway, cache (client-safe)', () => {
|
|
71
|
-
const sdk = new SDK() as any;
|
|
72
|
-
expect(sdk.queue).toBeUndefined();
|
|
73
|
-
expect(sdk.services).toBeUndefined();
|
|
74
|
-
expect(sdk.gateway).toBeUndefined();
|
|
75
|
-
expect(sdk.cache).toBeUndefined();
|
|
76
|
-
});
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
describe('DatabaseFacade', () => {
|
|
80
|
-
it('should execute a query', async () => {
|
|
81
|
-
const sdk = new SDK({ apiKey: 'key' });
|
|
82
|
-
const result = await sdk.database.dbQuery({
|
|
83
|
-
dbQueryRequest: { sql: 'SELECT 1', params: [] },
|
|
84
|
-
});
|
|
85
|
-
expect(result).toEqual({ results: [] });
|
|
86
|
-
});
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
describe('setApiKey', () => {
|
|
90
|
-
it('should recreate service instances', () => {
|
|
91
|
-
const sdk = new SDK({ apiKey: 'old-key' });
|
|
92
|
-
sdk.setApiKey('new-key');
|
|
93
|
-
expect(sdk.auth).toBeDefined();
|
|
94
|
-
expect(sdk.ai).toBeDefined();
|
|
95
|
-
expect(sdk.storage).toBeDefined();
|
|
96
|
-
expect(sdk.database).toBeDefined();
|
|
97
|
-
});
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
describe('streamGateway', () => {
|
|
101
|
-
it('should make POST to gateway endpoint', async () => {
|
|
102
|
-
const mockFetch = vi.fn().mockResolvedValue({
|
|
103
|
-
ok: true,
|
|
104
|
-
body: createMockStream('data: {"choices":[{"delta":{"content":"Hi"}}]}\n\ndata: [DONE]\n\n'),
|
|
105
|
-
});
|
|
106
|
-
vi.stubGlobal('fetch', mockFetch);
|
|
107
|
-
|
|
108
|
-
const sdk = new SDK({ serverUrl: 'https://api.test.com/v1' });
|
|
109
|
-
const result = await sdk.streamGateway({
|
|
110
|
-
apiSlug: 'bot',
|
|
111
|
-
messages: [{ role: 'user', content: 'Hello' }],
|
|
112
|
-
consumerKey: 'ask_live_123',
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
expect(result.text).toBe('Hi');
|
|
116
|
-
expect(mockFetch.mock.calls[0][0]).toBe('https://api.test.com/api/gateway/bot/v1/chat/completions');
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
it('should throw on non-OK response', async () => {
|
|
120
|
-
const mockFetch = vi.fn().mockResolvedValue({
|
|
121
|
-
ok: false,
|
|
122
|
-
status: 401,
|
|
123
|
-
json: vi.fn().mockResolvedValue({ error: 'Unauthorized' }),
|
|
124
|
-
});
|
|
125
|
-
vi.stubGlobal('fetch', mockFetch);
|
|
126
|
-
|
|
127
|
-
const sdk = new SDK({ serverUrl: 'https://api.test.com/v1' });
|
|
128
|
-
await expect(sdk.streamGateway({
|
|
129
|
-
apiSlug: 'bot',
|
|
130
|
-
messages: [{ role: 'user', content: 'Hi' }],
|
|
131
|
-
})).rejects.toThrow('Unauthorized');
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
it('should estimate tokens when usage not provided', async () => {
|
|
135
|
-
const mockFetch = vi.fn().mockResolvedValue({
|
|
136
|
-
ok: true,
|
|
137
|
-
body: createMockStream('data: {"choices":[{"delta":{"content":"Hello world"}}]}\n\ndata: [DONE]\n\n'),
|
|
138
|
-
});
|
|
139
|
-
vi.stubGlobal('fetch', mockFetch);
|
|
140
|
-
|
|
141
|
-
const sdk = new SDK({ serverUrl: 'https://api.test.com/v1' });
|
|
142
|
-
const result = await sdk.streamGateway({
|
|
143
|
-
apiSlug: 'bot',
|
|
144
|
-
messages: [{ role: 'user', content: 'Hi' }],
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
expect(result.tokensUsed).toBeGreaterThan(0);
|
|
148
|
-
});
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
describe('Aerostack alias', () => {
|
|
152
|
-
it('should be the same as SDK', () => {
|
|
153
|
-
expect(Aerostack).toBe(SDK);
|
|
154
|
-
});
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
describe('createClient', () => {
|
|
158
|
-
it('should return an SDK instance', () => {
|
|
159
|
-
const client = createClient({ apiKey: 'key' });
|
|
160
|
-
expect(client).toBeInstanceOf(SDK);
|
|
161
|
-
});
|
|
162
|
-
});
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
function createMockStream(text: string) {
|
|
166
|
-
const encoder = new TextEncoder();
|
|
167
|
-
const data = encoder.encode(text);
|
|
168
|
-
let read = false;
|
|
169
|
-
return {
|
|
170
|
-
getReader: () => ({
|
|
171
|
-
read: async () => {
|
|
172
|
-
if (!read) {
|
|
173
|
-
read = true;
|
|
174
|
-
return { done: false, value: data };
|
|
175
|
-
}
|
|
176
|
-
return { done: true, value: undefined };
|
|
177
|
-
},
|
|
178
|
-
cancel: vi.fn(),
|
|
179
|
-
}),
|
|
180
|
-
};
|
|
181
|
-
}
|