service-bridge 1.0.7 → 1.0.8-dev.19

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 (46) hide show
  1. package/README.md +51 -41
  2. package/dist/index.js +579 -33049
  3. package/package.json +13 -2
  4. package/biome.json +0 -28
  5. package/bun.lock +0 -249
  6. package/http/dist/express.d.ts +0 -51
  7. package/http/dist/express.d.ts.map +0 -1
  8. package/http/dist/express.test.d.ts +0 -2
  9. package/http/dist/express.test.d.ts.map +0 -1
  10. package/http/dist/fastify.d.ts +0 -43
  11. package/http/dist/fastify.d.ts.map +0 -1
  12. package/http/dist/fastify.test.d.ts +0 -2
  13. package/http/dist/fastify.test.d.ts.map +0 -1
  14. package/http/dist/index.d.ts +0 -7
  15. package/http/dist/index.d.ts.map +0 -1
  16. package/http/dist/trace.d.ts +0 -19
  17. package/http/dist/trace.d.ts.map +0 -1
  18. package/http/dist/trace.test.d.ts +0 -2
  19. package/http/dist/trace.test.d.ts.map +0 -1
  20. package/http/package.json +0 -49
  21. package/http/src/express.test.ts +0 -125
  22. package/http/src/express.ts +0 -209
  23. package/http/src/fastify.test.ts +0 -142
  24. package/http/src/fastify.ts +0 -159
  25. package/http/src/index.ts +0 -10
  26. package/http/src/sdk-augment.d.ts +0 -11
  27. package/http/src/servicebridge.d.ts +0 -23
  28. package/http/src/trace.test.ts +0 -97
  29. package/http/src/trace.ts +0 -56
  30. package/http/tsconfig.json +0 -17
  31. package/http/tsconfig.test.json +0 -6
  32. package/sdk/dist/generated/servicebridge-package-definition.d.ts +0 -4912
  33. package/sdk/dist/grpc-client.d.ts +0 -344
  34. package/sdk/dist/grpc-client.test.d.ts +0 -1
  35. package/sdk/dist/index.d.ts +0 -2
  36. package/sdk/package.json +0 -31
  37. package/sdk/scripts/generate-proto.ts +0 -65
  38. package/sdk/src/generated/servicebridge-package-definition.ts +0 -5423
  39. package/sdk/src/grpc-client.d.ts +0 -332
  40. package/sdk/src/grpc-client.d.ts.map +0 -1
  41. package/sdk/src/grpc-client.test.ts +0 -422
  42. package/sdk/src/grpc-client.ts +0 -3105
  43. package/sdk/src/index.d.ts +0 -3
  44. package/sdk/src/index.d.ts.map +0 -1
  45. package/sdk/src/index.ts +0 -31
  46. package/sdk/tsconfig.json +0 -13
package/README.md CHANGED
@@ -95,7 +95,7 @@ bun add service-bridge
95
95
  import { servicebridge } from "service-bridge";
96
96
 
97
97
  const sb = servicebridge(
98
- process.env.SERVICEBRIDGE_URL ?? "0.0.0.0:14445",
98
+ process.env.SERVICEBRIDGE_URL ?? "localhost:14445",
99
99
  process.env.SERVICEBRIDGE_SERVICE_KEY!,
100
100
  "payments",
101
101
  );
@@ -104,7 +104,7 @@ sb.handleRpc("charge", async (payload: { orderId: string; amount: number }) => {
104
104
  return { ok: true, txId: `tx_${Date.now()}`, orderId: payload.orderId };
105
105
  });
106
106
 
107
- await sb.serve({ host: "0.0.0.0" });
107
+ await sb.serve({ host: "localhost" });
108
108
  ```
109
109
 
110
110
  ### 3. Call it from another service
@@ -113,7 +113,7 @@ await sb.serve({ host: "0.0.0.0" });
113
113
  import { servicebridge } from "service-bridge";
114
114
 
115
115
  const sb = servicebridge(
116
- process.env.SERVICEBRIDGE_URL ?? "0.0.0.0:14445",
116
+ process.env.SERVICEBRIDGE_URL ?? "localhost:14445",
117
117
  process.env.SERVICEBRIDGE_SERVICE_KEY!,
118
118
  "orders",
119
119
  );
@@ -138,7 +138,7 @@ The SDK connects to a ServiceBridge runtime. The fastest way to start:
138
138
  bash <(curl -fsSL https://servicebridge.dev/install.sh)
139
139
  ```
140
140
 
141
- This installs ServiceBridge + PostgreSQL via Docker Compose and generates an admin password automatically. After install, the dashboard is at `http://localhost:14444` and the gRPC control plane at `0.0.0.0:14445`.
141
+ This installs ServiceBridge + PostgreSQL via Docker Compose and generates an admin password automatically. After install, the dashboard is at `http://localhost:14444` and the gRPC control plane at `localhost:14445`.
142
142
 
143
143
  For manual Docker Compose setup, configuration reference, and all runtime environment variables, see the **[Runtime Setup](../README.md#runtime-setup)** section in the main SDK README.
144
144
 
@@ -153,7 +153,7 @@ import { servicebridge } from "service-bridge";
153
153
 
154
154
  // --- Payments service (worker) ---
155
155
 
156
- const payments = servicebridge("0.0.0.0:14445", process.env.SERVICEBRIDGE_SERVICE_KEY!, "payments");
156
+ const payments = servicebridge("localhost:14445", process.env.SERVICEBRIDGE_SERVICE_KEY!, "payments");
157
157
 
158
158
  payments.handleRpc("charge", async (payload: { orderId: string; amount: number }, ctx) => {
159
159
  await ctx?.stream.write({ status: "charging", orderId: payload.orderId }, "progress");
@@ -164,13 +164,13 @@ payments.handleRpc("charge", async (payload: { orderId: string; amount: number }
164
164
  return { ok: true, txId: `tx_${Date.now()}` };
165
165
  });
166
166
 
167
- await payments.serve({ host: "0.0.0.0" });
167
+ await payments.serve({ host: "localhost" });
168
168
  ```
169
169
 
170
170
  ```ts
171
171
  // --- Orders service (caller + event publisher) ---
172
172
 
173
- const orders = servicebridge("0.0.0.0:14445", process.env.SERVICEBRIDGE_SERVICE_KEY!, "orders");
173
+ const orders = servicebridge("localhost:14445", process.env.SERVICEBRIDGE_SERVICE_KEY!, "orders");
174
174
 
175
175
  // Call payments, then publish event
176
176
  const charge = await orders.rpc<{ ok: boolean; txId: string }>("payments/charge", {
@@ -190,7 +190,7 @@ await orders.event("orders.completed", {
190
190
  ```ts
191
191
  // --- Notifications service (event consumer) ---
192
192
 
193
- const notifications = servicebridge("0.0.0.0:14445", process.env.SERVICEBRIDGE_SERVICE_KEY!, "notifications");
193
+ const notifications = servicebridge("localhost:14445", process.env.SERVICEBRIDGE_SERVICE_KEY!, "notifications");
194
194
 
195
195
  notifications.handleEvent("orders.*", async (payload, ctx) => {
196
196
  const body = payload as { orderId: string; txId: string };
@@ -198,7 +198,7 @@ notifications.handleEvent("orders.*", async (payload, ctx) => {
198
198
  // ... send email ...
199
199
  });
200
200
 
201
- await notifications.serve({ host: "0.0.0.0" });
201
+ await notifications.serve({ host: "localhost" });
202
202
  ```
203
203
 
204
204
  ```ts
@@ -230,7 +230,7 @@ Every step above — RPC, event publish, event delivery, workflow execution —
230
230
  - **Jobs** — cron, delayed, and workflow-triggered scheduling
231
231
 
232
232
  ### Security
233
- - **Auto mTLS** — automatic certificate provisioning for workers
233
+ - **TLS by default** — control plane TLS + worker mTLS with gRPC certificate provisioning
234
234
  - **Access Policy** — service-level caller/target restrictions and RBAC
235
235
 
236
236
  ### Observability
@@ -267,11 +267,11 @@ ServiceBridge keeps the core API shape consistent across Node.js, Go, and Python
267
267
  constructor, RPC, events, jobs, workflows, `runWorkflow`, streams, serve/stop, and `ServiceBridgeError`.
268
268
 
269
269
  Constructor-level defaults for `timeout`, `retries`, and `retryDelay` are available
270
- across all three SDKs. The following are intentionally language-specific today:
270
+ across all three SDKs. Parity differences are naming-only (language idioms):
271
271
 
272
- - Node-only constructor options: `workerTransport`, `workerTLS`
273
- - Node-only handler hints: `handleRpc.timeout`, `handleRpc.retryable`, `handleRpc.concurrency`, `handleEvent.concurrency`, `handleEvent.prefetch`
274
- - Node-only `serve()` fields: `instanceId`, `weight`, `transport`, `tls`
272
+ - Constructor TLS overrides: `workerTLS`/`caCert` (Node), `WorkerTLS`/`CACert` (Go), `worker_tls`/`ca_cert` (Python)
273
+ - Handler hints: timeout/retryable/concurrency/prefetch are advisory in all SDKs
274
+ - Shared `serve()` fields across SDKs: host, max in-flight, instance ID, weight, and per-serve TLS override
275
275
 
276
276
  ### `servicebridge(url, serviceKey, serviceName?, opts?)`
277
277
 
@@ -290,21 +290,22 @@ Creates an SDK client instance.
290
290
 
291
291
  | Option | Type | Default | Description |
292
292
  |---|---|---|---|
293
- | `timeout` | `number` | `30000` | Default timeout (ms) for SDK operations. |
293
+ | `timeout` | `number` | `30000` | Default hard timeout per RPC attempt (ms). |
294
294
  | `retries` | `number` | `3` | Default retry count for `rpc()`. |
295
295
  | `retryDelay` | `number` | `300` | Base backoff delay (ms) for `rpc()`. |
296
296
  | `discoveryRefreshMs` | `number` | `10000` | Discovery refresh period for endpoint updates. |
297
297
  | `queueMaxSize` | `number` | `1000` | Max offline queue size for control-plane writes. |
298
298
  | `queueOverflow` | `"drop-oldest" \| "drop-newest" \| "error"` | `"drop-oldest"` | Overflow strategy for offline queue. |
299
299
  | `heartbeatIntervalMs` | `number` | `10000` | Base heartbeat period for worker registrations. |
300
- | `workerTransport` | `"tls"` | `"tls"` | Worker server transport. |
301
- | `workerTLS` | `WorkerTLSOpts` | auto | Explicit cert/key/CA for worker mTLS. |
302
- | `adminUrl` | `string` | derived from `url` | HTTP admin base URL (TLS provisioning and management API calls). |
303
- | `adminSessionCookie` | `string` | `undefined` | Admin session cookie for browser-authenticated endpoints (e.g. `cancelWorkflowRun`). |
304
- | `adminCsrfToken` | `string` | `undefined` | CSRF token paired with `adminSessionCookie` for unsafe HTTP methods. |
305
- | `adminOrigin` | `string` | `undefined` | Origin header required by admin CSRF/origin checks. |
306
300
  | `captureLogs` | `boolean` | `true` | Forward `console.*` logs to ServiceBridge. |
307
301
 
302
+ ### Advanced TLS overrides
303
+
304
+ | Option | Type | Default | Description |
305
+ |---|---|---|---|
306
+ | `workerTLS` | `WorkerTLSOpts` | auto | Explicit cert/key/CA for worker mTLS. |
307
+ | `caCert` | `string \| Buffer` | from `serviceKey` | Optional control-plane CA override. By default SDK reads CA from sbv2 service key. |
308
+
308
309
  `WorkerTLSOpts`:
309
310
 
310
311
  ```ts
@@ -343,6 +344,10 @@ const user = await sb.rpc<{ id: string; name: string }>("users/get", { id: "u_1"
343
344
  });
344
345
  ```
345
346
 
347
+ `rpc()` is bounded even when a downstream worker is silent:
348
+ each attempt has a hard local timeout, retries are finite (`retries + 1` total attempts),
349
+ and after the final failed attempt the root RPC span is closed with `error`.
350
+
346
351
  ---
347
352
 
348
353
  ### `event(topic, payload?, opts?)`
@@ -503,9 +508,9 @@ Registers an RPC handler. Chainable.
503
508
 
504
509
  | Option | Type | Description |
505
510
  |---|---|---|
506
- | `timeout` | `number` | Node-only timeout hint (currently not hard-enforced by runtime). |
507
- | `retryable` | `boolean` | Node-only retry hint (currently metadata-level, not a strict policy switch). |
508
- | `concurrency` | `number` | Node-only concurrency hint (currently not hard-enforced). |
511
+ | `timeout` | `number` | Advisory timeout hint (currently metadata-level, not hard-enforced by runtime). |
512
+ | `retryable` | `boolean` | Advisory retry hint (currently metadata-level, not a strict policy switch). |
513
+ | `concurrency` | `number` | Advisory concurrency hint (currently not hard-enforced). |
509
514
  | `schema` | `RpcSchemaOpts` | Inline protobuf schema for binary encode/decode. |
510
515
  | `allowedCallers` | `string[]` | Allow-list of caller service names. |
511
516
 
@@ -536,8 +541,8 @@ Registers an event consumer handler. Chainable.
536
541
  | Option | Type | Description |
537
542
  |---|---|---|
538
543
  | `groupName` | `string` | Consumer group name. Default: `<service>.<pattern>`. |
539
- | `concurrency` | `number` | Node-only concurrency hint (currently not hard-enforced). |
540
- | `prefetch` | `number` | Node-only prefetch hint (currently not hard-enforced). |
544
+ | `concurrency` | `number` | Advisory concurrency hint (currently not hard-enforced). |
545
+ | `prefetch` | `number` | Advisory prefetch hint (currently not hard-enforced). |
541
546
  | `retryPolicyJson` | `string` | Retry policy JSON string. |
542
547
  | `filterExpr` | `string` | Server-side filter expression. |
543
548
 
@@ -577,15 +582,15 @@ the Node.js process).
577
582
 
578
583
  | Option | Type | Description |
579
584
  |---|---|---|
580
- | `host` | `string` | Bind host. Default: `0.0.0.0`. |
581
- | `instanceId` | `string` | Stable worker instance identifier (Node-only). |
582
- | `weight` | `number` | Scheduling/discovery weight hint (Node-only). |
583
- | `transport` | `"tls"` | Worker transport (Node-only in `serve()`). |
584
- | `tls` | `WorkerTLSOpts` | Per-serve TLS override (Node-only in `serve()`). |
585
+ | `host` | `string` | Bind host. Default: `localhost`. Use `0.0.0.0` in Docker/Kubernetes so ServiceBridge can reach the worker. |
586
+ | `maxInFlight` | `number` | Max in-flight runtime-originated commands over `OpenWorkerSession`. Default: `128`. |
587
+ | `instanceId` | `string` | Stable worker instance identifier. |
588
+ | `weight` | `number` | Scheduling/discovery weight hint. |
589
+ | `tls` | `WorkerTLSOpts` | Per-serve worker TLS override. |
585
590
 
586
591
  ```ts
587
592
  await sb.serve({
588
- host: "0.0.0.0",
593
+ host: "localhost",
589
594
  instanceId: process.env.HOSTNAME,
590
595
  });
591
596
  ```
@@ -693,6 +698,13 @@ identifier used by `ctx.stream.write(...)` (typically a trace ID).
693
698
  | `data` | `unknown` | JSON-decoded chunk payload. |
694
699
  | `runStatus` | `string \| undefined` | Final status on `run_complete`. |
695
700
 
701
+ Behavior:
702
+
703
+ - Auto-reconnect with exponential backoff (`500ms` → `5000ms`) on retryable stream failures.
704
+ - Deduplicates by `sequence` across reconnects.
705
+ - Enforces strict JSON for `type="chunk"` payloads (non-JSON chunk terminates stream with fatal error).
706
+ - Enforces internal queue limit `256`; overflow is fatal (consumer must drain promptly).
707
+
696
708
  ```ts
697
709
  for await (const evt of sb.watchRun(runId, { key: "output", fromSequence: 0 })) {
698
710
  if (evt.type === "chunk") {
@@ -859,7 +871,9 @@ Runs a Fastify handler inside the current trace context so downstream SDK calls
859
871
  ### TLS behavior
860
872
 
861
873
  - Worker transport is TLS-only.
862
- - If `workerTLS` is not provided, SDK auto-provisions certs through the admin API.
874
+ - Control plane is TLS-only. Trust source is embedded into sbv2 service key by default.
875
+ - Embedded/explicit CA PEM is validated with strict x509 parsing.
876
+ - If `workerTLS` is not provided, SDK auto-provisions worker certs via gRPC `ProvisionWorkerCertificate`.
863
877
  - `workerTLS.cert` and `workerTLS.key` must be provided together.
864
878
  - `serve({ tls })` overrides global `workerTLS` for a specific worker instance.
865
879
 
@@ -879,19 +893,15 @@ The SDK requires values you pass into `servicebridge(...)`. Common setup:
879
893
 
880
894
  | Variable | Required | Example | Description |
881
895
  |---|---|---|---|
882
- | `SERVICEBRIDGE_URL` | yes | `0.0.0.0:14445` | gRPC control plane URL |
883
- | `SERVICEBRIDGE_SERVICE_KEY` | yes | `sb_live_...` | Service authentication key |
896
+ | `SERVICEBRIDGE_URL` | yes | `localhost:14445` | gRPC control plane URL |
897
+ | `SERVICEBRIDGE_SERVICE_KEY` | yes | `sbv2.<id>.<secret>.<ca>` | Service authentication key (sbv2 only) |
884
898
  | `SERVICEBRIDGE_SERVICE` | yes (worker mode) | `orders` | Service name in registry |
885
- | `SERVICEBRIDGE_ADMIN_URL` | optional | `http://0.0.0.0:14444` | Explicit admin API base URL |
886
899
 
887
900
  ```ts
888
901
  const sb = servicebridge(
889
- process.env.SERVICEBRIDGE_URL ?? "0.0.0.0:14445",
902
+ process.env.SERVICEBRIDGE_URL ?? "localhost:14445",
890
903
  process.env.SERVICEBRIDGE_SERVICE_KEY!,
891
904
  process.env.SERVICEBRIDGE_SERVICE ?? "orders",
892
- {
893
- adminUrl: process.env.SERVICEBRIDGE_ADMIN_URL,
894
- },
895
905
  );
896
906
  ```
897
907
 
@@ -949,7 +959,7 @@ try {
949
959
  ## FAQ
950
960
 
951
961
  **How does ServiceBridge handle service failures?**
952
- RPC calls have configurable retries with exponential backoff. Events are durable (PostgreSQL-backed) with at-least-once delivery per consumer group. Failed deliveries are retried according to policy, then moved to DLQ. Workflows track step state and can be resumed.
962
+ RPC calls have configurable retries with exponential backoff and hard per-attempt timeouts, so a silent downstream service cannot keep a call pending forever. Events are durable (PostgreSQL-backed) with at-least-once delivery per consumer group. Failed deliveries are retried according to policy, then moved to DLQ. Workflows track step state and can be resumed.
953
963
 
954
964
  **Is there vendor lock-in?**
955
965
  ServiceBridge is self-hosted. The runtime is a single Go binary + PostgreSQL. SDK calls map to standard patterns (RPC, pub/sub, cron) — migrating away means replacing SDK calls with equivalent library calls.