ai.matey.http 0.2.2 → 0.3.0
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/CHANGELOG.md +22 -0
- package/dist/cjs/websocket/index.js +160 -0
- package/dist/cjs/websocket/index.js.map +1 -0
- package/dist/esm/websocket/index.js +156 -0
- package/dist/esm/websocket/index.js.map +1 -0
- package/dist/types/websocket/index.d.ts +95 -0
- package/dist/types/websocket/index.d.ts.map +1 -0
- package/package.json +11 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# ai.matey.http
|
|
2
2
|
|
|
3
|
+
## 0.3.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- d3fd2e2: Production HTTP endpoints: built-in `/health` + `/health/ready` + `/health/live`, Prometheus
|
|
8
|
+
`/metrics`, OpenAI-compatible `/v1/embeddings`, per-route rate limits via `RouteConfig.rateLimit`,
|
|
9
|
+
and a zero-dependency WebSocket streaming subpath (`ai.matey.http/websocket`).
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- Updated dependencies [dae4d01]
|
|
14
|
+
- Updated dependencies [e7df1d0]
|
|
15
|
+
- Updated dependencies [d3fd2e2]
|
|
16
|
+
- Updated dependencies [f227db2]
|
|
17
|
+
- Updated dependencies [2912b7d]
|
|
18
|
+
- Updated dependencies [aef9f4a]
|
|
19
|
+
- Updated dependencies [78731bb]
|
|
20
|
+
- Updated dependencies [b7e2312]
|
|
21
|
+
- ai.matey.types@0.3.0
|
|
22
|
+
- ai.matey.core@0.3.0
|
|
23
|
+
- ai.matey.http.core@0.3.0
|
|
24
|
+
|
|
3
25
|
## 0.2.1
|
|
4
26
|
|
|
5
27
|
### Patch Changes
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* WebSocket Streaming
|
|
4
|
+
*
|
|
5
|
+
* Transport-agnostic WebSocket handler for real-time AI chat. Zero-dependency
|
|
6
|
+
* by design: instead of bundling a WebSocket implementation, it accepts any
|
|
7
|
+
* socket satisfying the structural {@link WebSocketLike} interface — Node
|
|
8
|
+
* `ws` sockets, `Deno.upgradeWebSocket` sockets, Bun sockets, or browser
|
|
9
|
+
* WebSockets all qualify.
|
|
10
|
+
*
|
|
11
|
+
* Wire protocol (JSON text frames):
|
|
12
|
+
* - client → server: `{ type: 'chat', id, request }`, `{ type: 'cancel', id }`
|
|
13
|
+
* - server → client: `{ type: 'start' | 'chunk' | 'done' | 'error', id, ... }`
|
|
14
|
+
* plus periodic `{ type: 'ping' }` heartbeats
|
|
15
|
+
*
|
|
16
|
+
* @module
|
|
17
|
+
*/
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.createWebSocketHandler = createWebSocketHandler;
|
|
20
|
+
exports.attachWebSocketServer = attachWebSocketServer;
|
|
21
|
+
/**
|
|
22
|
+
* Create a per-connection handler streaming chat over a WebSocket.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* import { WebSocketServer } from 'ws';
|
|
27
|
+
* import { createWebSocketHandler } from 'ai.matey.http/websocket';
|
|
28
|
+
*
|
|
29
|
+
* const handleSocket = createWebSocketHandler(bridge);
|
|
30
|
+
* new WebSocketServer({ port: 8080 }).on('connection', handleSocket);
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
function createWebSocketHandler(bridge, options = {}) {
|
|
34
|
+
const maxConcurrentStreams = options.maxConcurrentStreams ?? 5;
|
|
35
|
+
const heartbeatMs = options.heartbeatMs ?? 30000;
|
|
36
|
+
return (socket) => {
|
|
37
|
+
const activeStreams = new Map();
|
|
38
|
+
const sendMessage = (message) => {
|
|
39
|
+
try {
|
|
40
|
+
socket.send(JSON.stringify(message));
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
options.onError?.(error instanceof Error ? error : new Error(String(error)));
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
let heartbeat;
|
|
47
|
+
if (heartbeatMs > 0) {
|
|
48
|
+
heartbeat = setInterval(() => sendMessage({ type: 'ping' }), heartbeatMs);
|
|
49
|
+
if (typeof heartbeat === 'object' && 'unref' in heartbeat) {
|
|
50
|
+
heartbeat.unref();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const cleanup = () => {
|
|
54
|
+
if (heartbeat) {
|
|
55
|
+
clearInterval(heartbeat);
|
|
56
|
+
}
|
|
57
|
+
for (const controller of activeStreams.values()) {
|
|
58
|
+
controller.abort();
|
|
59
|
+
}
|
|
60
|
+
activeStreams.clear();
|
|
61
|
+
};
|
|
62
|
+
const runChat = async (id, request) => {
|
|
63
|
+
if (activeStreams.size >= maxConcurrentStreams) {
|
|
64
|
+
sendMessage({
|
|
65
|
+
type: 'error',
|
|
66
|
+
id,
|
|
67
|
+
error: { message: `Too many concurrent streams (max ${maxConcurrentStreams})` },
|
|
68
|
+
});
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const controller = new AbortController();
|
|
72
|
+
activeStreams.set(id, controller);
|
|
73
|
+
sendMessage({ type: 'start', id });
|
|
74
|
+
try {
|
|
75
|
+
const stream = bridge.chatStream(request, { signal: controller.signal });
|
|
76
|
+
for await (const chunk of stream) {
|
|
77
|
+
if (controller.signal.aborted) {
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
sendMessage({ type: 'chunk', id, chunk });
|
|
81
|
+
}
|
|
82
|
+
if (!controller.signal.aborted) {
|
|
83
|
+
sendMessage({ type: 'done', id });
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
if (!controller.signal.aborted) {
|
|
88
|
+
sendMessage({
|
|
89
|
+
type: 'error',
|
|
90
|
+
id,
|
|
91
|
+
error: { message: error instanceof Error ? error.message : String(error) },
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
finally {
|
|
96
|
+
activeStreams.delete(id);
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
const onMessage = (raw) => {
|
|
100
|
+
let parsed;
|
|
101
|
+
try {
|
|
102
|
+
const text = typeof raw === 'string'
|
|
103
|
+
? raw
|
|
104
|
+
: raw instanceof Uint8Array
|
|
105
|
+
? new TextDecoder().decode(raw)
|
|
106
|
+
: String(raw);
|
|
107
|
+
parsed = JSON.parse(text);
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
sendMessage({ type: 'error', id: null, error: { message: 'Malformed JSON message' } });
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
switch (parsed.type) {
|
|
114
|
+
case 'chat':
|
|
115
|
+
if (!parsed.id || parsed.request === undefined) {
|
|
116
|
+
sendMessage({
|
|
117
|
+
type: 'error',
|
|
118
|
+
id: parsed.id ?? null,
|
|
119
|
+
error: { message: "'chat' requires 'id' and 'request'" },
|
|
120
|
+
});
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
void runChat(parsed.id, parsed.request);
|
|
124
|
+
break;
|
|
125
|
+
case 'cancel':
|
|
126
|
+
activeStreams.get(parsed.id)?.abort();
|
|
127
|
+
activeStreams.delete(parsed.id);
|
|
128
|
+
break;
|
|
129
|
+
case 'pong':
|
|
130
|
+
break;
|
|
131
|
+
default:
|
|
132
|
+
sendMessage({
|
|
133
|
+
type: 'error',
|
|
134
|
+
id: null,
|
|
135
|
+
error: {
|
|
136
|
+
message: `Unknown message type: ${String(parsed.type)}`,
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
// Support both listener styles; extract data from DOM MessageEvent
|
|
142
|
+
if (socket.on) {
|
|
143
|
+
socket.on('message', (data) => onMessage(data));
|
|
144
|
+
socket.on('close', cleanup);
|
|
145
|
+
socket.on('error', cleanup);
|
|
146
|
+
}
|
|
147
|
+
else if (socket.addEventListener) {
|
|
148
|
+
socket.addEventListener('message', (event) => onMessage(event.data ?? event));
|
|
149
|
+
socket.addEventListener('close', cleanup);
|
|
150
|
+
socket.addEventListener('error', cleanup);
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Attach the handler to a `ws`-style server's connection event.
|
|
156
|
+
*/
|
|
157
|
+
function attachWebSocketServer(server, bridge, options) {
|
|
158
|
+
server.on('connection', createWebSocketHandler(bridge, options));
|
|
159
|
+
}
|
|
160
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/websocket/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebSocket Streaming
|
|
3
|
+
*
|
|
4
|
+
* Transport-agnostic WebSocket handler for real-time AI chat. Zero-dependency
|
|
5
|
+
* by design: instead of bundling a WebSocket implementation, it accepts any
|
|
6
|
+
* socket satisfying the structural {@link WebSocketLike} interface — Node
|
|
7
|
+
* `ws` sockets, `Deno.upgradeWebSocket` sockets, Bun sockets, or browser
|
|
8
|
+
* WebSockets all qualify.
|
|
9
|
+
*
|
|
10
|
+
* Wire protocol (JSON text frames):
|
|
11
|
+
* - client → server: `{ type: 'chat', id, request }`, `{ type: 'cancel', id }`
|
|
12
|
+
* - server → client: `{ type: 'start' | 'chunk' | 'done' | 'error', id, ... }`
|
|
13
|
+
* plus periodic `{ type: 'ping' }` heartbeats
|
|
14
|
+
*
|
|
15
|
+
* @module
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Create a per-connection handler streaming chat over a WebSocket.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```typescript
|
|
22
|
+
* import { WebSocketServer } from 'ws';
|
|
23
|
+
* import { createWebSocketHandler } from 'ai.matey.http/websocket';
|
|
24
|
+
*
|
|
25
|
+
* const handleSocket = createWebSocketHandler(bridge);
|
|
26
|
+
* new WebSocketServer({ port: 8080 }).on('connection', handleSocket);
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export function createWebSocketHandler(bridge, options = {}) {
|
|
30
|
+
const maxConcurrentStreams = options.maxConcurrentStreams ?? 5;
|
|
31
|
+
const heartbeatMs = options.heartbeatMs ?? 30000;
|
|
32
|
+
return (socket) => {
|
|
33
|
+
const activeStreams = new Map();
|
|
34
|
+
const sendMessage = (message) => {
|
|
35
|
+
try {
|
|
36
|
+
socket.send(JSON.stringify(message));
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
options.onError?.(error instanceof Error ? error : new Error(String(error)));
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
let heartbeat;
|
|
43
|
+
if (heartbeatMs > 0) {
|
|
44
|
+
heartbeat = setInterval(() => sendMessage({ type: 'ping' }), heartbeatMs);
|
|
45
|
+
if (typeof heartbeat === 'object' && 'unref' in heartbeat) {
|
|
46
|
+
heartbeat.unref();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const cleanup = () => {
|
|
50
|
+
if (heartbeat) {
|
|
51
|
+
clearInterval(heartbeat);
|
|
52
|
+
}
|
|
53
|
+
for (const controller of activeStreams.values()) {
|
|
54
|
+
controller.abort();
|
|
55
|
+
}
|
|
56
|
+
activeStreams.clear();
|
|
57
|
+
};
|
|
58
|
+
const runChat = async (id, request) => {
|
|
59
|
+
if (activeStreams.size >= maxConcurrentStreams) {
|
|
60
|
+
sendMessage({
|
|
61
|
+
type: 'error',
|
|
62
|
+
id,
|
|
63
|
+
error: { message: `Too many concurrent streams (max ${maxConcurrentStreams})` },
|
|
64
|
+
});
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const controller = new AbortController();
|
|
68
|
+
activeStreams.set(id, controller);
|
|
69
|
+
sendMessage({ type: 'start', id });
|
|
70
|
+
try {
|
|
71
|
+
const stream = bridge.chatStream(request, { signal: controller.signal });
|
|
72
|
+
for await (const chunk of stream) {
|
|
73
|
+
if (controller.signal.aborted) {
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
sendMessage({ type: 'chunk', id, chunk });
|
|
77
|
+
}
|
|
78
|
+
if (!controller.signal.aborted) {
|
|
79
|
+
sendMessage({ type: 'done', id });
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
if (!controller.signal.aborted) {
|
|
84
|
+
sendMessage({
|
|
85
|
+
type: 'error',
|
|
86
|
+
id,
|
|
87
|
+
error: { message: error instanceof Error ? error.message : String(error) },
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
finally {
|
|
92
|
+
activeStreams.delete(id);
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
const onMessage = (raw) => {
|
|
96
|
+
let parsed;
|
|
97
|
+
try {
|
|
98
|
+
const text = typeof raw === 'string'
|
|
99
|
+
? raw
|
|
100
|
+
: raw instanceof Uint8Array
|
|
101
|
+
? new TextDecoder().decode(raw)
|
|
102
|
+
: String(raw);
|
|
103
|
+
parsed = JSON.parse(text);
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
sendMessage({ type: 'error', id: null, error: { message: 'Malformed JSON message' } });
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
switch (parsed.type) {
|
|
110
|
+
case 'chat':
|
|
111
|
+
if (!parsed.id || parsed.request === undefined) {
|
|
112
|
+
sendMessage({
|
|
113
|
+
type: 'error',
|
|
114
|
+
id: parsed.id ?? null,
|
|
115
|
+
error: { message: "'chat' requires 'id' and 'request'" },
|
|
116
|
+
});
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
void runChat(parsed.id, parsed.request);
|
|
120
|
+
break;
|
|
121
|
+
case 'cancel':
|
|
122
|
+
activeStreams.get(parsed.id)?.abort();
|
|
123
|
+
activeStreams.delete(parsed.id);
|
|
124
|
+
break;
|
|
125
|
+
case 'pong':
|
|
126
|
+
break;
|
|
127
|
+
default:
|
|
128
|
+
sendMessage({
|
|
129
|
+
type: 'error',
|
|
130
|
+
id: null,
|
|
131
|
+
error: {
|
|
132
|
+
message: `Unknown message type: ${String(parsed.type)}`,
|
|
133
|
+
},
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
// Support both listener styles; extract data from DOM MessageEvent
|
|
138
|
+
if (socket.on) {
|
|
139
|
+
socket.on('message', (data) => onMessage(data));
|
|
140
|
+
socket.on('close', cleanup);
|
|
141
|
+
socket.on('error', cleanup);
|
|
142
|
+
}
|
|
143
|
+
else if (socket.addEventListener) {
|
|
144
|
+
socket.addEventListener('message', (event) => onMessage(event.data ?? event));
|
|
145
|
+
socket.addEventListener('close', cleanup);
|
|
146
|
+
socket.addEventListener('error', cleanup);
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Attach the handler to a `ws`-style server's connection event.
|
|
152
|
+
*/
|
|
153
|
+
export function attachWebSocketServer(server, bridge, options) {
|
|
154
|
+
server.on('connection', createWebSocketHandler(bridge, options));
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/websocket/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebSocket Streaming
|
|
3
|
+
*
|
|
4
|
+
* Transport-agnostic WebSocket handler for real-time AI chat. Zero-dependency
|
|
5
|
+
* by design: instead of bundling a WebSocket implementation, it accepts any
|
|
6
|
+
* socket satisfying the structural {@link WebSocketLike} interface — Node
|
|
7
|
+
* `ws` sockets, `Deno.upgradeWebSocket` sockets, Bun sockets, or browser
|
|
8
|
+
* WebSockets all qualify.
|
|
9
|
+
*
|
|
10
|
+
* Wire protocol (JSON text frames):
|
|
11
|
+
* - client → server: `{ type: 'chat', id, request }`, `{ type: 'cancel', id }`
|
|
12
|
+
* - server → client: `{ type: 'start' | 'chunk' | 'done' | 'error', id, ... }`
|
|
13
|
+
* plus periodic `{ type: 'ping' }` heartbeats
|
|
14
|
+
*
|
|
15
|
+
* @module
|
|
16
|
+
*/
|
|
17
|
+
import type { Bridge } from 'ai.matey.core';
|
|
18
|
+
/**
|
|
19
|
+
* Structural WebSocket interface (satisfied by ws, Deno, Bun, browsers).
|
|
20
|
+
*/
|
|
21
|
+
export interface WebSocketLike {
|
|
22
|
+
send(data: string): void;
|
|
23
|
+
close(code?: number, reason?: string): void;
|
|
24
|
+
/** DOM-style listener registration. */
|
|
25
|
+
addEventListener?(type: 'message' | 'close' | 'error', listener: (event: unknown) => void): void;
|
|
26
|
+
/** Node ws-style listener registration. */
|
|
27
|
+
on?(type: 'message' | 'close' | 'error', listener: (...args: unknown[]) => void): void;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Client → server messages.
|
|
31
|
+
*/
|
|
32
|
+
export type WebSocketClientMessage = {
|
|
33
|
+
type: 'chat';
|
|
34
|
+
id: string;
|
|
35
|
+
request: unknown;
|
|
36
|
+
} | {
|
|
37
|
+
type: 'cancel';
|
|
38
|
+
id: string;
|
|
39
|
+
} | {
|
|
40
|
+
type: 'pong';
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Server → client messages.
|
|
44
|
+
*/
|
|
45
|
+
export type WebSocketServerMessage = {
|
|
46
|
+
type: 'start';
|
|
47
|
+
id: string;
|
|
48
|
+
} | {
|
|
49
|
+
type: 'chunk';
|
|
50
|
+
id: string;
|
|
51
|
+
chunk: unknown;
|
|
52
|
+
} | {
|
|
53
|
+
type: 'done';
|
|
54
|
+
id: string;
|
|
55
|
+
} | {
|
|
56
|
+
type: 'error';
|
|
57
|
+
id: string | null;
|
|
58
|
+
error: {
|
|
59
|
+
message: string;
|
|
60
|
+
code?: string;
|
|
61
|
+
};
|
|
62
|
+
} | {
|
|
63
|
+
type: 'ping';
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Options for the WebSocket handler.
|
|
67
|
+
*/
|
|
68
|
+
export interface WebSocketHandlerOptions {
|
|
69
|
+
/** Maximum concurrent streams per connection. @default 5 */
|
|
70
|
+
maxConcurrentStreams?: number;
|
|
71
|
+
/** Heartbeat interval in milliseconds (0 disables). @default 30000 */
|
|
72
|
+
heartbeatMs?: number;
|
|
73
|
+
/** Error observability hook. */
|
|
74
|
+
onError?: (error: Error) => void;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Create a per-connection handler streaming chat over a WebSocket.
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```typescript
|
|
81
|
+
* import { WebSocketServer } from 'ws';
|
|
82
|
+
* import { createWebSocketHandler } from 'ai.matey.http/websocket';
|
|
83
|
+
*
|
|
84
|
+
* const handleSocket = createWebSocketHandler(bridge);
|
|
85
|
+
* new WebSocketServer({ port: 8080 }).on('connection', handleSocket);
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
export declare function createWebSocketHandler(bridge: Bridge, options?: WebSocketHandlerOptions): (socket: WebSocketLike) => void;
|
|
89
|
+
/**
|
|
90
|
+
* Attach the handler to a `ws`-style server's connection event.
|
|
91
|
+
*/
|
|
92
|
+
export declare function attachWebSocketServer(server: {
|
|
93
|
+
on(event: 'connection', listener: (socket: WebSocketLike) => void): void;
|
|
94
|
+
}, bridge: Bridge, options?: WebSocketHandlerOptions): void;
|
|
95
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/websocket/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAE5C;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5C,uCAAuC;IACvC,gBAAgB,CAAC,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,GAAG,OAAO,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI,CAAC;IACjG,2CAA2C;IAC3C,EAAE,CAAC,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,GAAG,OAAO,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,GAAG,IAAI,CAAC;CACxF;AAED;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAC9B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GAC9C;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAErB;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAC9B;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC7B;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GAC7C;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC5B;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,KAAK,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GAC/E;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAErB;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,4DAA4D;IAC5D,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAE9B,sEAAsE;IACtE,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,gCAAgC;IAChC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,uBAA4B,GACpC,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,CAmIjC;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE;IAAE,EAAE,CAAC,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,GAAG,IAAI,CAAA;CAAE,EACpF,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,uBAAuB,GAChC,IAAI,CAEN"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai.matey.http",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "HTTP framework adapters for AI Matey - Universal AI Adapter System",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/cjs/index.js",
|
|
@@ -76,6 +76,16 @@
|
|
|
76
76
|
"types": "./dist/types/deno/index.d.ts",
|
|
77
77
|
"default": "./dist/cjs/deno/index.js"
|
|
78
78
|
}
|
|
79
|
+
},
|
|
80
|
+
"./websocket": {
|
|
81
|
+
"import": {
|
|
82
|
+
"types": "./dist/types/websocket/index.d.ts",
|
|
83
|
+
"default": "./dist/esm/websocket/index.js"
|
|
84
|
+
},
|
|
85
|
+
"require": {
|
|
86
|
+
"types": "./dist/types/websocket/index.d.ts",
|
|
87
|
+
"default": "./dist/cjs/websocket/index.js"
|
|
88
|
+
}
|
|
79
89
|
}
|
|
80
90
|
},
|
|
81
91
|
"files": [
|