@funduck/connectrpc-fastify 1.0.10 → 1.0.12
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 +29 -67
- package/dist/connectrpc.d.ts +1 -6
- package/dist/connectrpc.js +0 -15
- package/dist/connectrpc.js.map +1 -1
- package/dist/context-values.d.ts +29 -0
- package/dist/context-values.js +53 -0
- package/dist/context-values.js.map +1 -0
- package/dist/fastify-plugin.js +3 -8
- package/dist/fastify-plugin.js.map +1 -1
- package/dist/helpers.d.ts +4 -0
- package/dist/helpers.js +12 -5
- package/dist/helpers.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +7 -4
- package/dist/index.js.map +1 -1
- package/dist/interceptors.d.ts +7 -0
- package/dist/interceptors.js +26 -0
- package/dist/interceptors.js.map +1 -0
- package/dist/interfaces.d.ts +8 -20
- package/dist/interfaces.js.map +1 -1
- package/dist/middlewares.d.ts +3 -1
- package/dist/middlewares.js +37 -0
- package/dist/middlewares.js.map +1 -1
- package/dist/stores.d.ts +23 -13
- package/dist/stores.js +31 -18
- package/dist/stores.js.map +1 -1
- package/package.json +11 -8
- package/dist/execution-context.d.ts +0 -22
- package/dist/execution-context.js +0 -40
- package/dist/execution-context.js.map +0 -1
- package/dist/guards.d.ts +0 -11
- package/dist/guards.js +0 -95
- package/dist/guards.js.map +0 -1
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ This is a wrapper for [Connectrpc](https://github.com/connectrpc/connect-es) usi
|
|
|
9
9
|
|
|
10
10
|
If you are comfortable with HTTP/1 only and want a compact, ready-to-use setup, this repository is for you.
|
|
11
11
|
|
|
12
|
-
It simplifies the binding of controllers
|
|
12
|
+
It simplifies the binding of controllers and middlewares.
|
|
13
13
|
|
|
14
14
|
I use it as a basis for integration into Nestjs, which will be implemented [here](https://github.com/funduck/connectrpc-fastify-nestjs).
|
|
15
15
|
|
|
@@ -21,17 +21,22 @@ This library allows you to:
|
|
|
21
21
|
* Perform RPC with simple request and response messages
|
|
22
22
|
* Perform RPC with streaming responses
|
|
23
23
|
* Perform RPC with streaming requests
|
|
24
|
-
* Use middlewares
|
|
25
|
-
*
|
|
24
|
+
* Use middlewares with Fastify hooks
|
|
25
|
+
* Access HandlerContext in controllers (headers, context values, etc.)
|
|
26
26
|
|
|
27
27
|
*Bidirectional streaming RPC is currently out of scope because it requires HTTP/2, which is unstable on public networks. In practice, HTTP/1 provides more consistent performance.*
|
|
28
28
|
|
|
29
29
|
## How To Use
|
|
30
|
-
You can check out `test` directory for a complete example of server and client. Start reading from `test/server.ts`.
|
|
30
|
+
You can check out `test` directory for a complete example of server and client. Start reading from `test/demo/server.ts`.
|
|
31
31
|
|
|
32
32
|
### Controllers
|
|
33
33
|
Controller must implement the service interface and register itself with `ConnectRPC.registerController` in the constructor.
|
|
34
|
+
|
|
35
|
+
Controller methods receive `HandlerContext` which provides access to request headers, context values, and other metadata.
|
|
36
|
+
|
|
34
37
|
```TS
|
|
38
|
+
import type { HandlerContext } from '@connectrpc/connect';
|
|
39
|
+
|
|
35
40
|
export class ElizaController implements Service<typeof ElizaService> {
|
|
36
41
|
constructor() {
|
|
37
42
|
ConnectRPC.registerController(this, ElizaService);
|
|
@@ -39,7 +44,11 @@ export class ElizaController implements Service<typeof ElizaService> {
|
|
|
39
44
|
|
|
40
45
|
async say(
|
|
41
46
|
request: SayRequest,
|
|
47
|
+
context: HandlerContext,
|
|
42
48
|
) {
|
|
49
|
+
// Access headers from context
|
|
50
|
+
const authHeader = context.requestHeader.get('authorization');
|
|
51
|
+
|
|
43
52
|
return {
|
|
44
53
|
sentence: `You said: ${request.sentence}`,
|
|
45
54
|
};
|
|
@@ -66,91 +75,44 @@ try {
|
|
|
66
75
|
```
|
|
67
76
|
|
|
68
77
|
### Middlewares
|
|
69
|
-
|
|
78
|
+
Middlewares run as Fastify hooks and have access to raw request/response objects.
|
|
70
79
|
|
|
71
80
|
Middleware must implement `Middleware` interface and register itself with `ConnectRPC.registerMiddleware` in the constructor.
|
|
72
81
|
```TS
|
|
73
|
-
export class
|
|
82
|
+
export class AuthMiddleware implements Middleware {
|
|
74
83
|
constructor() {
|
|
75
84
|
ConnectRPC.registerMiddleware(this);
|
|
76
85
|
}
|
|
77
86
|
|
|
78
87
|
use(req: FastifyRequest['raw'], res: FastifyReply['raw'], next: () => void) {
|
|
88
|
+
// Check authentication
|
|
89
|
+
const authHeader = req.headers['authorization'];
|
|
90
|
+
if (!authHeader) {
|
|
91
|
+
res.statusCode = 401;
|
|
92
|
+
res.end('Unauthorized');
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
79
95
|
next();
|
|
80
96
|
}
|
|
81
97
|
}
|
|
82
98
|
```
|
|
83
99
|
|
|
84
|
-
|
|
100
|
+
Create an instance of the middleware before registering the ConnectRPC plugin.
|
|
85
101
|
```TS
|
|
86
|
-
const fastify = Fastify({
|
|
87
|
-
logger: true,
|
|
88
|
-
});
|
|
102
|
+
const fastify = Fastify({ logger: true });
|
|
89
103
|
|
|
90
104
|
new ElizaController();
|
|
91
|
-
|
|
92
|
-
new TestMiddleware1();
|
|
105
|
+
new AuthMiddleware();
|
|
93
106
|
|
|
94
107
|
await ConnectRPC.registerFastifyPlugin(fastify);
|
|
95
108
|
|
|
96
109
|
ConnectRPC.initMiddlewares(fastify, [
|
|
97
|
-
middlewareConfig(
|
|
98
|
-
//middlewareConfig(
|
|
99
|
-
//middlewareConfig(
|
|
110
|
+
middlewareConfig(AuthMiddleware), // Global middleware for all services and methods
|
|
111
|
+
// middlewareConfig(AuthMiddleware, ElizaService), // Middleware for all ElizaService methods
|
|
112
|
+
// middlewareConfig(AuthMiddleware, ElizaService, ['say']), // Middleware for specific method only
|
|
100
113
|
]);
|
|
101
114
|
|
|
102
|
-
|
|
103
|
-
await fastify.listen({ port: 3000 });
|
|
104
|
-
} catch (err) {
|
|
105
|
-
fastify.log.error(err);
|
|
106
|
-
process.exit(1);
|
|
107
|
-
}
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
### Guards
|
|
111
|
-
Guards are used to restrict access to certain services or methods.
|
|
112
|
-
|
|
113
|
-
Guard must implement `Guard` interface and register itself with `ConnectRPC.registerGuard` in the constructor.
|
|
114
|
-
```TS
|
|
115
|
-
export class TestGuard1 implements Guard {
|
|
116
|
-
constructor() {
|
|
117
|
-
ConnectRPC.registerGuard(this);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
canActivate(context: ExecutionContext): boolean {
|
|
121
|
-
return true;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
Then create an instance of the guard before registering the ConnectRPC plugin and initialize it similarly to middlewares.
|
|
127
|
-
```TS
|
|
128
|
-
const fastify = Fastify({
|
|
129
|
-
logger: true,
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
new ElizaController();
|
|
133
|
-
|
|
134
|
-
new TestMiddleware1();
|
|
135
|
-
|
|
136
|
-
new TestGuard1();
|
|
137
|
-
|
|
138
|
-
await ConnectRPC.registerFastifyPlugin(fastify);
|
|
139
|
-
|
|
140
|
-
ConnectRPC.initMiddlewares(fastify, [
|
|
141
|
-
middlewareConfig(TestMiddleware1), // Global middleware for all services and methods
|
|
142
|
-
// middlewareConfig(TestMiddleware1, ElizaService), // Middleware for all ElizaService methods
|
|
143
|
-
// middlewareConfig(TestMiddleware1, ElizaService, ['say']), // Middleware for ElizaService's say method only
|
|
144
|
-
]);
|
|
145
|
-
|
|
146
|
-
ConnectRPC.initGuards(fastify);
|
|
147
|
-
|
|
148
|
-
try {
|
|
149
|
-
await fastify.listen({ port: 3000 });
|
|
150
|
-
} catch (err) {
|
|
151
|
-
fastify.log.error(err);
|
|
152
|
-
process.exit(1);
|
|
153
|
-
}
|
|
115
|
+
await fastify.listen({ port: 3000 });
|
|
154
116
|
```
|
|
155
117
|
|
|
156
118
|
## Feedback
|
package/dist/connectrpc.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { GenService, GenServiceMethods } from '@bufbuild/protobuf/codegenv2';
|
|
2
2
|
import { FastifyInstance } from 'fastify';
|
|
3
|
-
import {
|
|
3
|
+
import { Logger, Middleware, MiddlewareConfigUnion, Service } from './interfaces';
|
|
4
4
|
declare class ConnectRPCClass {
|
|
5
5
|
setLogger(customLogger: Logger): void;
|
|
6
6
|
registerMiddleware(self: Middleware, options?: {
|
|
@@ -13,14 +13,9 @@ declare class ConnectRPCClass {
|
|
|
13
13
|
registerController<T extends GenServiceMethods>(self: Service<GenService<T>>, service: GenService<T>, options?: {
|
|
14
14
|
allowMultipleInstances?: boolean;
|
|
15
15
|
}): void;
|
|
16
|
-
registerGuard(self: Guard, options?: {
|
|
17
|
-
allowMultipleInstances?: boolean;
|
|
18
|
-
}): void;
|
|
19
16
|
registerFastifyPlugin(server: FastifyInstance): Promise<void>;
|
|
20
17
|
private _middlewaresInitialized;
|
|
21
18
|
initMiddlewares(server: FastifyInstance, middlewareConfigs: MiddlewareConfigUnion[]): Promise<void>;
|
|
22
|
-
private _guardsInitialized;
|
|
23
|
-
initGuards(server: FastifyInstance): Promise<void>;
|
|
24
19
|
}
|
|
25
20
|
/**
|
|
26
21
|
* Main ConnectRPC class to manage registration of controllers and middlewares
|
package/dist/connectrpc.js
CHANGED
|
@@ -2,14 +2,12 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ConnectRPC = void 0;
|
|
4
4
|
const fastify_plugin_1 = require("./fastify-plugin");
|
|
5
|
-
const guards_1 = require("./guards");
|
|
6
5
|
const helpers_1 = require("./helpers");
|
|
7
6
|
const middlewares_1 = require("./middlewares");
|
|
8
7
|
const stores_1 = require("./stores");
|
|
9
8
|
class ConnectRPCClass {
|
|
10
9
|
constructor() {
|
|
11
10
|
this._middlewaresInitialized = false;
|
|
12
|
-
this._guardsInitialized = false;
|
|
13
11
|
}
|
|
14
12
|
setLogger(customLogger) {
|
|
15
13
|
(0, helpers_1.setLogger)(customLogger);
|
|
@@ -24,9 +22,6 @@ class ConnectRPCClass {
|
|
|
24
22
|
registerController(self, service, options) {
|
|
25
23
|
stores_1.ControllersStore.registerInstance(self, service, options);
|
|
26
24
|
}
|
|
27
|
-
registerGuard(self, options) {
|
|
28
|
-
stores_1.GuardsStore.registerInstance(self, options);
|
|
29
|
-
}
|
|
30
25
|
registerFastifyPlugin(server) {
|
|
31
26
|
return (0, fastify_plugin_1.registerFastifyPlugin)(server);
|
|
32
27
|
}
|
|
@@ -34,19 +29,9 @@ class ConnectRPCClass {
|
|
|
34
29
|
if (this._middlewaresInitialized) {
|
|
35
30
|
throw new Error('Middlewares have already been initialized!');
|
|
36
31
|
}
|
|
37
|
-
if (this._guardsInitialized) {
|
|
38
|
-
throw new Error('Middlewares must be initialized before guards!');
|
|
39
|
-
}
|
|
40
32
|
this._middlewaresInitialized = true;
|
|
41
33
|
return (0, middlewares_1.initMiddlewares)(server, middlewareConfigs);
|
|
42
34
|
}
|
|
43
|
-
initGuards(server) {
|
|
44
|
-
if (this._guardsInitialized) {
|
|
45
|
-
throw new Error('Guards have already been initialized!');
|
|
46
|
-
}
|
|
47
|
-
this._guardsInitialized = true;
|
|
48
|
-
return (0, guards_1.initGuards)(server);
|
|
49
|
-
}
|
|
50
35
|
}
|
|
51
36
|
/**
|
|
52
37
|
* Main ConnectRPC class to manage registration of controllers and middlewares
|
package/dist/connectrpc.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connectrpc.js","sourceRoot":"","sources":["../src/connectrpc.ts"],"names":[],"mappings":";;;AAEA,qDAAyD;AACzD,
|
|
1
|
+
{"version":3,"file":"connectrpc.js","sourceRoot":"","sources":["../src/connectrpc.ts"],"names":[],"mappings":";;;AAEA,qDAAyD;AACzD,uCAAsC;AAOtC,+CAAgD;AAChD,qCAA6D;AAE7D,MAAM,eAAe;IAArB;QAgCU,4BAAuB,GAAG,KAAK,CAAC;IAY1C,CAAC;IA3CC,SAAS,CAAC,YAAoB;QAC5B,IAAA,mBAAS,EAAC,YAAY,CAAC,CAAC;IAC1B,CAAC;IAED,kBAAkB,CAChB,IAAgB,EAChB,OAEC;QAED,wBAAe,CAAC,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAClD,CAAC;IAED;;;OAGG;IACH,kBAAkB,CAChB,IAA4B,EAC5B,OAAsB,EACtB,OAEC;QAED,yBAAgB,CAAC,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAC5D,CAAC;IAED,qBAAqB,CAAC,MAAuB;QAC3C,OAAO,IAAA,sCAAqB,EAAC,MAAM,CAAC,CAAC;IACvC,CAAC;IAID,eAAe,CACb,MAAuB,EACvB,iBAA0C;QAE1C,IAAI,IAAI,CAAC,uBAAuB,EAAE,CAAC;YACjC,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;QAChE,CAAC;QACD,IAAI,CAAC,uBAAuB,GAAG,IAAI,CAAC;QACpC,OAAO,IAAA,6BAAe,EAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IACpD,CAAC;CACF;AAED;;GAEG;AACU,QAAA,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { ContextKey, ContextValues } from '@connectrpc/connect';
|
|
2
|
+
/**
|
|
3
|
+
* Custom ContextValues implementation that extends the standard ConnectRPC ContextValues
|
|
4
|
+
* with an entries() method to iterate over key-value pairs.
|
|
5
|
+
*/
|
|
6
|
+
export declare class CustomContextValues implements ContextValues {
|
|
7
|
+
private values;
|
|
8
|
+
/**
|
|
9
|
+
* Get a context value by key
|
|
10
|
+
*/
|
|
11
|
+
get<T>(key: ContextKey<T>): T;
|
|
12
|
+
/**
|
|
13
|
+
* Set a context value by key
|
|
14
|
+
*/
|
|
15
|
+
set<T>(key: ContextKey<T>, value: T): this;
|
|
16
|
+
/**
|
|
17
|
+
* Delete a context value by key
|
|
18
|
+
*/
|
|
19
|
+
delete(key: ContextKey<unknown>): this;
|
|
20
|
+
/**
|
|
21
|
+
* Iterate over all key-value pairs in the context
|
|
22
|
+
* Returns an iterator of [ContextKey, value] pairs
|
|
23
|
+
*/
|
|
24
|
+
entries(): IterableIterator<[symbol, unknown]>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Create a new CustomContextValues instance
|
|
28
|
+
*/
|
|
29
|
+
export declare function createCustomContextValues(): CustomContextValues;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CustomContextValues = void 0;
|
|
4
|
+
exports.createCustomContextValues = createCustomContextValues;
|
|
5
|
+
/**
|
|
6
|
+
* Custom ContextValues implementation that extends the standard ConnectRPC ContextValues
|
|
7
|
+
* with an entries() method to iterate over key-value pairs.
|
|
8
|
+
*/
|
|
9
|
+
class CustomContextValues {
|
|
10
|
+
constructor() {
|
|
11
|
+
this.values = new Map();
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Get a context value by key
|
|
15
|
+
*/
|
|
16
|
+
get(key) {
|
|
17
|
+
if (this.values.has(key.id)) {
|
|
18
|
+
return this.values.get(key.id);
|
|
19
|
+
}
|
|
20
|
+
return key.defaultValue;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Set a context value by key
|
|
24
|
+
*/
|
|
25
|
+
set(key, value) {
|
|
26
|
+
this.values.set(key.id, value);
|
|
27
|
+
return this;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Delete a context value by key
|
|
31
|
+
*/
|
|
32
|
+
delete(key) {
|
|
33
|
+
this.values.delete(key.id);
|
|
34
|
+
return this;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Iterate over all key-value pairs in the context
|
|
38
|
+
* Returns an iterator of [ContextKey, value] pairs
|
|
39
|
+
*/
|
|
40
|
+
*entries() {
|
|
41
|
+
for (const [id, value] of this.values.entries()) {
|
|
42
|
+
yield [id, value];
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
exports.CustomContextValues = CustomContextValues;
|
|
47
|
+
/**
|
|
48
|
+
* Create a new CustomContextValues instance
|
|
49
|
+
*/
|
|
50
|
+
function createCustomContextValues() {
|
|
51
|
+
return new CustomContextValues();
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=context-values.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-values.js","sourceRoot":"","sources":["../src/context-values.ts"],"names":[],"mappings":";;;AAiDA,8DAEC;AAjDD;;;GAGG;AACH,MAAa,mBAAmB;IAAhC;QACU,WAAM,GAAG,IAAI,GAAG,EAAmB,CAAC;IAqC9C,CAAC;IAnCC;;OAEG;IACH,GAAG,CAAI,GAAkB;QACvB,IAAI,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;YAC5B,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAM,CAAC;QACtC,CAAC;QACD,OAAO,GAAG,CAAC,YAAY,CAAC;IAC1B,CAAC;IAED;;OAEG;IACH,GAAG,CAAI,GAAkB,EAAE,KAAQ;QACjC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;QAC/B,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,GAAwB;QAC7B,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC3B,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;OAGG;IACH,CAAC,OAAO;QACN,KAAK,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC;YAChD,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;QACpB,CAAC;IACH,CAAC;CACF;AAtCD,kDAsCC;AAED;;GAEG;AACH,SAAgB,yBAAyB;IACvC,OAAO,IAAI,mBAAmB,EAAE,CAAC;AACnC,CAAC"}
|
package/dist/fastify-plugin.js
CHANGED
|
@@ -2,17 +2,13 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.registerFastifyPlugin = registerFastifyPlugin;
|
|
4
4
|
const connect_fastify_1 = require("@connectrpc/connect-fastify");
|
|
5
|
-
const guards_1 = require("./guards");
|
|
6
5
|
const helpers_1 = require("./helpers");
|
|
6
|
+
const interceptors_1 = require("./interceptors");
|
|
7
7
|
const stores_1 = require("./stores");
|
|
8
8
|
async function registerFastifyPlugin(server, options = {}) {
|
|
9
9
|
// Create implementations from controller instances
|
|
10
10
|
const implementations = new Map();
|
|
11
11
|
for (const { instance, service } of stores_1.ControllersStore.values()) {
|
|
12
|
-
const guards = (0, guards_1.getGuards)(instance);
|
|
13
|
-
if (guards.length > 0) {
|
|
14
|
-
helpers_1.logger.log(`Found ${guards.length} guards on controller ${instance.constructor.name}`);
|
|
15
|
-
}
|
|
16
12
|
const methodMappings = (0, helpers_1.discoverMethodMappings)(instance.__proto__, service);
|
|
17
13
|
// Create the implementation object
|
|
18
14
|
const implementation = {};
|
|
@@ -27,9 +23,7 @@ async function registerFastifyPlugin(server, options = {}) {
|
|
|
27
23
|
if (controllerMethod) {
|
|
28
24
|
// Bind the method with proper 'this' context
|
|
29
25
|
const bindedMethod = controllerMethod.bind(instance);
|
|
30
|
-
implementation[methodName] =
|
|
31
|
-
return bindedMethod(...args);
|
|
32
|
-
};
|
|
26
|
+
implementation[methodName] = bindedMethod;
|
|
33
27
|
// Store route metadata for guards and interceptors
|
|
34
28
|
stores_1.RouteMetadataStore.registerRoute(service.typeName, name, // PascalCase method name (e.g., "Say")
|
|
35
29
|
instance.constructor, controllerMethod, controllerMethodName, instance);
|
|
@@ -61,6 +55,7 @@ async function registerFastifyPlugin(server, options = {}) {
|
|
|
61
55
|
grpcWeb: false,
|
|
62
56
|
connect: true,
|
|
63
57
|
acceptCompression: options.acceptCompression ?? [],
|
|
58
|
+
interceptors: [interceptors_1.contextInterceptor],
|
|
64
59
|
routes: routes,
|
|
65
60
|
});
|
|
66
61
|
helpers_1.logger.log('Ready');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fastify-plugin.js","sourceRoot":"","sources":["../src/fastify-plugin.ts"],"names":[],"mappings":";;AASA,
|
|
1
|
+
{"version":3,"file":"fastify-plugin.js","sourceRoot":"","sources":["../src/fastify-plugin.ts"],"names":[],"mappings":"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"}
|
package/dist/helpers.d.ts
CHANGED
|
@@ -11,3 +11,7 @@ export declare function discoverMethodMappings(prototype: any, service: GenServi
|
|
|
11
11
|
export declare function convertMiddlewareToHook(middlewareInstance: any): (request: FastifyRequest, reply: FastifyReply) => Promise<void>;
|
|
12
12
|
export declare let logger: Logger;
|
|
13
13
|
export declare function setLogger(customLogger: Logger): void;
|
|
14
|
+
/**
|
|
15
|
+
* Generate a unique request ID
|
|
16
|
+
*/
|
|
17
|
+
export declare function generateRequestId(): string;
|
package/dist/helpers.js
CHANGED
|
@@ -4,6 +4,7 @@ exports.logger = void 0;
|
|
|
4
4
|
exports.discoverMethodMappings = discoverMethodMappings;
|
|
5
5
|
exports.convertMiddlewareToHook = convertMiddlewareToHook;
|
|
6
6
|
exports.setLogger = setLogger;
|
|
7
|
+
exports.generateRequestId = generateRequestId;
|
|
7
8
|
/**
|
|
8
9
|
* Automatically discover method mappings by matching service methods to controller methods
|
|
9
10
|
*/
|
|
@@ -55,22 +56,28 @@ function convertMiddlewareToHook(middlewareInstance) {
|
|
|
55
56
|
}
|
|
56
57
|
exports.logger = {
|
|
57
58
|
log: (...args) => {
|
|
58
|
-
console.info(...args);
|
|
59
|
+
// console.info(...args);
|
|
59
60
|
},
|
|
60
61
|
error: (...args) => {
|
|
61
|
-
console.error(...args);
|
|
62
|
+
// console.error(...args);
|
|
62
63
|
},
|
|
63
64
|
warn: (...args) => {
|
|
64
|
-
console.warn(...args);
|
|
65
|
+
// console.warn(...args);
|
|
65
66
|
},
|
|
66
67
|
debug: (...args) => {
|
|
67
|
-
console.debug(...args);
|
|
68
|
+
// console.debug(...args);
|
|
68
69
|
},
|
|
69
70
|
verbose: (...args) => {
|
|
70
|
-
console.log(...args);
|
|
71
|
+
// console.log(...args);
|
|
71
72
|
},
|
|
72
73
|
};
|
|
73
74
|
function setLogger(customLogger) {
|
|
74
75
|
exports.logger = customLogger;
|
|
75
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* Generate a unique request ID
|
|
79
|
+
*/
|
|
80
|
+
function generateRequestId() {
|
|
81
|
+
return `req_${Date.now()}_${Math.random().toString(36).substring(2, 15)}`;
|
|
82
|
+
}
|
|
76
83
|
//# sourceMappingURL=helpers.js.map
|
package/dist/helpers.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":";;;AAOA,wDAsCC;AAKD,0DAmBC;AAoBD,8BAEC;
|
|
1
|
+
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export declare function printMsg(): void;
|
|
2
2
|
export { ConnectRPC } from './connectrpc';
|
|
3
|
+
export { CustomContextValues, createCustomContextValues, } from './context-values';
|
|
3
4
|
export { middlewareConfig } from './interfaces';
|
|
4
|
-
export type {
|
|
5
|
-
export { initGuards } from './guards';
|
|
5
|
+
export type { Logger, Middleware, MiddlewareConfig, MiddlewareConfigUnion, Service, } from './interfaces';
|
|
6
6
|
export type { OmitConnectrpcFields } from './types';
|
|
7
|
+
export { getCustomContextValues } from './middlewares';
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.getCustomContextValues = exports.middlewareConfig = exports.createCustomContextValues = exports.CustomContextValues = exports.ConnectRPC = void 0;
|
|
4
4
|
exports.printMsg = printMsg;
|
|
5
5
|
function printMsg() {
|
|
6
|
-
console.
|
|
6
|
+
console.error('connectrpc-fastify is in development mode! not ready for production yet!');
|
|
7
7
|
}
|
|
8
8
|
var connectrpc_1 = require("./connectrpc");
|
|
9
9
|
Object.defineProperty(exports, "ConnectRPC", { enumerable: true, get: function () { return connectrpc_1.ConnectRPC; } });
|
|
10
|
+
var context_values_1 = require("./context-values");
|
|
11
|
+
Object.defineProperty(exports, "CustomContextValues", { enumerable: true, get: function () { return context_values_1.CustomContextValues; } });
|
|
12
|
+
Object.defineProperty(exports, "createCustomContextValues", { enumerable: true, get: function () { return context_values_1.createCustomContextValues; } });
|
|
10
13
|
var interfaces_1 = require("./interfaces");
|
|
11
14
|
Object.defineProperty(exports, "middlewareConfig", { enumerable: true, get: function () { return interfaces_1.middlewareConfig; } });
|
|
12
|
-
var
|
|
13
|
-
Object.defineProperty(exports, "
|
|
15
|
+
var middlewares_1 = require("./middlewares");
|
|
16
|
+
Object.defineProperty(exports, "getCustomContextValues", { enumerable: true, get: function () { return middlewares_1.getCustomContextValues; } });
|
|
14
17
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,4BAIC;AAJD,SAAgB,QAAQ;IACtB,OAAO,CAAC,KAAK,CACX,0EAA0E,CAC3E,CAAC;AACJ,CAAC;AAED,2CAA0C;AAAjC,wGAAA,UAAU,OAAA;AAEnB,mDAG0B;AAFxB,qHAAA,mBAAmB,OAAA;AACnB,2HAAA,yBAAyB,OAAA;AAG3B,2CAAgD;AAAvC,8GAAA,gBAAgB,OAAA;AAYzB,6CAAuD;AAA9C,qHAAA,sBAAsB,OAAA"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Interceptor } from '@connectrpc/connect';
|
|
2
|
+
/**
|
|
3
|
+
* ContextInterceptor - copies context values from MiddlewareContextStore to HandlerContext
|
|
4
|
+
* This interceptor should be first in the chain to ensure context values are available
|
|
5
|
+
* to subsequent interceptors and controllers.
|
|
6
|
+
*/
|
|
7
|
+
export declare const contextInterceptor: Interceptor;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.contextInterceptor = void 0;
|
|
4
|
+
const stores_1 = require("./stores");
|
|
5
|
+
/**
|
|
6
|
+
* ContextInterceptor - copies context values from MiddlewareContextStore to HandlerContext
|
|
7
|
+
* This interceptor should be first in the chain to ensure context values are available
|
|
8
|
+
* to subsequent interceptors and controllers.
|
|
9
|
+
*/
|
|
10
|
+
const contextInterceptor = (next) => async (req) => {
|
|
11
|
+
// Get the request ID from headers
|
|
12
|
+
const requestId = req.header.get('x-server-request-id');
|
|
13
|
+
if (requestId) {
|
|
14
|
+
const middlewareContext = stores_1.MiddlewareContextStore.get(requestId);
|
|
15
|
+
if (middlewareContext) {
|
|
16
|
+
// Copy context values from middleware context to handler context
|
|
17
|
+
for (const [key, value] of middlewareContext.contextValues.entries()) {
|
|
18
|
+
req.contextValues.set({ id: key, defaultValue: undefined }, value);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
// Continue with the next interceptor or handler
|
|
23
|
+
return await next(req);
|
|
24
|
+
};
|
|
25
|
+
exports.contextInterceptor = contextInterceptor;
|
|
26
|
+
//# sourceMappingURL=interceptors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interceptors.js","sourceRoot":"","sources":["../src/interceptors.ts"],"names":[],"mappings":";;;AACA,qCAAkD;AAElD;;;;GAIG;AACI,MAAM,kBAAkB,GAAgB,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;IACrE,kCAAkC;IAClC,MAAM,SAAS,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;IAExD,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,iBAAiB,GAAG,+BAAsB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAEhE,IAAI,iBAAiB,EAAE,CAAC;YACtB,iEAAiE;YACjE,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,iBAAiB,CAAC,aAAa,CAAC,OAAO,EAAE,EAAE,CAAC;gBACrE,GAAG,CAAC,aAAa,CAAC,GAAG,CACnB,EAAE,EAAE,EAAE,GAAG,EAAE,YAAY,EAAE,SAAS,EAAS,EAC3C,KAAK,CACN,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IAED,gDAAgD;IAChD,OAAO,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC;AACzB,CAAC,CAAC;AApBW,QAAA,kBAAkB,sBAoB7B"}
|
package/dist/interfaces.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { GenMessage, GenService } from '@bufbuild/protobuf/codegenv2';
|
|
2
|
+
import { HandlerContext } from '@connectrpc/connect';
|
|
2
3
|
import { FastifyReply, FastifyRequest } from 'fastify';
|
|
3
4
|
import { OmitConnectrpcFields } from './types';
|
|
4
5
|
export interface Logger {
|
|
@@ -28,16 +29,19 @@ type ExtractOutput<T> = T extends {
|
|
|
28
29
|
} ? M : never;
|
|
29
30
|
/**
|
|
30
31
|
* Convert a service method to a controller method signature
|
|
32
|
+
*
|
|
33
|
+
* Note: The context parameter receives a HandlerContext instance at runtime
|
|
34
|
+
* which provides access to headers, values, signal, and other request metadata.
|
|
31
35
|
*/
|
|
32
36
|
type ServiceMethod<T> = T extends {
|
|
33
37
|
methodKind: 'unary';
|
|
34
|
-
} ? (request: ExtractInput<T
|
|
38
|
+
} ? (request: ExtractInput<T>, context?: HandlerContext) => Promise<OmitConnectrpcFields<ExtractOutput<T>>> : T extends {
|
|
35
39
|
methodKind: 'server_streaming';
|
|
36
|
-
} ? (request: ExtractInput<T
|
|
40
|
+
} ? (request: ExtractInput<T>, context?: HandlerContext) => AsyncIterable<OmitConnectrpcFields<ExtractOutput<T>>> : T extends {
|
|
37
41
|
methodKind: 'client_streaming';
|
|
38
|
-
} ? (request: AsyncIterable<ExtractInput<T
|
|
42
|
+
} ? (request: AsyncIterable<ExtractInput<T>>, context?: HandlerContext) => Promise<OmitConnectrpcFields<ExtractOutput<T>>> : T extends {
|
|
39
43
|
methodKind: 'bidi_streaming';
|
|
40
|
-
} ? (request: AsyncIterable<ExtractInput<T
|
|
44
|
+
} ? (request: AsyncIterable<ExtractInput<T>>, context?: HandlerContext) => AsyncIterable<OmitConnectrpcFields<ExtractOutput<T>>> : never;
|
|
41
45
|
/**
|
|
42
46
|
* Generic interface that maps a ConnectRPC service to controller methods
|
|
43
47
|
*
|
|
@@ -106,20 +110,4 @@ export type MiddlewareConfigUnion = MiddlewareConfigGlobal | MiddlewareConfig<an
|
|
|
106
110
|
* This ensures proper type inference for method names based on the service
|
|
107
111
|
*/
|
|
108
112
|
export declare function middlewareConfig<T extends GenService<any>>(use: Type<Middleware>, on?: T, methods?: Array<ServiceMethodNames<T>>): MiddlewareConfigUnion;
|
|
109
|
-
export interface ExecutionContext {
|
|
110
|
-
getClass<T = any>(): Type<T>;
|
|
111
|
-
getHandler(): Function;
|
|
112
|
-
getArgs<T extends Array<any> = any[]>(): T;
|
|
113
|
-
getArgByIndex<T = any>(index: number): T;
|
|
114
|
-
switchToHttp(): {
|
|
115
|
-
getRequest(): FastifyRequest['raw'];
|
|
116
|
-
getResponse(): FastifyReply['raw'];
|
|
117
|
-
getNext<T = any>(): () => T;
|
|
118
|
-
};
|
|
119
|
-
switchToRpc(): any;
|
|
120
|
-
switchToWs(): any;
|
|
121
|
-
}
|
|
122
|
-
export interface Guard {
|
|
123
|
-
canActivate(context: ExecutionContext): boolean | Promise<boolean>;
|
|
124
|
-
}
|
|
125
113
|
export {};
|
package/dist/interfaces.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interfaces.js","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"interfaces.js","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":";;AAkJA,4CAUC;AAdD;;;GAGG;AACH,SAAgB,gBAAgB,CAC9B,GAAqB,EACrB,EAAM,EACN,OAAsC;IAEtC,OAAO;QACL,GAAG;QACH,EAAE;QACF,OAAO;KACR,CAAC;AACJ,CAAC"}
|
package/dist/middlewares.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
-
import { FastifyInstance } from 'fastify';
|
|
1
|
+
import { FastifyInstance, FastifyRequest } from 'fastify';
|
|
2
2
|
import { MiddlewareConfigUnion } from './interfaces';
|
|
3
|
+
/** This method allows middleware to access custom context values associated with a request */
|
|
4
|
+
export declare function getCustomContextValues(req: FastifyRequest['raw']): import("./context-values").CustomContextValues | null;
|
|
3
5
|
export declare function initMiddlewares(server: FastifyInstance, middlewareConfigs: MiddlewareConfigUnion[]): Promise<void>;
|
package/dist/middlewares.js
CHANGED
|
@@ -1,9 +1,46 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getCustomContextValues = getCustomContextValues;
|
|
3
4
|
exports.initMiddlewares = initMiddlewares;
|
|
5
|
+
const context_values_1 = require("./context-values");
|
|
4
6
|
const helpers_1 = require("./helpers");
|
|
5
7
|
const stores_1 = require("./stores");
|
|
8
|
+
function setupCustomContextValues(req) {
|
|
9
|
+
const requestId = (0, helpers_1.generateRequestId)();
|
|
10
|
+
// Store the request ID in a custom header
|
|
11
|
+
req.headers['x-server-request-id'] = requestId;
|
|
12
|
+
// Create and store the middleware context with ContextValues
|
|
13
|
+
stores_1.MiddlewareContextStore.set(requestId, {
|
|
14
|
+
contextValues: (0, context_values_1.createCustomContextValues)(),
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
/** This method allows middleware to access custom context values associated with a request */
|
|
18
|
+
function getCustomContextValues(req) {
|
|
19
|
+
const requestId = req.headers['x-server-request-id'];
|
|
20
|
+
if (requestId) {
|
|
21
|
+
const middlewareContext = stores_1.MiddlewareContextStore.get(requestId);
|
|
22
|
+
if (middlewareContext) {
|
|
23
|
+
return middlewareContext.contextValues;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
function clearCustomContextValues(req) {
|
|
29
|
+
const requestId = req.headers['x-server-request-id'];
|
|
30
|
+
if (requestId) {
|
|
31
|
+
stores_1.MiddlewareContextStore.delete(requestId);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
6
34
|
async function initMiddlewares(server, middlewareConfigs) {
|
|
35
|
+
// Add context middleware first - this stores req/res and creates ContextValues for interceptors
|
|
36
|
+
server.addHook('onRequest', async (request, reply) => {
|
|
37
|
+
setupCustomContextValues(request.raw);
|
|
38
|
+
// Clean up the context when the response finishes
|
|
39
|
+
reply.raw.on('finish', () => {
|
|
40
|
+
clearCustomContextValues(request.raw);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
helpers_1.logger.log('Applied context middleware for storing req/res objects and ContextValues');
|
|
7
44
|
for (const config of middlewareConfigs) {
|
|
8
45
|
// Convert method names to set with PascalCase
|
|
9
46
|
const methods = new Set((config.methods || []).map((m) => m[0].toUpperCase() + m.slice(1)));
|
package/dist/middlewares.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middlewares.js","sourceRoot":"","sources":["../src/middlewares.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"middlewares.js","sourceRoot":"","sources":["../src/middlewares.ts"],"names":[],"mappings":"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"}
|
package/dist/stores.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { GenService, GenServiceMethods } from '@bufbuild/protobuf/codegenv2';
|
|
2
|
-
import {
|
|
2
|
+
import { CustomContextValues } from './context-values';
|
|
3
|
+
import { Middleware, Service, Type } from './interfaces';
|
|
3
4
|
declare class ControllersStoreClass {
|
|
4
5
|
private controllers;
|
|
5
6
|
values(): {
|
|
@@ -7,6 +8,7 @@ declare class ControllersStoreClass {
|
|
|
7
8
|
service: GenService<any>;
|
|
8
9
|
target: Type<any>;
|
|
9
10
|
}[];
|
|
11
|
+
clear(): void;
|
|
10
12
|
registerInstance<T extends GenServiceMethods>(self: Service<GenService<T>>, service: GenService<T>, { allowMultipleInstances, }?: {
|
|
11
13
|
allowMultipleInstances?: boolean;
|
|
12
14
|
}): void;
|
|
@@ -17,6 +19,7 @@ export declare const ControllersStore: ControllersStoreClass;
|
|
|
17
19
|
*/
|
|
18
20
|
declare class MiddlewareStoreClass {
|
|
19
21
|
private middlewares;
|
|
22
|
+
clear(): void;
|
|
20
23
|
/**
|
|
21
24
|
* Register a middleware instance from its constructor
|
|
22
25
|
*/
|
|
@@ -34,6 +37,7 @@ export declare const MiddlewareStore: MiddlewareStoreClass;
|
|
|
34
37
|
*/
|
|
35
38
|
declare class RouteMetadataStoreClass {
|
|
36
39
|
private routes;
|
|
40
|
+
clear(): void;
|
|
37
41
|
/**
|
|
38
42
|
* Register route metadata for a specific service method
|
|
39
43
|
* @param serviceName - The full service name (e.g., "connectrpc.eliza.v1.ElizaService")
|
|
@@ -69,24 +73,30 @@ declare class RouteMetadataStoreClass {
|
|
|
69
73
|
}
|
|
70
74
|
export declare const RouteMetadataStore: RouteMetadataStoreClass;
|
|
71
75
|
/**
|
|
72
|
-
*
|
|
76
|
+
* Middleware context - contains both raw req/res and context values
|
|
73
77
|
*/
|
|
74
|
-
|
|
75
|
-
|
|
78
|
+
export interface MiddlewareContext {
|
|
79
|
+
contextValues: CustomContextValues;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Store for middleware context - maps request IDs to middleware context
|
|
83
|
+
* This allows interceptors to access both raw request/response objects and context values
|
|
84
|
+
*/
|
|
85
|
+
declare class MiddlewareContextStoreClass {
|
|
86
|
+
private contexts;
|
|
87
|
+
clear(): void;
|
|
76
88
|
/**
|
|
77
|
-
*
|
|
89
|
+
* Store middleware context by request ID
|
|
78
90
|
*/
|
|
79
|
-
|
|
80
|
-
allowMultipleInstances?: boolean;
|
|
81
|
-
}): void;
|
|
91
|
+
set(requestId: string, context: MiddlewareContext): void;
|
|
82
92
|
/**
|
|
83
|
-
* Get
|
|
93
|
+
* Get middleware context by request ID
|
|
84
94
|
*/
|
|
85
|
-
|
|
95
|
+
get(requestId: string): MiddlewareContext | null;
|
|
86
96
|
/**
|
|
87
|
-
*
|
|
97
|
+
* Delete middleware context by request ID
|
|
88
98
|
*/
|
|
89
|
-
|
|
99
|
+
delete(requestId: string): void;
|
|
90
100
|
}
|
|
91
|
-
export declare const
|
|
101
|
+
export declare const MiddlewareContextStore: MiddlewareContextStoreClass;
|
|
92
102
|
export {};
|
package/dist/stores.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.MiddlewareContextStore = exports.RouteMetadataStore = exports.MiddlewareStore = exports.ControllersStore = void 0;
|
|
4
4
|
class ControllersStoreClass {
|
|
5
5
|
constructor() {
|
|
6
6
|
this.controllers = new Map();
|
|
@@ -11,6 +11,10 @@ class ControllersStoreClass {
|
|
|
11
11
|
...data,
|
|
12
12
|
}));
|
|
13
13
|
}
|
|
14
|
+
// For testing purposes
|
|
15
|
+
clear() {
|
|
16
|
+
this.controllers.clear();
|
|
17
|
+
}
|
|
14
18
|
registerInstance(self, service, { allowMultipleInstances = false, } = {}) {
|
|
15
19
|
const controllerClass = self.constructor;
|
|
16
20
|
if (!allowMultipleInstances && this.controllers.has(controllerClass)) {
|
|
@@ -30,6 +34,10 @@ class MiddlewareStoreClass {
|
|
|
30
34
|
constructor() {
|
|
31
35
|
this.middlewares = new Map();
|
|
32
36
|
}
|
|
37
|
+
// For testing purposes
|
|
38
|
+
clear() {
|
|
39
|
+
this.middlewares.clear();
|
|
40
|
+
}
|
|
33
41
|
/**
|
|
34
42
|
* Register a middleware instance from its constructor
|
|
35
43
|
*/
|
|
@@ -55,6 +63,10 @@ class RouteMetadataStoreClass {
|
|
|
55
63
|
constructor() {
|
|
56
64
|
this.routes = new Map();
|
|
57
65
|
}
|
|
66
|
+
// For testing purposes
|
|
67
|
+
clear() {
|
|
68
|
+
this.routes.clear();
|
|
69
|
+
}
|
|
58
70
|
/**
|
|
59
71
|
* Register route metadata for a specific service method
|
|
60
72
|
* @param serviceName - The full service name (e.g., "connectrpc.eliza.v1.ElizaService")
|
|
@@ -90,34 +102,35 @@ class RouteMetadataStoreClass {
|
|
|
90
102
|
}
|
|
91
103
|
exports.RouteMetadataStore = new RouteMetadataStoreClass();
|
|
92
104
|
/**
|
|
93
|
-
* Store for
|
|
105
|
+
* Store for middleware context - maps request IDs to middleware context
|
|
106
|
+
* This allows interceptors to access both raw request/response objects and context values
|
|
94
107
|
*/
|
|
95
|
-
class
|
|
108
|
+
class MiddlewareContextStoreClass {
|
|
96
109
|
constructor() {
|
|
97
|
-
this.
|
|
110
|
+
this.contexts = new Map();
|
|
111
|
+
}
|
|
112
|
+
// For testing purposes
|
|
113
|
+
clear() {
|
|
114
|
+
this.contexts.clear();
|
|
98
115
|
}
|
|
99
116
|
/**
|
|
100
|
-
*
|
|
117
|
+
* Store middleware context by request ID
|
|
101
118
|
*/
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
if (!allowMultipleInstances && this.guards.has(guardClass)) {
|
|
105
|
-
throw new Error(`Guard ${guardClass.name} is already registered! This may happen if you export guard as provider and also register it in some Nest module.`);
|
|
106
|
-
}
|
|
107
|
-
this.guards.set(guardClass, self);
|
|
119
|
+
set(requestId, context) {
|
|
120
|
+
this.contexts.set(requestId, context);
|
|
108
121
|
}
|
|
109
122
|
/**
|
|
110
|
-
* Get
|
|
123
|
+
* Get middleware context by request ID
|
|
111
124
|
*/
|
|
112
|
-
|
|
113
|
-
return this.
|
|
125
|
+
get(requestId) {
|
|
126
|
+
return this.contexts.get(requestId) || null;
|
|
114
127
|
}
|
|
115
128
|
/**
|
|
116
|
-
*
|
|
129
|
+
* Delete middleware context by request ID
|
|
117
130
|
*/
|
|
118
|
-
|
|
119
|
-
|
|
131
|
+
delete(requestId) {
|
|
132
|
+
this.contexts.delete(requestId);
|
|
120
133
|
}
|
|
121
134
|
}
|
|
122
|
-
exports.
|
|
135
|
+
exports.MiddlewareContextStore = new MiddlewareContextStoreClass();
|
|
123
136
|
//# sourceMappingURL=stores.js.map
|
package/dist/stores.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stores.js","sourceRoot":"","sources":["../src/stores.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"stores.js","sourceRoot":"","sources":["../src/stores.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,33 +1,36 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@funduck/connectrpc-fastify",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.12",
|
|
4
4
|
"author": "Oleg Milekhin <qlfunduck@gmail.com>",
|
|
5
5
|
"description": "Wrapper for official @connectrpc/connect and fastify. Simplifies configuration, type safe binding to controller, simplifies use of middlewares and guards.",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
8
|
"scripts": {
|
|
9
9
|
"build": "npx rimraf dist; tsc -p tsconfig.build.json",
|
|
10
|
-
"compile-proto": "cd test && npx buf dep update; npx buf lint; npx buf generate",
|
|
11
|
-
"test": "npm run compile-proto && cd test && DEBUG=true npx tsx e2e-demo.ts",
|
|
10
|
+
"compile-proto": "cd test/demo && npx buf dep update; npx buf lint; npx buf generate",
|
|
11
|
+
"test:demo": "npm run compile-proto && cd test/demo && DEBUG=true npx tsx e2e-demo.ts",
|
|
12
|
+
"test": "npm run compile-proto && jest --verbose",
|
|
13
|
+
"test:coverage": "npm run compile-proto && jest --coverage --runInBand",
|
|
12
14
|
"publish:check": "npm test && npm run build && npm publish --tag latest --access public --dry-run",
|
|
13
15
|
"publish:latest": "npm publish --tag latest --access public"
|
|
14
16
|
},
|
|
15
17
|
"license": "MIT",
|
|
16
|
-
"dependencies": {
|
|
17
|
-
"@connectrpc/connect-fastify": "^2.1.1",
|
|
18
|
-
"type-fest": "^5.4.1"
|
|
19
|
-
},
|
|
20
18
|
"peerDependencies": {
|
|
21
19
|
"@bufbuild/protobuf": "^2.10.2",
|
|
22
|
-
"fastify": "^
|
|
20
|
+
"@connectrpc/connect-fastify": "^2.1.1",
|
|
21
|
+
"fastify": "^5.6.2",
|
|
22
|
+
"type-fest": "^5.4.1"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@bufbuild/buf": "^1.64.0",
|
|
26
26
|
"@bufbuild/protoc-gen-es": "^2.10.2",
|
|
27
27
|
"@connectrpc/connect": "^2.1.1",
|
|
28
28
|
"@connectrpc/connect-node": "^2.1.1",
|
|
29
|
+
"@types/jest": "^30.0.0",
|
|
29
30
|
"@types/node": "^25.0.9",
|
|
31
|
+
"jest": "^30.2.0",
|
|
30
32
|
"prettier-plugin-organize-imports": "^4.3.0",
|
|
33
|
+
"ts-jest": "^29.4.6",
|
|
31
34
|
"ts-node": "^10.9.2",
|
|
32
35
|
"typescript": "^5.9.3"
|
|
33
36
|
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { FastifyReply, FastifyRequest } from 'fastify';
|
|
2
|
-
import { ExecutionContext, Type } from './interfaces';
|
|
3
|
-
export declare class ManualExecutionContext implements ExecutionContext {
|
|
4
|
-
readonly request: FastifyRequest['raw'];
|
|
5
|
-
readonly response: FastifyReply['raw'];
|
|
6
|
-
readonly next: <T = any>() => T;
|
|
7
|
-
readonly args: any[];
|
|
8
|
-
readonly constructorRef: Type<any> | null;
|
|
9
|
-
readonly handler: Function | null;
|
|
10
|
-
constructor(request: FastifyRequest['raw'], response: FastifyReply['raw'], next: <T = any>() => T, args: any[], constructorRef?: Type<any> | null, handler?: Function | null);
|
|
11
|
-
getClass<T = any>(): Type<T>;
|
|
12
|
-
getHandler(): Function;
|
|
13
|
-
getArgs<T extends Array<any> = any[]>(): T;
|
|
14
|
-
getArgByIndex<T = any>(index: number): T;
|
|
15
|
-
switchToHttp(): this & {
|
|
16
|
-
getRequest: () => import("node:http").IncomingMessage;
|
|
17
|
-
getResponse: () => import("node:http").ServerResponse<import("node:http").IncomingMessage>;
|
|
18
|
-
getNext: () => <T = any>() => T;
|
|
19
|
-
};
|
|
20
|
-
switchToRpc(): void;
|
|
21
|
-
switchToWs(): void;
|
|
22
|
-
}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ManualExecutionContext = void 0;
|
|
4
|
-
class ManualExecutionContext {
|
|
5
|
-
constructor(request, response, next, args, constructorRef = null, handler = null) {
|
|
6
|
-
this.request = request;
|
|
7
|
-
this.response = response;
|
|
8
|
-
this.next = next;
|
|
9
|
-
this.args = args;
|
|
10
|
-
this.constructorRef = constructorRef;
|
|
11
|
-
this.handler = handler;
|
|
12
|
-
}
|
|
13
|
-
getClass() {
|
|
14
|
-
return this.constructorRef;
|
|
15
|
-
}
|
|
16
|
-
getHandler() {
|
|
17
|
-
return this.handler;
|
|
18
|
-
}
|
|
19
|
-
getArgs() {
|
|
20
|
-
return this.args;
|
|
21
|
-
}
|
|
22
|
-
getArgByIndex(index) {
|
|
23
|
-
return this.args[index];
|
|
24
|
-
}
|
|
25
|
-
switchToHttp() {
|
|
26
|
-
return Object.assign(this, {
|
|
27
|
-
getRequest: () => this.request,
|
|
28
|
-
getResponse: () => this.response,
|
|
29
|
-
getNext: () => this.next,
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
switchToRpc() {
|
|
33
|
-
throw new Error('Context switching to RPC is not supported.');
|
|
34
|
-
}
|
|
35
|
-
switchToWs() {
|
|
36
|
-
throw new Error('Context switching to WebSockets is not supported.');
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
exports.ManualExecutionContext = ManualExecutionContext;
|
|
40
|
-
//# sourceMappingURL=execution-context.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"execution-context.js","sourceRoot":"","sources":["../src/execution-context.ts"],"names":[],"mappings":";;;AAGA,MAAa,sBAAsB;IACjC,YACW,OAA8B,EAC9B,QAA6B,EAC7B,IAAsB,EACtB,IAAW,EACX,iBAAmC,IAAI,EACvC,UAA2B,IAAI;QAL/B,YAAO,GAAP,OAAO,CAAuB;QAC9B,aAAQ,GAAR,QAAQ,CAAqB;QAC7B,SAAI,GAAJ,IAAI,CAAkB;QACtB,SAAI,GAAJ,IAAI,CAAO;QACX,mBAAc,GAAd,cAAc,CAAyB;QACvC,YAAO,GAAP,OAAO,CAAwB;IACvC,CAAC;IAEJ,QAAQ;QACN,OAAO,IAAI,CAAC,cAAe,CAAC;IAC9B,CAAC;IAED,UAAU;QACR,OAAO,IAAI,CAAC,OAAQ,CAAC;IACvB,CAAC;IAED,OAAO;QACL,OAAO,IAAI,CAAC,IAAS,CAAC;IACxB,CAAC;IAED,aAAa,CAAU,KAAa;QAClC,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,CAAM,CAAC;IAC/B,CAAC;IAED,YAAY;QACV,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE;YACzB,UAAU,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO;YAC9B,WAAW,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ;YAChC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI;SACzB,CAAC,CAAC;IACL,CAAC;IAED,WAAW;QACT,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;IAChE,CAAC;IAED,UAAU;QACR,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;IACvE,CAAC;CACF;AAzCD,wDAyCC"}
|
package/dist/guards.d.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { FastifyInstance } from 'fastify';
|
|
2
|
-
import { ExecutionContext, Guard } from './interfaces';
|
|
3
|
-
export declare class ManualGuardExecutor {
|
|
4
|
-
executeGuard(guard: Guard, context: ExecutionContext): Promise<boolean>;
|
|
5
|
-
executeGuards(guards: Guard[], context: ExecutionContext): Promise<boolean>;
|
|
6
|
-
}
|
|
7
|
-
export declare function getGuards(controller: any): Guard[];
|
|
8
|
-
/**
|
|
9
|
-
* Initialize guards middleware - this should be called after all other middlewares are registered
|
|
10
|
-
*/
|
|
11
|
-
export declare function initGuards(server: FastifyInstance): Promise<void>;
|
package/dist/guards.js
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ManualGuardExecutor = void 0;
|
|
4
|
-
exports.getGuards = getGuards;
|
|
5
|
-
exports.initGuards = initGuards;
|
|
6
|
-
const execution_context_1 = require("./execution-context");
|
|
7
|
-
const helpers_1 = require("./helpers");
|
|
8
|
-
const stores_1 = require("./stores");
|
|
9
|
-
class ManualGuardExecutor {
|
|
10
|
-
async executeGuard(guard, context) {
|
|
11
|
-
const result = guard.canActivate(context);
|
|
12
|
-
// Handle synchronous boolean result
|
|
13
|
-
if (typeof result === 'boolean') {
|
|
14
|
-
return result;
|
|
15
|
-
}
|
|
16
|
-
// Handle Promise result
|
|
17
|
-
return await result;
|
|
18
|
-
}
|
|
19
|
-
async executeGuards(guards, context) {
|
|
20
|
-
for (const guard of guards) {
|
|
21
|
-
const canActivate = await this.executeGuard(guard, context);
|
|
22
|
-
if (!canActivate) {
|
|
23
|
-
return false;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
return true;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
exports.ManualGuardExecutor = ManualGuardExecutor;
|
|
30
|
-
function getGuards(controller) {
|
|
31
|
-
// Return all registered guards
|
|
32
|
-
// In a more sophisticated implementation, you could filter guards
|
|
33
|
-
// based on decorators on the controller or method
|
|
34
|
-
return stores_1.GuardsStore.getAllGuards();
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Initialize guards middleware - this should be called after all other middlewares are registered
|
|
38
|
-
*/
|
|
39
|
-
async function initGuards(server) {
|
|
40
|
-
const guardExecutor = new ManualGuardExecutor();
|
|
41
|
-
// Add a hook that runs after all other middlewares
|
|
42
|
-
server.addHook('preHandler', async (request, reply) => {
|
|
43
|
-
const url = request.url;
|
|
44
|
-
// Parse the URL to get the route
|
|
45
|
-
// Format: /package.ServiceName/MethodName
|
|
46
|
-
const match = url.match(/^\/([^/]+)\/([^/]+)$/);
|
|
47
|
-
if (!match) {
|
|
48
|
-
// Not a ConnectRPC route, skip guard execution
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
// Get route metadata
|
|
52
|
-
const routeMetadata = stores_1.RouteMetadataStore.getRouteMetadata(url);
|
|
53
|
-
if (!routeMetadata) {
|
|
54
|
-
// No metadata found for this route
|
|
55
|
-
helpers_1.logger.warn(`No route metadata found for ${url}`);
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
const { controllerClass, controllerMethod, controllerMethodName, instance, } = routeMetadata;
|
|
59
|
-
// Get guards for the controller
|
|
60
|
-
const guards = getGuards(instance);
|
|
61
|
-
if (guards.length === 0) {
|
|
62
|
-
// No guards to execute
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
// Create execution context
|
|
66
|
-
// Note: For ConnectRPC, we don't have the actual request arguments yet at this point
|
|
67
|
-
// They will be deserialized later by the ConnectRPC handler
|
|
68
|
-
const executionContext = new execution_context_1.ManualExecutionContext(request.raw, reply.raw, (() => undefined), [], // args will be populated later if needed
|
|
69
|
-
controllerClass, controllerMethod);
|
|
70
|
-
// Execute guards
|
|
71
|
-
try {
|
|
72
|
-
const canActivate = await guardExecutor.executeGuards(guards, executionContext);
|
|
73
|
-
if (!canActivate) {
|
|
74
|
-
// Guard rejected the request
|
|
75
|
-
reply.code(403).send({
|
|
76
|
-
code: 'permission_denied',
|
|
77
|
-
message: 'Forbidden',
|
|
78
|
-
});
|
|
79
|
-
throw new Error('Guard rejected the request');
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
catch (error) {
|
|
83
|
-
// If guard throws an error, reject the request
|
|
84
|
-
if (!reply.sent) {
|
|
85
|
-
reply.code(403).send({
|
|
86
|
-
code: 'permission_denied',
|
|
87
|
-
message: error instanceof Error ? error.message : 'Forbidden',
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
throw error;
|
|
91
|
-
}
|
|
92
|
-
});
|
|
93
|
-
helpers_1.logger.log('Guards middleware initialized');
|
|
94
|
-
}
|
|
95
|
-
//# sourceMappingURL=guards.js.map
|
package/dist/guards.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"guards.js","sourceRoot":"","sources":["../src/guards.ts"],"names":[],"mappings":";;;AAoCA,8BAKC;AAKD,gCAmFC;AAhID,2DAA6D;AAC7D,uCAAmC;AAEnC,qCAA2D;AAE3D,MAAa,mBAAmB;IAC9B,KAAK,CAAC,YAAY,CAChB,KAAY,EACZ,OAAyB;QAEzB,MAAM,MAAM,GAAG,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QAE1C,oCAAoC;QACpC,IAAI,OAAO,MAAM,KAAK,SAAS,EAAE,CAAC;YAChC,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,wBAAwB;QACxB,OAAO,MAAM,MAAM,CAAC;IACtB,CAAC;IAED,KAAK,CAAC,aAAa,CACjB,MAAe,EACf,OAAyB;QAEzB,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;YAC5D,IAAI,CAAC,WAAW,EAAE,CAAC;gBACjB,OAAO,KAAK,CAAC;YACf,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AA5BD,kDA4BC;AAED,SAAgB,SAAS,CAAC,UAAe;IACvC,+BAA+B;IAC/B,kEAAkE;IAClE,kDAAkD;IAClD,OAAO,oBAAW,CAAC,YAAY,EAAE,CAAC;AACpC,CAAC;AAED;;GAEG;AACI,KAAK,UAAU,UAAU,CAAC,MAAuB;IACtD,MAAM,aAAa,GAAG,IAAI,mBAAmB,EAAE,CAAC;IAEhD,mDAAmD;IACnD,MAAM,CAAC,OAAO,CACZ,YAAY,EACZ,KAAK,EAAE,OAAuB,EAAE,KAAmB,EAAE,EAAE;QACrD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;QAExB,iCAAiC;QACjC,0CAA0C;QAC1C,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC;QAEhD,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,+CAA+C;YAC/C,OAAO;QACT,CAAC;QAED,qBAAqB;QACrB,MAAM,aAAa,GAAG,2BAAkB,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC;QAE/D,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,mCAAmC;YACnC,gBAAM,CAAC,IAAI,CAAC,+BAA+B,GAAG,EAAE,CAAC,CAAC;YAClD,OAAO;QACT,CAAC;QAED,MAAM,EACJ,eAAe,EACf,gBAAgB,EAChB,oBAAoB,EACpB,QAAQ,GACT,GAAG,aAAa,CAAC;QAElB,gCAAgC;QAChC,MAAM,MAAM,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;QAEnC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,uBAAuB;YACvB,OAAO;QACT,CAAC;QAED,2BAA2B;QAC3B,qFAAqF;QACrF,4DAA4D;QAC5D,MAAM,gBAAgB,GAAG,IAAI,0CAAsB,CACjD,OAAO,CAAC,GAAG,EACX,KAAK,CAAC,GAAG,EACT,CAAC,GAAG,EAAE,CAAC,SAAS,CAAqB,EACrC,EAAE,EAAE,yCAAyC;QAC7C,eAAe,EACf,gBAAgB,CACjB,CAAC;QAEF,iBAAiB;QACjB,IAAI,CAAC;YACH,MAAM,WAAW,GAAG,MAAM,aAAa,CAAC,aAAa,CACnD,MAAM,EACN,gBAAgB,CACjB,CAAC;YAEF,IAAI,CAAC,WAAW,EAAE,CAAC;gBACjB,6BAA6B;gBAC7B,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;oBACnB,IAAI,EAAE,mBAAmB;oBACzB,OAAO,EAAE,WAAW;iBACrB,CAAC,CAAC;gBACH,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;YAChD,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,+CAA+C;YAC/C,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;gBAChB,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;oBACnB,IAAI,EAAE,mBAAmB;oBACzB,OAAO,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW;iBAC9D,CAAC,CAAC;YACL,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC,CACF,CAAC;IAEF,gBAAM,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAC;AAC9C,CAAC"}
|