@webda/grpc 4.0.0-beta.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.
- package/.webda/cache +4 -0
- package/CHANGELOG.md +54 -0
- package/LICENSE +166 -0
- package/README.md +100 -0
- package/lib/grpc-stream.d.ts +109 -0
- package/lib/grpc-stream.d.ts.map +1 -0
- package/lib/grpc-stream.js +162 -0
- package/lib/grpc-stream.js.map +1 -0
- package/lib/grpcservice.service.d.ts +112 -0
- package/lib/grpcservice.service.d.ts.map +1 -0
- package/lib/grpcservice.service.js +459 -0
- package/lib/grpcservice.service.js.map +1 -0
- package/lib/index.d.ts +5 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +4 -0
- package/lib/index.js.map +1 -0
- package/lib/proto-generator.d.ts +14 -0
- package/lib/proto-generator.d.ts.map +1 -0
- package/lib/proto-generator.js +312 -0
- package/lib/proto-generator.js.map +1 -0
- package/package.json +42 -0
- package/src/build-integration.spec.ts +187 -0
- package/src/grpc-stream.spec.ts +417 -0
- package/src/grpc-stream.ts +192 -0
- package/src/grpcservice.service.ts +462 -0
- package/src/grpcservice.spec.ts +1092 -0
- package/src/index.ts +4 -0
- package/src/proto-generator.spec.ts +696 -0
- package/src/proto-generator.ts +338 -0
- package/tsconfig.json +33 -0
- package/vitest.config.ts +20 -0
- package/webda.module.json +111 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { OperationsTransport, OperationsTransportParameters, OperationDefinition } from "@webda/core";
|
|
2
|
+
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
3
|
+
/**
|
|
4
|
+
* Parameters for the gRPC service
|
|
5
|
+
*/
|
|
6
|
+
export declare class GrpcServiceParameters extends OperationsTransportParameters {
|
|
7
|
+
/**
|
|
8
|
+
* Path to the generated .proto file
|
|
9
|
+
* @default ".webda/app.proto"
|
|
10
|
+
*/
|
|
11
|
+
protoFile?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Protobuf package name
|
|
14
|
+
* @default "webda"
|
|
15
|
+
*/
|
|
16
|
+
packageName?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Load and apply default parameter values.
|
|
19
|
+
* @param params - raw configuration object to load into this parameters instance
|
|
20
|
+
* @returns this instance with defaults applied
|
|
21
|
+
*/
|
|
22
|
+
load(params?: any): this;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* gRPC transport service.
|
|
26
|
+
*
|
|
27
|
+
* Exposes Webda operations as gRPC services over HTTP/2.
|
|
28
|
+
* Hooks into the HttpServer via the `Webda.Init.Http` event to intercept
|
|
29
|
+
* requests with `content-type: application/grpc`.
|
|
30
|
+
*
|
|
31
|
+
* Run `webdac build` to generate the .proto file from operations.
|
|
32
|
+
*
|
|
33
|
+
* @WebdaModda
|
|
34
|
+
*/
|
|
35
|
+
export declare class GrpcService<T extends GrpcServiceParameters = GrpcServiceParameters> extends OperationsTransport<T> {
|
|
36
|
+
/** Loaded protobuf definitions */
|
|
37
|
+
private definitions;
|
|
38
|
+
/** Map of gRPC path → operation ID */
|
|
39
|
+
private rpcToOperation;
|
|
40
|
+
/** Map of gRPC path → method definition */
|
|
41
|
+
private rpcMethods;
|
|
42
|
+
/**
|
|
43
|
+
* Generate a .proto file from the current operation registry.
|
|
44
|
+
*
|
|
45
|
+
* @returns a promise that resolves when the proto file has been written to disk
|
|
46
|
+
*/
|
|
47
|
+
build(): Promise<void>;
|
|
48
|
+
/**
|
|
49
|
+
* Count unique service prefixes in operations
|
|
50
|
+
* @param operations - map of operation IDs to their definitions
|
|
51
|
+
* @returns the number of distinct gRPC service groups derived from operation prefixes
|
|
52
|
+
*/
|
|
53
|
+
private countServices;
|
|
54
|
+
/**
|
|
55
|
+
* Initialize the gRPC transport: load proto, build RPC map, hook into HTTP/2.
|
|
56
|
+
* @returns a promise resolving to this service instance once initialization is complete
|
|
57
|
+
*/
|
|
58
|
+
init(): Promise<this>;
|
|
59
|
+
/**
|
|
60
|
+
* Build the mapping from gRPC path → operation ID using the loaded proto definitions.
|
|
61
|
+
*/
|
|
62
|
+
private buildRpcMap;
|
|
63
|
+
/**
|
|
64
|
+
* Handle an incoming gRPC request.
|
|
65
|
+
*
|
|
66
|
+
* Called by the HttpServer when content-type is application/grpc.
|
|
67
|
+
*
|
|
68
|
+
* @param req - HTTP/2 request carrying the gRPC method path and framed message body
|
|
69
|
+
* @param res - HTTP/2 response used to write gRPC frames and trailers
|
|
70
|
+
* @returns a promise that resolves when the response has been fully sent
|
|
71
|
+
*/
|
|
72
|
+
handleGrpcRequest(req: IncomingMessage, res: ServerResponse): Promise<void>;
|
|
73
|
+
/**
|
|
74
|
+
* Handle a unary gRPC call (single request → single response).
|
|
75
|
+
* @param stream - the active GrpcStream for this request
|
|
76
|
+
* @param opId - the Webda operation ID to invoke
|
|
77
|
+
* @param methodDef - the protobuf method definition with serializer functions
|
|
78
|
+
* @returns a promise that resolves when the unary response has been sent
|
|
79
|
+
*/
|
|
80
|
+
private handleUnary;
|
|
81
|
+
/**
|
|
82
|
+
* Handle server streaming (single request → stream of responses).
|
|
83
|
+
* Maps to AsyncGenerator operations.
|
|
84
|
+
* @param stream - the active GrpcStream for this request
|
|
85
|
+
* @param opId - the Webda operation ID to invoke
|
|
86
|
+
* @param methodDef - the protobuf method definition with serializer functions
|
|
87
|
+
* @returns a promise that resolves when all response frames have been sent
|
|
88
|
+
*/
|
|
89
|
+
private handleServerStreaming;
|
|
90
|
+
/**
|
|
91
|
+
* Handle client or bidirectional streaming.
|
|
92
|
+
* @param stream - the active GrpcStream for this request
|
|
93
|
+
* @param opId - the Webda operation ID to invoke
|
|
94
|
+
* @param streaming - streaming mode, either "client" or "bidi"
|
|
95
|
+
* @returns a promise that resolves when the operation completes and the response is sent
|
|
96
|
+
*/
|
|
97
|
+
private handleStreamingRequest;
|
|
98
|
+
/**
|
|
99
|
+
* Map a Webda error to a gRPC status code.
|
|
100
|
+
* @param err - the error thrown by a Webda operation, expected to have a getResponseCode method
|
|
101
|
+
* @returns the corresponding gRPC status code integer
|
|
102
|
+
*/
|
|
103
|
+
private errorToGrpcStatus;
|
|
104
|
+
/**
|
|
105
|
+
* No-op — gRPC operations are exposed via the proto definition, not individual routes.
|
|
106
|
+
* @param _operationId - the operation ID (unused; routing is handled by the proto definition)
|
|
107
|
+
* @param _definition - the operation definition (unused)
|
|
108
|
+
* @returns void
|
|
109
|
+
*/
|
|
110
|
+
exposeOperation(_operationId: string, _definition: OperationDefinition): void;
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=grpcservice.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grpcservice.service.d.ts","sourceRoot":"","sources":["../src/grpcservice.service.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,6BAA6B,EAC7B,mBAAmB,EAWpB,MAAM,aAAa,CAAC;AAOrB,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAEjE;;GAEG;AACH,qBAAa,qBAAsB,SAAQ,6BAA6B;IACtE;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;;OAIG;IACH,IAAI,CAAC,MAAM,GAAE,GAAQ,GAAG,IAAI,CAK3B;CACF;AAED;;;;;;;;;;GAUG;AACH,qBAAa,WAAW,CACtB,CAAC,SAAS,qBAAqB,GAAG,qBAAqB,CACvD,SAAQ,mBAAmB,CAAC,CAAC,CAAC;IAC9B,kCAAkC;IAClC,OAAO,CAAC,WAAW,CAAgC;IACnD,sCAAsC;IACtC,OAAO,CAAC,cAAc,CAAkC;IACxD,2CAA2C;IAC3C,OAAO,CAAC,UAAU,CAAkE;IAEpF;;;;OAIG;IAKG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CA4B3B;IAED;;;;OAIG;IACH,OAAO,CAAC,aAAa;IASrB;;;OAGG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CA0D1B;IAED;;OAEG;IACH,OAAO,CAAC,WAAW;IAkCnB;;;;;;;;OAQG;IACG,iBAAiB,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAmChF;IAED;;;;;;OAMG;IACH,OAAO,CAAC,WAAW;IAoDnB;;;;;;;OAOG;IACH,OAAO,CAAC,qBAAqB;IAqC7B;;;;;;OAMG;IACH,OAAO,CAAC,sBAAsB;IA2C9B;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IAoBzB;;;;;OAKG;IACH,eAAe,CAAC,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,mBAAmB,GAAG,IAAI,CAE5E;CACF"}
|
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
|
|
2
|
+
var useValue = arguments.length > 2;
|
|
3
|
+
for (var i = 0; i < initializers.length; i++) {
|
|
4
|
+
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
|
|
5
|
+
}
|
|
6
|
+
return useValue ? value : void 0;
|
|
7
|
+
};
|
|
8
|
+
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
|
|
9
|
+
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
|
|
10
|
+
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
|
|
11
|
+
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
|
|
12
|
+
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
|
|
13
|
+
var _, done = false;
|
|
14
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
15
|
+
var context = {};
|
|
16
|
+
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
|
|
17
|
+
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
|
|
18
|
+
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
|
|
19
|
+
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
|
|
20
|
+
if (kind === "accessor") {
|
|
21
|
+
if (result === void 0) continue;
|
|
22
|
+
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
|
|
23
|
+
if (_ = accept(result.get)) descriptor.get = _;
|
|
24
|
+
if (_ = accept(result.set)) descriptor.set = _;
|
|
25
|
+
if (_ = accept(result.init)) initializers.unshift(_);
|
|
26
|
+
}
|
|
27
|
+
else if (_ = accept(result)) {
|
|
28
|
+
if (kind === "field") initializers.unshift(_);
|
|
29
|
+
else descriptor[key] = _;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (target) Object.defineProperty(target, contextIn.name, descriptor);
|
|
33
|
+
done = true;
|
|
34
|
+
};
|
|
35
|
+
import { OperationsTransport, OperationsTransportParameters, callOperation, SimpleOperationContext, useApplication, useCore, BuildCommand, runWithInstanceStorage, useInstanceStorage } from "@webda/core";
|
|
36
|
+
import { useLog } from "@webda/workout";
|
|
37
|
+
import * as protoLoader from "@grpc/proto-loader";
|
|
38
|
+
import { existsSync, writeFileSync, mkdirSync } from "node:fs";
|
|
39
|
+
import { dirname } from "node:path";
|
|
40
|
+
import { GrpcStream, GrpcStatus } from "./grpc-stream.js";
|
|
41
|
+
import { generateProto } from "./proto-generator.js";
|
|
42
|
+
/**
|
|
43
|
+
* Parameters for the gRPC service
|
|
44
|
+
*/
|
|
45
|
+
export class GrpcServiceParameters extends OperationsTransportParameters {
|
|
46
|
+
/**
|
|
47
|
+
* Path to the generated .proto file
|
|
48
|
+
* @default ".webda/app.proto"
|
|
49
|
+
*/
|
|
50
|
+
protoFile;
|
|
51
|
+
/**
|
|
52
|
+
* Protobuf package name
|
|
53
|
+
* @default "webda"
|
|
54
|
+
*/
|
|
55
|
+
packageName;
|
|
56
|
+
/**
|
|
57
|
+
* Load and apply default parameter values.
|
|
58
|
+
* @param params - raw configuration object to load into this parameters instance
|
|
59
|
+
* @returns this instance with defaults applied
|
|
60
|
+
*/
|
|
61
|
+
load(params = {}) {
|
|
62
|
+
super.load(params);
|
|
63
|
+
this.protoFile ??= ".webda/app.proto";
|
|
64
|
+
this.packageName ??= "webda";
|
|
65
|
+
return this;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* gRPC transport service.
|
|
70
|
+
*
|
|
71
|
+
* Exposes Webda operations as gRPC services over HTTP/2.
|
|
72
|
+
* Hooks into the HttpServer via the `Webda.Init.Http` event to intercept
|
|
73
|
+
* requests with `content-type: application/grpc`.
|
|
74
|
+
*
|
|
75
|
+
* Run `webdac build` to generate the .proto file from operations.
|
|
76
|
+
*
|
|
77
|
+
* @WebdaModda
|
|
78
|
+
*/
|
|
79
|
+
let GrpcService = (() => {
|
|
80
|
+
let _classSuper = OperationsTransport;
|
|
81
|
+
let _instanceExtraInitializers = [];
|
|
82
|
+
let _build_decorators;
|
|
83
|
+
return class GrpcService extends _classSuper {
|
|
84
|
+
static {
|
|
85
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
86
|
+
_build_decorators = [BuildCommand({
|
|
87
|
+
description: "Generate protobuf definition from operations",
|
|
88
|
+
requires: ["rest-domain"]
|
|
89
|
+
})];
|
|
90
|
+
__esDecorate(this, null, _build_decorators, { kind: "method", name: "build", static: false, private: false, access: { has: obj => "build" in obj, get: obj => obj.build }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
91
|
+
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
92
|
+
}
|
|
93
|
+
/** Loaded protobuf definitions */
|
|
94
|
+
definitions = __runInitializers(this, _instanceExtraInitializers);
|
|
95
|
+
/** Map of gRPC path → operation ID */
|
|
96
|
+
rpcToOperation = new Map();
|
|
97
|
+
/** Map of gRPC path → method definition */
|
|
98
|
+
rpcMethods = new Map();
|
|
99
|
+
/**
|
|
100
|
+
* Generate a .proto file from the current operation registry.
|
|
101
|
+
*
|
|
102
|
+
* @returns a promise that resolves when the proto file has been written to disk
|
|
103
|
+
*/
|
|
104
|
+
async build() {
|
|
105
|
+
const outPath = this.parameters.protoFile;
|
|
106
|
+
const operations = this.getOperations();
|
|
107
|
+
const app = useApplication();
|
|
108
|
+
const schemas = { ...(app.getSchemas?.() || {}) };
|
|
109
|
+
// Fold per-model input schemas into the flat schemas map so that `$ref`
|
|
110
|
+
// lookups like `WebdaSample/Post` resolve to a concrete message shape —
|
|
111
|
+
// `getSchemas()` only returns operation-level schemas, not model ones.
|
|
112
|
+
const models = app.getModels?.() || {};
|
|
113
|
+
for (const modelId of Object.keys(models)) {
|
|
114
|
+
const metadata = models[modelId]?.Metadata;
|
|
115
|
+
const inputSchema = metadata?.Schemas?.Input;
|
|
116
|
+
if (inputSchema && !schemas[modelId]) {
|
|
117
|
+
schemas[modelId] = inputSchema;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
const proto = generateProto(operations, schemas, this.parameters.packageName);
|
|
121
|
+
// Ensure directory exists
|
|
122
|
+
const dir = dirname(outPath);
|
|
123
|
+
if (!existsSync(dir)) {
|
|
124
|
+
mkdirSync(dir, { recursive: true });
|
|
125
|
+
}
|
|
126
|
+
writeFileSync(outPath, proto, "utf-8");
|
|
127
|
+
this.log("INFO", `Generated proto file: ${outPath}`);
|
|
128
|
+
this.log("INFO", ` ${Object.keys(operations).length} operations → ${this.countServices(operations)} services`);
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Count unique service prefixes in operations
|
|
132
|
+
* @param operations - map of operation IDs to their definitions
|
|
133
|
+
* @returns the number of distinct gRPC service groups derived from operation prefixes
|
|
134
|
+
*/
|
|
135
|
+
countServices(operations) {
|
|
136
|
+
const prefixes = new Set();
|
|
137
|
+
for (const opId of Object.keys(operations)) {
|
|
138
|
+
const dot = opId.indexOf(".");
|
|
139
|
+
prefixes.add(dot > 0 ? opId.substring(0, dot) : "Default");
|
|
140
|
+
}
|
|
141
|
+
return prefixes.size;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Initialize the gRPC transport: load proto, build RPC map, hook into HTTP/2.
|
|
145
|
+
* @returns a promise resolving to this service instance once initialization is complete
|
|
146
|
+
*/
|
|
147
|
+
async init() {
|
|
148
|
+
await super.init();
|
|
149
|
+
// Load proto file if it exists
|
|
150
|
+
if (existsSync(this.parameters.protoFile)) {
|
|
151
|
+
try {
|
|
152
|
+
this.definitions = protoLoader.loadSync(this.parameters.protoFile, {
|
|
153
|
+
keepCase: true,
|
|
154
|
+
longs: String,
|
|
155
|
+
enums: String,
|
|
156
|
+
defaults: true,
|
|
157
|
+
oneofs: true
|
|
158
|
+
});
|
|
159
|
+
this.buildRpcMap();
|
|
160
|
+
useLog("INFO", `Loaded gRPC definitions from ${this.parameters.protoFile} — ${this.rpcToOperation.size} RPC methods mapped`);
|
|
161
|
+
}
|
|
162
|
+
catch (err) {
|
|
163
|
+
useLog("WARN", `Failed to load proto file: ${err.message}`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
useLog("WARN", `Proto file not found: ${this.parameters.protoFile}. Run 'webdac build' to generate it.`);
|
|
168
|
+
}
|
|
169
|
+
// Plug the gRPC dispatcher into every HttpServer instance in the app.
|
|
170
|
+
// Serving both REST (HTTP/1.1 or TLS+ALPN) and plaintext gRPC (h2c) means
|
|
171
|
+
// configuring two HttpServer services with different protocols; gRPC
|
|
172
|
+
// doesn't care which one — it claims any `application/grpc` request.
|
|
173
|
+
//
|
|
174
|
+
// AsyncLocalStorage doesn't reliably cross HTTP/2 data events, so capture
|
|
175
|
+
// the InstanceStorage here and re-enter it per request.
|
|
176
|
+
const capturedStorage = useInstanceStorage();
|
|
177
|
+
const servers = Object.values(useCore().getServices()).filter(s => typeof s.registerRequestInterceptor === "function");
|
|
178
|
+
if (servers.length === 0) {
|
|
179
|
+
useLog("WARN", "No HttpServer found — gRPC cannot register its interceptor");
|
|
180
|
+
return this;
|
|
181
|
+
}
|
|
182
|
+
const interceptor = (req, res) => {
|
|
183
|
+
const contentType = req.headers["content-type"] || "";
|
|
184
|
+
if (!contentType.startsWith("application/grpc"))
|
|
185
|
+
return false;
|
|
186
|
+
runWithInstanceStorage(capturedStorage, () => {
|
|
187
|
+
this.handleGrpcRequest(req, res).catch(err => {
|
|
188
|
+
useLog("ERROR", "[GrpcService] handler failed:", err);
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
return true;
|
|
192
|
+
};
|
|
193
|
+
for (const server of servers) {
|
|
194
|
+
server.registerRequestInterceptor(interceptor);
|
|
195
|
+
}
|
|
196
|
+
return this;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Build the mapping from gRPC path → operation ID using the loaded proto definitions.
|
|
200
|
+
*/
|
|
201
|
+
buildRpcMap() {
|
|
202
|
+
if (!this.definitions)
|
|
203
|
+
return;
|
|
204
|
+
const operations = this.getOperations();
|
|
205
|
+
const pkg = this.parameters.packageName;
|
|
206
|
+
// `protoLoader.loadSync` returns a flat map where service entries are plain
|
|
207
|
+
// objects keyed by method name (each method has a `.path`), mixed with
|
|
208
|
+
// top-level message types. Walk both levels so we catch every method.
|
|
209
|
+
const visitMethod = (methodDef) => {
|
|
210
|
+
if (!methodDef?.path)
|
|
211
|
+
return;
|
|
212
|
+
const parts = methodDef.path.split("/").filter(Boolean);
|
|
213
|
+
if (parts.length !== 2)
|
|
214
|
+
return;
|
|
215
|
+
const [fullService, method] = parts;
|
|
216
|
+
const serviceName = fullService.replace(`${pkg}.`, "").replace(/Service$/, "");
|
|
217
|
+
const opId = `${serviceName}.${method}`;
|
|
218
|
+
if (operations[opId]) {
|
|
219
|
+
this.rpcToOperation.set(methodDef.path, opId);
|
|
220
|
+
this.rpcMethods.set(methodDef.path, methodDef);
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
for (const def of Object.values(this.definitions)) {
|
|
224
|
+
if (typeof def !== "object" || def === null)
|
|
225
|
+
continue;
|
|
226
|
+
if (def.path) {
|
|
227
|
+
visitMethod(def);
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
// Service object — iterate its method members
|
|
231
|
+
for (const inner of Object.values(def)) {
|
|
232
|
+
if (typeof inner === "object" && inner?.path)
|
|
233
|
+
visitMethod(inner);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Handle an incoming gRPC request.
|
|
240
|
+
*
|
|
241
|
+
* Called by the HttpServer when content-type is application/grpc.
|
|
242
|
+
*
|
|
243
|
+
* @param req - HTTP/2 request carrying the gRPC method path and framed message body
|
|
244
|
+
* @param res - HTTP/2 response used to write gRPC frames and trailers
|
|
245
|
+
* @returns a promise that resolves when the response has been fully sent
|
|
246
|
+
*/
|
|
247
|
+
async handleGrpcRequest(req, res) {
|
|
248
|
+
const grpcPath = req.url;
|
|
249
|
+
const opId = this.rpcToOperation.get(grpcPath);
|
|
250
|
+
const methodDef = this.rpcMethods.get(grpcPath);
|
|
251
|
+
if (!opId || !methodDef) {
|
|
252
|
+
res.writeHead(200, {
|
|
253
|
+
"content-type": "application/grpc",
|
|
254
|
+
"grpc-status": String(GrpcStatus.UNIMPLEMENTED),
|
|
255
|
+
"grpc-message": encodeURIComponent(`Method not found: ${grpcPath}`)
|
|
256
|
+
});
|
|
257
|
+
res.end();
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
const stream = new GrpcStream(req, res, methodDef);
|
|
261
|
+
const operation = this.getOperations()[opId];
|
|
262
|
+
const grpc = operation?.grpc;
|
|
263
|
+
const streaming = (typeof grpc === "object" && grpc ? grpc.streaming : undefined) || "none";
|
|
264
|
+
try {
|
|
265
|
+
if (streaming === "bidi" || streaming === "client") {
|
|
266
|
+
// Client/bidi streaming — collect messages and process
|
|
267
|
+
await this.handleStreamingRequest(stream, opId, streaming);
|
|
268
|
+
}
|
|
269
|
+
else if (streaming === "server") {
|
|
270
|
+
// Server streaming — single request, stream responses
|
|
271
|
+
await this.handleServerStreaming(stream, opId, methodDef);
|
|
272
|
+
}
|
|
273
|
+
else {
|
|
274
|
+
// Unary — single request, single response
|
|
275
|
+
await this.handleUnary(stream, opId, methodDef);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
catch (err) {
|
|
279
|
+
const status = this.errorToGrpcStatus(err);
|
|
280
|
+
stream.sendError(status, err.message || "Internal error");
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Handle a unary gRPC call (single request → single response).
|
|
285
|
+
* @param stream - the active GrpcStream for this request
|
|
286
|
+
* @param opId - the Webda operation ID to invoke
|
|
287
|
+
* @param methodDef - the protobuf method definition with serializer functions
|
|
288
|
+
* @returns a promise that resolves when the unary response has been sent
|
|
289
|
+
*/
|
|
290
|
+
handleUnary(stream, opId, methodDef) {
|
|
291
|
+
// AsyncLocalStorage doesn't always propagate through the HTTP/2 'data'
|
|
292
|
+
// event that drives GrpcStream.onMessage, so capture the storage here and
|
|
293
|
+
// re-enter it inside the callback.
|
|
294
|
+
const instanceStorage = useInstanceStorage();
|
|
295
|
+
return new Promise((resolve, reject) => {
|
|
296
|
+
stream.onMessage(message => {
|
|
297
|
+
runWithInstanceStorage(instanceStorage, async () => {
|
|
298
|
+
try {
|
|
299
|
+
const ctx = new SimpleOperationContext();
|
|
300
|
+
await ctx.init();
|
|
301
|
+
// Proto3 `optional` fields deserialize with an extra `_field: "field"`
|
|
302
|
+
// marker (synthetic oneof tracking). Drop those so the payload matches
|
|
303
|
+
// the backing JSON schema which forbids additional properties.
|
|
304
|
+
const cleaned = typeof message === "object" && message !== null && !Array.isArray(message)
|
|
305
|
+
? Object.fromEntries(Object.entries(message).filter(([k]) => !k.startsWith("_")))
|
|
306
|
+
: message;
|
|
307
|
+
ctx.setInput(Buffer.from(JSON.stringify(cleaned)));
|
|
308
|
+
await callOperation(ctx, opId);
|
|
309
|
+
const output = ctx.getOutput();
|
|
310
|
+
// Operation return values may be plain strings/numbers (e.g. version
|
|
311
|
+
// strings, publish ids). Wrap them in a `{value: ...}` object so the
|
|
312
|
+
// proto response is always a valid message shape.
|
|
313
|
+
let response = {};
|
|
314
|
+
if (output !== undefined && output !== null && output !== "") {
|
|
315
|
+
try {
|
|
316
|
+
response = JSON.parse(output);
|
|
317
|
+
if (typeof response !== "object" || response === null) {
|
|
318
|
+
response = { value: response };
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
catch {
|
|
322
|
+
response = { value: output };
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
stream.sendUnary(response);
|
|
326
|
+
resolve();
|
|
327
|
+
}
|
|
328
|
+
catch (err) {
|
|
329
|
+
useLog("ERROR", `[gRPC ${opId}] handler threw:`, err);
|
|
330
|
+
const status = this.errorToGrpcStatus(err);
|
|
331
|
+
stream.sendError(status, err.message);
|
|
332
|
+
resolve(); // Don't reject — error was sent via gRPC status
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
});
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Handle server streaming (single request → stream of responses).
|
|
340
|
+
* Maps to AsyncGenerator operations.
|
|
341
|
+
* @param stream - the active GrpcStream for this request
|
|
342
|
+
* @param opId - the Webda operation ID to invoke
|
|
343
|
+
* @param methodDef - the protobuf method definition with serializer functions
|
|
344
|
+
* @returns a promise that resolves when all response frames have been sent
|
|
345
|
+
*/
|
|
346
|
+
handleServerStreaming(stream, opId, methodDef) {
|
|
347
|
+
return new Promise((resolve, reject) => {
|
|
348
|
+
stream.onMessage(async (message) => {
|
|
349
|
+
try {
|
|
350
|
+
const ctx = new SimpleOperationContext();
|
|
351
|
+
await ctx.init();
|
|
352
|
+
ctx.setInput(Buffer.from(JSON.stringify(message)));
|
|
353
|
+
await callOperation(ctx, opId);
|
|
354
|
+
// callOperation writes chunks to ctx for AsyncGenerators
|
|
355
|
+
// For now, send the full output as a single response
|
|
356
|
+
const output = ctx.getOutput();
|
|
357
|
+
if (output) {
|
|
358
|
+
// Try to parse as NDJSON (multiple JSON objects)
|
|
359
|
+
const lines = output.split("\n").filter(Boolean);
|
|
360
|
+
for (const line of lines) {
|
|
361
|
+
try {
|
|
362
|
+
stream.send(JSON.parse(line));
|
|
363
|
+
}
|
|
364
|
+
catch {
|
|
365
|
+
stream.send({ data: line });
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
stream.end(GrpcStatus.OK);
|
|
370
|
+
resolve();
|
|
371
|
+
}
|
|
372
|
+
catch (err) {
|
|
373
|
+
const status = this.errorToGrpcStatus(err);
|
|
374
|
+
stream.sendError(status, err.message);
|
|
375
|
+
resolve();
|
|
376
|
+
}
|
|
377
|
+
});
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Handle client or bidirectional streaming.
|
|
382
|
+
* @param stream - the active GrpcStream for this request
|
|
383
|
+
* @param opId - the Webda operation ID to invoke
|
|
384
|
+
* @param streaming - streaming mode, either "client" or "bidi"
|
|
385
|
+
* @returns a promise that resolves when the operation completes and the response is sent
|
|
386
|
+
*/
|
|
387
|
+
handleStreamingRequest(stream, opId, streaming) {
|
|
388
|
+
return new Promise((resolve) => {
|
|
389
|
+
const messages = [];
|
|
390
|
+
stream.onMessage(message => {
|
|
391
|
+
messages.push(message);
|
|
392
|
+
});
|
|
393
|
+
stream.onEnd(async () => {
|
|
394
|
+
try {
|
|
395
|
+
// For client streaming: process all collected messages
|
|
396
|
+
const ctx = new SimpleOperationContext();
|
|
397
|
+
await ctx.init();
|
|
398
|
+
ctx.setInput(Buffer.from(JSON.stringify(messages)));
|
|
399
|
+
await callOperation(ctx, opId);
|
|
400
|
+
const output = ctx.getOutput();
|
|
401
|
+
const response = output ? JSON.parse(output) : {};
|
|
402
|
+
if (streaming === "bidi") {
|
|
403
|
+
// Bidi: send response for each input message
|
|
404
|
+
stream.send(response);
|
|
405
|
+
}
|
|
406
|
+
else {
|
|
407
|
+
// Client streaming: single response
|
|
408
|
+
stream.sendUnary(response);
|
|
409
|
+
}
|
|
410
|
+
resolve();
|
|
411
|
+
}
|
|
412
|
+
catch (err) {
|
|
413
|
+
const status = this.errorToGrpcStatus(err);
|
|
414
|
+
stream.sendError(status, err.message);
|
|
415
|
+
resolve();
|
|
416
|
+
}
|
|
417
|
+
});
|
|
418
|
+
stream.onCancel(() => {
|
|
419
|
+
resolve();
|
|
420
|
+
});
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Map a Webda error to a gRPC status code.
|
|
425
|
+
* @param err - the error thrown by a Webda operation, expected to have a getResponseCode method
|
|
426
|
+
* @returns the corresponding gRPC status code integer
|
|
427
|
+
*/
|
|
428
|
+
errorToGrpcStatus(err) {
|
|
429
|
+
const code = err?.getResponseCode?.();
|
|
430
|
+
switch (code) {
|
|
431
|
+
case 400:
|
|
432
|
+
return GrpcStatus.INVALID_ARGUMENT;
|
|
433
|
+
case 401:
|
|
434
|
+
return GrpcStatus.UNAUTHENTICATED;
|
|
435
|
+
case 403:
|
|
436
|
+
return GrpcStatus.PERMISSION_DENIED;
|
|
437
|
+
case 404:
|
|
438
|
+
return GrpcStatus.NOT_FOUND;
|
|
439
|
+
case 409:
|
|
440
|
+
return GrpcStatus.ALREADY_EXISTS;
|
|
441
|
+
case 429:
|
|
442
|
+
return GrpcStatus.RESOURCE_EXHAUSTED;
|
|
443
|
+
default:
|
|
444
|
+
return GrpcStatus.INTERNAL;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* No-op — gRPC operations are exposed via the proto definition, not individual routes.
|
|
449
|
+
* @param _operationId - the operation ID (unused; routing is handled by the proto definition)
|
|
450
|
+
* @param _definition - the operation definition (unused)
|
|
451
|
+
* @returns void
|
|
452
|
+
*/
|
|
453
|
+
exposeOperation(_operationId, _definition) {
|
|
454
|
+
// gRPC doesn't register routes individually — handled by proto definition
|
|
455
|
+
}
|
|
456
|
+
};
|
|
457
|
+
})();
|
|
458
|
+
export { GrpcService };
|
|
459
|
+
//# sourceMappingURL=grpcservice.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grpcservice.service.js","sourceRoot":"","sources":["../src/grpcservice.service.ts"],"names":[],"mappings":"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"}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { GrpcService, GrpcServiceParameters } from "./grpcservice.service.js";
|
|
2
|
+
export { GrpcStream, GrpcStatus } from "./grpc-stream.js";
|
|
3
|
+
export type { GrpcMethodDef } from "./grpc-stream.js";
|
|
4
|
+
export { generateProto } from "./proto-generator.js";
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAC9E,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC1D,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC"}
|
package/lib/index.js
ADDED
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAC9E,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE1D,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { OperationDefinition } from "@webda/core";
|
|
2
|
+
import type { JSONSchema7 } from "json-schema";
|
|
3
|
+
/**
|
|
4
|
+
* Generate a .proto file from registered operations and their schemas.
|
|
5
|
+
*
|
|
6
|
+
* Groups operations by prefix (e.g., "Post.Create" → service PostService)
|
|
7
|
+
* and converts JSON Schema input/output types to protobuf messages.
|
|
8
|
+
* @param operations - map of operation IDs to their definitions
|
|
9
|
+
* @param schemas - all known JSON schemas keyed by schema reference name
|
|
10
|
+
* @param packageName - protobuf package name to use in the generated file
|
|
11
|
+
* @returns the complete .proto file content as a string
|
|
12
|
+
*/
|
|
13
|
+
export declare function generateProto(operations: Record<string, Omit<OperationDefinition, "service" | "method">>, schemas: Record<string, JSONSchema7>, packageName?: string): string;
|
|
14
|
+
//# sourceMappingURL=proto-generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proto-generator.d.ts","sourceRoot":"","sources":["../src/proto-generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAC3B,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,mBAAmB,EAAE,SAAS,GAAG,QAAQ,CAAC,CAAC,EAC3E,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACpC,WAAW,GAAE,MAAgB,GAC5B,MAAM,CA+GR"}
|