@inferencesh/sdk 0.6.14 → 0.6.19

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 (89) hide show
  1. package/README.md +1 -1
  2. package/dist/agent/actions.js +10 -0
  3. package/dist/agent/provider.d.ts +2 -1
  4. package/dist/agent/provider.js +5 -5
  5. package/dist/agent/types.d.ts +3 -0
  6. package/dist/api/apps.d.ts +4 -0
  7. package/dist/api/apps.js +6 -0
  8. package/dist/api/index.d.ts +3 -3
  9. package/dist/http/index.d.ts +3 -3
  10. package/dist/index.d.ts +9 -9
  11. package/dist/types.d.ts +131 -19
  12. package/dist/types.js +26 -9
  13. package/package.json +8 -5
  14. package/dist/agent/actions.test.d.ts +0 -1
  15. package/dist/agent/actions.test.js +0 -820
  16. package/dist/agent/api.test.d.ts +0 -1
  17. package/dist/agent/api.test.js +0 -246
  18. package/dist/agent/reducer.test.d.ts +0 -1
  19. package/dist/agent/reducer.test.js +0 -131
  20. package/dist/agent/types.test.d.ts +0 -1
  21. package/dist/agent/types.test.js +0 -75
  22. package/dist/api/agents.test.d.ts +0 -1
  23. package/dist/api/agents.test.js +0 -1014
  24. package/dist/api/api-keys.test.d.ts +0 -1
  25. package/dist/api/api-keys.test.js +0 -44
  26. package/dist/api/apps.test.d.ts +0 -1
  27. package/dist/api/apps.test.js +0 -135
  28. package/dist/api/chats.test.d.ts +0 -1
  29. package/dist/api/chats.test.js +0 -85
  30. package/dist/api/engines.test.d.ts +0 -1
  31. package/dist/api/engines.test.js +0 -133
  32. package/dist/api/files.test.d.ts +0 -1
  33. package/dist/api/files.test.js +0 -256
  34. package/dist/api/flow-runs.test.d.ts +0 -1
  35. package/dist/api/flow-runs.test.js +0 -97
  36. package/dist/api/flows.test.d.ts +0 -1
  37. package/dist/api/flows.test.js +0 -118
  38. package/dist/api/integrations.test.d.ts +0 -1
  39. package/dist/api/integrations.test.js +0 -109
  40. package/dist/api/knowledge.test.d.ts +0 -1
  41. package/dist/api/knowledge.test.js +0 -238
  42. package/dist/api/mcp-servers.test.d.ts +0 -1
  43. package/dist/api/mcp-servers.test.js +0 -98
  44. package/dist/api/projects.test.d.ts +0 -1
  45. package/dist/api/projects.test.js +0 -61
  46. package/dist/api/search.test.d.ts +0 -1
  47. package/dist/api/search.test.js +0 -50
  48. package/dist/api/secrets.test.d.ts +0 -1
  49. package/dist/api/secrets.test.js +0 -61
  50. package/dist/api/sessions.test.d.ts +0 -1
  51. package/dist/api/sessions.test.js +0 -61
  52. package/dist/api/tasks.test.d.ts +0 -1
  53. package/dist/api/tasks.test.js +0 -381
  54. package/dist/api/teams.test.d.ts +0 -1
  55. package/dist/api/teams.test.js +0 -139
  56. package/dist/client.test.d.ts +0 -1
  57. package/dist/client.test.js +0 -446
  58. package/dist/http/client.test.d.ts +0 -1
  59. package/dist/http/client.test.js +0 -435
  60. package/dist/http/errors.test.d.ts +0 -1
  61. package/dist/http/errors.test.js +0 -66
  62. package/dist/http/poll.test.d.ts +0 -1
  63. package/dist/http/poll.test.js +0 -146
  64. package/dist/http/streamable.test.d.ts +0 -4
  65. package/dist/http/streamable.test.js +0 -510
  66. package/dist/integration.test.d.ts +0 -9
  67. package/dist/integration.test.js +0 -107
  68. package/dist/proxy/express.test.d.ts +0 -1
  69. package/dist/proxy/express.test.js +0 -106
  70. package/dist/proxy/hono.test.d.ts +0 -1
  71. package/dist/proxy/hono.test.js +0 -90
  72. package/dist/proxy/index.test.d.ts +0 -1
  73. package/dist/proxy/index.test.js +0 -173
  74. package/dist/proxy/nextjs.test.d.ts +0 -1
  75. package/dist/proxy/nextjs.test.js +0 -125
  76. package/dist/proxy/remix.test.d.ts +0 -1
  77. package/dist/proxy/remix.test.js +0 -66
  78. package/dist/proxy/svelte.test.d.ts +0 -1
  79. package/dist/proxy/svelte.test.js +0 -69
  80. package/dist/sessions.integration.test.d.ts +0 -13
  81. package/dist/sessions.integration.test.js +0 -310
  82. package/dist/stream.test.d.ts +0 -1
  83. package/dist/stream.test.js +0 -363
  84. package/dist/streamable.integration.test.d.ts +0 -11
  85. package/dist/streamable.integration.test.js +0 -150
  86. package/dist/tool-builder.test.d.ts +0 -1
  87. package/dist/tool-builder.test.js +0 -407
  88. package/dist/utils.test.d.ts +0 -1
  89. package/dist/utils.test.js +0 -43
@@ -1,510 +0,0 @@
1
- /**
2
- * Unit tests for streamable HTTP client
3
- */
4
- import { streamable, streamableRaw, StreamableManager } from './streamable';
5
- // Mock fetch for unit tests
6
- const mockFetch = (chunks) => {
7
- let chunkIndex = 0;
8
- const mockReader = {
9
- read: jest.fn().mockImplementation(async () => {
10
- if (chunkIndex >= chunks.length) {
11
- return { done: true, value: undefined };
12
- }
13
- const chunk = chunks[chunkIndex++];
14
- return { done: false, value: new TextEncoder().encode(chunk) };
15
- }),
16
- releaseLock: jest.fn(),
17
- };
18
- return jest.fn().mockResolvedValue({
19
- ok: true,
20
- status: 200,
21
- body: {
22
- getReader: () => mockReader,
23
- },
24
- });
25
- };
26
- describe('streamable', () => {
27
- const originalFetch = global.fetch;
28
- afterEach(() => {
29
- global.fetch = originalFetch;
30
- });
31
- it('should parse NDJSON lines', async () => {
32
- global.fetch = mockFetch([
33
- '{"id":1,"name":"first"}\n',
34
- '{"id":2,"name":"second"}\n',
35
- ]);
36
- const results = [];
37
- for await (const item of streamable('http://test.com/stream')) {
38
- results.push(item);
39
- }
40
- expect(results).toHaveLength(2);
41
- expect(results[0]).toEqual({ id: 1, name: 'first' });
42
- expect(results[1]).toEqual({ id: 2, name: 'second' });
43
- });
44
- it('should skip heartbeats by default', async () => {
45
- global.fetch = mockFetch([
46
- '{"id":1}\n',
47
- '{"type":"heartbeat"}\n',
48
- '{"id":2}\n',
49
- ]);
50
- const results = [];
51
- for await (const item of streamable('http://test.com/stream')) {
52
- results.push(item);
53
- }
54
- expect(results).toHaveLength(2);
55
- expect(results[0]).toEqual({ id: 1 });
56
- expect(results[1]).toEqual({ id: 2 });
57
- });
58
- it('should include heartbeats when skipHeartbeats is false', async () => {
59
- global.fetch = mockFetch([
60
- '{"id":1}\n',
61
- '{"type":"heartbeat"}\n',
62
- '{"id":2}\n',
63
- ]);
64
- const results = [];
65
- for await (const item of streamable('http://test.com/stream', { skipHeartbeats: false })) {
66
- results.push(item);
67
- }
68
- expect(results).toHaveLength(3);
69
- });
70
- it('should unwrap data from wrapped messages', async () => {
71
- global.fetch = mockFetch([
72
- '{"data":{"id":1},"fields":["id"]}\n',
73
- '{"event":"update","data":{"id":2}}\n',
74
- ]);
75
- const results = [];
76
- for await (const item of streamable('http://test.com/stream')) {
77
- results.push(item);
78
- }
79
- expect(results).toHaveLength(2);
80
- expect(results[0]).toEqual({ id: 1 });
81
- expect(results[1]).toEqual({ id: 2 });
82
- });
83
- it('should handle chunked data across multiple reads', async () => {
84
- global.fetch = mockFetch([
85
- '{"id":1}\n{"id":', // First chunk ends mid-JSON
86
- '2}\n', // Second chunk completes it
87
- ]);
88
- const results = [];
89
- for await (const item of streamable('http://test.com/stream')) {
90
- results.push(item);
91
- }
92
- expect(results).toHaveLength(2);
93
- expect(results[0]).toEqual({ id: 1 });
94
- expect(results[1]).toEqual({ id: 2 });
95
- });
96
- it('should handle empty lines', async () => {
97
- global.fetch = mockFetch([
98
- '{"id":1}\n',
99
- '\n',
100
- '{"id":2}\n',
101
- '\n\n',
102
- ]);
103
- const results = [];
104
- for await (const item of streamable('http://test.com/stream')) {
105
- results.push(item);
106
- }
107
- expect(results).toHaveLength(2);
108
- });
109
- it('should set correct headers', async () => {
110
- const mockFetchFn = mockFetch(['{"ok":true}\n']);
111
- global.fetch = mockFetchFn;
112
- const results = [];
113
- for await (const item of streamable('http://test.com/stream', {
114
- headers: { 'Authorization': 'Bearer token' },
115
- })) {
116
- results.push(item);
117
- }
118
- expect(mockFetchFn).toHaveBeenCalledWith('http://test.com/stream', expect.objectContaining({
119
- method: 'GET',
120
- headers: expect.objectContaining({
121
- 'Accept': 'application/x-ndjson',
122
- 'Authorization': 'Bearer token',
123
- }),
124
- }));
125
- });
126
- it('should use POST when body is provided', async () => {
127
- const mockFetchFn = mockFetch(['{"ok":true}\n']);
128
- global.fetch = mockFetchFn;
129
- const results = [];
130
- for await (const item of streamable('http://test.com/stream', {
131
- body: { query: 'test' },
132
- })) {
133
- results.push(item);
134
- }
135
- expect(mockFetchFn).toHaveBeenCalledWith('http://test.com/stream', expect.objectContaining({
136
- method: 'POST',
137
- headers: expect.objectContaining({
138
- 'Content-Type': 'application/json',
139
- }),
140
- body: JSON.stringify({ query: 'test' }),
141
- }));
142
- });
143
- it('should throw on HTTP error', async () => {
144
- global.fetch = jest.fn().mockResolvedValue({
145
- ok: false,
146
- status: 401,
147
- text: async () => 'Unauthorized',
148
- });
149
- await expect(async () => {
150
- for await (const _ of streamable('http://test.com/stream')) {
151
- // consume
152
- }
153
- }).rejects.toThrow('HTTP 401: Unauthorized');
154
- });
155
- it('should throw when the response has no body', async () => {
156
- global.fetch = jest.fn().mockResolvedValue({
157
- ok: true,
158
- status: 200,
159
- body: null,
160
- });
161
- await expect(async () => {
162
- for await (const _ of streamable('http://test.com/stream')) {
163
- // consume
164
- }
165
- }).rejects.toThrow('No response body');
166
- });
167
- // Edge cases for chunking/buffering
168
- describe('chunking edge cases', () => {
169
- it('should handle message split across many chunks', async () => {
170
- // Split a single JSON object into 5 tiny chunks
171
- global.fetch = mockFetch([
172
- '{"id":',
173
- '123,',
174
- '"name"',
175
- ':"test',
176
- '"}\n',
177
- ]);
178
- const results = [];
179
- for await (const item of streamable('http://test.com/stream')) {
180
- results.push(item);
181
- }
182
- expect(results).toHaveLength(1);
183
- expect(results[0]).toEqual({ id: 123, name: 'test' });
184
- });
185
- it('should handle single-byte chunks', async () => {
186
- const json = '{"id":1}\n';
187
- const chunks = json.split('').map(c => c); // One char per chunk
188
- global.fetch = mockFetch(chunks);
189
- const results = [];
190
- for await (const item of streamable('http://test.com/stream')) {
191
- results.push(item);
192
- }
193
- expect(results).toHaveLength(1);
194
- expect(results[0]).toEqual({ id: 1 });
195
- });
196
- it('should handle newline exactly at chunk boundary', async () => {
197
- global.fetch = mockFetch([
198
- '{"id":1}',
199
- '\n',
200
- '{"id":2}\n',
201
- ]);
202
- const results = [];
203
- for await (const item of streamable('http://test.com/stream')) {
204
- results.push(item);
205
- }
206
- expect(results).toHaveLength(2);
207
- });
208
- it('should handle multiple messages in single chunk', async () => {
209
- global.fetch = mockFetch([
210
- '{"id":1}\n{"id":2}\n{"id":3}\n',
211
- ]);
212
- const results = [];
213
- for await (const item of streamable('http://test.com/stream')) {
214
- results.push(item);
215
- }
216
- expect(results).toHaveLength(3);
217
- });
218
- it('should handle empty chunks', async () => {
219
- global.fetch = mockFetch([
220
- '{"id":1}\n',
221
- '',
222
- '',
223
- '{"id":2}\n',
224
- ]);
225
- const results = [];
226
- for await (const item of streamable('http://test.com/stream')) {
227
- results.push(item);
228
- }
229
- expect(results).toHaveLength(2);
230
- });
231
- it('should handle trailing data without final newline', async () => {
232
- global.fetch = mockFetch([
233
- '{"id":1}\n',
234
- '{"id":2}', // No trailing newline
235
- ]);
236
- const results = [];
237
- for await (const item of streamable('http://test.com/stream')) {
238
- results.push(item);
239
- }
240
- expect(results).toHaveLength(2);
241
- });
242
- });
243
- describe('unicode handling', () => {
244
- it('should handle unicode in messages', async () => {
245
- global.fetch = mockFetch([
246
- '{"text":"Hello 世界 🎉"}\n',
247
- ]);
248
- const results = [];
249
- for await (const item of streamable('http://test.com/stream')) {
250
- results.push(item);
251
- }
252
- expect(results[0]).toEqual({ text: 'Hello 世界 🎉' });
253
- });
254
- it('should handle unicode split across chunks', async () => {
255
- // 世 is 3 bytes in UTF-8: E4 B8 96
256
- // Split it across chunks
257
- const encoder = new TextEncoder();
258
- const fullText = '{"text":"世"}\n';
259
- const bytes = encoder.encode(fullText);
260
- // Create mock that returns raw bytes split mid-character
261
- let chunkIndex = 0;
262
- const chunks = [
263
- bytes.slice(0, 10), // '{"text":"' + first byte of 世
264
- bytes.slice(10), // rest of 世 + '"}\n'
265
- ];
266
- const mockReader = {
267
- read: jest.fn().mockImplementation(async () => {
268
- if (chunkIndex >= chunks.length) {
269
- return { done: true, value: undefined };
270
- }
271
- return { done: false, value: chunks[chunkIndex++] };
272
- }),
273
- releaseLock: jest.fn(),
274
- };
275
- global.fetch = jest.fn().mockResolvedValue({
276
- ok: true,
277
- body: { getReader: () => mockReader },
278
- });
279
- const results = [];
280
- for await (const item of streamable('http://test.com/stream')) {
281
- results.push(item);
282
- }
283
- expect(results[0]).toEqual({ text: '世' });
284
- });
285
- });
286
- describe('error handling', () => {
287
- it('should handle invalid JSON gracefully', async () => {
288
- global.fetch = mockFetch([
289
- '{"id":1}\n',
290
- 'not valid json\n',
291
- '{"id":2}\n',
292
- ]);
293
- const results = [];
294
- await expect(async () => {
295
- for await (const item of streamable('http://test.com/stream')) {
296
- results.push(item);
297
- }
298
- }).rejects.toThrow(); // Should throw on invalid JSON
299
- // First valid message should have been processed
300
- expect(results).toHaveLength(1);
301
- });
302
- it('should handle network error mid-stream', async () => {
303
- let readCount = 0;
304
- const mockReader = {
305
- read: jest.fn().mockImplementation(async () => {
306
- readCount++;
307
- if (readCount === 1) {
308
- return { done: false, value: new TextEncoder().encode('{"id":1}\n') };
309
- }
310
- throw new Error('Network error');
311
- }),
312
- releaseLock: jest.fn(),
313
- };
314
- global.fetch = jest.fn().mockResolvedValue({
315
- ok: true,
316
- body: { getReader: () => mockReader },
317
- });
318
- const results = [];
319
- await expect(async () => {
320
- for await (const item of streamable('http://test.com/stream')) {
321
- results.push(item);
322
- }
323
- }).rejects.toThrow('Network error');
324
- expect(results).toHaveLength(1);
325
- });
326
- });
327
- });
328
- describe('streamableRaw', () => {
329
- const originalFetch = global.fetch;
330
- afterEach(() => {
331
- global.fetch = originalFetch;
332
- });
333
- it('should preserve event and fields in raw mode', async () => {
334
- global.fetch = mockFetch([
335
- '{"event":"update","data":{"id":1},"fields":["id"]}\n',
336
- ]);
337
- const results = [];
338
- for await (const item of streamableRaw('http://test.com/stream')) {
339
- results.push(item);
340
- }
341
- expect(results).toHaveLength(1);
342
- expect(results[0]).toEqual({
343
- event: 'update',
344
- data: { id: 1 },
345
- fields: ['id'],
346
- });
347
- });
348
- });
349
- describe('StreamableManager', () => {
350
- const originalFetch = global.fetch;
351
- afterEach(() => {
352
- global.fetch = originalFetch;
353
- });
354
- it('should call onData for each message', async () => {
355
- global.fetch = mockFetch([
356
- '{"id":1}\n',
357
- '{"id":2}\n',
358
- ]);
359
- const messages = [];
360
- const manager = new StreamableManager({
361
- url: 'http://test.com/stream',
362
- onData: (data) => messages.push(data),
363
- });
364
- await manager.start();
365
- expect(messages).toHaveLength(2);
366
- expect(messages[0]).toEqual({ id: 1 });
367
- expect(messages[1]).toEqual({ id: 2 });
368
- });
369
- it('should call onPartialData for partial updates', async () => {
370
- global.fetch = mockFetch([
371
- '{"data":{"id":1},"fields":["id"]}\n',
372
- ]);
373
- const partials = [];
374
- const manager = new StreamableManager({
375
- url: 'http://test.com/stream',
376
- onPartialData: (data, fields) => partials.push({ data, fields }),
377
- });
378
- await manager.start();
379
- expect(partials).toHaveLength(1);
380
- expect(partials[0]).toEqual({ data: { id: 1 }, fields: ['id'] });
381
- });
382
- it('should call lifecycle callbacks', async () => {
383
- global.fetch = mockFetch(['{"ok":true}\n']);
384
- const events = [];
385
- const manager = new StreamableManager({
386
- url: 'http://test.com/stream',
387
- onStart: () => events.push('start'),
388
- onEnd: () => events.push('end'),
389
- onData: () => events.push('data'),
390
- });
391
- await manager.start();
392
- expect(events).toEqual(['start', 'data', 'end']);
393
- });
394
- it('should dispatch typed events to addEventListener subscribers', async () => {
395
- global.fetch = mockFetch([
396
- '{"event":"chats","data":{"id":"chat-1","status":"busy"}}\n',
397
- '{"event":"chat_messages","data":{"id":"msg-1","content":"hi"}}\n',
398
- ]);
399
- const onChat = jest.fn();
400
- const onMessage = jest.fn();
401
- const manager = new StreamableManager({
402
- url: 'http://test.com/stream',
403
- onData: jest.fn(),
404
- });
405
- manager.addEventListener('chats', onChat);
406
- manager.addEventListener('chat_messages', onMessage);
407
- await manager.start();
408
- expect(onChat).toHaveBeenCalledWith({ id: 'chat-1', status: 'busy' });
409
- expect(onMessage).toHaveBeenCalledWith({ id: 'msg-1', content: 'hi' });
410
- });
411
- it('should stop dispatching to an unsubscribed listener', async () => {
412
- global.fetch = mockFetch([
413
- '{"event":"chats","data":{"id":"chat-1"}}\n',
414
- ]);
415
- const removedListener = jest.fn();
416
- const activeListener = jest.fn();
417
- const manager = new StreamableManager({
418
- url: 'http://test.com/stream',
419
- });
420
- const unsubscribe = manager.addEventListener('chats', removedListener);
421
- manager.addEventListener('chats', activeListener);
422
- unsubscribe();
423
- await manager.start();
424
- expect(removedListener).not.toHaveBeenCalled();
425
- expect(activeListener).toHaveBeenCalledWith({ id: 'chat-1' });
426
- });
427
- it('should ignore start() when a stream is already running', async () => {
428
- let readCount = 0;
429
- const mockReader = {
430
- read: jest.fn().mockImplementation(async () => {
431
- readCount++;
432
- if (readCount > 3) {
433
- return { done: true, value: undefined };
434
- }
435
- await new Promise((resolve) => setTimeout(resolve, 20));
436
- return { done: false, value: new TextEncoder().encode('{"id":1}\n') };
437
- }),
438
- releaseLock: jest.fn(),
439
- };
440
- global.fetch = jest.fn().mockResolvedValue({
441
- ok: true,
442
- body: { getReader: () => mockReader },
443
- });
444
- const onStart = jest.fn();
445
- const manager = new StreamableManager({
446
- url: 'http://test.com/stream',
447
- onStart,
448
- onData: () => { },
449
- });
450
- const firstStart = manager.start();
451
- await manager.start();
452
- await firstStart;
453
- expect(onStart).toHaveBeenCalledTimes(1);
454
- expect(global.fetch).toHaveBeenCalledTimes(1);
455
- });
456
- it('should handle stop()', async () => {
457
- let readCount = 0;
458
- const mockReader = {
459
- read: jest.fn().mockImplementation(async () => {
460
- readCount++;
461
- if (readCount > 10) {
462
- return { done: true, value: undefined };
463
- }
464
- await new Promise(resolve => setTimeout(resolve, 10));
465
- return { done: false, value: new TextEncoder().encode('{"id":1}\n') };
466
- }),
467
- releaseLock: jest.fn(),
468
- };
469
- global.fetch = jest.fn().mockResolvedValue({
470
- ok: true,
471
- body: { getReader: () => mockReader },
472
- });
473
- const manager = new StreamableManager({
474
- url: 'http://test.com/stream',
475
- onData: () => { },
476
- });
477
- // Start and immediately stop
478
- const startPromise = manager.start();
479
- setTimeout(() => manager.stop(), 25);
480
- await startPromise;
481
- // Should have stopped before reading all 10
482
- expect(readCount).toBeLessThan(10);
483
- });
484
- it('should call onError when the stream request fails', async () => {
485
- global.fetch = jest.fn().mockResolvedValue({
486
- ok: false,
487
- status: 503,
488
- text: async () => 'Service unavailable',
489
- });
490
- const onError = jest.fn();
491
- const manager = new StreamableManager({
492
- url: 'http://test.com/stream',
493
- onError,
494
- });
495
- await manager.start();
496
- expect(onError).toHaveBeenCalledWith(expect.objectContaining({ message: 'HTTP 503: Service unavailable' }));
497
- });
498
- it('should route partial updates to onData when onPartialData is not provided', async () => {
499
- global.fetch = mockFetch([
500
- '{"data":{"id":1,"status":"busy"},"fields":["status"]}\n',
501
- ]);
502
- const onData = jest.fn();
503
- const manager = new StreamableManager({
504
- url: 'http://test.com/stream',
505
- onData,
506
- });
507
- await manager.start();
508
- expect(onData).toHaveBeenCalledWith({ id: 1, status: 'busy' });
509
- });
510
- });
@@ -1,9 +0,0 @@
1
- /**
2
- * Integration tests for @inferencesh/sdk
3
- *
4
- * These tests hit the real API and require INFERENCE_API_KEY to be set.
5
- * Run with: npm run test:integration
6
- *
7
- * @jest-environment node
8
- */
9
- export {};
@@ -1,107 +0,0 @@
1
- /**
2
- * Integration tests for @inferencesh/sdk
3
- *
4
- * These tests hit the real API and require INFERENCE_API_KEY to be set.
5
- * Run with: npm run test:integration
6
- *
7
- * @jest-environment node
8
- */
9
- import { Inference, inference } from './index';
10
- import { TaskStatusCompleted, TaskStatusFailed } from './types';
11
- // Skip all tests if no API key is set
12
- const API_KEY = process.env.INFERENCE_API_KEY;
13
- const BASE_URL = process.env.INFERENCE_BASE_URL || 'https://api.inference.sh';
14
- // Use a pinned app version that's known to work
15
- const TEST_APP = 'infsh/text-templating@53bk0yzk';
16
- const describeIfApiKey = API_KEY ? describe : describe.skip;
17
- describeIfApiKey('Integration Tests', () => {
18
- let client;
19
- beforeAll(() => {
20
- client = new Inference({
21
- apiKey: API_KEY,
22
- baseUrl: BASE_URL,
23
- });
24
- });
25
- describe('Basic Run', () => {
26
- it('should run a simple task and wait for completion', async () => {
27
- const result = await client.run({
28
- app: TEST_APP,
29
- input: { template: 'Hello {1}!', strings: ['Jest'] },
30
- });
31
- expect(result).toBeDefined();
32
- expect(result.id).toBeDefined();
33
- expect(result.status).toBe(TaskStatusCompleted);
34
- expect(result.output).toBeDefined();
35
- }, 60000); // 60 second timeout for API call
36
- });
37
- describe('Run with Updates', () => {
38
- it('should receive status updates during task execution', async () => {
39
- const updates = [];
40
- const result = await client.run({
41
- app: TEST_APP,
42
- input: { template: 'Testing {1}', strings: ['SDK'] },
43
- }, {
44
- onUpdate: (update) => {
45
- updates.push(update.status);
46
- },
47
- });
48
- expect(result.status).toBe(TaskStatusCompleted);
49
- expect(updates.length).toBeGreaterThan(0);
50
- }, 60000);
51
- });
52
- describe('Fire and Forget', () => {
53
- it('should submit a task without waiting for completion', async () => {
54
- const result = await client.run({
55
- app: TEST_APP,
56
- input: { template: '{1}', strings: ['Fire and forget'] },
57
- }, { wait: false });
58
- expect(result).toBeDefined();
59
- expect(result.id).toBeDefined();
60
- // Status should NOT be completed yet (task was just submitted)
61
- expect(result.status).not.toBe(TaskStatusCompleted);
62
- expect(result.status).not.toBe(TaskStatusFailed);
63
- }, 30000);
64
- });
65
- describe('Factory Function', () => {
66
- it('should work with lowercase inference() factory', async () => {
67
- const factoryClient = inference({
68
- apiKey: API_KEY,
69
- baseUrl: BASE_URL,
70
- });
71
- const result = await factoryClient.run({
72
- app: TEST_APP,
73
- input: { template: '{1}', strings: ['Factory test'] },
74
- }, { wait: false });
75
- expect(result).toBeDefined();
76
- expect(result.id).toBeDefined();
77
- }, 30000);
78
- });
79
- describe('Webhook', () => {
80
- it('should deliver webhook on task completion', async () => {
81
- const result = await client.run({
82
- app: TEST_APP,
83
- input: { template: 'Webhook test {1}', strings: ['hello'] },
84
- webhook: 'https://webhook.site/bbe9ba01-3ab2-4056-a1b1-1cf6969987d5',
85
- });
86
- expect(result.status).toBe(TaskStatusCompleted);
87
- expect(result.output).toBeDefined();
88
- }, 60000);
89
- });
90
- describe('Error Handling', () => {
91
- it('should throw an error for non-existent app', async () => {
92
- await expect(client.run({
93
- app: 'non-existent/app-that-does-not-exist@xyz123',
94
- input: {},
95
- }, { wait: false })).rejects.toThrow();
96
- }, 30000);
97
- });
98
- });
99
- // Add a simple test that always runs to ensure Jest doesn't complain about no tests
100
- describe('Integration Test Setup', () => {
101
- it('should have API key check', () => {
102
- if (!API_KEY) {
103
- console.log('⚠️ Skipping integration tests - INFERENCE_API_KEY not set');
104
- }
105
- expect(true).toBe(true);
106
- });
107
- });
@@ -1 +0,0 @@
1
- export {};