service-bridge 1.8.5-dev.49 → 2.0.0-alpha
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/LICENSE +21 -0
- package/README.md +386 -1053
- package/dist/http/express/index.d.ts +31 -0
- package/dist/http/express/index.js +2765 -0
- package/dist/http/express/index.js.map +1 -0
- package/dist/http/fastify/index.d.ts +38 -0
- package/dist/http/fastify/index.js +2726 -0
- package/dist/http/fastify/index.js.map +1 -0
- package/dist/http/hono/index.d.ts +39 -0
- package/dist/http/hono/index.js +2706 -0
- package/dist/http/hono/index.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.js +14907 -2722
- package/dist/index.js.map +1 -0
- package/dist/service-bridge-CPmirNES.d.ts +2261 -0
- package/package.json +107 -123
- package/dist/express.d.ts +0 -51
- package/dist/express.js +0 -129
- package/dist/fastify.d.ts +0 -43
- package/dist/fastify.js +0 -122
- package/dist/trace.d.ts +0 -19
package/package.json
CHANGED
|
@@ -1,125 +1,109 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
"express": {
|
|
110
|
-
"optional": true
|
|
111
|
-
},
|
|
112
|
-
"fastify": {
|
|
113
|
-
"optional": true
|
|
114
|
-
}
|
|
115
|
-
},
|
|
116
|
-
"devDependencies": {
|
|
117
|
-
"@biomejs/biome": "^2.4.5",
|
|
118
|
-
"@types/bun": "latest",
|
|
119
|
-
"@types/express": "^5.0.6",
|
|
120
|
-
"@types/node": "^20.0.0",
|
|
121
|
-
"express": "^4.21.2",
|
|
122
|
-
"fastify": "^4.29.0",
|
|
123
|
-
"typescript": "^5.3.0"
|
|
124
|
-
}
|
|
2
|
+
"name": "service-bridge",
|
|
3
|
+
"version": "2.0.0-alpha",
|
|
4
|
+
"description": "TypeScript SDK for ServiceBridge — RPC, durable events, workflows, jobs and observability over a single self-hosted gRPC runtime with mTLS.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"module": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/service-bridge/sdk.git",
|
|
13
|
+
"directory": "node"
|
|
14
|
+
},
|
|
15
|
+
"homepage": "https://servicebridge.dev",
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"tag": "alpha",
|
|
18
|
+
"access": "public",
|
|
19
|
+
"provenance": true
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"microservices",
|
|
23
|
+
"rpc",
|
|
24
|
+
"events",
|
|
25
|
+
"workflows",
|
|
26
|
+
"grpc",
|
|
27
|
+
"mtls",
|
|
28
|
+
"observability"
|
|
29
|
+
],
|
|
30
|
+
"engines": {
|
|
31
|
+
"node": ">=18",
|
|
32
|
+
"bun": ">=1.0"
|
|
33
|
+
},
|
|
34
|
+
"files": [
|
|
35
|
+
"dist",
|
|
36
|
+
"README.md",
|
|
37
|
+
"LICENSE"
|
|
38
|
+
],
|
|
39
|
+
"scripts": {
|
|
40
|
+
"dev": "bun run --hot index.ts",
|
|
41
|
+
"start": "bun run index.ts",
|
|
42
|
+
"build": "tsup",
|
|
43
|
+
"prepack": "bun run build",
|
|
44
|
+
"lint": "biome check .",
|
|
45
|
+
"format": "biome format --write .",
|
|
46
|
+
"typecheck": "tsc --noEmit",
|
|
47
|
+
"check": "biome check --write . && tsc --noEmit"
|
|
48
|
+
},
|
|
49
|
+
"exports": {
|
|
50
|
+
".": {
|
|
51
|
+
"types": "./dist/index.d.ts",
|
|
52
|
+
"import": "./dist/index.js"
|
|
53
|
+
},
|
|
54
|
+
"./express": {
|
|
55
|
+
"types": "./dist/http/express/index.d.ts",
|
|
56
|
+
"import": "./dist/http/express/index.js"
|
|
57
|
+
},
|
|
58
|
+
"./fastify": {
|
|
59
|
+
"types": "./dist/http/fastify/index.d.ts",
|
|
60
|
+
"import": "./dist/http/fastify/index.js"
|
|
61
|
+
},
|
|
62
|
+
"./hono": {
|
|
63
|
+
"types": "./dist/http/hono/index.d.ts",
|
|
64
|
+
"import": "./dist/http/hono/index.js"
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
"devDependencies": {
|
|
68
|
+
"@biomejs/biome": "^2.4.15",
|
|
69
|
+
"@hono/node-server": "^2.0.4",
|
|
70
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
71
|
+
"@types/bun": "latest",
|
|
72
|
+
"@types/express": "^5.0.6",
|
|
73
|
+
"@types/pg": "^8.20.0",
|
|
74
|
+
"express": "^5.2.1",
|
|
75
|
+
"fast-check": "^4.8.0",
|
|
76
|
+
"fastify": "^5",
|
|
77
|
+
"hono": "^4",
|
|
78
|
+
"pg": "^8.21.0",
|
|
79
|
+
"ts-proto": "^2.11.8",
|
|
80
|
+
"tsup": "^8.5.1"
|
|
81
|
+
},
|
|
82
|
+
"peerDependencies": {
|
|
83
|
+
"express": "^4 || ^5",
|
|
84
|
+
"fastify": "^4 || ^5",
|
|
85
|
+
"hono": "^4",
|
|
86
|
+
"typescript": "^5"
|
|
87
|
+
},
|
|
88
|
+
"peerDependenciesMeta": {
|
|
89
|
+
"express": {
|
|
90
|
+
"optional": true
|
|
91
|
+
},
|
|
92
|
+
"fastify": {
|
|
93
|
+
"optional": true
|
|
94
|
+
},
|
|
95
|
+
"hono": {
|
|
96
|
+
"optional": true
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
"dependencies": {
|
|
100
|
+
"@bufbuild/protobuf": "^2.12.0",
|
|
101
|
+
"@grpc/grpc-js": "1.14.3",
|
|
102
|
+
"@peculiar/x509": "^2.0.0",
|
|
103
|
+
"better-sqlite3": "^12.10.0",
|
|
104
|
+
"fastify-plugin": "^5.0.1",
|
|
105
|
+
"protobufjs": "^8.4.0",
|
|
106
|
+
"reflect-metadata": "^0.2.2",
|
|
107
|
+
"uuidv7": "^1.2.1"
|
|
108
|
+
}
|
|
125
109
|
}
|
package/dist/express.d.ts
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import type { Application, NextFunction, Request, Response } from "express";
|
|
2
|
-
import type { ServiceBridgeService } from "service-bridge";
|
|
3
|
-
import type { IncomingTraceContext } from "./trace";
|
|
4
|
-
import { extractTraceFromHeaders } from "./trace";
|
|
5
|
-
export { extractTraceFromHeaders };
|
|
6
|
-
export type { IncomingTraceContext };
|
|
7
|
-
declare global {
|
|
8
|
-
namespace Express {
|
|
9
|
-
interface Request {
|
|
10
|
-
servicebridge: ServiceBridgeService;
|
|
11
|
-
traceId?: string;
|
|
12
|
-
spanId?: string;
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
export interface ServiceBridgeExpressOptions {
|
|
17
|
-
/** ServiceBridge client (from servicebridge()). Required. */
|
|
18
|
-
client: ServiceBridgeService;
|
|
19
|
-
/** Paths to skip tracing. Default: [] */
|
|
20
|
-
excludePaths?: string[];
|
|
21
|
-
/** Set x-trace-id response header for propagation. Default: true */
|
|
22
|
-
propagateTraceHeader?: boolean;
|
|
23
|
-
/**
|
|
24
|
-
* Auto-register route patterns in the ServiceBridge HTTP catalog on first hit.
|
|
25
|
-
* Routes appear in the UI after their first request. Default: true.
|
|
26
|
-
* Use registerExpressRoutes() for eager (pre-traffic) registration.
|
|
27
|
-
*/
|
|
28
|
-
autoRegister?: boolean;
|
|
29
|
-
}
|
|
30
|
-
export declare function servicebridgeMiddleware(options: ServiceBridgeExpressOptions): (req: Request, res: Response, next: NextFunction) => void;
|
|
31
|
-
export interface RegisterExpressRoutesOptions {
|
|
32
|
-
/** Stable identifier for this process instance used in http_instances. */
|
|
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
|
-
* Scan an Express application's route table and register every route pattern
|
|
43
|
-
* in the ServiceBridge HTTP catalog. Safe to call multiple times (idempotent).
|
|
44
|
-
*
|
|
45
|
-
* @example
|
|
46
|
-
* app.get('/users/:id', handler);
|
|
47
|
-
* app.post('/orders', handler);
|
|
48
|
-
* app.listen(3000, () => registerExpressRoutes(app, sb));
|
|
49
|
-
*/
|
|
50
|
-
export declare function registerExpressRoutes(app: Application, client: ServiceBridgeService, opts?: RegisterExpressRoutesOptions): Promise<void>;
|
|
51
|
-
//# sourceMappingURL=express.d.ts.map
|
package/dist/express.js
DELETED
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
// http/src/express.ts
|
|
2
|
-
import { withTraceContext } from "service-bridge";
|
|
3
|
-
|
|
4
|
-
// http/src/trace.ts
|
|
5
|
-
function parseTraceparent(traceparent) {
|
|
6
|
-
const parts = traceparent.trim().split("-");
|
|
7
|
-
if (parts.length !== 4 || parts[0] !== "00")
|
|
8
|
-
return null;
|
|
9
|
-
const [, traceId, parentSpanId] = parts;
|
|
10
|
-
if (!traceId || !parentSpanId || traceId.length !== 32 || parentSpanId.length !== 16)
|
|
11
|
-
return null;
|
|
12
|
-
return { traceId, parentSpanId };
|
|
13
|
-
}
|
|
14
|
-
function randomTraceId() {
|
|
15
|
-
return crypto.randomUUID().replace(/-/g, "");
|
|
16
|
-
}
|
|
17
|
-
function extractTraceFromHeaders(headers) {
|
|
18
|
-
const traceparent = headers.traceparent;
|
|
19
|
-
const tp = Array.isArray(traceparent) ? traceparent[0] : traceparent;
|
|
20
|
-
if (tp) {
|
|
21
|
-
const parsed = parseTraceparent(tp);
|
|
22
|
-
if (parsed)
|
|
23
|
-
return parsed;
|
|
24
|
-
}
|
|
25
|
-
const xTraceId = headers["x-trace-id"];
|
|
26
|
-
const traceId = Array.isArray(xTraceId) ? xTraceId[0] : xTraceId;
|
|
27
|
-
if (traceId && typeof traceId === "string") {
|
|
28
|
-
return { traceId: traceId.trim(), parentSpanId: "" };
|
|
29
|
-
}
|
|
30
|
-
return { traceId: randomTraceId(), parentSpanId: "" };
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// http/src/express.ts
|
|
34
|
-
function servicebridgeMiddleware(options) {
|
|
35
|
-
const {
|
|
36
|
-
client,
|
|
37
|
-
excludePaths = [],
|
|
38
|
-
propagateTraceHeader = true,
|
|
39
|
-
autoRegister = true
|
|
40
|
-
} = options;
|
|
41
|
-
const registeredPatterns = new Set;
|
|
42
|
-
return function middleware(req, res, next) {
|
|
43
|
-
const path = req.path ?? req.url?.split("?")[0] ?? "/";
|
|
44
|
-
if (excludePaths.some((p) => path.startsWith(p))) {
|
|
45
|
-
req.servicebridge = client;
|
|
46
|
-
next();
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
const headers = {};
|
|
50
|
-
for (const [k, v] of Object.entries(req.headers)) {
|
|
51
|
-
if (v != null)
|
|
52
|
-
headers[k.toLowerCase()] = v;
|
|
53
|
-
}
|
|
54
|
-
const traceCtx = extractTraceFromHeaders(headers);
|
|
55
|
-
const span = client.startHttpSpan({
|
|
56
|
-
method: req.method,
|
|
57
|
-
path,
|
|
58
|
-
traceId: traceCtx.traceId,
|
|
59
|
-
parentSpanId: traceCtx.parentSpanId
|
|
60
|
-
});
|
|
61
|
-
req.servicebridge = client;
|
|
62
|
-
req.traceId = span.traceId;
|
|
63
|
-
req.spanId = span.spanId;
|
|
64
|
-
if (propagateTraceHeader) {
|
|
65
|
-
res.setHeader("x-trace-id", span.traceId);
|
|
66
|
-
}
|
|
67
|
-
const onFinish = () => {
|
|
68
|
-
res.off("finish", onFinish);
|
|
69
|
-
res.off("close", onFinish);
|
|
70
|
-
span.end({
|
|
71
|
-
statusCode: res.statusCode,
|
|
72
|
-
success: res.statusCode < 400
|
|
73
|
-
});
|
|
74
|
-
if (autoRegister) {
|
|
75
|
-
const routePattern = req.route?.path;
|
|
76
|
-
if (routePattern && typeof routePattern === "string") {
|
|
77
|
-
const key = `${req.method}:${routePattern}`;
|
|
78
|
-
if (!registeredPatterns.has(key)) {
|
|
79
|
-
registeredPatterns.add(key);
|
|
80
|
-
client.registerHttpEndpoint({ method: req.method, route: routePattern }).catch(() => {
|
|
81
|
-
registeredPatterns.delete(key);
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
};
|
|
87
|
-
res.on("finish", onFinish);
|
|
88
|
-
res.on("close", onFinish);
|
|
89
|
-
withTraceContext({ traceId: span.traceId, spanId: span.spanId }, () => {
|
|
90
|
-
next();
|
|
91
|
-
});
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
async function registerExpressRoutes(app, client, opts = {}) {
|
|
95
|
-
const { instanceId, endpoint, allowedCallers = [], excludePaths = [] } = opts;
|
|
96
|
-
const routes = extractExpressRoutes(app);
|
|
97
|
-
await Promise.allSettled(routes.filter(({ path }) => !excludePaths.some((p) => path.startsWith(p))).map(({ method, path: route }) => client.registerHttpEndpoint({
|
|
98
|
-
method,
|
|
99
|
-
route,
|
|
100
|
-
instanceId,
|
|
101
|
-
endpoint,
|
|
102
|
-
allowedCallers
|
|
103
|
-
})));
|
|
104
|
-
}
|
|
105
|
-
function getLayerStack(app) {
|
|
106
|
-
const r = app._router ?? app.router;
|
|
107
|
-
return r?.stack ?? app.stack ?? [];
|
|
108
|
-
}
|
|
109
|
-
function extractExpressRoutes(app, prefix = "") {
|
|
110
|
-
const routes = [];
|
|
111
|
-
const stack = getLayerStack(app);
|
|
112
|
-
for (const layer of stack) {
|
|
113
|
-
if (layer.route) {
|
|
114
|
-
const routePath = prefix + (layer.route.path ?? "");
|
|
115
|
-
const methods = Object.keys(layer.route.methods ?? {}).filter((m) => m !== "_all");
|
|
116
|
-
for (const method of methods) {
|
|
117
|
-
routes.push({ method: method.toUpperCase(), path: routePath });
|
|
118
|
-
}
|
|
119
|
-
} else if (layer.name === "router" && layer.handle) {
|
|
120
|
-
routes.push(...extractExpressRoutes(layer.handle, prefix));
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
return routes;
|
|
124
|
-
}
|
|
125
|
-
export {
|
|
126
|
-
servicebridgeMiddleware,
|
|
127
|
-
registerExpressRoutes,
|
|
128
|
-
extractTraceFromHeaders
|
|
129
|
-
};
|
package/dist/fastify.d.ts
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
|
|
2
|
-
import type { ServiceBridgeService } from "service-bridge";
|
|
3
|
-
declare module "fastify" {
|
|
4
|
-
interface FastifyRequest {
|
|
5
|
-
servicebridge: ServiceBridgeService;
|
|
6
|
-
traceId?: string;
|
|
7
|
-
spanId?: string;
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
export interface ServiceBridgeFastifyOptions {
|
|
11
|
-
/** ServiceBridge client (from servicebridge()). Required. */
|
|
12
|
-
client: ServiceBridgeService;
|
|
13
|
-
/** Paths to skip tracing. Default: [] */
|
|
14
|
-
excludePaths?: string[];
|
|
15
|
-
/** Set x-trace-id response header for propagation. Default: true */
|
|
16
|
-
propagateTraceHeader?: boolean;
|
|
17
|
-
/**
|
|
18
|
-
* Auto-register every route in the ServiceBridge HTTP catalog via Fastify's
|
|
19
|
-
* onRoute hook. Routes appear in the UI as soon as the server starts (before
|
|
20
|
-
* any traffic). Default: true.
|
|
21
|
-
*/
|
|
22
|
-
autoRegister?: boolean;
|
|
23
|
-
/**
|
|
24
|
-
* Options forwarded to registerHttpEndpoint for each auto-discovered route.
|
|
25
|
-
*/
|
|
26
|
-
register?: {
|
|
27
|
-
/** Stable identifier for this process instance. */
|
|
28
|
-
instanceId?: string;
|
|
29
|
-
/** Address where this service can be reached, e.g. "http://10.0.0.1:3000" */
|
|
30
|
-
endpoint?: string;
|
|
31
|
-
/** Service names allowed to call these endpoints. Default: [] */
|
|
32
|
-
allowedCallers?: string[];
|
|
33
|
-
/** Path prefixes to exclude from registration. Default: [] */
|
|
34
|
-
excludePaths?: string[];
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
export declare function servicebridgePlugin(fastify: FastifyInstance, options: ServiceBridgeFastifyOptions): Promise<void>;
|
|
38
|
-
/**
|
|
39
|
-
* Wraps a route handler to run inside trace context.
|
|
40
|
-
* Use when the handler calls req.servicebridge.rpc() or event() — ensures trace propagation.
|
|
41
|
-
*/
|
|
42
|
-
export declare function wrapHandler<T>(handler: (request: FastifyRequest, reply: FastifyReply) => T): (request: FastifyRequest, reply: FastifyReply) => T;
|
|
43
|
-
//# sourceMappingURL=fastify.d.ts.map
|
package/dist/fastify.js
DELETED
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
// http/src/fastify.ts
|
|
2
|
-
import { withTraceContext } from "service-bridge";
|
|
3
|
-
|
|
4
|
-
// http/src/trace.ts
|
|
5
|
-
function parseTraceparent(traceparent) {
|
|
6
|
-
const parts = traceparent.trim().split("-");
|
|
7
|
-
if (parts.length !== 4 || parts[0] !== "00")
|
|
8
|
-
return null;
|
|
9
|
-
const [, traceId, parentSpanId] = parts;
|
|
10
|
-
if (!traceId || !parentSpanId || traceId.length !== 32 || parentSpanId.length !== 16)
|
|
11
|
-
return null;
|
|
12
|
-
return { traceId, parentSpanId };
|
|
13
|
-
}
|
|
14
|
-
function randomTraceId() {
|
|
15
|
-
return crypto.randomUUID().replace(/-/g, "");
|
|
16
|
-
}
|
|
17
|
-
function extractTraceFromHeaders(headers) {
|
|
18
|
-
const traceparent = headers.traceparent;
|
|
19
|
-
const tp = Array.isArray(traceparent) ? traceparent[0] : traceparent;
|
|
20
|
-
if (tp) {
|
|
21
|
-
const parsed = parseTraceparent(tp);
|
|
22
|
-
if (parsed)
|
|
23
|
-
return parsed;
|
|
24
|
-
}
|
|
25
|
-
const xTraceId = headers["x-trace-id"];
|
|
26
|
-
const traceId = Array.isArray(xTraceId) ? xTraceId[0] : xTraceId;
|
|
27
|
-
if (traceId && typeof traceId === "string") {
|
|
28
|
-
return { traceId: traceId.trim(), parentSpanId: "" };
|
|
29
|
-
}
|
|
30
|
-
return { traceId: randomTraceId(), parentSpanId: "" };
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// http/src/fastify.ts
|
|
34
|
-
async function servicebridgePlugin(fastify, options) {
|
|
35
|
-
const {
|
|
36
|
-
client,
|
|
37
|
-
excludePaths = [],
|
|
38
|
-
propagateTraceHeader = true,
|
|
39
|
-
autoRegister = true,
|
|
40
|
-
register: registerOpts = {}
|
|
41
|
-
} = options;
|
|
42
|
-
fastify.decorateRequest("servicebridge", null);
|
|
43
|
-
fastify.decorateRequest("traceId", null);
|
|
44
|
-
fastify.decorateRequest("spanId", null);
|
|
45
|
-
if (autoRegister) {
|
|
46
|
-
const excludeReg = registerOpts.excludePaths ?? [];
|
|
47
|
-
fastify.addHook("onRoute", (routeOptions) => {
|
|
48
|
-
const routePath = routeOptions.url ?? routeOptions.path ?? "";
|
|
49
|
-
if (excludeReg.some((p) => routePath.startsWith(p)))
|
|
50
|
-
return;
|
|
51
|
-
const methods = Array.isArray(routeOptions.method) ? routeOptions.method : [routeOptions.method];
|
|
52
|
-
for (const method of methods) {
|
|
53
|
-
if (method === "HEAD" || method === "OPTIONS")
|
|
54
|
-
continue;
|
|
55
|
-
client.registerHttpEndpoint({
|
|
56
|
-
method,
|
|
57
|
-
route: routePath,
|
|
58
|
-
instanceId: registerOpts.instanceId,
|
|
59
|
-
endpoint: registerOpts.endpoint,
|
|
60
|
-
allowedCallers: registerOpts.allowedCallers ?? []
|
|
61
|
-
}).catch(() => {});
|
|
62
|
-
}
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
fastify.addHook("onRequest", async (request, reply) => {
|
|
66
|
-
request.servicebridge = client;
|
|
67
|
-
const path = request.url?.split("?")[0] ?? "/";
|
|
68
|
-
if (excludePaths.some((p) => path.startsWith(p))) {
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
const headers = {};
|
|
72
|
-
for (const [k, v] of Object.entries(request.headers)) {
|
|
73
|
-
if (typeof v === "string" || Array.isArray(v)) {
|
|
74
|
-
headers[k.toLowerCase()] = v;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
const traceCtx = extractTraceFromHeaders(headers);
|
|
78
|
-
const span = client.startHttpSpan({
|
|
79
|
-
method: request.method,
|
|
80
|
-
path,
|
|
81
|
-
traceId: traceCtx.traceId,
|
|
82
|
-
parentSpanId: traceCtx.parentSpanId
|
|
83
|
-
});
|
|
84
|
-
let ended = false;
|
|
85
|
-
const endSpan = (opts) => {
|
|
86
|
-
if (ended)
|
|
87
|
-
return;
|
|
88
|
-
ended = true;
|
|
89
|
-
span.end(opts);
|
|
90
|
-
};
|
|
91
|
-
request.traceId = span.traceId;
|
|
92
|
-
request.spanId = span.spanId;
|
|
93
|
-
if (propagateTraceHeader) {
|
|
94
|
-
reply.header("x-trace-id", span.traceId);
|
|
95
|
-
}
|
|
96
|
-
request.raw.once("close", () => {
|
|
97
|
-
if (!reply.sent) {
|
|
98
|
-
endSpan({ success: false, error: "connection closed" });
|
|
99
|
-
}
|
|
100
|
-
});
|
|
101
|
-
reply.raw.once("finish", () => {
|
|
102
|
-
endSpan({
|
|
103
|
-
statusCode: reply.statusCode,
|
|
104
|
-
success: reply.statusCode < 400
|
|
105
|
-
});
|
|
106
|
-
});
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
function wrapHandler(handler) {
|
|
110
|
-
return (request, reply) => {
|
|
111
|
-
const traceId = request.traceId;
|
|
112
|
-
const spanId = request.spanId;
|
|
113
|
-
if (traceId && spanId) {
|
|
114
|
-
return withTraceContext({ traceId, spanId }, () => handler(request, reply));
|
|
115
|
-
}
|
|
116
|
-
return handler(request, reply);
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
export {
|
|
120
|
-
wrapHandler,
|
|
121
|
-
servicebridgePlugin
|
|
122
|
-
};
|
package/dist/trace.d.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
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
|
-
* Extract distributed trace context from incoming HTTP request headers.
|
|
12
|
-
*
|
|
13
|
-
* Priority:
|
|
14
|
-
* 1. W3C `traceparent` — full parent info (traceId + parentSpanId)
|
|
15
|
-
* 2. `x-trace-id` — traceId only, no parent span known
|
|
16
|
-
* 3. Nothing — generate a fresh traceId, no parent
|
|
17
|
-
*/
|
|
18
|
-
export declare function extractTraceFromHeaders(headers: Record<string, string | string[] | undefined>): IncomingTraceContext;
|
|
19
|
-
//# sourceMappingURL=trace.d.ts.map
|