@soulcraft/sdk 1.0.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/dist/client/index.d.ts +62 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +60 -0
- package/dist/client/index.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/modules/ai/index.d.ts +55 -0
- package/dist/modules/ai/index.d.ts.map +1 -0
- package/dist/modules/ai/index.js +263 -0
- package/dist/modules/ai/index.js.map +1 -0
- package/dist/modules/ai/types.d.ts +216 -0
- package/dist/modules/ai/types.d.ts.map +1 -0
- package/dist/modules/ai/types.js +30 -0
- package/dist/modules/ai/types.js.map +1 -0
- package/dist/modules/auth/backchannel.d.ts +85 -0
- package/dist/modules/auth/backchannel.d.ts.map +1 -0
- package/dist/modules/auth/backchannel.js +168 -0
- package/dist/modules/auth/backchannel.js.map +1 -0
- package/dist/modules/auth/config.d.ts +122 -0
- package/dist/modules/auth/config.d.ts.map +1 -0
- package/dist/modules/auth/config.js +158 -0
- package/dist/modules/auth/config.js.map +1 -0
- package/dist/modules/auth/middleware.d.ts +146 -0
- package/dist/modules/auth/middleware.d.ts.map +1 -0
- package/dist/modules/auth/middleware.js +204 -0
- package/dist/modules/auth/middleware.js.map +1 -0
- package/dist/modules/auth/types.d.ts +162 -0
- package/dist/modules/auth/types.d.ts.map +1 -0
- package/dist/modules/auth/types.js +14 -0
- package/dist/modules/auth/types.js.map +1 -0
- package/dist/modules/billing/types.d.ts +7 -0
- package/dist/modules/billing/types.d.ts.map +1 -0
- package/dist/modules/billing/types.js +7 -0
- package/dist/modules/billing/types.js.map +1 -0
- package/dist/modules/brainy/auth.d.ts +104 -0
- package/dist/modules/brainy/auth.d.ts.map +1 -0
- package/dist/modules/brainy/auth.js +144 -0
- package/dist/modules/brainy/auth.js.map +1 -0
- package/dist/modules/brainy/errors.d.ts +118 -0
- package/dist/modules/brainy/errors.d.ts.map +1 -0
- package/dist/modules/brainy/errors.js +142 -0
- package/dist/modules/brainy/errors.js.map +1 -0
- package/dist/modules/brainy/events.d.ts +63 -0
- package/dist/modules/brainy/events.d.ts.map +1 -0
- package/dist/modules/brainy/events.js +14 -0
- package/dist/modules/brainy/events.js.map +1 -0
- package/dist/modules/brainy/proxy.d.ts +48 -0
- package/dist/modules/brainy/proxy.d.ts.map +1 -0
- package/dist/modules/brainy/proxy.js +95 -0
- package/dist/modules/brainy/proxy.js.map +1 -0
- package/dist/modules/brainy/types.d.ts +83 -0
- package/dist/modules/brainy/types.d.ts.map +1 -0
- package/dist/modules/brainy/types.js +21 -0
- package/dist/modules/brainy/types.js.map +1 -0
- package/dist/modules/events/index.d.ts +41 -0
- package/dist/modules/events/index.d.ts.map +1 -0
- package/dist/modules/events/index.js +53 -0
- package/dist/modules/events/index.js.map +1 -0
- package/dist/modules/events/types.d.ts +129 -0
- package/dist/modules/events/types.d.ts.map +1 -0
- package/dist/modules/events/types.js +32 -0
- package/dist/modules/events/types.js.map +1 -0
- package/dist/modules/formats/types.d.ts +7 -0
- package/dist/modules/formats/types.d.ts.map +1 -0
- package/dist/modules/formats/types.js +7 -0
- package/dist/modules/formats/types.js.map +1 -0
- package/dist/modules/hall/types.d.ts +56 -0
- package/dist/modules/hall/types.d.ts.map +1 -0
- package/dist/modules/hall/types.js +16 -0
- package/dist/modules/hall/types.js.map +1 -0
- package/dist/modules/kits/types.d.ts +7 -0
- package/dist/modules/kits/types.d.ts.map +1 -0
- package/dist/modules/kits/types.js +7 -0
- package/dist/modules/kits/types.js.map +1 -0
- package/dist/modules/license/types.d.ts +7 -0
- package/dist/modules/license/types.d.ts.map +1 -0
- package/dist/modules/license/types.js +7 -0
- package/dist/modules/license/types.js.map +1 -0
- package/dist/modules/notifications/types.d.ts +7 -0
- package/dist/modules/notifications/types.d.ts.map +1 -0
- package/dist/modules/notifications/types.js +7 -0
- package/dist/modules/notifications/types.js.map +1 -0
- package/dist/modules/skills/index.d.ts +60 -0
- package/dist/modules/skills/index.d.ts.map +1 -0
- package/dist/modules/skills/index.js +253 -0
- package/dist/modules/skills/index.js.map +1 -0
- package/dist/modules/skills/types.d.ts +127 -0
- package/dist/modules/skills/types.d.ts.map +1 -0
- package/dist/modules/skills/types.js +23 -0
- package/dist/modules/skills/types.js.map +1 -0
- package/dist/modules/versions/types.d.ts +31 -0
- package/dist/modules/versions/types.d.ts.map +1 -0
- package/dist/modules/versions/types.js +9 -0
- package/dist/modules/versions/types.js.map +1 -0
- package/dist/modules/vfs/types.d.ts +26 -0
- package/dist/modules/vfs/types.d.ts.map +1 -0
- package/dist/modules/vfs/types.js +11 -0
- package/dist/modules/vfs/types.js.map +1 -0
- package/dist/server/create-sdk.d.ts +70 -0
- package/dist/server/create-sdk.d.ts.map +1 -0
- package/dist/server/create-sdk.js +125 -0
- package/dist/server/create-sdk.js.map +1 -0
- package/dist/server/hall-handlers.d.ts +195 -0
- package/dist/server/hall-handlers.d.ts.map +1 -0
- package/dist/server/hall-handlers.js +239 -0
- package/dist/server/hall-handlers.js.map +1 -0
- package/dist/server/handlers.d.ts +216 -0
- package/dist/server/handlers.d.ts.map +1 -0
- package/dist/server/handlers.js +214 -0
- package/dist/server/handlers.js.map +1 -0
- package/dist/server/index.d.ts +52 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +50 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/instance-pool.d.ts +299 -0
- package/dist/server/instance-pool.d.ts.map +1 -0
- package/dist/server/instance-pool.js +359 -0
- package/dist/server/instance-pool.js.map +1 -0
- package/dist/transports/http.d.ts +86 -0
- package/dist/transports/http.d.ts.map +1 -0
- package/dist/transports/http.js +134 -0
- package/dist/transports/http.js.map +1 -0
- package/dist/transports/local.d.ts +76 -0
- package/dist/transports/local.d.ts.map +1 -0
- package/dist/transports/local.js +101 -0
- package/dist/transports/local.js.map +1 -0
- package/dist/transports/sse.d.ts +99 -0
- package/dist/transports/sse.d.ts.map +1 -0
- package/dist/transports/sse.js +192 -0
- package/dist/transports/sse.js.map +1 -0
- package/dist/transports/transport.d.ts +68 -0
- package/dist/transports/transport.d.ts.map +1 -0
- package/dist/transports/transport.js +14 -0
- package/dist/transports/transport.js.map +1 -0
- package/dist/transports/ws.d.ts +135 -0
- package/dist/transports/ws.d.ts.map +1 -0
- package/dist/transports/ws.js +331 -0
- package/dist/transports/ws.js.map +1 -0
- package/dist/types.d.ts +152 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/docs/ADR-001-sdk-design.md +282 -0
- package/docs/IMPLEMENTATION-PLAN.md +708 -0
- package/docs/USAGE.md +646 -0
- package/docs/kit-sdk-guide.md +474 -0
- package/package.json +61 -0
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module transports/sse
|
|
3
|
+
* @description SSE transport — receives server-pushed platform events via EventSource.
|
|
4
|
+
*
|
|
5
|
+
* Connects to `{baseUrl}/api/workspace/events` using the browser's native
|
|
6
|
+
* `EventSource` API and dispatches typed {@link BrainyChangeEvent} objects to
|
|
7
|
+
* registered listeners.
|
|
8
|
+
*
|
|
9
|
+
* This transport is **receive-only** — it does not support outbound RPC calls.
|
|
10
|
+
* Use it alongside the HTTP transport when you need live VFS and entity change
|
|
11
|
+
* events without the overhead of a persistent WebSocket.
|
|
12
|
+
*
|
|
13
|
+
* `EventSource` handles reconnection natively: the browser automatically
|
|
14
|
+
* retries after a connection drop using the server-sent `retry:` interval.
|
|
15
|
+
* Additional manual backoff is applied on error events to prevent thundering herd.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* import { createSDK } from '@soulcraft/sdk/client'
|
|
20
|
+
*
|
|
21
|
+
* const sdk = createSDK({
|
|
22
|
+
* mode: 'client',
|
|
23
|
+
* product: 'venue',
|
|
24
|
+
* transport: 'sse',
|
|
25
|
+
* baseUrl: 'https://venue.soulcraft.com',
|
|
26
|
+
* })
|
|
27
|
+
*
|
|
28
|
+
* // Subscribe to live data changes (VFS writes, entity mutations, etc.)
|
|
29
|
+
* sdk.brainy.onDataChange((event) => {
|
|
30
|
+
* if (event.event === 'update' && event.entity?.nounType === 'Booking') {
|
|
31
|
+
* refreshBookingList()
|
|
32
|
+
* }
|
|
33
|
+
* })
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
import { SDKError } from '../modules/brainy/errors.js';
|
|
37
|
+
/**
|
|
38
|
+
* Transport that receives platform change events via Server-Sent Events.
|
|
39
|
+
*
|
|
40
|
+
* RPC calls are not supported — `call()` throws immediately. For outbound
|
|
41
|
+
* operations pair this transport with an `HttpTransport` instance.
|
|
42
|
+
*
|
|
43
|
+
* Connect by calling `connect()`. The underlying `EventSource` will reconnect
|
|
44
|
+
* automatically on drop; `close()` permanently disconnects and prevents reconnects.
|
|
45
|
+
*/
|
|
46
|
+
export class SseTransport {
|
|
47
|
+
eventsUrl;
|
|
48
|
+
workspaceId;
|
|
49
|
+
eventSource = null;
|
|
50
|
+
changeListeners = [];
|
|
51
|
+
closed = false;
|
|
52
|
+
reconnectAttempts = 0;
|
|
53
|
+
maxReconnectAttempts = 10;
|
|
54
|
+
reconnectTimer = null;
|
|
55
|
+
/**
|
|
56
|
+
* @param baseUrl - Base URL of the SDK server, e.g. `'https://venue.soulcraft.com'`.
|
|
57
|
+
* @param workspaceId - Optional workspace ID added as `?workspaceId=` query param.
|
|
58
|
+
*/
|
|
59
|
+
constructor(baseUrl, workspaceId) {
|
|
60
|
+
const base = baseUrl.replace(/\/$/, '');
|
|
61
|
+
const params = workspaceId ? `?workspaceId=${encodeURIComponent(workspaceId)}` : '';
|
|
62
|
+
this.eventsUrl = `${base}/api/workspace/events${params}`;
|
|
63
|
+
this.workspaceId = workspaceId;
|
|
64
|
+
}
|
|
65
|
+
// ── SDKTransport interface ───────────────────────────────────────────────
|
|
66
|
+
/**
|
|
67
|
+
* Not supported — SSE is a server-push-only transport.
|
|
68
|
+
*
|
|
69
|
+
* @throws {@link SDKError} always.
|
|
70
|
+
*/
|
|
71
|
+
async call(_method, _args) {
|
|
72
|
+
throw new SDKError('SSE_NO_RPC', 'SDK/sse: SSE transport does not support RPC calls. Use HttpTransport for outbound operations.');
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Registers a listener for real-time change events received from the server.
|
|
76
|
+
*
|
|
77
|
+
* @param handler - Called with each {@link BrainyChangeEvent} as it arrives.
|
|
78
|
+
*/
|
|
79
|
+
onEvent(handler) {
|
|
80
|
+
this.changeListeners.push(handler);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Removes a previously registered change event listener.
|
|
84
|
+
*
|
|
85
|
+
* @param handler - The same function reference passed to {@link SseTransport.onEvent}.
|
|
86
|
+
*/
|
|
87
|
+
offEvent(handler) {
|
|
88
|
+
const idx = this.changeListeners.indexOf(handler);
|
|
89
|
+
if (idx !== -1)
|
|
90
|
+
this.changeListeners.splice(idx, 1);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Returns `true` when the `EventSource` is in the `OPEN` state.
|
|
94
|
+
*/
|
|
95
|
+
isAlive() {
|
|
96
|
+
return this.eventSource?.readyState === EventSource.OPEN;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Permanently closes the SSE connection and cancels any pending reconnect.
|
|
100
|
+
*/
|
|
101
|
+
async close() {
|
|
102
|
+
this.closed = true;
|
|
103
|
+
this._clearReconnectTimer();
|
|
104
|
+
if (this.eventSource) {
|
|
105
|
+
this.eventSource.close();
|
|
106
|
+
this.eventSource = null;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// ── Connection management ────────────────────────────────────────────────
|
|
110
|
+
/**
|
|
111
|
+
* Opens the SSE connection to the server.
|
|
112
|
+
*
|
|
113
|
+
* Idempotent — calling `connect()` when already connected is a no-op.
|
|
114
|
+
* The SDK's `createSDK` client factory calls this automatically when
|
|
115
|
+
* `sdk.connect()` is invoked.
|
|
116
|
+
*/
|
|
117
|
+
connect() {
|
|
118
|
+
if (this.closed) {
|
|
119
|
+
throw new Error('SseTransport: cannot reconnect after close()');
|
|
120
|
+
}
|
|
121
|
+
if (this.eventSource)
|
|
122
|
+
return;
|
|
123
|
+
this._openEventSource();
|
|
124
|
+
}
|
|
125
|
+
// ── Internal ─────────────────────────────────────────────────────────────
|
|
126
|
+
_openEventSource() {
|
|
127
|
+
if (this.closed)
|
|
128
|
+
return;
|
|
129
|
+
try {
|
|
130
|
+
this.eventSource = new EventSource(this.eventsUrl);
|
|
131
|
+
this.eventSource.onopen = () => {
|
|
132
|
+
this.reconnectAttempts = 0;
|
|
133
|
+
};
|
|
134
|
+
this.eventSource.onmessage = (event) => {
|
|
135
|
+
if (!event.data || event.data.trim().startsWith(':'))
|
|
136
|
+
return;
|
|
137
|
+
let data;
|
|
138
|
+
try {
|
|
139
|
+
data = JSON.parse(event.data);
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
if (data.type === 'connected')
|
|
145
|
+
return; // Internal handshake — no listener notify
|
|
146
|
+
if (data.type === 'change') {
|
|
147
|
+
const changeEvent = data;
|
|
148
|
+
for (const listener of this.changeListeners) {
|
|
149
|
+
try {
|
|
150
|
+
listener(changeEvent);
|
|
151
|
+
}
|
|
152
|
+
catch (err) {
|
|
153
|
+
console.error('[SDK/sse] Change listener threw', err);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
this.eventSource.onerror = () => {
|
|
159
|
+
if (this.closed)
|
|
160
|
+
return;
|
|
161
|
+
this.eventSource?.close();
|
|
162
|
+
this.eventSource = null;
|
|
163
|
+
this._scheduleReconnect();
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
catch (err) {
|
|
167
|
+
console.error('[SDK/sse] Failed to create EventSource', err);
|
|
168
|
+
this._scheduleReconnect();
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
_scheduleReconnect() {
|
|
172
|
+
if (this.closed || this.reconnectAttempts >= this.maxReconnectAttempts) {
|
|
173
|
+
if (this.reconnectAttempts >= this.maxReconnectAttempts) {
|
|
174
|
+
console.error(`[SDK/sse] Max reconnect attempts reached for ${this.eventsUrl}`);
|
|
175
|
+
}
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
const backoffMs = Math.min(1000 * Math.pow(2, this.reconnectAttempts), 30_000);
|
|
179
|
+
this.reconnectAttempts++;
|
|
180
|
+
this.reconnectTimer = setTimeout(() => {
|
|
181
|
+
this.reconnectTimer = null;
|
|
182
|
+
this._openEventSource();
|
|
183
|
+
}, backoffMs);
|
|
184
|
+
}
|
|
185
|
+
_clearReconnectTimer() {
|
|
186
|
+
if (this.reconnectTimer) {
|
|
187
|
+
clearTimeout(this.reconnectTimer);
|
|
188
|
+
this.reconnectTimer = null;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=sse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sse.js","sourceRoot":"","sources":["../../src/transports/sse.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module transports/transport
|
|
3
|
+
* @description Transport interface contract for @soulcraft/sdk.
|
|
4
|
+
*
|
|
5
|
+
* All four transports (local, HTTP, WebSocket, SSE) implement this interface.
|
|
6
|
+
* The `sdk.brainy` Proxy wraps the chosen transport and maps any property access
|
|
7
|
+
* chain + function call into a `transport.call()` dispatch, so a consumer calling
|
|
8
|
+
* `sdk.brainy.vfs.readdir('/')` triggers `transport.call('vfs.readdir', ['/'])`.
|
|
9
|
+
*
|
|
10
|
+
* The SSE transport is receive-only (no `call()` — it throws if called) and is
|
|
11
|
+
* used alongside the HTTP transport to receive live VFS and entity change events.
|
|
12
|
+
*/
|
|
13
|
+
import type { BrainyChangeEvent } from '../modules/brainy/events.js';
|
|
14
|
+
/**
|
|
15
|
+
* Contract that every SDK transport must fulfil.
|
|
16
|
+
*
|
|
17
|
+
* Implementations are responsible for:
|
|
18
|
+
* - Serializing method names and arguments to the wire format
|
|
19
|
+
* - Deserializing results or errors from the server
|
|
20
|
+
* - Maintaining connection state (WebSocket transport)
|
|
21
|
+
* - Emitting change events (WebSocket and SSE transports; no-op for others)
|
|
22
|
+
*/
|
|
23
|
+
export interface SDKTransport {
|
|
24
|
+
/**
|
|
25
|
+
* Dispatch an RPC call for the given Brainy method.
|
|
26
|
+
*
|
|
27
|
+
* @param method - Dot-separated Brainy method name (e.g. `'vfs.readdir'`, `'find'`).
|
|
28
|
+
* @param args - Positional arguments to forward to the Brainy method.
|
|
29
|
+
* @returns A Promise resolving to whatever the Brainy method returns.
|
|
30
|
+
* @throws {@link SDKDisconnectedError} if not connected.
|
|
31
|
+
* @throws {@link SDKTimeoutError} if the call exceeds the timeout.
|
|
32
|
+
* @throws {@link SDKRpcError} if the server returns an error response.
|
|
33
|
+
*/
|
|
34
|
+
call(method: string, args: unknown[]): Promise<unknown>;
|
|
35
|
+
/**
|
|
36
|
+
* Register a listener for real-time change events.
|
|
37
|
+
*
|
|
38
|
+
* For transports that do not support push (HTTP, local), this is a no-op.
|
|
39
|
+
* WebSocket and SSE transports dispatch events as they arrive.
|
|
40
|
+
*
|
|
41
|
+
* @param handler - Called with each {@link BrainyChangeEvent}.
|
|
42
|
+
*/
|
|
43
|
+
onEvent(handler: (event: BrainyChangeEvent) => void): void;
|
|
44
|
+
/**
|
|
45
|
+
* Remove a previously registered change event listener.
|
|
46
|
+
*
|
|
47
|
+
* @param handler - The same function reference passed to {@link SDKTransport.onEvent}.
|
|
48
|
+
*/
|
|
49
|
+
offEvent(handler: (event: BrainyChangeEvent) => void): void;
|
|
50
|
+
/**
|
|
51
|
+
* Returns `true` if the transport has an active, usable connection.
|
|
52
|
+
*
|
|
53
|
+
* Local transport always returns `true`.
|
|
54
|
+
* HTTP transport always returns `true` (errors surface per-call).
|
|
55
|
+
* WebSocket transport returns `true` only when connected.
|
|
56
|
+
* SSE transport returns `true` when the EventSource is open.
|
|
57
|
+
*/
|
|
58
|
+
isAlive(): boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Gracefully shut down this transport, releasing any open connections.
|
|
61
|
+
*
|
|
62
|
+
* Local and HTTP transports are no-ops.
|
|
63
|
+
* WebSocket closes with code 1000.
|
|
64
|
+
* SSE closes the EventSource.
|
|
65
|
+
*/
|
|
66
|
+
close(): Promise<void>;
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=transport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/transports/transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAA;AAEpE;;;;;;;;GAQG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;;;;;;OASG;IACH,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAEvD;;;;;;;OAOG;IACH,OAAO,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,GAAG,IAAI,CAAA;IAE1D;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,GAAG,IAAI,CAAA;IAE3D;;;;;;;OAOG;IACH,OAAO,IAAI,OAAO,CAAA;IAElB;;;;;;OAMG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACvB"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module transports/transport
|
|
3
|
+
* @description Transport interface contract for @soulcraft/sdk.
|
|
4
|
+
*
|
|
5
|
+
* All four transports (local, HTTP, WebSocket, SSE) implement this interface.
|
|
6
|
+
* The `sdk.brainy` Proxy wraps the chosen transport and maps any property access
|
|
7
|
+
* chain + function call into a `transport.call()` dispatch, so a consumer calling
|
|
8
|
+
* `sdk.brainy.vfs.readdir('/')` triggers `transport.call('vfs.readdir', ['/'])`.
|
|
9
|
+
*
|
|
10
|
+
* The SSE transport is receive-only (no `call()` — it throws if called) and is
|
|
11
|
+
* used alongside the HTTP transport to receive live VFS and entity change events.
|
|
12
|
+
*/
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=transport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../../src/transports/transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module transports/ws
|
|
3
|
+
* @description WebSocket transport — bidirectional MessagePack RPC with push change events.
|
|
4
|
+
*
|
|
5
|
+
* ## Wire protocol
|
|
6
|
+
*
|
|
7
|
+
* **Client → Server** (binary MessagePack):
|
|
8
|
+
* ```
|
|
9
|
+
* { id: string, method: string, args: unknown[] }
|
|
10
|
+
* ```
|
|
11
|
+
*
|
|
12
|
+
* **Server → Client** (binary MessagePack), three message kinds:
|
|
13
|
+
* 1. Ready handshake: `{ type: 'ready', scope: string }`
|
|
14
|
+
* 2. RPC response: `{ id: string, result?: unknown, error?: { code, message } }`
|
|
15
|
+
* 3. Change push: `{ type: 'change', event: 'add'|'update'|'delete'|'relate'|'unrelate', entity?, relation? }`
|
|
16
|
+
*
|
|
17
|
+
* ## Auth
|
|
18
|
+
*
|
|
19
|
+
* The capability token is sent as `Authorization: Bearer <token>` on the WebSocket
|
|
20
|
+
* upgrade request (Bun-specific header injection). The optional `scope` parameter
|
|
21
|
+
* is passed as a query string so Venue can select the correct tenant brain.
|
|
22
|
+
*
|
|
23
|
+
* ## Reconnection
|
|
24
|
+
*
|
|
25
|
+
* On unexpected disconnection the transport automatically retries with exponential
|
|
26
|
+
* backoff (1 s → 30 s cap) up to `maxReconnectAttempts` times.
|
|
27
|
+
* Auth failures (close codes 4001, 4003) do not retry.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* import { createSDK } from '@soulcraft/sdk/client'
|
|
32
|
+
*
|
|
33
|
+
* const sdk = createSDK({
|
|
34
|
+
* mode: 'client',
|
|
35
|
+
* product: 'workshop',
|
|
36
|
+
* transport: 'ws',
|
|
37
|
+
* baseUrl: 'wss://venue.soulcraft.com',
|
|
38
|
+
* auth: { token: capabilityToken },
|
|
39
|
+
* })
|
|
40
|
+
*
|
|
41
|
+
* await sdk.connect()
|
|
42
|
+
*
|
|
43
|
+
* sdk.brainy.onDataChange((event) => {
|
|
44
|
+
* console.log('Remote change:', event.event, event.entity?.nounType)
|
|
45
|
+
* })
|
|
46
|
+
*
|
|
47
|
+
* const results = await sdk.brainy.find({ query: 'inventory' })
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
import type { SDKTransport } from './transport.js';
|
|
51
|
+
import type { BrainyChangeEvent } from '../modules/brainy/events.js';
|
|
52
|
+
/**
|
|
53
|
+
* Transport that communicates via MessagePack-encoded WebSocket RPC.
|
|
54
|
+
*
|
|
55
|
+
* Supports both outbound RPC calls and inbound change push events from the
|
|
56
|
+
* server. Auto-reconnects on unexpected disconnection.
|
|
57
|
+
*
|
|
58
|
+
* Call `connect()` once before making any `call()` invocations. The SDK's
|
|
59
|
+
* `createSDK` client factory calls this automatically when `sdk.connect()` is
|
|
60
|
+
* invoked.
|
|
61
|
+
*/
|
|
62
|
+
export declare class WsTransport implements SDKTransport {
|
|
63
|
+
private ws;
|
|
64
|
+
private readonly wsUrl;
|
|
65
|
+
private readonly authToken;
|
|
66
|
+
private readonly scope;
|
|
67
|
+
private readonly timeoutMs;
|
|
68
|
+
private readonly maxReconnectAttempts;
|
|
69
|
+
private readonly pending;
|
|
70
|
+
private nextId;
|
|
71
|
+
private connectionState;
|
|
72
|
+
private readonly changeListeners;
|
|
73
|
+
private connectResolve;
|
|
74
|
+
private connectReject;
|
|
75
|
+
private reconnectAttempts;
|
|
76
|
+
private reconnectTimer;
|
|
77
|
+
/**
|
|
78
|
+
* @param wsUrl - WebSocket endpoint URL, e.g. `'wss://venue.soulcraft.com/api/brainy/ws'`.
|
|
79
|
+
* @param authToken - HMAC-signed capability token from `createCapabilityToken()`.
|
|
80
|
+
* @param scope - Optional scope (tenant slug) passed as `?scope=` on connect.
|
|
81
|
+
* @param timeoutMs - RPC call timeout in milliseconds. Default: 30 000.
|
|
82
|
+
* @param maxReconnectAttempts - Max reconnect attempts on unexpected disconnect. Default: 10.
|
|
83
|
+
*/
|
|
84
|
+
constructor(wsUrl: string, authToken: string, scope?: string, timeoutMs?: number, maxReconnectAttempts?: number);
|
|
85
|
+
/**
|
|
86
|
+
* Sends a MessagePack-encoded RPC request and awaits the response.
|
|
87
|
+
*
|
|
88
|
+
* @param method - Dot-separated Brainy method name (e.g. `'vfs.readdir'`).
|
|
89
|
+
* @param args - Positional arguments to forward.
|
|
90
|
+
* @returns Whatever the server's Brainy method returns.
|
|
91
|
+
* @throws {@link SDKDisconnectedError} if not connected.
|
|
92
|
+
* @throws {@link SDKTimeoutError} after `timeoutMs` ms.
|
|
93
|
+
* @throws {@link SDKRpcError} if the server reports an error.
|
|
94
|
+
*/
|
|
95
|
+
call(method: string, args: unknown[]): Promise<unknown>;
|
|
96
|
+
/**
|
|
97
|
+
* Registers a listener for real-time change push events from the server.
|
|
98
|
+
*
|
|
99
|
+
* @param handler - Called with each {@link BrainyChangeEvent} as it arrives.
|
|
100
|
+
*/
|
|
101
|
+
onEvent(handler: (event: BrainyChangeEvent) => void): void;
|
|
102
|
+
/**
|
|
103
|
+
* Removes a previously registered change event listener.
|
|
104
|
+
*
|
|
105
|
+
* @param handler - The same function reference passed to {@link WsTransport.onEvent}.
|
|
106
|
+
*/
|
|
107
|
+
offEvent(handler: (event: BrainyChangeEvent) => void): void;
|
|
108
|
+
/**
|
|
109
|
+
* Returns `true` when the WebSocket is in the connected state.
|
|
110
|
+
*/
|
|
111
|
+
isAlive(): boolean;
|
|
112
|
+
/**
|
|
113
|
+
* Closes the WebSocket connection permanently.
|
|
114
|
+
*
|
|
115
|
+
* After `close()`, this transport instance cannot be reconnected.
|
|
116
|
+
* All pending RPC calls are rejected with {@link SDKDisconnectedError}.
|
|
117
|
+
*/
|
|
118
|
+
close(): Promise<void>;
|
|
119
|
+
/**
|
|
120
|
+
* Establishes the WebSocket connection and waits for the server `ready` message.
|
|
121
|
+
*
|
|
122
|
+
* Must be called once before any `call()` invocations. Resolves when the server
|
|
123
|
+
* confirms successful authentication and scope selection. The SDK's `createSDK`
|
|
124
|
+
* client factory exposes this as `sdk.connect()`.
|
|
125
|
+
*
|
|
126
|
+
* @throws Error if authentication fails (close codes 4001 / 4003).
|
|
127
|
+
* @throws Error if no `ready` message arrives within 15 seconds.
|
|
128
|
+
*/
|
|
129
|
+
connect(): Promise<void>;
|
|
130
|
+
private _openSocket;
|
|
131
|
+
private _handleMessage;
|
|
132
|
+
private _handleClose;
|
|
133
|
+
private _rejectAllPending;
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=ws.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ws.d.ts","sourceRoot":"","sources":["../../src/transports/ws.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAClD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAA;AAkDpE;;;;;;;;;GASG;AACH,qBAAa,WAAY,YAAW,YAAY;IAC9C,OAAO,CAAC,EAAE,CAAyB;IACnC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;IAC9B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAQ;IAClC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAoB;IAC1C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAQ;IAClC,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAQ;IAE7C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgC;IACxD,OAAO,CAAC,MAAM,CAAI;IAElB,OAAO,CAAC,eAAe,CAAkC;IACzD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAgD;IAEhF,OAAO,CAAC,cAAc,CAA4B;IAClD,OAAO,CAAC,aAAa,CAAoC;IAEzD,OAAO,CAAC,iBAAiB,CAAI;IAC7B,OAAO,CAAC,cAAc,CAA6C;IAEnE;;;;;;OAMG;gBAED,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,KAAK,CAAC,EAAE,MAAM,EACd,SAAS,SAAS,EAClB,oBAAoB,SAAK;IAW3B;;;;;;;;;OASG;IACG,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IAoB7D;;;;OAIG;IACH,OAAO,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,GAAG,IAAI;IAI1D;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,GAAG,IAAI;IAK3D;;OAEG;IACH,OAAO,IAAI,OAAO;IAIlB;;;;;OAKG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAe5B;;;;;;;;;OASG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IA8B9B,OAAO,CAAC,WAAW;IA2BnB,OAAO,CAAC,cAAc;IAsDtB,OAAO,CAAC,YAAY;IA2DpB,OAAO,CAAC,iBAAiB;CAO1B"}
|