@haiai/haiai 0.1.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.
- package/README.md +127 -0
- package/bin/haiai.cjs +70 -0
- package/dist/cjs/a2a.js +352 -0
- package/dist/cjs/a2a.js.map +1 -0
- package/dist/cjs/agent.js +236 -0
- package/dist/cjs/agent.js.map +1 -0
- package/dist/cjs/client.js +2168 -0
- package/dist/cjs/client.js.map +1 -0
- package/dist/cjs/config.js +176 -0
- package/dist/cjs/config.js.map +1 -0
- package/dist/cjs/errors.js +102 -0
- package/dist/cjs/errors.js.map +1 -0
- package/dist/cjs/hash.js +52 -0
- package/dist/cjs/hash.js.map +1 -0
- package/dist/cjs/index.js +84 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/integrations.js +193 -0
- package/dist/cjs/integrations.js.map +1 -0
- package/dist/cjs/jacs.js +66 -0
- package/dist/cjs/jacs.js.map +1 -0
- package/dist/cjs/mime.js +100 -0
- package/dist/cjs/mime.js.map +1 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/signing.js +190 -0
- package/dist/cjs/signing.js.map +1 -0
- package/dist/cjs/sse.js +76 -0
- package/dist/cjs/sse.js.map +1 -0
- package/dist/cjs/types.js +6 -0
- package/dist/cjs/types.js.map +1 -0
- package/dist/cjs/verify.js +76 -0
- package/dist/cjs/verify.js.map +1 -0
- package/dist/cjs/ws.js +206 -0
- package/dist/cjs/ws.js.map +1 -0
- package/dist/esm/a2a.js +305 -0
- package/dist/esm/a2a.js.map +1 -0
- package/dist/esm/agent.js +231 -0
- package/dist/esm/agent.js.map +1 -0
- package/dist/esm/client.js +2131 -0
- package/dist/esm/client.js.map +1 -0
- package/dist/esm/config.js +171 -0
- package/dist/esm/config.js.map +1 -0
- package/dist/esm/errors.js +88 -0
- package/dist/esm/errors.js.map +1 -0
- package/dist/esm/hash.js +49 -0
- package/dist/esm/hash.js.map +1 -0
- package/dist/esm/index.js +27 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/integrations.js +147 -0
- package/dist/esm/integrations.js.map +1 -0
- package/dist/esm/jacs.js +61 -0
- package/dist/esm/jacs.js.map +1 -0
- package/dist/esm/mime.js +97 -0
- package/dist/esm/mime.js.map +1 -0
- package/dist/esm/signing.js +183 -0
- package/dist/esm/signing.js.map +1 -0
- package/dist/esm/sse.js +73 -0
- package/dist/esm/sse.js.map +1 -0
- package/dist/esm/types.js +5 -0
- package/dist/esm/types.js.map +1 -0
- package/dist/esm/verify.js +72 -0
- package/dist/esm/verify.js.map +1 -0
- package/dist/esm/ws.js +168 -0
- package/dist/esm/ws.js.map +1 -0
- package/dist/types/a2a.d.ts +52 -0
- package/dist/types/a2a.d.ts.map +1 -0
- package/dist/types/agent.d.ts +202 -0
- package/dist/types/agent.d.ts.map +1 -0
- package/dist/types/client.d.ts +486 -0
- package/dist/types/client.d.ts.map +1 -0
- package/dist/types/config.d.ts +31 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/errors.d.ts +50 -0
- package/dist/types/errors.d.ts.map +1 -0
- package/dist/types/hash.d.ts +32 -0
- package/dist/types/hash.d.ts.map +1 -0
- package/dist/types/index.d.ts +22 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/integrations.d.ts +25 -0
- package/dist/types/integrations.d.ts.map +1 -0
- package/dist/types/jacs.d.ts +26 -0
- package/dist/types/jacs.d.ts.map +1 -0
- package/dist/types/mime.d.ts +39 -0
- package/dist/types/mime.d.ts.map +1 -0
- package/dist/types/signing.d.ts +58 -0
- package/dist/types/signing.d.ts.map +1 -0
- package/dist/types/sse.d.ts +8 -0
- package/dist/types/sse.d.ts.map +1 -0
- package/dist/types/types.d.ts +652 -0
- package/dist/types/types.d.ts.map +1 -0
- package/dist/types/verify.d.ts +20 -0
- package/dist/types/verify.d.ts.map +1 -0
- package/dist/types/ws.d.ts +30 -0
- package/dist/types/ws.d.ts.map +1 -0
- package/examples/a2a_quickstart.ts +138 -0
- package/examples/hai_quickstart.ts +111 -0
- package/examples/mcp_quickstart.ts +53 -0
- package/npm/@haiai/cli-darwin-arm64/package.json +16 -0
- package/npm/@haiai/cli-darwin-x64/package.json +16 -0
- package/npm/@haiai/cli-linux-arm64/package.json +16 -0
- package/npm/@haiai/cli-linux-x64/package.json +16 -0
- package/npm/@haiai/cli-win32-x64/package.json +16 -0
- package/package.json +68 -0
- package/scripts/build-platform-packages.js +132 -0
- package/scripts/smoke-package.cjs +114 -0
- package/scripts/write-cjs-package.cjs +9 -0
- package/src/a2a.ts +463 -0
- package/src/agent.ts +302 -0
- package/src/client.ts +2504 -0
- package/src/config.ts +204 -0
- package/src/errors.ts +99 -0
- package/src/hash.ts +66 -0
- package/src/index.ts +163 -0
- package/src/integrations.ts +210 -0
- package/src/jacs.ts +86 -0
- package/src/mime.ts +131 -0
- package/src/signing.ts +233 -0
- package/src/sse.ts +86 -0
- package/src/types.ts +773 -0
- package/src/verify.ts +89 -0
- package/src/ws.ts +198 -0
- package/tests/_debug_jacs.cjs +29 -0
- package/tests/a2a-contract.test.ts +271 -0
- package/tests/a2a-fixtures.test.ts +73 -0
- package/tests/a2a.test.ts +379 -0
- package/tests/binary.test.ts +90 -0
- package/tests/client-api-methods.test.ts +176 -0
- package/tests/client-path-escaping.test.ts +80 -0
- package/tests/client-register.test.ts +61 -0
- package/tests/config.test.ts +281 -0
- package/tests/contract.test.ts +360 -0
- package/tests/cross-lang-contract.test.ts +67 -0
- package/tests/email-conformance.test.ts +289 -0
- package/tests/email-integration.test.ts +217 -0
- package/tests/email.test.ts +767 -0
- package/tests/errors.test.ts +167 -0
- package/tests/init-contract.test.ts +129 -0
- package/tests/integrations.test.ts +132 -0
- package/tests/jacs-passthrough.test.ts +125 -0
- package/tests/key-cache.test.ts +201 -0
- package/tests/key-integration.test.ts +119 -0
- package/tests/key-lookups.test.ts +187 -0
- package/tests/key-rotation.test.ts +362 -0
- package/tests/mime.test.ts +127 -0
- package/tests/security.test.ts +109 -0
- package/tests/setup.ts +60 -0
- package/tests/signing.test.ts +142 -0
- package/tests/sse.test.ts +125 -0
- package/tests/types.test.ts +294 -0
- package/tests/verify-link.test.ts +81 -0
- package/tests/ws.test.ts +213 -0
- package/tsconfig.cjs.json +11 -0
- package/tsconfig.json +22 -0
- package/vitest.config.ts +11 -0
package/tests/ws.test.ts
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import type { WsLike } from '../src/ws.js';
|
|
3
|
+
import { wsRecv, wsEventStream } from '../src/ws.js';
|
|
4
|
+
import { HaiConnectionError, WebSocketError } from '../src/errors.js';
|
|
5
|
+
|
|
6
|
+
/** Create a mock WebSocket that supports on/once/close */
|
|
7
|
+
function createMockWs(): WsLike & {
|
|
8
|
+
_trigger(event: string, ...args: unknown[]): void;
|
|
9
|
+
_listeners: Map<string, Array<(...args: unknown[]) => void>>;
|
|
10
|
+
} {
|
|
11
|
+
const listeners = new Map<string, Array<(...args: unknown[]) => void>>();
|
|
12
|
+
|
|
13
|
+
const ws: WsLike & {
|
|
14
|
+
_trigger(event: string, ...args: unknown[]): void;
|
|
15
|
+
_listeners: Map<string, Array<(...args: unknown[]) => void>>;
|
|
16
|
+
} = {
|
|
17
|
+
readyState: 1, // OPEN
|
|
18
|
+
_listeners: listeners,
|
|
19
|
+
send: vi.fn(),
|
|
20
|
+
close: vi.fn(() => {
|
|
21
|
+
(ws as { readyState: number }).readyState = 3; // CLOSED
|
|
22
|
+
}),
|
|
23
|
+
on(event: string, listener: (...args: unknown[]) => void) {
|
|
24
|
+
if (!listeners.has(event)) listeners.set(event, []);
|
|
25
|
+
listeners.get(event)!.push(listener);
|
|
26
|
+
},
|
|
27
|
+
once(event: string, listener: (...args: unknown[]) => void) {
|
|
28
|
+
if (!listeners.has(event)) listeners.set(event, []);
|
|
29
|
+
const wrapped = (...args: unknown[]) => {
|
|
30
|
+
const idx = listeners.get(event)!.indexOf(wrapped);
|
|
31
|
+
if (idx >= 0) listeners.get(event)!.splice(idx, 1);
|
|
32
|
+
listener(...args);
|
|
33
|
+
};
|
|
34
|
+
listeners.get(event)!.push(wrapped);
|
|
35
|
+
},
|
|
36
|
+
_trigger(event: string, ...args: unknown[]) {
|
|
37
|
+
const handlers = listeners.get(event) ?? [];
|
|
38
|
+
for (const h of [...handlers]) {
|
|
39
|
+
h(...args);
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
return ws;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Helper to wait for microtasks to flush */
|
|
48
|
+
const tick = () => new Promise(r => setTimeout(r, 0));
|
|
49
|
+
|
|
50
|
+
describe('ws', () => {
|
|
51
|
+
describe('wsRecv', () => {
|
|
52
|
+
it('receives and parses JSON message', async () => {
|
|
53
|
+
const ws = createMockWs();
|
|
54
|
+
const promise = wsRecv(ws);
|
|
55
|
+
|
|
56
|
+
ws._trigger('message', JSON.stringify({ type: 'connected', status: 'ok' }));
|
|
57
|
+
|
|
58
|
+
const result = await promise;
|
|
59
|
+
expect(result).toEqual({ type: 'connected', status: 'ok' });
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('returns raw string for non-JSON message', async () => {
|
|
63
|
+
const ws = createMockWs();
|
|
64
|
+
const promise = wsRecv(ws);
|
|
65
|
+
|
|
66
|
+
ws._trigger('message', 'not-json');
|
|
67
|
+
|
|
68
|
+
const result = await promise;
|
|
69
|
+
expect(result).toBe('not-json');
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('handles Buffer input', async () => {
|
|
73
|
+
const ws = createMockWs();
|
|
74
|
+
const promise = wsRecv(ws);
|
|
75
|
+
|
|
76
|
+
ws._trigger('message', Buffer.from('{"key":"value"}'));
|
|
77
|
+
|
|
78
|
+
const result = await promise;
|
|
79
|
+
expect(result).toEqual({ key: 'value' });
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('rejects on close', async () => {
|
|
83
|
+
const ws = createMockWs();
|
|
84
|
+
const promise = wsRecv(ws);
|
|
85
|
+
|
|
86
|
+
ws._trigger('close');
|
|
87
|
+
|
|
88
|
+
await expect(promise).rejects.toThrow(HaiConnectionError);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('rejects on error with WebSocketError', async () => {
|
|
92
|
+
const ws = createMockWs();
|
|
93
|
+
const promise = wsRecv(ws);
|
|
94
|
+
|
|
95
|
+
ws._trigger('error', new Error('connection lost'));
|
|
96
|
+
|
|
97
|
+
await expect(promise).rejects.toThrow(WebSocketError);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
describe('wsEventStream', () => {
|
|
102
|
+
it('yields events from messages', async () => {
|
|
103
|
+
const ws = createMockWs();
|
|
104
|
+
const stream = wsEventStream(ws);
|
|
105
|
+
|
|
106
|
+
// Send messages, then close after a separate tick so generator can yield
|
|
107
|
+
setTimeout(() => {
|
|
108
|
+
ws._trigger('message', JSON.stringify({ type: 'heartbeat', timestamp: 123 }));
|
|
109
|
+
ws._trigger('message', JSON.stringify({ type: 'benchmark_job', run_id: 'r1' }));
|
|
110
|
+
// Close after a separate tick to allow generator to process messages
|
|
111
|
+
setTimeout(() => ws._trigger('close'), 5);
|
|
112
|
+
}, 10);
|
|
113
|
+
|
|
114
|
+
const events = [];
|
|
115
|
+
for await (const event of stream) {
|
|
116
|
+
events.push(event);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
expect(events).toHaveLength(2);
|
|
120
|
+
expect(events[0].eventType).toBe('heartbeat');
|
|
121
|
+
expect(events[1].eventType).toBe('benchmark_job');
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('extracts event_type from data', async () => {
|
|
125
|
+
const ws = createMockWs();
|
|
126
|
+
const stream = wsEventStream(ws);
|
|
127
|
+
|
|
128
|
+
setTimeout(() => {
|
|
129
|
+
ws._trigger('message', JSON.stringify({ event_type: 'custom_event', data: 'test' }));
|
|
130
|
+
setTimeout(() => ws._trigger('close'), 5);
|
|
131
|
+
}, 10);
|
|
132
|
+
|
|
133
|
+
const events = [];
|
|
134
|
+
for await (const event of stream) {
|
|
135
|
+
events.push(event);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
expect(events[0].eventType).toBe('custom_event');
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it('extracts event id', async () => {
|
|
142
|
+
const ws = createMockWs();
|
|
143
|
+
const stream = wsEventStream(ws);
|
|
144
|
+
|
|
145
|
+
setTimeout(() => {
|
|
146
|
+
ws._trigger('message', JSON.stringify({ type: 'test', id: 'evt-42' }));
|
|
147
|
+
setTimeout(() => ws._trigger('close'), 5);
|
|
148
|
+
}, 10);
|
|
149
|
+
|
|
150
|
+
const events = [];
|
|
151
|
+
for await (const event of stream) {
|
|
152
|
+
events.push(event);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
expect(events[0].id).toBe('evt-42');
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('handles non-JSON messages as raw text', async () => {
|
|
159
|
+
const ws = createMockWs();
|
|
160
|
+
const stream = wsEventStream(ws);
|
|
161
|
+
|
|
162
|
+
setTimeout(() => {
|
|
163
|
+
ws._trigger('message', 'plain text message');
|
|
164
|
+
setTimeout(() => ws._trigger('close'), 5);
|
|
165
|
+
}, 10);
|
|
166
|
+
|
|
167
|
+
const events = [];
|
|
168
|
+
for await (const event of stream) {
|
|
169
|
+
events.push(event);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
expect(events[0].eventType).toBe('message');
|
|
173
|
+
expect(events[0].data).toBe('plain text message');
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it('stores raw text', async () => {
|
|
177
|
+
const ws = createMockWs();
|
|
178
|
+
const stream = wsEventStream(ws);
|
|
179
|
+
|
|
180
|
+
const rawJson = JSON.stringify({ type: 'test', data: { x: 1 } });
|
|
181
|
+
setTimeout(() => {
|
|
182
|
+
ws._trigger('message', rawJson);
|
|
183
|
+
setTimeout(() => ws._trigger('close'), 5);
|
|
184
|
+
}, 10);
|
|
185
|
+
|
|
186
|
+
const events = [];
|
|
187
|
+
for await (const event of stream) {
|
|
188
|
+
events.push(event);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
expect(events[0].raw).toBe(rawJson);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it('throws on WebSocket error', async () => {
|
|
195
|
+
const ws = createMockWs();
|
|
196
|
+
const stream = wsEventStream(ws);
|
|
197
|
+
|
|
198
|
+
setTimeout(() => {
|
|
199
|
+
ws._trigger('error', new Error('connection reset'));
|
|
200
|
+
}, 10);
|
|
201
|
+
|
|
202
|
+
const events = [];
|
|
203
|
+
try {
|
|
204
|
+
for await (const event of stream) {
|
|
205
|
+
events.push(event);
|
|
206
|
+
}
|
|
207
|
+
expect.fail('should have thrown');
|
|
208
|
+
} catch (e) {
|
|
209
|
+
expect(e).toBeInstanceOf(Error);
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
});
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ES2022",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"lib": ["ES2022"],
|
|
7
|
+
"outDir": "./dist/esm",
|
|
8
|
+
"declarationDir": "./dist/types",
|
|
9
|
+
"rootDir": "./src",
|
|
10
|
+
"strict": true,
|
|
11
|
+
"declaration": true,
|
|
12
|
+
"declarationMap": true,
|
|
13
|
+
"sourceMap": true,
|
|
14
|
+
"esModuleInterop": true,
|
|
15
|
+
"skipLibCheck": true,
|
|
16
|
+
"forceConsistentCasingInFileNames": true,
|
|
17
|
+
"resolveJsonModule": true,
|
|
18
|
+
"isolatedModules": true
|
|
19
|
+
},
|
|
20
|
+
"include": ["src/**/*.ts"],
|
|
21
|
+
"exclude": ["node_modules", "dist", "tests"]
|
|
22
|
+
}
|
package/vitest.config.ts
ADDED