@themainstack/communication 1.0.2 → 1.1.0
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 +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -1
- package/dist/proto-generator/index.d.ts +10 -0
- package/dist/proto-generator/index.js +21 -2
- package/package.json +2 -2
- package/src/index.ts +2 -1
- package/src/proto-generator/index.ts +24 -3
- package/tests/any-type.spec.ts +100 -0
- package/publish-config.npmrc +0 -1
package/README.md
CHANGED
|
@@ -182,6 +182,7 @@ See `examples/full-grpc-demo.ts` in the repository for a complete working exampl
|
|
|
182
182
|
### Proto Generation
|
|
183
183
|
- `generateProtoFromMethods(methods, options)` - Generate proto with service definition
|
|
184
184
|
- `generateProtoFromFunction(fn, name)` - Generate proto for a single message
|
|
185
|
+
- `AnyType` - Marker symbol for `google.protobuf.Any` dynamic fields
|
|
185
186
|
|
|
186
187
|
### Server
|
|
187
188
|
- `GrpcServerFactory.createServer(options, handlers)` - Create a gRPC server
|
package/dist/index.d.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* 3. Client Factory - Call gRPC services from other services
|
|
10
10
|
* 4. Error Handling - Standardized error translation
|
|
11
11
|
*/
|
|
12
|
-
export { generateProtoFromMethods, generateProtoFromFunction } from './proto-generator';
|
|
12
|
+
export { generateProtoFromMethods, generateProtoFromFunction, AnyType } from './proto-generator';
|
|
13
13
|
export type { MethodDefinition, GenerateProtoOptions } from './proto-generator';
|
|
14
14
|
export { GrpcServerFactory, exposeAsGrpc } from './grpc/server-factory';
|
|
15
15
|
export type { GrpcServerOptions, ServerMethodHandler } from './grpc/server-factory';
|
package/dist/index.js
CHANGED
|
@@ -11,12 +11,13 @@
|
|
|
11
11
|
* 4. Error Handling - Standardized error translation
|
|
12
12
|
*/
|
|
13
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
-
exports.GrpcError = exports.handleGrpcError = exports.GrpcClientFactory = exports.exposeAsGrpc = exports.GrpcServerFactory = exports.generateProtoFromFunction = exports.generateProtoFromMethods = void 0;
|
|
14
|
+
exports.GrpcError = exports.handleGrpcError = exports.GrpcClientFactory = exports.exposeAsGrpc = exports.GrpcServerFactory = exports.AnyType = exports.generateProtoFromFunction = exports.generateProtoFromMethods = void 0;
|
|
15
15
|
// Proto Generation
|
|
16
16
|
// Auto-generate .proto files from TypeScript types
|
|
17
17
|
var proto_generator_1 = require("./proto-generator");
|
|
18
18
|
Object.defineProperty(exports, "generateProtoFromMethods", { enumerable: true, get: function () { return proto_generator_1.generateProtoFromMethods; } });
|
|
19
19
|
Object.defineProperty(exports, "generateProtoFromFunction", { enumerable: true, get: function () { return proto_generator_1.generateProtoFromFunction; } });
|
|
20
|
+
Object.defineProperty(exports, "AnyType", { enumerable: true, get: function () { return proto_generator_1.AnyType; } });
|
|
20
21
|
// Server Factory
|
|
21
22
|
// Expose existing functions as gRPC endpoints
|
|
22
23
|
var server_factory_1 = require("./grpc/server-factory");
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Marker symbol to indicate a field should use google.protobuf.Any type.
|
|
3
|
+
* Use this in your sample objects to mark dynamic/generic fields.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* requestSample: () => ({ id: '', data: AnyType })
|
|
7
|
+
*/
|
|
8
|
+
export declare const AnyType: unique symbol;
|
|
1
9
|
/**
|
|
2
10
|
* Options for generating a proto file
|
|
3
11
|
*/
|
|
@@ -10,6 +18,8 @@ export interface GenerateProtoOptions {
|
|
|
10
18
|
outputDir?: string;
|
|
11
19
|
/** Output filename (default: derived from serviceName or 'generated.proto') */
|
|
12
20
|
outputFilename?: string;
|
|
21
|
+
/** Enable google.protobuf.Any for dynamic types marked with AnyType symbol (default: true) */
|
|
22
|
+
enableAnyType?: boolean;
|
|
13
23
|
}
|
|
14
24
|
/**
|
|
15
25
|
* Definition of a gRPC method with request and response generators
|
|
@@ -33,10 +33,19 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.AnyType = void 0;
|
|
36
37
|
exports.generateProtoFromMethods = generateProtoFromMethods;
|
|
37
38
|
exports.generateProtoFromFunction = generateProtoFromFunction;
|
|
38
39
|
const fs = __importStar(require("fs"));
|
|
39
40
|
const path = __importStar(require("path"));
|
|
41
|
+
/**
|
|
42
|
+
* Marker symbol to indicate a field should use google.protobuf.Any type.
|
|
43
|
+
* Use this in your sample objects to mark dynamic/generic fields.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* requestSample: () => ({ id: '', data: AnyType })
|
|
47
|
+
*/
|
|
48
|
+
exports.AnyType = Symbol('google.protobuf.Any');
|
|
40
49
|
/**
|
|
41
50
|
* Generate a complete .proto file from method definitions
|
|
42
51
|
*
|
|
@@ -45,10 +54,11 @@ const path = __importStar(require("path"));
|
|
|
45
54
|
* @returns The generated proto string
|
|
46
55
|
*/
|
|
47
56
|
function generateProtoFromMethods(methods, options = {}) {
|
|
48
|
-
const { packageName, serviceName = 'GeneratedService', outputDir, outputFilename } = options;
|
|
57
|
+
const { packageName, serviceName = 'GeneratedService', outputDir, outputFilename, enableAnyType = true } = options;
|
|
49
58
|
const messages = [];
|
|
50
59
|
const protoMethods = [];
|
|
51
60
|
const processedObjects = new Set();
|
|
61
|
+
let usesAnyType = false;
|
|
52
62
|
// Helper: Capitalize string
|
|
53
63
|
function capitalize(s) {
|
|
54
64
|
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
@@ -72,7 +82,12 @@ function generateProtoFromMethods(methods, options = {}) {
|
|
|
72
82
|
let type = "string";
|
|
73
83
|
let rule = undefined;
|
|
74
84
|
const valueType = typeof value;
|
|
75
|
-
|
|
85
|
+
// Check for AnyType marker symbol
|
|
86
|
+
if (enableAnyType && (value === exports.AnyType || (typeof value === 'symbol' && value.description === 'google.protobuf.Any'))) {
|
|
87
|
+
type = "google.protobuf.Any";
|
|
88
|
+
usesAnyType = true;
|
|
89
|
+
}
|
|
90
|
+
else if (value === null || value === undefined) {
|
|
76
91
|
type = "string";
|
|
77
92
|
}
|
|
78
93
|
else if (valueType === "string") {
|
|
@@ -140,6 +155,10 @@ function generateProtoFromMethods(methods, options = {}) {
|
|
|
140
155
|
if (packageName) {
|
|
141
156
|
lines.push(`package ${packageName};`, '');
|
|
142
157
|
}
|
|
158
|
+
// Add google.protobuf.Any import if needed
|
|
159
|
+
if (usesAnyType) {
|
|
160
|
+
lines.push('import "google/protobuf/any.proto";', '');
|
|
161
|
+
}
|
|
143
162
|
// Service definition
|
|
144
163
|
lines.push(`// ${serviceName} - Auto-generated gRPC service`);
|
|
145
164
|
lines.push(`service ${serviceName} {`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@themainstack/communication",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Unified gRPC framework for inter-service communication - auto-generates protos, creates servers, and provides type-safe clients",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -23,4 +23,4 @@
|
|
|
23
23
|
"@grpc/grpc-js": "^1.14.3",
|
|
24
24
|
"@grpc/proto-loader": "^0.8.0"
|
|
25
25
|
}
|
|
26
|
-
}
|
|
26
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
2
|
import * as path from 'path';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Marker symbol to indicate a field should use google.protobuf.Any type.
|
|
6
|
+
* Use this in your sample objects to mark dynamic/generic fields.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* requestSample: () => ({ id: '', data: AnyType })
|
|
10
|
+
*/
|
|
11
|
+
export const AnyType = Symbol('google.protobuf.Any');
|
|
12
|
+
|
|
4
13
|
/**
|
|
5
14
|
* Maps JavaScript/TypeScript runtime types to Protobuf types.
|
|
6
15
|
*/
|
|
7
|
-
type ProtoType = "double" | "float" | "int32" | "int64" | "bool" | "string" | "bytes" | string;
|
|
16
|
+
type ProtoType = "double" | "float" | "int32" | "int64" | "bool" | "string" | "bytes" | "google.protobuf.Any" | string;
|
|
8
17
|
|
|
9
18
|
interface ProtoField {
|
|
10
19
|
name: string;
|
|
@@ -36,6 +45,8 @@ export interface GenerateProtoOptions {
|
|
|
36
45
|
outputDir?: string;
|
|
37
46
|
/** Output filename (default: derived from serviceName or 'generated.proto') */
|
|
38
47
|
outputFilename?: string;
|
|
48
|
+
/** Enable google.protobuf.Any for dynamic types marked with AnyType symbol (default: true) */
|
|
49
|
+
enableAnyType?: boolean;
|
|
39
50
|
}
|
|
40
51
|
|
|
41
52
|
/**
|
|
@@ -61,11 +72,12 @@ export function generateProtoFromMethods(
|
|
|
61
72
|
methods: MethodDefinition<any, any>[],
|
|
62
73
|
options: GenerateProtoOptions = {}
|
|
63
74
|
): string {
|
|
64
|
-
const { packageName, serviceName = 'GeneratedService', outputDir, outputFilename } = options;
|
|
75
|
+
const { packageName, serviceName = 'GeneratedService', outputDir, outputFilename, enableAnyType = true } = options;
|
|
65
76
|
|
|
66
77
|
const messages: ProtoMessage[] = [];
|
|
67
78
|
const protoMethods: ProtoMethod[] = [];
|
|
68
79
|
const processedObjects = new Set<object>();
|
|
80
|
+
let usesAnyType = false;
|
|
69
81
|
|
|
70
82
|
// Helper: Capitalize string
|
|
71
83
|
function capitalize(s: string): string {
|
|
@@ -96,7 +108,11 @@ export function generateProtoFromMethods(
|
|
|
96
108
|
|
|
97
109
|
const valueType = typeof value;
|
|
98
110
|
|
|
99
|
-
|
|
111
|
+
// Check for AnyType marker symbol
|
|
112
|
+
if (enableAnyType && (value === AnyType || (typeof value === 'symbol' && value.description === 'google.protobuf.Any'))) {
|
|
113
|
+
type = "google.protobuf.Any";
|
|
114
|
+
usesAnyType = true;
|
|
115
|
+
} else if (value === null || value === undefined) {
|
|
100
116
|
type = "string";
|
|
101
117
|
} else if (valueType === "string") {
|
|
102
118
|
type = "string";
|
|
@@ -167,6 +183,11 @@ export function generateProtoFromMethods(
|
|
|
167
183
|
lines.push(`package ${packageName};`, '');
|
|
168
184
|
}
|
|
169
185
|
|
|
186
|
+
// Add google.protobuf.Any import if needed
|
|
187
|
+
if (usesAnyType) {
|
|
188
|
+
lines.push('import "google/protobuf/any.proto";', '');
|
|
189
|
+
}
|
|
190
|
+
|
|
170
191
|
// Service definition
|
|
171
192
|
lines.push(`// ${serviceName} - Auto-generated gRPC service`);
|
|
172
193
|
lines.push(`service ${serviceName} {`);
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { generateProtoFromMethods, AnyType } from '../src/index';
|
|
3
|
+
|
|
4
|
+
describe('google.protobuf.Any support', () => {
|
|
5
|
+
it('should export AnyType symbol', () => {
|
|
6
|
+
expect(AnyType).toBeDefined();
|
|
7
|
+
expect(typeof AnyType).toBe('symbol');
|
|
8
|
+
expect(AnyType.description).toBe('google.protobuf.Any');
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('should generate proto with google.protobuf.Any for marked fields', () => {
|
|
12
|
+
const proto = generateProtoFromMethods([
|
|
13
|
+
{
|
|
14
|
+
name: 'ProcessGenericData',
|
|
15
|
+
requestSample: () => ({
|
|
16
|
+
id: '',
|
|
17
|
+
data: AnyType,
|
|
18
|
+
}),
|
|
19
|
+
responseSample: () => ({
|
|
20
|
+
success: true,
|
|
21
|
+
result: AnyType,
|
|
22
|
+
}),
|
|
23
|
+
}
|
|
24
|
+
], {
|
|
25
|
+
packageName: 'generic.v1',
|
|
26
|
+
serviceName: 'GenericService',
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// Should include the import statement
|
|
30
|
+
expect(proto).toContain('import "google/protobuf/any.proto";');
|
|
31
|
+
|
|
32
|
+
// Should use google.protobuf.Any type
|
|
33
|
+
expect(proto).toContain('google.protobuf.Any data = 2;');
|
|
34
|
+
expect(proto).toContain('google.protobuf.Any result = 2;');
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('should not include import if no Any types are used', () => {
|
|
38
|
+
const proto = generateProtoFromMethods([
|
|
39
|
+
{
|
|
40
|
+
name: 'SimpleMethod',
|
|
41
|
+
requestSample: () => ({ id: '', amount: 0 }),
|
|
42
|
+
responseSample: () => ({ success: true }),
|
|
43
|
+
}
|
|
44
|
+
], {
|
|
45
|
+
packageName: 'simple.v1',
|
|
46
|
+
serviceName: 'SimpleService',
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
expect(proto).not.toContain('import "google/protobuf/any.proto";');
|
|
50
|
+
expect(proto).not.toContain('google.protobuf.Any');
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('should handle mixed fields with some Any types', () => {
|
|
54
|
+
const proto = generateProtoFromMethods([
|
|
55
|
+
{
|
|
56
|
+
name: 'MixedMethod',
|
|
57
|
+
requestSample: () => ({
|
|
58
|
+
id: '',
|
|
59
|
+
name: 'test',
|
|
60
|
+
metadata: AnyType,
|
|
61
|
+
count: 0,
|
|
62
|
+
}),
|
|
63
|
+
responseSample: () => ({
|
|
64
|
+
status: 'ok',
|
|
65
|
+
payload: AnyType,
|
|
66
|
+
}),
|
|
67
|
+
}
|
|
68
|
+
], {
|
|
69
|
+
packageName: 'mixed.v1',
|
|
70
|
+
serviceName: 'MixedService',
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
expect(proto).toContain('import "google/protobuf/any.proto";');
|
|
74
|
+
expect(proto).toContain('string id = 1;');
|
|
75
|
+
expect(proto).toContain('string name = 2;');
|
|
76
|
+
expect(proto).toContain('google.protobuf.Any metadata = 3;');
|
|
77
|
+
expect(proto).toContain('int32 count = 4;');
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('should respect enableAnyType: false option', () => {
|
|
81
|
+
const proto = generateProtoFromMethods([
|
|
82
|
+
{
|
|
83
|
+
name: 'DisabledAny',
|
|
84
|
+
requestSample: () => ({
|
|
85
|
+
id: '',
|
|
86
|
+
data: AnyType,
|
|
87
|
+
}),
|
|
88
|
+
responseSample: () => ({ success: true }),
|
|
89
|
+
}
|
|
90
|
+
], {
|
|
91
|
+
packageName: 'test.v1',
|
|
92
|
+
serviceName: 'TestService',
|
|
93
|
+
enableAnyType: false,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// When disabled, AnyType should be treated as a regular value (string fallback)
|
|
97
|
+
expect(proto).not.toContain('import "google/protobuf/any.proto";');
|
|
98
|
+
expect(proto).not.toContain('google.protobuf.Any');
|
|
99
|
+
});
|
|
100
|
+
});
|
package/publish-config.npmrc
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
//registry.npmjs.org/:_authToken=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
|