@cortexkit/subc-client 0.3.0 → 0.3.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/dist/auth.d.ts ADDED
@@ -0,0 +1,19 @@
1
+ import type { ConnectionInfo } from "./connection-file.js";
2
+ import { SubcSocket } from "./socket.js";
3
+ export declare const NONCE_LEN = 32;
4
+ export declare const PROOF_LEN = 32;
5
+ export declare const MAX_AUTH_MESSAGE_LEN = 4096;
6
+ export declare const SERVER_PROOF_DOMAIN = "subc-server-v1";
7
+ export declare const CLIENT_AUTH_DOMAIN = "subc-client-v1";
8
+ export declare const DEFAULT_CLIENT_ROLE = "client";
9
+ export declare class AuthError extends Error {
10
+ }
11
+ /** HMAC-SHA256 over domain ‖ client_nonce ‖ server_nonce ‖ daemon_id. */
12
+ export declare function computeProof(key: Uint8Array, domain: string, clientNonce: Uint8Array, serverNonce: Uint8Array, daemonId: Uint8Array): Uint8Array;
13
+ /**
14
+ * Run the client handshake over an already-connected socket. Resolves on
15
+ * success; throws AuthError on any proof/identity mismatch or framing fault.
16
+ * The whole exchange is bounded by `deadlineMs` (epoch ms).
17
+ */
18
+ export declare function authenticateClient(sock: SubcSocket, conn: ConnectionInfo, deadlineMs: number): Promise<void>;
19
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,eAAO,MAAM,SAAS,KAAK,CAAC;AAC5B,eAAO,MAAM,SAAS,KAAK,CAAC;AAC5B,eAAO,MAAM,oBAAoB,OAAO,CAAC;AACzC,eAAO,MAAM,mBAAmB,mBAAmB,CAAC;AACpD,eAAO,MAAM,kBAAkB,mBAAmB,CAAC;AACnD,eAAO,MAAM,mBAAmB,WAAW,CAAC;AAE5C,qBAAa,SAAU,SAAQ,KAAK;CAAG;AAEvC,yEAAyE;AACzE,wBAAgB,YAAY,CAC1B,GAAG,EAAE,UAAU,EACf,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,UAAU,EACvB,WAAW,EAAE,UAAU,EACvB,QAAQ,EAAE,UAAU,GACnB,UAAU,CAOZ;AA2CD;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,cAAc,EACpB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CAwBf"}
package/dist/auth.js ADDED
@@ -0,0 +1,84 @@
1
+ // Port of subc-transport's auth.rs client handshake. The proof construction,
2
+ // domain strings, message framing, and verification order must match the Rust
3
+ // byte-for-byte: a single byte of drift fails authentication outright.
4
+ //
5
+ // Handshake (client side):
6
+ // 1. send ClientHello { client_nonce, role }
7
+ // 2. receive ServerProof { daemon_id, server_nonce, daemon_ver, server_proof }
8
+ // 3. verify server_proof == HMAC(key, "subc-server-v1" ‖ cn ‖ sn ‖ did) (constant-time)
9
+ // and daemon_id == the id from the connection file
10
+ // 4. send ClientAuth { client_auth = HMAC(key, "subc-client-v1" ‖ cn ‖ sn ‖ did) }
11
+ //
12
+ // Each message on the wire is a 4-byte little-endian length prefix followed by
13
+ // the JSON body. Byte arrays (nonces, proofs, ids) serialize as JSON arrays of
14
+ // numbers, matching serde's default for [u8; N].
15
+ import { createHmac, randomBytes, timingSafeEqual } from "node:crypto";
16
+ export const NONCE_LEN = 32;
17
+ export const PROOF_LEN = 32;
18
+ export const MAX_AUTH_MESSAGE_LEN = 4096;
19
+ export const SERVER_PROOF_DOMAIN = "subc-server-v1";
20
+ export const CLIENT_AUTH_DOMAIN = "subc-client-v1";
21
+ export const DEFAULT_CLIENT_ROLE = "client";
22
+ export class AuthError extends Error {
23
+ }
24
+ /** HMAC-SHA256 over domain ‖ client_nonce ‖ server_nonce ‖ daemon_id. */
25
+ export function computeProof(key, domain, clientNonce, serverNonce, daemonId) {
26
+ const mac = createHmac("sha256", Buffer.from(key));
27
+ mac.update(Buffer.from(domain, "utf8"));
28
+ mac.update(Buffer.from(clientNonce));
29
+ mac.update(Buffer.from(serverNonce));
30
+ mac.update(Buffer.from(daemonId));
31
+ return new Uint8Array(mac.digest());
32
+ }
33
+ function constantTimeEq(a, b) {
34
+ if (a.length !== b.length)
35
+ return false;
36
+ return timingSafeEqual(Buffer.from(a), Buffer.from(b));
37
+ }
38
+ async function writeMessage(sock, value, deadlineMs) {
39
+ const json = Buffer.from(JSON.stringify(value), "utf8");
40
+ if (json.length > MAX_AUTH_MESSAGE_LEN) {
41
+ throw new AuthError(`auth message too large: ${json.length} > ${MAX_AUTH_MESSAGE_LEN}`);
42
+ }
43
+ const lenPrefix = new Uint8Array(4);
44
+ new DataView(lenPrefix.buffer).setUint32(0, json.length, true);
45
+ await sock.write(lenPrefix, deadlineMs);
46
+ await sock.write(json, deadlineMs);
47
+ }
48
+ async function readMessage(sock, deadlineMs) {
49
+ const lenBytes = await sock.readExact(4, deadlineMs);
50
+ const len = new DataView(lenBytes.buffer, lenBytes.byteOffset, 4).getUint32(0, true);
51
+ if (len > MAX_AUTH_MESSAGE_LEN) {
52
+ throw new AuthError(`auth message too large: ${len} > ${MAX_AUTH_MESSAGE_LEN}`);
53
+ }
54
+ const body = len === 0 ? new Uint8Array(0) : await sock.readExact(len, deadlineMs);
55
+ try {
56
+ return JSON.parse(Buffer.from(body).toString("utf8"));
57
+ }
58
+ catch (err) {
59
+ throw new AuthError(`auth message JSON decode failed: ${String(err)}`);
60
+ }
61
+ }
62
+ /**
63
+ * Run the client handshake over an already-connected socket. Resolves on
64
+ * success; throws AuthError on any proof/identity mismatch or framing fault.
65
+ * The whole exchange is bounded by `deadlineMs` (epoch ms).
66
+ */
67
+ export async function authenticateClient(sock, conn, deadlineMs) {
68
+ const clientNonce = new Uint8Array(randomBytes(NONCE_LEN));
69
+ await writeMessage(sock, { client_nonce: Array.from(clientNonce), role: DEFAULT_CLIENT_ROLE }, deadlineMs);
70
+ const proof = await readMessage(sock, deadlineMs);
71
+ const serverNonce = Uint8Array.from(proof.server_nonce);
72
+ const daemonId = Uint8Array.from(proof.daemon_id);
73
+ const serverProof = Uint8Array.from(proof.server_proof);
74
+ const expected = computeProof(conn.key, SERVER_PROOF_DOMAIN, clientNonce, serverNonce, daemonId);
75
+ if (!constantTimeEq(expected, serverProof)) {
76
+ throw new AuthError("server proof mismatch — wrong key or impostor daemon");
77
+ }
78
+ if (!constantTimeEq(daemonId, conn.daemonId)) {
79
+ throw new AuthError("daemon id mismatch — connection file points at a different daemon");
80
+ }
81
+ const clientAuth = computeProof(conn.key, CLIENT_AUTH_DOMAIN, clientNonce, serverNonce, daemonId);
82
+ await writeMessage(sock, { client_auth: Array.from(clientAuth) }, deadlineMs);
83
+ }
84
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,265 @@
1
+ import { type ConnectionInfo } from "./connection-file.js";
2
+ import { Priority } from "./envelope.js";
3
+ export declare const SUBC_MODULE_ID_ENV = "SUBC_MODULE_ID";
4
+ export declare const SUBC_LAUNCH_NONCE_ENV = "SUBC_LAUNCH_NONCE";
5
+ export interface BindIdentity {
6
+ project_root: string;
7
+ harness: string;
8
+ session: string;
9
+ }
10
+ export type RouteTarget = {
11
+ kind: "tool_provider";
12
+ module_id: string;
13
+ } | {
14
+ kind: "management_surface";
15
+ module_id: string;
16
+ } | {
17
+ kind: "internal_service";
18
+ module_id: string;
19
+ service_id: string;
20
+ };
21
+ export type ManagedRouteKind = "management_surface" | "tool_provider";
22
+ export interface ConsumerIdentity {
23
+ module_id: string;
24
+ launch_nonce: string;
25
+ }
26
+ export interface RouteOpenOptions {
27
+ /** Optional override for the consumer identity; by default the SUBC_MODULE_ID and SUBC_LAUNCH_NONCE environment variables are used when both are non-empty. Set null to send route.open without consumer_identity. */
28
+ consumerIdentity?: ConsumerIdentity | null;
29
+ }
30
+ export interface CatalogEntry {
31
+ module_id: string;
32
+ roles: unknown[];
33
+ control_ops: string[];
34
+ }
35
+ export interface RequestOptions {
36
+ priority?: Priority;
37
+ timeoutMs?: number;
38
+ /** Called for each interim PUSH / StreamData frame before the terminal reply. */
39
+ onProgress?: (body: Uint8Array) => void;
40
+ }
41
+ export interface ManagedCallOptions extends RequestOptions {
42
+ /** Overrides the per-client identity used for route.open before this call. */
43
+ identity?: BindIdentity;
44
+ /** Defaults to management_surface, matching the store/host management APIs. */
45
+ targetKind?: ManagedRouteKind;
46
+ /** Optional override for the consumer identity; by default the SUBC_MODULE_ID and SUBC_LAUNCH_NONCE environment variables are used when both are non-empty. Set null to send route.open without consumer_identity. */
47
+ consumerIdentity?: ConsumerIdentity | null;
48
+ }
49
+ export interface SubscribeOptions {
50
+ priority?: Priority;
51
+ }
52
+ export interface CloseRouteOptions {
53
+ /**
54
+ * Await in-flight UNARY requests on the route to settle before tearing it down.
55
+ * Subscriptions are always aborted (a held-open stream cannot be drained).
56
+ * Defaults to false: close immediately, aborting everything in flight.
57
+ */
58
+ drain?: boolean;
59
+ /** Consumer identity to use when looking up the route to close; only needed for routes opened with a non-default consumer identity. */
60
+ consumerIdentity?: ConsumerIdentity | null;
61
+ }
62
+ /**
63
+ * Capped exponential reconnect backoff. maxAttempts includes the first immediate
64
+ * reconnect attempt; sleeps happen only between failed transient attempts.
65
+ */
66
+ export interface ReconnectBackoff {
67
+ /** First retry delay. */
68
+ baseMs: number;
69
+ /** Delay ceiling (doubling is capped here). */
70
+ capMs: number;
71
+ /** Max attempts (including the first) before giving up. */
72
+ maxAttempts: number;
73
+ }
74
+ export declare const DEFAULT_RECONNECT_BACKOFF: ReconnectBackoff;
75
+ export type SubcCallErrorKind = "not_sent" | "outcome_unknown" | "terminal";
76
+ /**
77
+ * Managed call failure with send-outcome semantics.
78
+ *
79
+ * `not_sent` is intentionally narrow: the request bytes provably never left the
80
+ * local process (the connection was already closed, or net.Socket.write failed
81
+ * before queuing bytes). Managed call() may retry only this case.
82
+ *
83
+ * `outcome_unknown` is the safe default once bytes have been handed to the local
84
+ * socket. The daemon or module may have received the request before the response
85
+ * was lost, so call() never retries it automatically; the caller must decide
86
+ * whether the operation is idempotent or needs a check-then-act recovery.
87
+ *
88
+ * `terminal` covers protocol Error frames and non-retryable client/setup errors.
89
+ */
90
+ export declare class SubcCallError extends Error {
91
+ readonly kind: SubcCallErrorKind;
92
+ readonly code?: string | undefined;
93
+ readonly cause?: unknown | undefined;
94
+ constructor(kind: SubcCallErrorKind, message: string, code?: string | undefined, cause?: unknown | undefined);
95
+ }
96
+ /**
97
+ * A live subscription to a provider's event stream, riding a single held-open
98
+ * request. `onEvent` fires for each StreamData frame; `closed` resolves when the
99
+ * provider ends the stream (StreamEnd) and rejects on an Error terminal or a route
100
+ * GOODBYE. `unsubscribe` cancels the held-open request so the provider unwinds.
101
+ */
102
+ export interface Subscription {
103
+ /** Cancel the subscription: sends Cancel on the held-open request; idempotent. */
104
+ unsubscribe(): void;
105
+ /** Resolves on StreamEnd; rejects on an Error terminal or route close. */
106
+ readonly closed: Promise<void>;
107
+ }
108
+ export declare class SubcError extends Error {
109
+ readonly code?: string | undefined;
110
+ constructor(message: string, code?: string | undefined);
111
+ }
112
+ export interface ConnectOptions {
113
+ connectionFile: string;
114
+ handshakeTimeoutMs?: number;
115
+ /** Default route identity used by managed call(); can be overridden per call. */
116
+ identity?: BindIdentity;
117
+ /** Default route target kind used by managed call(); defaults to management_surface. */
118
+ targetKind?: ManagedRouteKind;
119
+ /** Backoff for managed reconnect after a connection drop. */
120
+ reconnectBackoff?: ReconnectBackoff;
121
+ /** Injectable sleep for timer-free reconnect tests. */
122
+ sleep?: (ms: number) => Promise<void>;
123
+ /**
124
+ * Hard cap on the timeout-arbitration grace window (see
125
+ * TIMEOUT_ARBITRATION_GRACE_MS). A reply whose bytes are actively arriving when
126
+ * the request deadline fires is given up to this long to finish dispatching
127
+ * before the call settles as a timeout. Bounded and never a deadline extension;
128
+ * exposed mainly so tests can prove the arbitration deterministically.
129
+ */
130
+ timeoutArbitrationGraceMs?: number;
131
+ }
132
+ export declare class SubcClient {
133
+ private sock;
134
+ private currentConn;
135
+ private readonly opts;
136
+ private nextCorr;
137
+ private readonly pending;
138
+ private readonly routes;
139
+ private closedErr;
140
+ private closeStarted;
141
+ private reconnecting;
142
+ private generation;
143
+ private readerActive;
144
+ private constructor();
145
+ get conn(): ConnectionInfo;
146
+ /** Read the connection file, connect, authenticate, and start the read loop. */
147
+ static connect(opts: ConnectOptions): Promise<SubcClient>;
148
+ /** List modules subc knows about (channel-0 catalog.list). */
149
+ catalogList(moduleId?: string): Promise<CatalogEntry[]>;
150
+ /** Open a route to a provider (channel-0 route.open); returns the route channel. */
151
+ routeOpen(target: RouteTarget, identity: BindIdentity, opts?: RouteOpenOptions): Promise<number>;
152
+ /** Send a data-plane request on a route channel and await its terminal reply. */
153
+ request(routeChannel: number, body: unknown, opts?: RequestOptions): Promise<unknown>;
154
+ /**
155
+ * Managed route + request convenience. Opens and caches a route for the module,
156
+ * reconnecting and re-opening cached routes after connection drops.
157
+ */
158
+ call<Response = unknown>(moduleId: string, method: string, params?: unknown, opts?: ManagedCallOptions): Promise<Response>;
159
+ /**
160
+ * Open a held-open event subscription on a route channel. Sends one Request the
161
+ * provider keeps open, delivering each interim StreamData frame to `onEvent`; the
162
+ * returned `closed` settles on the StreamEnd terminal (resolve) or an Error / route
163
+ * GOODBYE (reject). Events ride this held-open request's correlation id — they are
164
+ * never unsolicited, so they are not dropped. Call `unsubscribe()` to cancel.
165
+ */
166
+ subscribe(routeChannel: number, body: unknown, onEvent: (event: Uint8Array) => void, opts?: SubscribeOptions): Subscription;
167
+ /**
168
+ * Tear down ONE managed route (a route opened via `call()`), keyed by its
169
+ * (target, identity). Idempotent and never throws — callers over-call on
170
+ * session-end. The teardown:
171
+ * - flips a tombstone on the cached route and removes it from the cache, so an
172
+ * in-flight `openCachedRoute` for the same key will NOT install its channel
173
+ * (the generation guard: close beats a racing reopen), and a later `call()`
174
+ * opens a fresh route (this is NOT a permanent tombstone);
175
+ * - settles in-flight requests on the channel as RouteClosed (managed requests
176
+ * keep their at-most-once classification: outcome_unknown if already sent,
177
+ * not_sent otherwise; subscriptions always abort);
178
+ * - sends a best-effort route GOODBYE so subc releases the route and notifies
179
+ * the module to free per-session resources.
180
+ * `opts.drain` waits for in-flight UNARY requests to settle before tearing down.
181
+ */
182
+ closeRoute(target: Extract<RouteTarget, {
183
+ kind: ManagedRouteKind;
184
+ }>, identity: BindIdentity, opts?: CloseRouteOptions): Promise<void>;
185
+ /**
186
+ * Tear down ONE route by its channel number — the primitive for callers that
187
+ * opened a route with `routeOpen` directly (e.g. a tool route carrying raw
188
+ * {name, arguments}) and hold the channel themselves. Idempotent, never throws.
189
+ * Settles in-flight requests on the channel as RouteClosed and sends a best-effort
190
+ * route GOODBYE. `opts.drain` awaits in-flight UNARY requests first; subscriptions
191
+ * are always aborted (a held-open stream cannot be drained).
192
+ */
193
+ closeRouteChannel(channel: number, opts?: CloseRouteOptions): Promise<void>;
194
+ close(): void;
195
+ /** Resolve once every in-flight UNARY request on the channel (snapshot at call
196
+ * time) has settled. Subscriptions are excluded — they are aborted, not drained. */
197
+ private drainUnaryOnChannel;
198
+ /** Send a best-effort header-only route GOODBYE for `channel`. One-way: the daemon
199
+ * releases the route and relays a route-gone GOODBYE to the module; no ack. */
200
+ private sendRouteGoodbye;
201
+ private static openConnection;
202
+ private controlRpc;
203
+ private send;
204
+ /**
205
+ * A request-deadline timer has fired. Before settling as a timeout, arbitrate
206
+ * the timer-vs-poll race: a reply may already be in the socket buffer, unread
207
+ * only because the loop was starved. Yield one check phase (setImmediate) so a
208
+ * fully-buffered reply dispatches and wins via settle()'s identity guard; then,
209
+ * only while the reader is actively draining THIS socket (a frame mid-arrival),
210
+ * grant a single hard-capped grace before finally settling. Absent replies
211
+ * still settle right after the check phase. The settle carries the deadline
212
+ * marker so the managed classifier reports deadline-not-drop.
213
+ */
214
+ private arbitrateTimeout;
215
+ private managedRequest;
216
+ private sendManaged;
217
+ private cachedRouteChannel;
218
+ private openCachedRoute;
219
+ private ensureConnectedForManaged;
220
+ private scheduleReconnectAfterDrop;
221
+ private reconnectAfterDrop;
222
+ private reconnectWithRetry;
223
+ private replaceConnection;
224
+ private reopenCachedRoutes;
225
+ private timeoutMessage;
226
+ private routeClosedDuringOpen;
227
+ private readLoop;
228
+ private dispatch;
229
+ /**
230
+ * Settle a pending exactly once. The object-identity guard (the map still
231
+ * holds THIS pending under `key`) is the single-winner primitive: whichever of
232
+ * dispatch, a timeout, fail(), failChannel(), a GOODBYE, or a deferred timeout
233
+ * arbitration reaches it first wins, and every later caller no-ops. This is what
234
+ * makes the deferred-timeout arbitration safe — it cannot double-settle, reject
235
+ * an already-resolved promise, or delete a pending re-created for a later corr.
236
+ * Returns true when this call was the settler.
237
+ */
238
+ private settle;
239
+ private rejectPending;
240
+ private errorFromFrame;
241
+ private failChannel;
242
+ private fail;
243
+ private notSentCallError;
244
+ private outcomeUnknownCallError;
245
+ private terminalCallError;
246
+ private notSentRecoveryError;
247
+ private encode;
248
+ private parseJson;
249
+ }
250
+ export declare function isConsumerReconnectTransient(err: unknown): boolean;
251
+ /**
252
+ * The closed set of route.open rejection codes that mean "the target is
253
+ * momentarily unavailable but the request could succeed on retry" — the target
254
+ * is booting, mid-reload, transiently absent, or the bind relay timed out. A
255
+ * daemon-rejected route.open is provably pre-send (no data frame ever left the
256
+ * client), so these classify as not_sent; the managed path retries them in-place
257
+ * within ROUTE_OPEN_RETRY_DEADLINE_MS. Permanent rejections (bad_consumer_identity,
258
+ * config_divergence, unknown_target, ...) are excluded — they are pre-send but
259
+ * would never succeed, so retrying them would only storm the daemon. Kept
260
+ * byte-identical to subc-client-rs is_retryable_route_open_code for cross-client
261
+ * classification parity.
262
+ */
263
+ export declare function isRetryableRouteOpenCode(code: string | undefined): boolean;
264
+ export declare function connectionFileExists(path: string): Promise<boolean>;
265
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}