@service-bridge/node 0.1.3

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 (51) hide show
  1. package/README.md +854 -0
  2. package/biome.json +28 -0
  3. package/bun.lock +249 -0
  4. package/dist/express.d.ts +51 -0
  5. package/dist/express.js +129 -0
  6. package/dist/fastify.d.ts +43 -0
  7. package/dist/fastify.js +122 -0
  8. package/dist/index.js +34410 -0
  9. package/dist/trace.d.ts +19 -0
  10. package/http/dist/express.d.ts +51 -0
  11. package/http/dist/express.d.ts.map +1 -0
  12. package/http/dist/express.test.d.ts +2 -0
  13. package/http/dist/express.test.d.ts.map +1 -0
  14. package/http/dist/fastify.d.ts +43 -0
  15. package/http/dist/fastify.d.ts.map +1 -0
  16. package/http/dist/fastify.test.d.ts +2 -0
  17. package/http/dist/fastify.test.d.ts.map +1 -0
  18. package/http/dist/index.d.ts +7 -0
  19. package/http/dist/index.d.ts.map +1 -0
  20. package/http/dist/trace.d.ts +19 -0
  21. package/http/dist/trace.d.ts.map +1 -0
  22. package/http/dist/trace.test.d.ts +2 -0
  23. package/http/dist/trace.test.d.ts.map +1 -0
  24. package/http/package.json +48 -0
  25. package/http/src/express.test.ts +125 -0
  26. package/http/src/express.ts +209 -0
  27. package/http/src/fastify.test.ts +142 -0
  28. package/http/src/fastify.ts +159 -0
  29. package/http/src/index.ts +10 -0
  30. package/http/src/sdk-augment.d.ts +11 -0
  31. package/http/src/servicebridge.d.ts +23 -0
  32. package/http/src/trace.test.ts +97 -0
  33. package/http/src/trace.ts +56 -0
  34. package/http/tsconfig.json +17 -0
  35. package/http/tsconfig.test.json +6 -0
  36. package/package.json +65 -0
  37. package/sdk/dist/generated/servicebridge-package-definition.d.ts +4709 -0
  38. package/sdk/dist/grpc-client.d.ts +304 -0
  39. package/sdk/dist/grpc-client.test.d.ts +1 -0
  40. package/sdk/dist/index.d.ts +2 -0
  41. package/sdk/package.json +30 -0
  42. package/sdk/scripts/generate-proto.ts +65 -0
  43. package/sdk/src/generated/servicebridge-package-definition.ts +5198 -0
  44. package/sdk/src/grpc-client.d.ts +305 -0
  45. package/sdk/src/grpc-client.d.ts.map +1 -0
  46. package/sdk/src/grpc-client.test.ts +422 -0
  47. package/sdk/src/grpc-client.ts +2924 -0
  48. package/sdk/src/index.d.ts +3 -0
  49. package/sdk/src/index.d.ts.map +1 -0
  50. package/sdk/src/index.ts +29 -0
  51. package/sdk/tsconfig.json +13 -0
@@ -0,0 +1,142 @@
1
+ // @ts-nocheck
2
+ import { describe, expect, it } from "bun:test";
3
+ import { EventEmitter } from "node:events";
4
+ import { getTraceContext } from "@service-bridge/node";
5
+ import { servicebridgePlugin, wrapHandler } from "./fastify";
6
+
7
+ describe("servicebridgePlugin", () => {
8
+ it("decorates request, propagates header and closes span on finish", async () => {
9
+ let onRequest: unknown;
10
+ const ended: Array<Record<string, unknown>> = [];
11
+ const client = {
12
+ startHttpSpan(opts: Record<string, unknown>) {
13
+ expect(opts.method).toBe("POST");
14
+ expect(opts.path).toBe("/rpc");
15
+ expect(opts.traceId).toBe("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
16
+ expect(opts.parentSpanId).toBe("1111111111111111");
17
+ return {
18
+ traceId: "trace-id",
19
+ spanId: "span-id",
20
+ end(opts: Record<string, unknown>) {
21
+ ended.push(opts);
22
+ },
23
+ };
24
+ },
25
+ };
26
+ const fastify = {
27
+ decorateRequest() {},
28
+ addHook(name: string, handler: unknown) {
29
+ if (name === "onRequest") {
30
+ onRequest = handler;
31
+ }
32
+ },
33
+ };
34
+
35
+ await servicebridgePlugin(fastify as never, { client: client as never });
36
+
37
+ const request = {
38
+ method: "POST",
39
+ url: "/rpc?x=1",
40
+ headers: {
41
+ traceparent: "00-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-1111111111111111-01",
42
+ },
43
+ raw: new EventEmitter(),
44
+ };
45
+ const reply = {
46
+ statusCode: 201,
47
+ sent: true,
48
+ headers: {} as Record<string, string>,
49
+ raw: new EventEmitter(),
50
+ header(name: string, value: string) {
51
+ this.headers[name.toLowerCase()] = value;
52
+ },
53
+ };
54
+
55
+ await (onRequest as (request: unknown, reply: unknown) => Promise<void>)(
56
+ request,
57
+ reply,
58
+ );
59
+
60
+ expect(request.servicebridge).toBe(client);
61
+ expect(request.traceId).toBe("trace-id");
62
+ expect(request.spanId).toBe("span-id");
63
+ expect(reply.headers["x-trace-id"]).toBe("trace-id");
64
+
65
+ reply.raw.emit("finish");
66
+ request.raw.emit("close");
67
+
68
+ expect(ended).toEqual([{ statusCode: 201, success: true }]);
69
+ });
70
+
71
+ it("skips tracing for excluded paths", async () => {
72
+ let onRequest: unknown;
73
+ const client = {
74
+ startHttpSpan() {
75
+ throw new Error("must not be called");
76
+ },
77
+ };
78
+ const fastify = {
79
+ decorateRequest() {},
80
+ addHook(_name: string, handler: unknown) {
81
+ onRequest = handler;
82
+ },
83
+ };
84
+
85
+ await servicebridgePlugin(fastify as never, {
86
+ client: client as never,
87
+ excludePaths: ["/health"],
88
+ propagateTraceHeader: false,
89
+ });
90
+
91
+ const request = {
92
+ method: "GET",
93
+ url: "/health/live",
94
+ headers: {},
95
+ raw: new EventEmitter(),
96
+ };
97
+ const reply = {
98
+ statusCode: 200,
99
+ sent: false,
100
+ headers: {} as Record<string, string>,
101
+ raw: new EventEmitter(),
102
+ header(name: string, value: string) {
103
+ this.headers[name.toLowerCase()] = value;
104
+ },
105
+ };
106
+
107
+ await (onRequest as (request: unknown, reply: unknown) => Promise<void>)(
108
+ request,
109
+ reply,
110
+ );
111
+
112
+ expect(request.servicebridge).toBe(client);
113
+ expect(request.traceId).toBeUndefined();
114
+ expect(request.spanId).toBeUndefined();
115
+ expect(reply.headers["x-trace-id"]).toBeUndefined();
116
+ });
117
+ });
118
+
119
+ describe("wrapHandler", () => {
120
+ it("runs handler inside trace context when trace ids exist", () => {
121
+ const handler = wrapHandler((request: { traceId?: string }) => {
122
+ expect(request.traceId).toBe("trace-id");
123
+ expect(getTraceContext()).toEqual({
124
+ traceId: "trace-id",
125
+ spanId: "span-id",
126
+ });
127
+ return "ok";
128
+ });
129
+
130
+ const result = handler(
131
+ { traceId: "trace-id", spanId: "span-id" } as never,
132
+ {} as never,
133
+ );
134
+ expect(result).toBe("ok");
135
+ });
136
+
137
+ it("calls handler directly when there is no trace context", () => {
138
+ const handler = wrapHandler(() => getTraceContext());
139
+ const result = handler({} as never, {} as never);
140
+ expect(result).toBeUndefined();
141
+ });
142
+ });
@@ -0,0 +1,159 @@
1
+ import type { ServiceBridgeService } from "@service-bridge/node";
2
+ import { runWithTraceContext } from "@service-bridge/node";
3
+ import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
4
+ import type { IncomingTraceContext } from "./trace";
5
+ import { extractTraceFromHeaders } from "./trace";
6
+
7
+ declare module "fastify" {
8
+ interface FastifyRequest {
9
+ servicebridge: ServiceBridgeService;
10
+ traceId?: string;
11
+ spanId?: string;
12
+ }
13
+ }
14
+
15
+ export interface ServiceBridgeFastifyOptions {
16
+ /** ServiceBridge client (from servicebridge()). Required. */
17
+ client: ServiceBridgeService;
18
+ /** Paths to skip tracing. Default: [] */
19
+ excludePaths?: string[];
20
+ /** Set x-trace-id response header for propagation. Default: true */
21
+ propagateTraceHeader?: boolean;
22
+ /**
23
+ * Auto-register every route in the ServiceBridge HTTP catalog via Fastify's
24
+ * onRoute hook. Routes appear in the UI as soon as the server starts (before
25
+ * any traffic). Default: true.
26
+ */
27
+ autoRegister?: boolean;
28
+ /**
29
+ * Options forwarded to registerHttpEndpoint for each auto-discovered route.
30
+ */
31
+ register?: {
32
+ /** Stable identifier for this process instance. */
33
+ instanceId?: string;
34
+ /** Address where this service can be reached, e.g. "http://10.0.0.1:3000" */
35
+ endpoint?: string;
36
+ /** Service names allowed to call these endpoints. Default: [] */
37
+ allowedCallers?: string[];
38
+ /** Path prefixes to exclude from registration. Default: [] */
39
+ excludePaths?: string[];
40
+ };
41
+ }
42
+
43
+ export async function servicebridgePlugin(
44
+ fastify: FastifyInstance,
45
+ options: ServiceBridgeFastifyOptions,
46
+ ): Promise<void> {
47
+ const {
48
+ client,
49
+ excludePaths = [],
50
+ propagateTraceHeader = true,
51
+ autoRegister = true,
52
+ register: registerOpts = {},
53
+ } = options;
54
+
55
+ fastify.decorateRequest("servicebridge", null);
56
+ fastify.decorateRequest("traceId", null);
57
+ fastify.decorateRequest("spanId", null);
58
+
59
+ // Auto-register each route in the catalog as soon as it's declared.
60
+ if (autoRegister) {
61
+ const excludeReg = registerOpts.excludePaths ?? [];
62
+ fastify.addHook("onRoute", (routeOptions) => {
63
+ const routePath = routeOptions.url ?? routeOptions.path ?? "";
64
+ if (excludeReg.some((p) => routePath.startsWith(p))) return;
65
+
66
+ const methods = Array.isArray(routeOptions.method)
67
+ ? routeOptions.method
68
+ : [routeOptions.method];
69
+
70
+ for (const method of methods) {
71
+ // HEAD/OPTIONS are framework-managed and rarely meaningful in the catalog.
72
+ if (method === "HEAD" || method === "OPTIONS") continue;
73
+ client
74
+ .registerHttpEndpoint({
75
+ method,
76
+ route: routePath,
77
+ instanceId: registerOpts.instanceId,
78
+ endpoint: registerOpts.endpoint,
79
+ allowedCallers: registerOpts.allowedCallers ?? [],
80
+ })
81
+ .catch(() => {
82
+ // Non-fatal: server may not be reachable yet at plugin-load time.
83
+ });
84
+ }
85
+ });
86
+ }
87
+
88
+ fastify.addHook(
89
+ "onRequest",
90
+ async (request: FastifyRequest, reply: FastifyReply) => {
91
+ request.servicebridge = client;
92
+
93
+ const path = request.url?.split("?")[0] ?? "/";
94
+ if (excludePaths.some((p) => path.startsWith(p))) {
95
+ return;
96
+ }
97
+
98
+ const headers: Record<string, string | string[] | undefined> = {};
99
+ for (const [k, v] of Object.entries(request.headers)) {
100
+ if (typeof v === "string" || Array.isArray(v)) {
101
+ headers[k.toLowerCase()] = v;
102
+ }
103
+ }
104
+ const traceCtx: IncomingTraceContext = extractTraceFromHeaders(headers);
105
+
106
+ const span = client.startHttpSpan({
107
+ method: request.method,
108
+ path,
109
+ traceId: traceCtx.traceId,
110
+ parentSpanId: traceCtx.parentSpanId,
111
+ });
112
+ let ended = false;
113
+ const endSpan = (opts: Parameters<typeof span.end>[0]) => {
114
+ if (ended) return;
115
+ ended = true;
116
+ span.end(opts);
117
+ };
118
+
119
+ request.traceId = span.traceId;
120
+ request.spanId = span.spanId;
121
+
122
+ if (propagateTraceHeader) {
123
+ reply.header("x-trace-id", span.traceId);
124
+ }
125
+
126
+ request.raw.once("close", () => {
127
+ if (!reply.sent) {
128
+ endSpan({ success: false, error: "connection closed" });
129
+ }
130
+ });
131
+
132
+ reply.raw.once("finish", () => {
133
+ endSpan({
134
+ statusCode: reply.statusCode,
135
+ success: reply.statusCode < 400,
136
+ });
137
+ });
138
+ },
139
+ );
140
+ }
141
+
142
+ /**
143
+ * Wraps a route handler to run inside trace context.
144
+ * Use when the handler calls req.servicebridge.rpc() or event() — ensures trace propagation.
145
+ */
146
+ export function wrapHandler<T>(
147
+ handler: (request: FastifyRequest, reply: FastifyReply) => T,
148
+ ): (request: FastifyRequest, reply: FastifyReply) => T {
149
+ return (request: FastifyRequest, reply: FastifyReply) => {
150
+ const traceId = request.traceId;
151
+ const spanId = request.spanId;
152
+ if (traceId && spanId) {
153
+ return runWithTraceContext({ traceId, spanId }, () =>
154
+ handler(request, reply),
155
+ ) as T;
156
+ }
157
+ return handler(request, reply);
158
+ };
159
+ }
@@ -0,0 +1,10 @@
1
+ export type {
2
+ RegisterExpressRoutesOptions,
3
+ ServiceBridgeExpressOptions,
4
+ } from "./express";
5
+ export { registerExpressRoutes, servicebridgeMiddleware } from "./express";
6
+ export type { ServiceBridgeFastifyOptions } from "./fastify";
7
+ export { servicebridgePlugin, wrapHandler } from "./fastify";
8
+
9
+ export type { IncomingTraceContext } from "./trace";
10
+ export { extractTraceFromHeaders } from "./trace";
@@ -0,0 +1,11 @@
1
+ declare module "@service-bridge/node" {
2
+ interface ServiceBridgeService {
3
+ registerHttpEndpoint(opts: {
4
+ method: string;
5
+ route: string;
6
+ instanceId?: string;
7
+ endpoint?: string;
8
+ allowedCallers?: string[];
9
+ }): Promise<void>;
10
+ }
11
+ }
@@ -0,0 +1,23 @@
1
+ declare module "@service-bridge/node" {
2
+ export interface TraceCtx {
3
+ traceId: string;
4
+ spanId: string;
5
+ }
6
+
7
+ export interface HttpSpan {
8
+ traceId: string;
9
+ spanId: string;
10
+ end(opts: { statusCode?: number; success?: boolean; error?: string }): void;
11
+ }
12
+
13
+ export interface ServiceBridgeService {
14
+ startHttpSpan(opts: {
15
+ method: string;
16
+ path: string;
17
+ traceId?: string;
18
+ parentSpanId?: string;
19
+ }): HttpSpan;
20
+ }
21
+
22
+ export function runWithTraceContext<T>(ctx: TraceCtx, fn: () => T): T;
23
+ }
@@ -0,0 +1,97 @@
1
+ // @ts-nocheck
2
+ import { describe, expect, it } from "bun:test";
3
+ import { extractTraceFromHeaders } from "./trace";
4
+
5
+ describe("extractTraceFromHeaders", () => {
6
+ it("parses valid W3C traceparent and extracts parent span", () => {
7
+ const ctx = extractTraceFromHeaders({
8
+ traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
9
+ });
10
+ expect(ctx.traceId).toBe("4bf92f3577b34da6a3ce929d0e0e4736");
11
+ expect(ctx.parentSpanId).toBe("00f067aa0ba902b7");
12
+ });
13
+
14
+ it("uses x-trace-id when traceparent is absent, no parent span", () => {
15
+ const ctx = extractTraceFromHeaders({
16
+ "x-trace-id": "trace-from-header",
17
+ });
18
+ expect(ctx.traceId).toBe("trace-from-header");
19
+ // x-trace-id provides no parent span info — parentSpanId must be empty
20
+ expect(ctx.parentSpanId).toBe("");
21
+ });
22
+
23
+ it("generates fresh trace when no headers present", () => {
24
+ const ctx = extractTraceFromHeaders({});
25
+ expect(ctx.traceId.length).toBeGreaterThan(0);
26
+ expect(ctx.parentSpanId).toBe("");
27
+ });
28
+
29
+ it("ignores malformed traceparent and falls back", () => {
30
+ const ctx = extractTraceFromHeaders({
31
+ traceparent: "bad-value",
32
+ "x-trace-id": "fallback-trace",
33
+ });
34
+ expect(ctx.traceId).toBe("fallback-trace");
35
+ expect(ctx.parentSpanId).toBe("");
36
+ });
37
+
38
+ it("uses the first traceparent value when header is an array", () => {
39
+ const ctx = extractTraceFromHeaders({
40
+ traceparent: [
41
+ "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
42
+ "00-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-bbbbbbbbbbbbbbbb-01",
43
+ ],
44
+ });
45
+ expect(ctx.traceId).toBe("4bf92f3577b34da6a3ce929d0e0e4736");
46
+ expect(ctx.parentSpanId).toBe("00f067aa0ba902b7");
47
+ });
48
+
49
+ it("rejects unsupported traceparent versions and falls back", () => {
50
+ const ctx = extractTraceFromHeaders({
51
+ traceparent: "ff-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
52
+ "x-trace-id": "fallback-trace",
53
+ });
54
+ expect(ctx.traceId).toBe("fallback-trace");
55
+ expect(ctx.parentSpanId).toBe("");
56
+ });
57
+
58
+ it("rejects malformed traceparent lengths and falls back", () => {
59
+ const ctx = extractTraceFromHeaders({
60
+ traceparent: "00-short-too-short-01",
61
+ "x-trace-id": "fallback-trace",
62
+ });
63
+ expect(ctx.traceId).toBe("fallback-trace");
64
+ expect(ctx.parentSpanId).toBe("");
65
+ });
66
+
67
+ it("preserves current behavior for non-hex traceparent ids", () => {
68
+ const ctx = extractTraceFromHeaders({
69
+ traceparent: "00-zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz-yyyyyyyyyyyyyyyy-01",
70
+ });
71
+ expect(ctx.traceId).toBe("zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz");
72
+ expect(ctx.parentSpanId).toBe("yyyyyyyyyyyyyyyy");
73
+ });
74
+
75
+ it("trims x-trace-id without inventing a parent span", () => {
76
+ const ctx = extractTraceFromHeaders({
77
+ "x-trace-id": " external-trace-id ",
78
+ });
79
+ expect(ctx.traceId).toBe("external-trace-id");
80
+ expect(ctx.parentSpanId).toBe("");
81
+ });
82
+
83
+ it("keeps empty x-trace-id as current fallback behavior", () => {
84
+ const ctx = extractTraceFromHeaders({
85
+ "x-trace-id": " ",
86
+ });
87
+ expect(ctx.traceId).toBe("");
88
+ expect(ctx.parentSpanId).toBe("");
89
+ });
90
+
91
+ it("generates a 32-char trace id when nothing is provided", () => {
92
+ const ctx = extractTraceFromHeaders({});
93
+ expect(ctx.traceId).toHaveLength(32);
94
+ expect(ctx.traceId.includes("-")).toBe(false);
95
+ expect(ctx.parentSpanId).toBe("");
96
+ });
97
+ });
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Result of extracting trace context from incoming HTTP headers.
3
+ * traceId — the trace this request belongs to (carry-over or newly generated).
4
+ * parentSpanId — the caller's span ID to use as parent, empty string if unknown.
5
+ */
6
+ export interface IncomingTraceContext {
7
+ traceId: string;
8
+ parentSpanId: string;
9
+ }
10
+
11
+ /** Parse W3C traceparent: 00-{32hex}-{16hex}-{flags} */
12
+ function parseTraceparent(traceparent: string): IncomingTraceContext | null {
13
+ const parts = traceparent.trim().split("-");
14
+ if (parts.length !== 4 || parts[0] !== "00") return null;
15
+ const [, traceId, parentSpanId] = parts;
16
+ if (
17
+ !traceId ||
18
+ !parentSpanId ||
19
+ traceId.length !== 32 ||
20
+ parentSpanId.length !== 16
21
+ )
22
+ return null;
23
+ return { traceId, parentSpanId };
24
+ }
25
+
26
+ function randomTraceId(): string {
27
+ return crypto.randomUUID().replace(/-/g, "");
28
+ }
29
+
30
+ /**
31
+ * Extract distributed trace context from incoming HTTP request headers.
32
+ *
33
+ * Priority:
34
+ * 1. W3C `traceparent` — full parent info (traceId + parentSpanId)
35
+ * 2. `x-trace-id` — traceId only, no parent span known
36
+ * 3. Nothing — generate a fresh traceId, no parent
37
+ */
38
+ export function extractTraceFromHeaders(
39
+ headers: Record<string, string | string[] | undefined>,
40
+ ): IncomingTraceContext {
41
+ const traceparent = headers.traceparent;
42
+ const tp = Array.isArray(traceparent) ? traceparent[0] : traceparent;
43
+ if (tp) {
44
+ const parsed = parseTraceparent(tp);
45
+ if (parsed) return parsed;
46
+ }
47
+
48
+ const xTraceId = headers["x-trace-id"];
49
+ const traceId = Array.isArray(xTraceId) ? xTraceId[0] : xTraceId;
50
+ if (traceId && typeof traceId === "string") {
51
+ // Caller provided a trace ID but no parent span — this request is the root of this trace.
52
+ return { traceId: traceId.trim(), parentSpanId: "" };
53
+ }
54
+
55
+ return { traceId: randomTraceId(), parentSpanId: "" };
56
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "compilerOptions": {
3
+ "baseUrl": ".",
4
+ "paths": { "@service-bridge/node": ["../dist/index"] },
5
+ "target": "ES2022",
6
+ "module": "ESNext",
7
+ "moduleResolution": "bundler",
8
+ "strict": true,
9
+ "skipLibCheck": true,
10
+ "types": ["node"],
11
+ "declaration": true,
12
+ "declarationMap": true,
13
+ "outDir": "dist",
14
+ "rootDir": "src"
15
+ },
16
+ "include": ["src/**/*"]
17
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "paths": { "@service-bridge/node": ["../sdk/src/index"] }
5
+ }
6
+ }
package/package.json ADDED
@@ -0,0 +1,65 @@
1
+ {
2
+ "name": "@service-bridge/node",
3
+ "version": "0.1.3",
4
+ "type": "module",
5
+ "private": false,
6
+ "license": "SEE LICENSE IN LICENSE",
7
+ "publishConfig": {
8
+ "access": "public"
9
+ },
10
+ "main": "dist/index.js",
11
+ "types": "dist/index.d.ts",
12
+ "exports": {
13
+ ".": {
14
+ "import": "./dist/index.js",
15
+ "types": "./dist/index.d.ts"
16
+ },
17
+ "./express": {
18
+ "import": "./dist/express.js",
19
+ "types": "./dist/express.d.ts"
20
+ },
21
+ "./fastify": {
22
+ "import": "./dist/fastify.js",
23
+ "types": "./dist/fastify.d.ts"
24
+ }
25
+ },
26
+ "scripts": {
27
+ "generate:proto": "bun run sdk/scripts/generate-proto.ts",
28
+ "build:core": "bun run generate:proto && bun build sdk/src/index.ts --outdir=dist --target=node",
29
+ "build:types": "bunx tsc -p sdk/tsconfig.json --emitDeclarationOnly --outDir dist && bunx tsc -p http/tsconfig.json --emitDeclarationOnly --outDir http/dist && cp http/dist/express.d.ts http/dist/fastify.d.ts http/dist/trace.d.ts dist/",
30
+ "build:express": "bun build ./http/src/express.ts --outfile=dist/express.js --target=node -e @service-bridge/node",
31
+ "build:fastify": "bun build ./http/src/fastify.ts --outfile=dist/fastify.js --target=node -e @service-bridge/node",
32
+ "build": "bun run build:core && bun run build:express && bun run build:fastify && bun run build:types",
33
+ "test:sdk": "bun test sdk",
34
+ "test:http": "bun test --tsconfig-override http/tsconfig.test.json http",
35
+ "test": "bun run test:sdk && bun run test:http",
36
+ "typecheck": "bunx tsc -p sdk/tsconfig.json --noEmit && bunx tsc -p http/tsconfig.json --noEmit",
37
+ "lint": "bunx biome check .",
38
+ "lint:fix": "bunx biome check . --write"
39
+ },
40
+ "dependencies": {
41
+ "@grpc/grpc-js": "^1.9.0",
42
+ "@grpc/proto-loader": "^0.7.10",
43
+ "protobufjs": "^8.0.0"
44
+ },
45
+ "peerDependencies": {
46
+ "express": ">=4.0.0",
47
+ "fastify": ">=4.0.0"
48
+ },
49
+ "peerDependenciesMeta": {
50
+ "express": {
51
+ "optional": true
52
+ },
53
+ "fastify": {
54
+ "optional": true
55
+ }
56
+ },
57
+ "devDependencies": {
58
+ "@biomejs/biome": "^2.4.5",
59
+ "@types/bun": "latest",
60
+ "@types/express": "^4.17.21",
61
+ "@types/node": "^20.0.0",
62
+ "fastify": "^4.29.0",
63
+ "typescript": "^5.3.0"
64
+ }
65
+ }