@nats-kit/rpc 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.
Files changed (96) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/LICENSE +21 -0
  3. package/README.md +94 -0
  4. package/dist/commonjs/client.d.ts +9 -0
  5. package/dist/commonjs/client.d.ts.map +1 -0
  6. package/dist/commonjs/client.js +307 -0
  7. package/dist/commonjs/client.js.map +1 -0
  8. package/dist/commonjs/contract.d.ts +59 -0
  9. package/dist/commonjs/contract.d.ts.map +1 -0
  10. package/dist/commonjs/contract.js +56 -0
  11. package/dist/commonjs/contract.js.map +1 -0
  12. package/dist/commonjs/errors.d.ts +58 -0
  13. package/dist/commonjs/errors.d.ts.map +1 -0
  14. package/dist/commonjs/errors.js +74 -0
  15. package/dist/commonjs/errors.js.map +1 -0
  16. package/dist/commonjs/eslint/index.d.ts +22 -0
  17. package/dist/commonjs/eslint/index.d.ts.map +1 -0
  18. package/dist/commonjs/eslint/index.js +33 -0
  19. package/dist/commonjs/eslint/index.js.map +1 -0
  20. package/dist/commonjs/events.d.ts +55 -0
  21. package/dist/commonjs/events.d.ts.map +1 -0
  22. package/dist/commonjs/events.js +82 -0
  23. package/dist/commonjs/events.js.map +1 -0
  24. package/dist/commonjs/headers.d.ts +53 -0
  25. package/dist/commonjs/headers.d.ts.map +1 -0
  26. package/dist/commonjs/headers.js +116 -0
  27. package/dist/commonjs/headers.js.map +1 -0
  28. package/dist/commonjs/index.d.ts +15 -0
  29. package/dist/commonjs/index.d.ts.map +1 -0
  30. package/dist/commonjs/index.js +61 -0
  31. package/dist/commonjs/index.js.map +1 -0
  32. package/dist/commonjs/kv.d.ts +13 -0
  33. package/dist/commonjs/kv.d.ts.map +1 -0
  34. package/dist/commonjs/kv.js +23 -0
  35. package/dist/commonjs/kv.js.map +1 -0
  36. package/dist/commonjs/package.json +4 -0
  37. package/dist/commonjs/server.d.ts +45 -0
  38. package/dist/commonjs/server.d.ts.map +1 -0
  39. package/dist/commonjs/server.js +433 -0
  40. package/dist/commonjs/server.js.map +1 -0
  41. package/dist/commonjs/types.d.ts +100 -0
  42. package/dist/commonjs/types.d.ts.map +1 -0
  43. package/dist/commonjs/types.js +3 -0
  44. package/dist/commonjs/types.js.map +1 -0
  45. package/dist/esm/client.d.ts +9 -0
  46. package/dist/esm/client.d.ts.map +1 -0
  47. package/dist/esm/client.js +304 -0
  48. package/dist/esm/client.js.map +1 -0
  49. package/dist/esm/contract.d.ts +59 -0
  50. package/dist/esm/contract.d.ts.map +1 -0
  51. package/dist/esm/contract.js +48 -0
  52. package/dist/esm/contract.js.map +1 -0
  53. package/dist/esm/errors.d.ts +58 -0
  54. package/dist/esm/errors.d.ts.map +1 -0
  55. package/dist/esm/errors.js +67 -0
  56. package/dist/esm/errors.js.map +1 -0
  57. package/dist/esm/eslint/index.d.ts +22 -0
  58. package/dist/esm/eslint/index.d.ts.map +1 -0
  59. package/dist/esm/eslint/index.js +30 -0
  60. package/dist/esm/eslint/index.js.map +1 -0
  61. package/dist/esm/events.d.ts +55 -0
  62. package/dist/esm/events.d.ts.map +1 -0
  63. package/dist/esm/events.js +77 -0
  64. package/dist/esm/events.js.map +1 -0
  65. package/dist/esm/headers.d.ts +53 -0
  66. package/dist/esm/headers.d.ts.map +1 -0
  67. package/dist/esm/headers.js +108 -0
  68. package/dist/esm/headers.js.map +1 -0
  69. package/dist/esm/index.d.ts +15 -0
  70. package/dist/esm/index.d.ts.map +1 -0
  71. package/dist/esm/index.js +25 -0
  72. package/dist/esm/index.js.map +1 -0
  73. package/dist/esm/kv.d.ts +13 -0
  74. package/dist/esm/kv.d.ts.map +1 -0
  75. package/dist/esm/kv.js +20 -0
  76. package/dist/esm/kv.js.map +1 -0
  77. package/dist/esm/package.json +4 -0
  78. package/dist/esm/server.d.ts +45 -0
  79. package/dist/esm/server.d.ts.map +1 -0
  80. package/dist/esm/server.js +426 -0
  81. package/dist/esm/server.js.map +1 -0
  82. package/dist/esm/types.d.ts +100 -0
  83. package/dist/esm/types.d.ts.map +1 -0
  84. package/dist/esm/types.js +2 -0
  85. package/dist/esm/types.js.map +1 -0
  86. package/package.json +103 -0
  87. package/src/client.ts +377 -0
  88. package/src/contract.ts +105 -0
  89. package/src/errors.ts +100 -0
  90. package/src/eslint/index.ts +30 -0
  91. package/src/events.ts +139 -0
  92. package/src/headers.ts +147 -0
  93. package/src/index.ts +76 -0
  94. package/src/kv.ts +33 -0
  95. package/src/server.ts +500 -0
  96. package/src/types.ts +119 -0
@@ -0,0 +1,426 @@
1
+ import { Svcm } from "@nats-io/services";
2
+ import { nuid } from "@nats-io/nuid";
3
+ import { headers as buildMsgHdrs, noopTelemetry, } from "@nats-kit/core";
4
+ import { groupSubject, methodSubject, serviceName, } from "./contract.js";
5
+ import { isRpcError, STATUS_BY_SERVICE_CODE } from "./errors.js";
6
+ import { CONTENT_TYPE_JSON, HEADER_CONTENT_TYPE, parseRequestHeaders } from "./headers.js";
7
+ const DEFAULT_REBUILD_DELAY_MS = 1000;
8
+ /** Build a successful `RpcResult`. */
9
+ export function ok(result) {
10
+ return { ok: true, result };
11
+ }
12
+ /** Build a domain-error `RpcResult`. */
13
+ export function fail(code, message, details) {
14
+ return { ok: false, error: { code, message, details } };
15
+ }
16
+ function encodeEnvelope(value) {
17
+ return new TextEncoder().encode(JSON.stringify(value));
18
+ }
19
+ function jsonResponseHeaders() {
20
+ const h = buildMsgHdrs();
21
+ h.set(HEADER_CONTENT_TYPE, CONTENT_TYPE_JSON);
22
+ return h;
23
+ }
24
+ /**
25
+ * Build the `ServiceHandler` for one contract method — dispatch order fixed
26
+ * by design §2.4 / wire spec §4.5.
27
+ *
28
+ * The library's own synchronous try/catch around `handler(err, msg)` (see
29
+ * `ServiceImpl.setupHandler`) cannot observe an `async` handler's rejection,
30
+ * so it never counts our service errors toward `num_errors` — we build every
31
+ * response (success, domain error, service error) explicitly instead of
32
+ * throwing, which is what lets a 400/403 carry a JSON `details` body. This is
33
+ * a documented deviation from `nats micro stats` incrementing on our service
34
+ * errors; see the package README.
35
+ *
36
+ * Exported for unit tests (mock `ServiceMsg` + assert the dispatch order) and
37
+ * for advanced embedding over a transport other than `@nats-io/services`'
38
+ * `ServiceHandler`. Not part of the documented public API surface.
39
+ */
40
+ export function buildEndpointHandler(contract, methodName, options, drainSignal) {
41
+ const rawMethodDef = contract.methods[methodName];
42
+ if (!rawMethodDef) {
43
+ throw new Error(`createRpcServer: contract has no method "${methodName}"`);
44
+ }
45
+ const methodDef = rawMethodDef;
46
+ // The generic `RpcHandlers<C>` mapping is only meaningful at the contract
47
+ // author's call site; this dispatcher is generic over an arbitrary method
48
+ // name, so it deals in `unknown` and lets zod re-establish the real types.
49
+ const handler = options.handlers[methodName];
50
+ const authorize = options.authorize;
51
+ const logger = options.logger;
52
+ const telemetry = options.telemetry ?? noopTelemetry;
53
+ const subject = methodSubject(contract, methodName);
54
+ return (err, msg) => {
55
+ if (err)
56
+ return; // subscription-level error: the library is already closing the service.
57
+ void dispatch(msg).catch((dispatchErr) => {
58
+ logger?.error({ err: dispatchErr, subject }, "RPC dispatch crashed unexpectedly");
59
+ try {
60
+ msg.respondError(500, "internal error");
61
+ }
62
+ catch {
63
+ // best-effort — the connection may already be gone.
64
+ }
65
+ });
66
+ };
67
+ async function dispatch(msg) {
68
+ const start = Date.now();
69
+ let outcome = "ok";
70
+ let requestId = "unknown";
71
+ let responded = false;
72
+ const respond = (data) => {
73
+ responded = true;
74
+ msg.respond(data, { headers: jsonResponseHeaders() });
75
+ };
76
+ const respondError = (code, description, data) => {
77
+ responded = true;
78
+ if (data) {
79
+ msg.respondError(code, description, data, { headers: jsonResponseHeaders() });
80
+ }
81
+ else {
82
+ msg.respondError(code, description);
83
+ }
84
+ };
85
+ let deadlineTimer;
86
+ try {
87
+ if (drainSignal.aborted) {
88
+ respondError(503, "shutting down");
89
+ outcome = "service-error";
90
+ return;
91
+ }
92
+ // 1. header parse.
93
+ const parsed = parseRequestHeaders(msg.headers);
94
+ if (!parsed.ok) {
95
+ respondError(400, parsed.message);
96
+ outcome = "service-error";
97
+ return;
98
+ }
99
+ const { value: h } = parsed;
100
+ requestId = h.requestId;
101
+ if (h.callerKind === "user" && !h.callerId) {
102
+ respondError(401, "user caller requires Nk-Caller-Id");
103
+ outcome = "service-error";
104
+ return;
105
+ }
106
+ // 2. deadline check — already past ⇒ 503, handler never invoked.
107
+ if (h.deadlineMs !== undefined && h.deadlineMs <= Date.now()) {
108
+ respondError(503, "deadline already passed");
109
+ outcome = "service-error";
110
+ return;
111
+ }
112
+ // 3. requiredRoles.
113
+ const requiredRoles = methodDef.requiredRoles ?? [];
114
+ const missingRole = requiredRoles.find((role) => !h.roles.includes(role));
115
+ if (missingRole) {
116
+ respondError(403, `missing role: ${missingRole}`);
117
+ outcome = "service-error";
118
+ return;
119
+ }
120
+ // Contract/implementation skew: the endpoint exists (there's a
121
+ // subscription) but no handler is bound for it — wire spec §4.5's 404.
122
+ // A genuinely unknown method never reaches here at all: no endpoint
123
+ // means no subscription, so the caller sees no-responders instead.
124
+ if (typeof handler !== "function") {
125
+ respondError(404, "unknown method");
126
+ outcome = "service-error";
127
+ return;
128
+ }
129
+ // Build the deadline/drain-combined abort signal for the handler.
130
+ const signals = [drainSignal];
131
+ if (h.deadlineMs !== undefined) {
132
+ const deadlineController = new AbortController();
133
+ deadlineTimer = setTimeout(() => deadlineController.abort(), Math.max(0, h.deadlineMs - Date.now()));
134
+ signals.push(deadlineController.signal);
135
+ }
136
+ const handlerSignal = AbortSignal.any(signals);
137
+ const ctx = {
138
+ caller: { kind: h.callerKind, id: h.callerId, roles: h.roles },
139
+ requestId: h.requestId,
140
+ signal: handlerSignal,
141
+ headers: msg.headers,
142
+ subject: msg.subject,
143
+ method: methodName,
144
+ deadlineMs: h.deadlineMs,
145
+ traceparent: h.traceparent,
146
+ };
147
+ // Body parsing gets its own try: `msg.json()` throws on non-UTF-8/
148
+ // non-JSON bodies, and that failure must never be mistaken for a
149
+ // handler crash (500) — it's a client mistake (400).
150
+ let body;
151
+ try {
152
+ body = msg.json();
153
+ }
154
+ catch (bodyErr) {
155
+ respondError(400, "malformed request body", encodeEnvelope({
156
+ details: { message: bodyErr instanceof Error ? bodyErr.message : String(bodyErr) },
157
+ }));
158
+ outcome = "service-error";
159
+ return;
160
+ }
161
+ // 4. input schema parse.
162
+ const parsedInput = methodDef.input.safeParse(body);
163
+ if (!parsedInput.success) {
164
+ respondError(400, "input validation failed", encodeEnvelope({ details: { issues: parsedInput.error.issues } }));
165
+ outcome = "service-error";
166
+ return;
167
+ }
168
+ // 5. authorize hook.
169
+ if (authorize) {
170
+ try {
171
+ await authorize(ctx, methodName);
172
+ }
173
+ catch (authErr) {
174
+ if (isRpcError(authErr)) {
175
+ const status = STATUS_BY_SERVICE_CODE[authErr.code] ?? 500;
176
+ respondError(status, authErr.message);
177
+ }
178
+ else {
179
+ respondError(500, "authorization hook threw");
180
+ }
181
+ outcome = "service-error";
182
+ return;
183
+ }
184
+ }
185
+ // 6. handler, 7. output schema parse — share a catch: any throw here
186
+ // (handler rejection, or an unexpected throw while validating output)
187
+ // is a server bug, never a client mistake, so it always maps to 500.
188
+ try {
189
+ const result = (await handler(parsedInput.data, ctx));
190
+ if (!result.ok) {
191
+ outcome = "domain-error";
192
+ respond(encodeEnvelope({ ok: false, error: result.error }));
193
+ return;
194
+ }
195
+ const parsedOutput = methodDef.output.safeParse(result.result);
196
+ if (!parsedOutput.success) {
197
+ respondError(500, "handler returned a value the output schema rejects");
198
+ outcome = "service-error";
199
+ return;
200
+ }
201
+ // Wire spec §4.3: a method with no output sends `"result": null`
202
+ // explicitly (never an omitted key) — `parsedOutput.data` is
203
+ // `undefined` for `z.void()`/`z.undefined()`, which `JSON.stringify`
204
+ // would otherwise drop from the object entirely.
205
+ respond(encodeEnvelope({ ok: true, result: parsedOutput.data ?? null }));
206
+ }
207
+ catch (handlerErr) {
208
+ outcome = "service-error";
209
+ // Never leak the real error message on the wire — it's server-internal
210
+ // detail, not something the caller should see or parse. Logged instead.
211
+ logger?.error({ err: handlerErr, requestId, subject }, "RPC handler threw");
212
+ // `responded` guards against a second response when the throw came
213
+ // from `respond()` itself (already sent) rather than the handler.
214
+ if (!responded)
215
+ respondError(500, "internal error");
216
+ }
217
+ }
218
+ catch (unexpectedErr) {
219
+ // Defensive net: anything that slipped past the wrapped sections
220
+ // above. `responded` guards against answering the same request twice.
221
+ outcome = "service-error";
222
+ if (!responded) {
223
+ try {
224
+ respondError(500, "internal error");
225
+ }
226
+ catch {
227
+ logger?.error({ err: unexpectedErr, subject }, "failed to respond with error");
228
+ }
229
+ }
230
+ }
231
+ finally {
232
+ if (deadlineTimer)
233
+ clearTimeout(deadlineTimer);
234
+ const durationMs = Date.now() - start;
235
+ logger?.debug?.({ subject, requestId, outcome, durationMs }, "RPC request handled");
236
+ telemetry.onRpcHandled?.(subject, outcome, durationMs);
237
+ }
238
+ }
239
+ }
240
+ /** Resolve on the next `onReconnect()` emission, on abort, or on completion (mirrors core's internal helper). */
241
+ function waitForReconnectOrAbort(nats, signal) {
242
+ if (signal.aborted)
243
+ return Promise.resolve("aborted");
244
+ return new Promise((resolve) => {
245
+ let settled = false;
246
+ // Holder object (not a reassigned `let`) so `settle` can unsubscribe even
247
+ // when the reconnect observable is a COMPLETED subject that signals
248
+ // synchronously during `.subscribe()` below — i.e. before the subscribe
249
+ // call itself has returned. Mirrors the core's internal helper.
250
+ const holder = {};
251
+ const settle = (outcome) => {
252
+ if (settled)
253
+ return;
254
+ settled = true;
255
+ signal.removeEventListener("abort", onAbort);
256
+ holder.sub?.unsubscribe();
257
+ resolve(outcome);
258
+ };
259
+ const onAbort = () => settle("aborted");
260
+ signal.addEventListener("abort", onAbort);
261
+ holder.sub = nats.onReconnect().subscribe({
262
+ next: () => settle("reconnect"),
263
+ complete: () => settle("completed"),
264
+ error: () => settle("completed"),
265
+ });
266
+ });
267
+ }
268
+ function abortableSleep(ms, signal) {
269
+ return new Promise((resolve) => {
270
+ if (signal.aborted) {
271
+ resolve();
272
+ return;
273
+ }
274
+ const onAbort = () => {
275
+ clearTimeout(timer);
276
+ resolve();
277
+ };
278
+ const timer = setTimeout(() => {
279
+ signal.removeEventListener("abort", onAbort);
280
+ resolve();
281
+ }, ms);
282
+ signal.addEventListener("abort", onAbort, { once: true });
283
+ });
284
+ }
285
+ function abortPromise(signal) {
286
+ if (signal.aborted)
287
+ return Promise.resolve();
288
+ return new Promise((resolve) => {
289
+ signal.addEventListener("abort", () => resolve(), { once: true });
290
+ });
291
+ }
292
+ /**
293
+ * True for the synchronous config errors `Svcm.add` throws (wrapped in a
294
+ * rejected promise) for an invalid `name`/`queue` or a non-SemVer `version`
295
+ * (design §3). These never become valid by retrying, so the supervisor must
296
+ * reject `handle.done` instead of looping — as opposed to a genuine
297
+ * connection error, which is retried after the next reconnect.
298
+ */
299
+ function isTerminalConfigError(err) {
300
+ if (!(err instanceof Error))
301
+ return false;
302
+ return (/ name required$/.test(err.message) ||
303
+ /^invalid .* name - /.test(err.message) ||
304
+ /is not a semver value$/.test(err.message));
305
+ }
306
+ /**
307
+ * Start the reconnect supervisor loop for one contract (design §3).
308
+ *
309
+ * `Svcm`-backed `Service` instances permanently stop on connection loss with
310
+ * no restart path, so this loop rebuilds the service every time it stops
311
+ * (healthy stop or connection loss) until `signal` aborts.
312
+ */
313
+ export function createRpcServer(contract, options) {
314
+ const { nats, signal, logger } = options;
315
+ const telemetry = options.telemetry ?? noopTelemetry;
316
+ const rebuildDelayMs = options.rebuildDelayMs ?? DEFAULT_REBUILD_DELAY_MS;
317
+ const queue = options.queue;
318
+ // Combined abort: external `signal` OR an internal stop() call. Draining
319
+ // starts the instant either fires, per design §3's shutdown notes.
320
+ const internalController = new AbortController();
321
+ const drainSignal = AbortSignal.any([signal, internalController.signal]);
322
+ let currentServiceId;
323
+ let resolveDone;
324
+ let rejectDone;
325
+ const done = new Promise((resolve, reject) => {
326
+ resolveDone = resolve;
327
+ rejectDone = reject;
328
+ });
329
+ // `rejectDone(fatal)` (below) can fire before any consumer has awaited or
330
+ // `.catch()`-ed `done` (e.g. a terminal config error surfacing on the very
331
+ // first tick) — without this, that's an unhandled rejection. This dummy
332
+ // handler keeps the rejection observed without swallowing it: `done`
333
+ // itself still rejects for every real consumer that awaits it.
334
+ void done.catch(() => undefined);
335
+ // Registered once — every iteration reuses the same settled/pending
336
+ // promise instead of adding a fresh `drainSignal` abort listener per
337
+ // rebuild.
338
+ const drainAborted = abortPromise(drainSignal).then(() => null);
339
+ void (async () => {
340
+ try {
341
+ while (!drainSignal.aborted) {
342
+ let svc;
343
+ try {
344
+ // Racing against `drainAborted` (rather than a bare `await`) makes
345
+ // shutdown responsive even while `waitForReady()` is still
346
+ // pending — the eventual settlement is otherwise never observed,
347
+ // so it's `.catch()`-ed to avoid an unhandled rejection.
348
+ const readyPromise = nats.waitForReady();
349
+ await Promise.race([readyPromise, drainAborted]);
350
+ if (drainSignal.aborted) {
351
+ void readyPromise.catch(() => undefined);
352
+ break;
353
+ }
354
+ const nc = nats.getConnection();
355
+ svc = await new Svcm(nc).add({
356
+ name: serviceName(contract),
357
+ version: contract.version,
358
+ description: contract.description,
359
+ metadata: contract.metadata,
360
+ queue,
361
+ });
362
+ currentServiceId = svc.info().id;
363
+ try {
364
+ const group = svc.addGroup(groupSubject(contract), queue);
365
+ for (const methodName of Object.keys(contract.methods)) {
366
+ group.addEndpoint(methodName, buildEndpointHandler(contract, methodName, options, drainSignal));
367
+ }
368
+ }
369
+ catch (groupErr) {
370
+ // The service was created but addGroup/addEndpoint failed
371
+ // (e.g. a bad method name) — stop it before retrying so we
372
+ // don't leak a half-wired service.
373
+ await svc.stop().catch(() => undefined);
374
+ throw groupErr;
375
+ }
376
+ if (drainSignal.aborted) {
377
+ await svc.stop();
378
+ break;
379
+ }
380
+ telemetry.onRpcServiceStarted?.(svc.info().name, svc.info().id);
381
+ logger?.log({ name: svc.info().name, id: svc.info().id }, "RPC service started");
382
+ const stopErr = await Promise.race([svc.stopped.then((e) => e), drainAborted]);
383
+ await svc.stop();
384
+ telemetry.onRpcServiceStopped?.(svc.info().name, svc.info().id, stopErr ?? undefined);
385
+ logger?.log({ name: svc.info().name, id: svc.info().id }, "RPC service stopped — will rebuild");
386
+ }
387
+ catch (error) {
388
+ if (drainSignal.aborted)
389
+ break;
390
+ // Config errors (bad name/queue, non-SemVer version) never become
391
+ // valid by retrying while the connection is healthy — reject
392
+ // `done` and stop the loop instead of waiting on a reconnect that
393
+ // will never fix anything.
394
+ if (isTerminalConfigError(error))
395
+ throw error;
396
+ logger?.error({ err: error }, "RPC service failed to start — will retry on reconnect");
397
+ const waitOutcome = await waitForReconnectOrAbort(nats, drainSignal);
398
+ if (waitOutcome === "completed")
399
+ break;
400
+ continue;
401
+ }
402
+ if (drainSignal.aborted)
403
+ break;
404
+ await abortableSleep(rebuildDelayMs, drainSignal);
405
+ }
406
+ resolveDone();
407
+ }
408
+ catch (fatal) {
409
+ rejectDone(fatal);
410
+ }
411
+ })();
412
+ return {
413
+ done,
414
+ serviceId: () => currentServiceId,
415
+ stop: async () => {
416
+ internalController.abort();
417
+ await done;
418
+ },
419
+ };
420
+ }
421
+ // Re-export request id helper for consumers who want to mint one manually
422
+ // (e.g. logging correlation before a call is made).
423
+ export function newRequestId() {
424
+ return nuid.next();
425
+ }
426
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,100 @@
1
+ import { type z } from "zod";
2
+ import { type MsgHdrs, type NatsConnectionLike, type NatsLogger, type NatsTelemetry } from "@nats-kit/core";
3
+ import { type ServiceContract } from "./contract.js";
4
+ /** Caller identity stamped on a request (§2.2, §4.2). */
5
+ export interface RpcCaller {
6
+ kind: "user" | "service";
7
+ /** Keycloak subject for `user`; service name for `service`. */
8
+ id?: string;
9
+ roles?: readonly string[];
10
+ }
11
+ export interface RpcCallOptions {
12
+ timeoutMs?: number;
13
+ /** Overrides the client-level caller for this call. */
14
+ caller?: RpcCaller;
15
+ /** Supply your own correlation id; otherwise a nuid is minted. */
16
+ requestId?: string;
17
+ /** Sets `Nk-Deadline`. Defaults to now + effective timeout. */
18
+ deadlineMs?: number;
19
+ /** Extra `Nk-*` headers. `Nats-*` and reserved names are rejected. */
20
+ headers?: Record<string, string>;
21
+ /** W3C traceparent to propagate. */
22
+ traceparent?: string;
23
+ /** Cancels the in-flight request locally. */
24
+ signal?: AbortSignal;
25
+ }
26
+ /** One typed method per contract method, resolving with `z.output` or rejecting with `RpcError`. */
27
+ export type RpcClient<C extends ServiceContract> = {
28
+ [K in keyof C["methods"]]: (input: z.input<C["methods"][K]["input"]>, opts?: RpcCallOptions) => Promise<z.output<C["methods"][K]["output"]>>;
29
+ };
30
+ export interface RpcClientOptions {
31
+ nats: NatsConnectionLike;
32
+ /** Default caller identity stamped on every call. */
33
+ caller?: RpcCaller;
34
+ /** Fallback when a method declares no `timeoutMs`. Default 10_000. */
35
+ defaultTimeoutMs?: number;
36
+ /**
37
+ * Validate responses against `output` before resolving. Default TRUE.
38
+ * Per-client opt-out only (no per-call override).
39
+ */
40
+ validateResponses?: boolean;
41
+ logger?: NatsLogger;
42
+ telemetry?: NatsTelemetry;
43
+ }
44
+ /** Per-request context handed to a server handler (§2.4). */
45
+ export interface RpcContext {
46
+ caller: Required<Pick<RpcCaller, "kind">> & RpcCaller & {
47
+ roles: readonly string[];
48
+ };
49
+ requestId: string;
50
+ /** Aborts at `Nk-Deadline`, or when the server drains. */
51
+ signal: AbortSignal;
52
+ headers: MsgHdrs;
53
+ subject: string;
54
+ method: string;
55
+ deadlineMs?: number;
56
+ traceparent?: string;
57
+ }
58
+ export type RpcResult<T, E extends string> = {
59
+ ok: true;
60
+ result: T;
61
+ } | {
62
+ ok: false;
63
+ error: {
64
+ code: E;
65
+ message: string;
66
+ details?: unknown;
67
+ };
68
+ };
69
+ export type RpcHandlers<C extends ServiceContract> = {
70
+ [K in keyof C["methods"]]: (input: z.output<C["methods"][K]["input"]>, ctx: RpcContext) => Promise<RpcResult<z.input<C["methods"][K]["output"]>, C["methods"][K]["errors"] extends readonly (infer E extends string)[] ? E : never>>;
71
+ };
72
+ /**
73
+ * Optional escape hatch for policy the contract's `requiredRoles` cannot
74
+ * express. Runs AFTER the library's `requiredRoles` check and before
75
+ * dispatch. Return normally to allow; throw an `RpcError` to deny.
76
+ */
77
+ export type RpcAuthorize<C extends ServiceContract> = (ctx: Omit<RpcContext, "signal">, method: keyof C["methods"] & string) => void | Promise<void>;
78
+ export interface RpcServerOptions<C extends ServiceContract> {
79
+ nats: NatsConnectionLike;
80
+ handlers: RpcHandlers<C>;
81
+ /** Optional second gate, run only after `requiredRoles` passed. */
82
+ authorize?: RpcAuthorize<C>;
83
+ /** Queue group. Defaults to micro's `"q"`; `""` disables load balancing. */
84
+ queue?: string;
85
+ /** Stops the supervisor and drains. */
86
+ signal: AbortSignal;
87
+ /** Delay before rebuilding after the service stops. Default 1000. */
88
+ rebuildDelayMs?: number;
89
+ logger?: NatsLogger;
90
+ telemetry?: NatsTelemetry;
91
+ }
92
+ export interface RpcServerHandle {
93
+ /** Resolves when the supervisor loop has exited. */
94
+ readonly done: Promise<void>;
95
+ /** Current micro service id (nuid). Changes on every rebuild. */
96
+ serviceId(): string | undefined;
97
+ /** Aborts the server's signal (if it owns one) and awaits `done`. */
98
+ stop(): Promise<void>;
99
+ }
100
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,103 @@
1
+ {
2
+ "name": "@nats-kit/rpc",
3
+ "version": "0.3.0",
4
+ "description": "Typed request/reply RPC over NATS: zod contracts, an ADR-32 micro server/client, and a reconnect supervisor.",
5
+ "keywords": [
6
+ "nats",
7
+ "rpc",
8
+ "micro",
9
+ "adr-32",
10
+ "zod",
11
+ "messaging",
12
+ "microservices"
13
+ ],
14
+ "license": "MIT",
15
+ "homepage": "https://github.com/anatoly-lab/nats-kit/tree/main/packages/nats-kit-rpc#readme",
16
+ "bugs": {
17
+ "url": "https://github.com/anatoly-lab/nats-kit/issues"
18
+ },
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "git+https://github.com/anatoly-lab/nats-kit.git",
22
+ "directory": "packages/nats-kit-rpc"
23
+ },
24
+ "publishConfig": {
25
+ "access": "public"
26
+ },
27
+ "engines": {
28
+ "node": ">=22.0.0"
29
+ },
30
+ "sideEffects": false,
31
+ "files": [
32
+ "dist",
33
+ "src",
34
+ "!src/**/*.test.ts",
35
+ "!src/**/__tests__/**",
36
+ "!src/package.json",
37
+ "README.md",
38
+ "CHANGELOG.md",
39
+ "LICENSE"
40
+ ],
41
+ "tshy": {
42
+ "selfLink": false,
43
+ "exports": {
44
+ ".": "./src/index.ts",
45
+ "./eslint": "./src/eslint/index.ts",
46
+ "./package.json": "./package.json"
47
+ },
48
+ "project": "./tsconfig.build.json",
49
+ "exclude": [
50
+ "src/**/*.test.ts",
51
+ "src/**/__tests__/**"
52
+ ]
53
+ },
54
+ "dependencies": {
55
+ "@nats-io/nats-core": "^3.4.0",
56
+ "@nats-io/nuid": "^3.0.0",
57
+ "@nats-io/services": "^3.4.0",
58
+ "zod": "^4.4.3",
59
+ "@nats-kit/core": "^0.3.0"
60
+ },
61
+ "devDependencies": {
62
+ "@types/node": "26.0.1",
63
+ "rimraf": "6.1.3",
64
+ "testcontainers": "12.0.4",
65
+ "typescript": "6.0.3",
66
+ "vitest": "4.1.9"
67
+ },
68
+ "type": "module",
69
+ "exports": {
70
+ ".": {
71
+ "import": {
72
+ "types": "./dist/esm/index.d.ts",
73
+ "default": "./dist/esm/index.js"
74
+ },
75
+ "require": {
76
+ "types": "./dist/commonjs/index.d.ts",
77
+ "default": "./dist/commonjs/index.js"
78
+ }
79
+ },
80
+ "./eslint": {
81
+ "import": {
82
+ "types": "./dist/esm/eslint/index.d.ts",
83
+ "default": "./dist/esm/eslint/index.js"
84
+ },
85
+ "require": {
86
+ "types": "./dist/commonjs/eslint/index.d.ts",
87
+ "default": "./dist/commonjs/eslint/index.js"
88
+ }
89
+ },
90
+ "./package.json": "./package.json"
91
+ },
92
+ "main": "./dist/commonjs/index.js",
93
+ "types": "./dist/commonjs/index.d.ts",
94
+ "module": "./dist/esm/index.js",
95
+ "scripts": {
96
+ "build": "tshy",
97
+ "typecheck": "tsc -p tsconfig.json --noEmit",
98
+ "lint": "eslint .",
99
+ "test": "vitest run",
100
+ "test:integration": "vitest run --config vitest.integration.config.ts",
101
+ "clean": "rimraf dist .turbo .tshy-build .tsbuildinfo *.tsbuildinfo"
102
+ }
103
+ }