@glubean/grpc 0.1.1
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/README.md +166 -0
- package/dist/index.d.ts +172 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +273 -0
- package/dist/index.js.map +1 -0
- package/package.json +34 -0
package/README.md
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# @glubean/grpc
|
|
2
|
+
|
|
3
|
+
gRPC plugin for [Glubean](https://glubean.dev) — workflow-level gRPC testing with built-in tracing.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @glubean/grpc @grpc/grpc-js @grpc/proto-loader
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
`@grpc/grpc-js` and `@grpc/proto-loader` are peer dependencies — you install them alongside the plugin.
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { test, configure } from "@glubean/sdk";
|
|
17
|
+
import { grpc } from "@glubean/grpc";
|
|
18
|
+
|
|
19
|
+
const { users } = configure({
|
|
20
|
+
plugins: {
|
|
21
|
+
users: grpc({
|
|
22
|
+
proto: "./protos/users.proto",
|
|
23
|
+
address: "{{USER_SERVICE_ADDR}}",
|
|
24
|
+
package: "acme.users.v1",
|
|
25
|
+
service: "UsersService",
|
|
26
|
+
metadata: { authorization: "Bearer {{API_TOKEN}}" },
|
|
27
|
+
}),
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
export const getUser = test("get-user", async (ctx) => {
|
|
32
|
+
const res = await users.call("GetUser", { id: "u_123" });
|
|
33
|
+
ctx.expect(res.status.code).toBe(0);
|
|
34
|
+
ctx.expect(res.message.user.id).toBe("u_123");
|
|
35
|
+
});
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Standalone (without `configure()`)
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
import { createGrpcClient } from "@glubean/grpc";
|
|
42
|
+
|
|
43
|
+
const client = createGrpcClient({
|
|
44
|
+
proto: "./protos/billing.proto",
|
|
45
|
+
address: "localhost:50051",
|
|
46
|
+
package: "acme.billing.v1",
|
|
47
|
+
service: "BillingService",
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const res = await client.call("CreateInvoice", {
|
|
51
|
+
customer_id: "cus_123",
|
|
52
|
+
amount_cents: 1200,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
console.log(res.status.code); // 0 = OK
|
|
56
|
+
console.log(res.message); // decoded response
|
|
57
|
+
console.log(res.duration); // ms
|
|
58
|
+
|
|
59
|
+
client.close();
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## API
|
|
63
|
+
|
|
64
|
+
### `grpc(options)` — Plugin Factory
|
|
65
|
+
|
|
66
|
+
For use with `configure({ plugins })`. Supports `{{template}}` placeholders in `address` and `metadata` values, resolved from Glubean vars and secrets.
|
|
67
|
+
|
|
68
|
+
| Option | Type | Description |
|
|
69
|
+
|--------|------|-------------|
|
|
70
|
+
| `proto` | `string` | Path to `.proto` file |
|
|
71
|
+
| `address` | `string` | Server address (`host:port`), supports `{{VAR}}` |
|
|
72
|
+
| `package` | `string` | Protobuf package name |
|
|
73
|
+
| `service` | `string` | Service name |
|
|
74
|
+
| `metadata` | `Record<string, string>` | Static metadata, supports `{{VAR}}` |
|
|
75
|
+
| `tls` | `boolean` | Use TLS (default: `false`) |
|
|
76
|
+
| `deadlineMs` | `number` | Default deadline in ms (default: `30000`) |
|
|
77
|
+
|
|
78
|
+
### `createGrpcClient(options, hooks?)` — Standalone
|
|
79
|
+
|
|
80
|
+
Same options as above (without template support). Optional `hooks` parameter for instrumentation:
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
createGrpcClient(options, {
|
|
84
|
+
event: (ev) => { /* trace event */ },
|
|
85
|
+
});
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### `client.call(method, request, options?)`
|
|
89
|
+
|
|
90
|
+
Make a unary RPC call.
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
const res = await client.call("GetUser", { id: "u_123" }, {
|
|
94
|
+
deadlineMs: 5000,
|
|
95
|
+
metadata: { "x-request-id": "abc" },
|
|
96
|
+
});
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Returns `GrpcCallResult`:
|
|
100
|
+
|
|
101
|
+
| Field | Type | Description |
|
|
102
|
+
|-------|------|-------------|
|
|
103
|
+
| `message` | `T` | Decoded response |
|
|
104
|
+
| `status.code` | `number` | gRPC status code (0 = OK) |
|
|
105
|
+
| `status.details` | `string` | Status details |
|
|
106
|
+
| `duration` | `number` | Call duration in ms |
|
|
107
|
+
| `responseMetadata` | `Record<string, string>` | Server response metadata |
|
|
108
|
+
|
|
109
|
+
Errors don't throw — they return with a non-zero `status.code` for assertion-friendly testing.
|
|
110
|
+
|
|
111
|
+
### `client.close()`
|
|
112
|
+
|
|
113
|
+
Close the underlying gRPC channel.
|
|
114
|
+
|
|
115
|
+
## Tracing
|
|
116
|
+
|
|
117
|
+
Every RPC call emits a single `trace` event with the full request/response cycle:
|
|
118
|
+
|
|
119
|
+
| Field | Type | Description |
|
|
120
|
+
|-------|------|-------------|
|
|
121
|
+
| `protocol` | `"grpc"` | Protocol discriminator |
|
|
122
|
+
| `target` | `string` | `Service/Method` |
|
|
123
|
+
| `status` | `number` | gRPC status code (0 = OK) |
|
|
124
|
+
| `durationMs` | `number` | Call duration in ms |
|
|
125
|
+
| `ok` | `boolean` | `true` if status is 0 |
|
|
126
|
+
| `service` | `string` | Service name |
|
|
127
|
+
| `method` | `string` | RPC method name |
|
|
128
|
+
| `peer` | `string` | Server address |
|
|
129
|
+
| `request` | `object` | Request payload |
|
|
130
|
+
| `response` | `object` | Response payload (success only) |
|
|
131
|
+
| `metadata` | `object` | Merged request metadata (static + per-call) |
|
|
132
|
+
|
|
133
|
+
These traces share the same event channel as HTTP traces, enabling unified timeline rendering in the Glubean dashboard.
|
|
134
|
+
|
|
135
|
+
## Auth
|
|
136
|
+
|
|
137
|
+
Static metadata (including auth tokens) is sent with every call:
|
|
138
|
+
|
|
139
|
+
```ts
|
|
140
|
+
grpc({
|
|
141
|
+
// ...
|
|
142
|
+
metadata: { authorization: "Bearer {{API_TOKEN}}" },
|
|
143
|
+
});
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Per-call metadata overrides static values:
|
|
147
|
+
|
|
148
|
+
```ts
|
|
149
|
+
await client.call("GetUser", { id: "u_123" }, {
|
|
150
|
+
metadata: { authorization: "Bearer per-call-token" },
|
|
151
|
+
});
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Scope
|
|
155
|
+
|
|
156
|
+
This is a v1 focused on unary RPC. Not included:
|
|
157
|
+
|
|
158
|
+
- Server / client / bidirectional streaming
|
|
159
|
+
- Reflection-based service discovery
|
|
160
|
+
- Static codegen / type generation
|
|
161
|
+
- grpc-web / Connect RPC
|
|
162
|
+
- Retry policies
|
|
163
|
+
|
|
164
|
+
## License
|
|
165
|
+
|
|
166
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* gRPC plugin for Glubean tests.
|
|
3
|
+
*
|
|
4
|
+
* Provides a thin wrapper over `@grpc/grpc-js` that simplifies
|
|
5
|
+
* unary gRPC calls with auto-tracing via Glubean events.
|
|
6
|
+
*
|
|
7
|
+
* ## Usage
|
|
8
|
+
*
|
|
9
|
+
* ### As a plugin via `configure()` (recommended)
|
|
10
|
+
*
|
|
11
|
+
* ```ts
|
|
12
|
+
* import { test, configure } from "@glubean/sdk";
|
|
13
|
+
* import { grpc } from "@glubean/grpc";
|
|
14
|
+
*
|
|
15
|
+
* const { users } = configure({
|
|
16
|
+
* plugins: {
|
|
17
|
+
* users: grpc({
|
|
18
|
+
* proto: "./protos/users.proto",
|
|
19
|
+
* address: "{{USER_SERVICE_ADDR}}",
|
|
20
|
+
* package: "acme.users.v1",
|
|
21
|
+
* service: "UsersService",
|
|
22
|
+
* }),
|
|
23
|
+
* },
|
|
24
|
+
* });
|
|
25
|
+
*
|
|
26
|
+
* export const getUser = test("get-user", async (ctx) => {
|
|
27
|
+
* const res = await users.call("GetUser", { id: "u_123" });
|
|
28
|
+
* ctx.expect(res.status.code).toBe(0);
|
|
29
|
+
* ctx.expect(res.message.user.id).toBe("u_123");
|
|
30
|
+
* });
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* ### Standalone (without `configure()`)
|
|
34
|
+
*
|
|
35
|
+
* ```ts
|
|
36
|
+
* import { createGrpcClient } from "@glubean/grpc";
|
|
37
|
+
*
|
|
38
|
+
* const client = createGrpcClient({
|
|
39
|
+
* proto: "./protos/users.proto",
|
|
40
|
+
* address: "localhost:50051",
|
|
41
|
+
* package: "acme.users.v1",
|
|
42
|
+
* service: "UsersService",
|
|
43
|
+
* });
|
|
44
|
+
*
|
|
45
|
+
* const res = await client.call("GetUser", { id: "u_123" });
|
|
46
|
+
* ```
|
|
47
|
+
*
|
|
48
|
+
* @module grpc
|
|
49
|
+
*/
|
|
50
|
+
import type * as grpcTypes from "@grpc/grpc-js";
|
|
51
|
+
import type { PluginFactory } from "@glubean/sdk";
|
|
52
|
+
/** Options for creating a gRPC client. */
|
|
53
|
+
export interface GrpcClientOptions {
|
|
54
|
+
/** Path to the .proto file */
|
|
55
|
+
proto: string;
|
|
56
|
+
/** gRPC server address (host:port) */
|
|
57
|
+
address: string;
|
|
58
|
+
/** Protobuf package name (e.g., "acme.users.v1") */
|
|
59
|
+
package: string;
|
|
60
|
+
/** Service name within the package (e.g., "UsersService") */
|
|
61
|
+
service: string;
|
|
62
|
+
/** Static metadata sent with every call */
|
|
63
|
+
metadata?: Record<string, string>;
|
|
64
|
+
/** Use TLS credentials. Default: false (insecure) */
|
|
65
|
+
tls?: boolean;
|
|
66
|
+
/** Default deadline in milliseconds for all calls */
|
|
67
|
+
deadlineMs?: number;
|
|
68
|
+
}
|
|
69
|
+
/** gRPC status returned with every call. */
|
|
70
|
+
export interface GrpcStatus {
|
|
71
|
+
/** gRPC status code (0 = OK) */
|
|
72
|
+
code: number;
|
|
73
|
+
/** Human-readable status details */
|
|
74
|
+
details: string;
|
|
75
|
+
}
|
|
76
|
+
/** Result of a unary gRPC call. */
|
|
77
|
+
export interface GrpcCallResult<T = unknown> {
|
|
78
|
+
/** Decoded response message */
|
|
79
|
+
message: T;
|
|
80
|
+
/** gRPC status */
|
|
81
|
+
status: GrpcStatus;
|
|
82
|
+
/** Response metadata from the server */
|
|
83
|
+
responseMetadata: Record<string, string>;
|
|
84
|
+
/** Duration of the call in milliseconds */
|
|
85
|
+
duration: number;
|
|
86
|
+
}
|
|
87
|
+
/** Per-call options. */
|
|
88
|
+
export interface GrpcCallOptions {
|
|
89
|
+
/** Override deadline for this call (ms) */
|
|
90
|
+
deadlineMs?: number;
|
|
91
|
+
/** Additional metadata for this call only */
|
|
92
|
+
metadata?: Record<string, string>;
|
|
93
|
+
}
|
|
94
|
+
/** A gRPC client bound to a specific service. */
|
|
95
|
+
export interface GrpcClient {
|
|
96
|
+
/** Make a unary RPC call. */
|
|
97
|
+
call<T = unknown>(method: string, request: Record<string, unknown>, options?: GrpcCallOptions): Promise<GrpcCallResult<T>>;
|
|
98
|
+
/** Close the underlying channel. */
|
|
99
|
+
close(): void;
|
|
100
|
+
/** The underlying `@grpc/grpc-js` client for direct access (streaming, channel state, etc.). */
|
|
101
|
+
raw: grpcTypes.Client;
|
|
102
|
+
}
|
|
103
|
+
/** Hooks for Glubean runtime instrumentation. */
|
|
104
|
+
export interface GrpcHooks {
|
|
105
|
+
event?: (ev: {
|
|
106
|
+
type: string;
|
|
107
|
+
data: Record<string, unknown>;
|
|
108
|
+
}) => void;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Create a gRPC client bound to a specific service.
|
|
112
|
+
*
|
|
113
|
+
* @param options Client configuration
|
|
114
|
+
* @param hooks Optional Glubean runtime hooks for action/event/log
|
|
115
|
+
* @returns A bound `GrpcClient` instance
|
|
116
|
+
*/
|
|
117
|
+
export declare function createGrpcClient(options: GrpcClientOptions, hooks?: GrpcHooks): GrpcClient;
|
|
118
|
+
/**
|
|
119
|
+
* Plugin options for use with `configure()`.
|
|
120
|
+
* `address` supports `{{VAR}}` template syntax.
|
|
121
|
+
* `metadata` values support `{{VAR}}` template syntax.
|
|
122
|
+
*/
|
|
123
|
+
export interface GrpcPluginOptions {
|
|
124
|
+
/** Path to the .proto file */
|
|
125
|
+
proto: string;
|
|
126
|
+
/** Var key or `{{template}}` for the gRPC address */
|
|
127
|
+
address: string;
|
|
128
|
+
/** Protobuf package name */
|
|
129
|
+
package: string;
|
|
130
|
+
/** Service name */
|
|
131
|
+
service: string;
|
|
132
|
+
/** Metadata with `{{template}}` support */
|
|
133
|
+
metadata?: Record<string, string>;
|
|
134
|
+
/** Use TLS */
|
|
135
|
+
tls?: boolean;
|
|
136
|
+
/** Default deadline in ms */
|
|
137
|
+
deadlineMs?: number;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Create a gRPC plugin for use with `configure({ plugins })`.
|
|
141
|
+
*
|
|
142
|
+
* Resolves `{{template}}` placeholders in `address` and `metadata` using
|
|
143
|
+
* the Glubean runtime (vars and secrets).
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```ts
|
|
147
|
+
* import { test, configure } from "@glubean/sdk";
|
|
148
|
+
* import { grpc } from "@glubean/grpc";
|
|
149
|
+
*
|
|
150
|
+
* const { billing } = configure({
|
|
151
|
+
* plugins: {
|
|
152
|
+
* billing: grpc({
|
|
153
|
+
* proto: "./protos/billing.proto",
|
|
154
|
+
* address: "{{BILLING_ADDR}}",
|
|
155
|
+
* package: "acme.billing.v1",
|
|
156
|
+
* service: "BillingService",
|
|
157
|
+
* metadata: { authorization: "Bearer {{API_TOKEN}}" },
|
|
158
|
+
* }),
|
|
159
|
+
* },
|
|
160
|
+
* });
|
|
161
|
+
*
|
|
162
|
+
* export const createInvoice = test("create-invoice", async (ctx) => {
|
|
163
|
+
* const res = await billing.call("CreateInvoice", {
|
|
164
|
+
* customer_id: "cus_123",
|
|
165
|
+
* amount_cents: 1200,
|
|
166
|
+
* });
|
|
167
|
+
* ctx.expect(res.status.code).toBe(0);
|
|
168
|
+
* });
|
|
169
|
+
* ```
|
|
170
|
+
*/
|
|
171
|
+
export declare function grpc(options: GrpcPluginOptions): PluginFactory<GrpcClient>;
|
|
172
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* gRPC plugin for Glubean tests.
|
|
3
|
+
*
|
|
4
|
+
* Provides a thin wrapper over `@grpc/grpc-js` that simplifies
|
|
5
|
+
* unary gRPC calls with auto-tracing via Glubean events.
|
|
6
|
+
*
|
|
7
|
+
* ## Usage
|
|
8
|
+
*
|
|
9
|
+
* ### As a plugin via `configure()` (recommended)
|
|
10
|
+
*
|
|
11
|
+
* ```ts
|
|
12
|
+
* import { test, configure } from "@glubean/sdk";
|
|
13
|
+
* import { grpc } from "@glubean/grpc";
|
|
14
|
+
*
|
|
15
|
+
* const { users } = configure({
|
|
16
|
+
* plugins: {
|
|
17
|
+
* users: grpc({
|
|
18
|
+
* proto: "./protos/users.proto",
|
|
19
|
+
* address: "{{USER_SERVICE_ADDR}}",
|
|
20
|
+
* package: "acme.users.v1",
|
|
21
|
+
* service: "UsersService",
|
|
22
|
+
* }),
|
|
23
|
+
* },
|
|
24
|
+
* });
|
|
25
|
+
*
|
|
26
|
+
* export const getUser = test("get-user", async (ctx) => {
|
|
27
|
+
* const res = await users.call("GetUser", { id: "u_123" });
|
|
28
|
+
* ctx.expect(res.status.code).toBe(0);
|
|
29
|
+
* ctx.expect(res.message.user.id).toBe("u_123");
|
|
30
|
+
* });
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* ### Standalone (without `configure()`)
|
|
34
|
+
*
|
|
35
|
+
* ```ts
|
|
36
|
+
* import { createGrpcClient } from "@glubean/grpc";
|
|
37
|
+
*
|
|
38
|
+
* const client = createGrpcClient({
|
|
39
|
+
* proto: "./protos/users.proto",
|
|
40
|
+
* address: "localhost:50051",
|
|
41
|
+
* package: "acme.users.v1",
|
|
42
|
+
* service: "UsersService",
|
|
43
|
+
* });
|
|
44
|
+
*
|
|
45
|
+
* const res = await client.call("GetUser", { id: "u_123" });
|
|
46
|
+
* ```
|
|
47
|
+
*
|
|
48
|
+
* @module grpc
|
|
49
|
+
*/
|
|
50
|
+
import { definePlugin } from "@glubean/sdk/plugin";
|
|
51
|
+
let grpcJs;
|
|
52
|
+
let protoLoader;
|
|
53
|
+
try {
|
|
54
|
+
grpcJs = await import("@grpc/grpc-js");
|
|
55
|
+
protoLoader = await import("@grpc/proto-loader");
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
throw new Error('@glubean/grpc requires "@grpc/grpc-js" and "@grpc/proto-loader" as peer dependencies.\n' +
|
|
59
|
+
"Install them with:\n\n" +
|
|
60
|
+
" npm install @grpc/grpc-js @grpc/proto-loader\n");
|
|
61
|
+
}
|
|
62
|
+
// =============================================================================
|
|
63
|
+
// Client implementation
|
|
64
|
+
// =============================================================================
|
|
65
|
+
/**
|
|
66
|
+
* Resolve a nested package from a loaded proto definition.
|
|
67
|
+
*
|
|
68
|
+
* For example, `resolvePackage(def, "acme.users.v1")` traverses
|
|
69
|
+
* `def.acme.users.v1`.
|
|
70
|
+
*/
|
|
71
|
+
function resolvePackage(packageDef, packageName) {
|
|
72
|
+
const parts = packageName.split(".");
|
|
73
|
+
let current = packageDef;
|
|
74
|
+
for (const part of parts) {
|
|
75
|
+
const next = current[part];
|
|
76
|
+
if (!next || typeof next !== "object") {
|
|
77
|
+
throw new Error(`Package "${packageName}" not found in proto definition (failed at "${part}")`);
|
|
78
|
+
}
|
|
79
|
+
current = next;
|
|
80
|
+
}
|
|
81
|
+
return current;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Build gRPC metadata from a plain object.
|
|
85
|
+
*/
|
|
86
|
+
function buildMetadata(base, extra) {
|
|
87
|
+
const md = new grpcJs.Metadata();
|
|
88
|
+
if (base) {
|
|
89
|
+
for (const [k, v] of Object.entries(base)) {
|
|
90
|
+
md.set(k, v);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
if (extra) {
|
|
94
|
+
for (const [k, v] of Object.entries(extra)) {
|
|
95
|
+
md.set(k, v);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return md;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Create a gRPC client bound to a specific service.
|
|
102
|
+
*
|
|
103
|
+
* @param options Client configuration
|
|
104
|
+
* @param hooks Optional Glubean runtime hooks for action/event/log
|
|
105
|
+
* @returns A bound `GrpcClient` instance
|
|
106
|
+
*/
|
|
107
|
+
export function createGrpcClient(options, hooks) {
|
|
108
|
+
const packageDefinition = protoLoader.loadSync(options.proto, {
|
|
109
|
+
keepCase: true,
|
|
110
|
+
longs: String,
|
|
111
|
+
enums: String,
|
|
112
|
+
defaults: true,
|
|
113
|
+
oneofs: true,
|
|
114
|
+
});
|
|
115
|
+
const packageDef = grpcJs.loadPackageDefinition(packageDefinition);
|
|
116
|
+
const servicePkg = resolvePackage(packageDef, options.package);
|
|
117
|
+
const ServiceConstructor = servicePkg[options.service];
|
|
118
|
+
if (!ServiceConstructor || typeof ServiceConstructor !== "function") {
|
|
119
|
+
throw new Error(`Service "${options.service}" not found in package "${options.package}"`);
|
|
120
|
+
}
|
|
121
|
+
const credentials = options.tls
|
|
122
|
+
? grpcJs.credentials.createSsl()
|
|
123
|
+
: grpcJs.credentials.createInsecure();
|
|
124
|
+
const client = new ServiceConstructor(options.address, credentials);
|
|
125
|
+
return {
|
|
126
|
+
call(method, request, callOptions) {
|
|
127
|
+
return new Promise((resolve, reject) => {
|
|
128
|
+
const fn = client[method];
|
|
129
|
+
if (typeof fn !== "function") {
|
|
130
|
+
reject(new Error(`Method "${method}" not found on service "${options.service}"`));
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
const md = buildMetadata(options.metadata, callOptions?.metadata);
|
|
134
|
+
const deadlineMs = callOptions?.deadlineMs ?? options.deadlineMs ?? 30_000;
|
|
135
|
+
const deadline = new Date(Date.now() + deadlineMs);
|
|
136
|
+
const target = `${options.service}/${method}`;
|
|
137
|
+
// Merge static + per-call metadata into a plain object for tracing
|
|
138
|
+
const mergedMetadata = {
|
|
139
|
+
...options.metadata,
|
|
140
|
+
...callOptions?.metadata,
|
|
141
|
+
};
|
|
142
|
+
const start = performance.now();
|
|
143
|
+
let responseMetadata = {};
|
|
144
|
+
const call = fn.call(client, request, md, { deadline }, (err, response) => {
|
|
145
|
+
const durationMs = Math.round(performance.now() - start);
|
|
146
|
+
if (err) {
|
|
147
|
+
const status = {
|
|
148
|
+
code: err.code ?? grpcJs.status.UNKNOWN,
|
|
149
|
+
details: err.details ?? err.message,
|
|
150
|
+
};
|
|
151
|
+
// Extract response metadata from error if available
|
|
152
|
+
if (err.metadata) {
|
|
153
|
+
for (const [k, values] of Object.entries(err.metadata.getMap())) {
|
|
154
|
+
responseMetadata[k] = String(values);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
hooks?.event?.({
|
|
158
|
+
type: "trace",
|
|
159
|
+
data: {
|
|
160
|
+
protocol: "grpc",
|
|
161
|
+
target,
|
|
162
|
+
status: status.code,
|
|
163
|
+
durationMs,
|
|
164
|
+
ok: false,
|
|
165
|
+
service: options.service,
|
|
166
|
+
method,
|
|
167
|
+
peer: options.address,
|
|
168
|
+
request,
|
|
169
|
+
metadata: mergedMetadata,
|
|
170
|
+
},
|
|
171
|
+
});
|
|
172
|
+
// Still resolve with status info instead of rejecting
|
|
173
|
+
// This matches Glubean's pattern of returning results for assertions
|
|
174
|
+
resolve({
|
|
175
|
+
message: (response ?? {}),
|
|
176
|
+
status,
|
|
177
|
+
responseMetadata,
|
|
178
|
+
duration: durationMs,
|
|
179
|
+
});
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
hooks?.event?.({
|
|
183
|
+
type: "trace",
|
|
184
|
+
data: {
|
|
185
|
+
protocol: "grpc",
|
|
186
|
+
target,
|
|
187
|
+
status: grpcJs.status.OK,
|
|
188
|
+
durationMs,
|
|
189
|
+
ok: true,
|
|
190
|
+
service: options.service,
|
|
191
|
+
method,
|
|
192
|
+
peer: options.address,
|
|
193
|
+
request,
|
|
194
|
+
response,
|
|
195
|
+
metadata: mergedMetadata,
|
|
196
|
+
},
|
|
197
|
+
});
|
|
198
|
+
resolve({
|
|
199
|
+
message: response,
|
|
200
|
+
status: { code: grpcJs.status.OK, details: "OK" },
|
|
201
|
+
responseMetadata,
|
|
202
|
+
duration: durationMs,
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
// Capture response headers metadata
|
|
206
|
+
call.on("metadata", (md) => {
|
|
207
|
+
for (const [k, values] of Object.entries(md.getMap())) {
|
|
208
|
+
responseMetadata[k] = String(values);
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
},
|
|
213
|
+
close() {
|
|
214
|
+
client.close();
|
|
215
|
+
},
|
|
216
|
+
raw: client,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Create a gRPC plugin for use with `configure({ plugins })`.
|
|
221
|
+
*
|
|
222
|
+
* Resolves `{{template}}` placeholders in `address` and `metadata` using
|
|
223
|
+
* the Glubean runtime (vars and secrets).
|
|
224
|
+
*
|
|
225
|
+
* @example
|
|
226
|
+
* ```ts
|
|
227
|
+
* import { test, configure } from "@glubean/sdk";
|
|
228
|
+
* import { grpc } from "@glubean/grpc";
|
|
229
|
+
*
|
|
230
|
+
* const { billing } = configure({
|
|
231
|
+
* plugins: {
|
|
232
|
+
* billing: grpc({
|
|
233
|
+
* proto: "./protos/billing.proto",
|
|
234
|
+
* address: "{{BILLING_ADDR}}",
|
|
235
|
+
* package: "acme.billing.v1",
|
|
236
|
+
* service: "BillingService",
|
|
237
|
+
* metadata: { authorization: "Bearer {{API_TOKEN}}" },
|
|
238
|
+
* }),
|
|
239
|
+
* },
|
|
240
|
+
* });
|
|
241
|
+
*
|
|
242
|
+
* export const createInvoice = test("create-invoice", async (ctx) => {
|
|
243
|
+
* const res = await billing.call("CreateInvoice", {
|
|
244
|
+
* customer_id: "cus_123",
|
|
245
|
+
* amount_cents: 1200,
|
|
246
|
+
* });
|
|
247
|
+
* ctx.expect(res.status.code).toBe(0);
|
|
248
|
+
* });
|
|
249
|
+
* ```
|
|
250
|
+
*/
|
|
251
|
+
export function grpc(options) {
|
|
252
|
+
return definePlugin((runtime) => {
|
|
253
|
+
const resolvedAddress = runtime.resolveTemplate(options.address);
|
|
254
|
+
const resolvedMetadata = options.metadata
|
|
255
|
+
? Object.fromEntries(Object.entries(options.metadata).map(([k, v]) => [
|
|
256
|
+
k,
|
|
257
|
+
runtime.resolveTemplate(v),
|
|
258
|
+
]))
|
|
259
|
+
: undefined;
|
|
260
|
+
return createGrpcClient({
|
|
261
|
+
proto: options.proto,
|
|
262
|
+
address: resolvedAddress,
|
|
263
|
+
package: options.package,
|
|
264
|
+
service: options.service,
|
|
265
|
+
metadata: resolvedMetadata,
|
|
266
|
+
tls: options.tls,
|
|
267
|
+
deadlineMs: options.deadlineMs,
|
|
268
|
+
}, {
|
|
269
|
+
event: (ev) => runtime.event(ev),
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@glubean/grpc",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"exports": {
|
|
6
|
+
".": {
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"import": "./dist/index.js"
|
|
9
|
+
}
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist"
|
|
13
|
+
],
|
|
14
|
+
"publishConfig": {
|
|
15
|
+
"access": "public"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@glubean/sdk": "0.1.7"
|
|
19
|
+
},
|
|
20
|
+
"peerDependencies": {
|
|
21
|
+
"@grpc/grpc-js": "^1.12.0",
|
|
22
|
+
"@grpc/proto-loader": "^0.7.0"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@grpc/grpc-js": "^1.14.0",
|
|
26
|
+
"@grpc/proto-loader": "^0.7.0",
|
|
27
|
+
"vitest": "^3.2.1",
|
|
28
|
+
"typescript": "^5.8.3"
|
|
29
|
+
},
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "tsc -p tsconfig.build.json",
|
|
32
|
+
"test": "vitest run"
|
|
33
|
+
}
|
|
34
|
+
}
|