@themainstack/communication 1.1.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.GrpcClientFactory = void 0;
37
37
  const grpc = __importStar(require("@grpc/grpc-js"));
38
38
  const protoLoader = __importStar(require("@grpc/proto-loader"));
39
+ const struct_utils_1 = require("./struct-utils");
39
40
  class GrpcClientFactory {
40
41
  static createClient(options) {
41
42
  const packageDefinition = protoLoader.loadSync(options.protoPath, {
@@ -67,7 +68,69 @@ class GrpcClientFactory {
67
68
  throw new Error(`Service '${options.serviceName}' not found in ${location}`);
68
69
  }
69
70
  const ServiceClient = serviceDef[options.serviceName];
70
- return new ServiceClient(options.url, options.credentials || grpc.credentials.createInsecure(), options.channelOptions);
71
+ const client = new ServiceClient(options.url, options.credentials || grpc.credentials.createInsecure(), options.channelOptions);
72
+ // Wrap the client to intercept methods and handle Struct conversion automatically
73
+ const wrapper = new Proxy(client, {
74
+ get(target, prop) {
75
+ const value = target[prop];
76
+ // If accessing a method function, wrap it
77
+ if (typeof prop === 'string' && typeof value === 'function') {
78
+ // Find the method definition in the proto package definition
79
+ // packageDefinition uses flattened keys: 'package.Service.Method' or 'Service.Method' if in root
80
+ const methodKey = packageName
81
+ ? `${packageName}.${options.serviceName}`
82
+ : options.serviceName;
83
+ // We need to look up the method definition to get request type
84
+ // The loaded packageDefinition is a flat map of FQN -> type definition
85
+ // But we don't have easy link from method name to request FQN here without traversing.
86
+ // Fortunately, ServiceClient.service (available on constructor) has the method definitions!
87
+ const serviceDefinition = ServiceClient.service;
88
+ const methodDef = serviceDefinition[prop];
89
+ if (methodDef && !methodDef.requestStream && !methodDef.responseStream) {
90
+ return (...args) => {
91
+ const request = args[0];
92
+ if (request && typeof request === 'object') {
93
+ // Introspect and convert Struct fields
94
+ const requestType = methodDef.requestType; // This contains the type definition structure
95
+ if (requestType && requestType.format === 'Protocol Buffer 3 DescriptorProto') {
96
+ // With @grpc/grpc-js and proto-loader, type info is attached
97
+ // traverse fields to find google.protobuf.Struct
98
+ for (const field of requestType.type.field) {
99
+ if (field.typeName === 'google.protobuf.Struct' && request[field.name]) {
100
+ // Auto-convert JSON to Struct
101
+ request[field.name] = (0, struct_utils_1.jsonToStruct)(request[field.name]);
102
+ }
103
+ }
104
+ }
105
+ }
106
+ // Intercept callback to unwrap Response Structs
107
+ const originalCallback = typeof args[args.length - 1] === 'function'
108
+ ? args[args.length - 1]
109
+ : undefined;
110
+ if (originalCallback) {
111
+ args[args.length - 1] = (err, response) => {
112
+ if (response && typeof response === 'object') {
113
+ const responseType = methodDef.responseType;
114
+ if (responseType && responseType.format === 'Protocol Buffer 3 DescriptorProto') {
115
+ for (const field of responseType.type.field) {
116
+ if (field.typeName === 'google.protobuf.Struct' && response[field.name]) {
117
+ // Auto-convert Struct -> JSON
118
+ response[field.name] = (0, struct_utils_1.structToJson)(response[field.name]);
119
+ }
120
+ }
121
+ }
122
+ }
123
+ originalCallback(err, response);
124
+ };
125
+ }
126
+ return value.apply(target, args);
127
+ };
128
+ }
129
+ }
130
+ return value;
131
+ }
132
+ });
133
+ return wrapper;
71
134
  }
72
135
  }
73
136
  exports.GrpcClientFactory = GrpcClientFactory;
@@ -39,6 +39,7 @@ const grpc = __importStar(require("@grpc/grpc-js"));
39
39
  const protoLoader = __importStar(require("@grpc/proto-loader"));
40
40
  const path = __importStar(require("path"));
41
41
  const proto_generator_1 = require("../proto-generator");
42
+ const struct_utils_1 = require("./struct-utils");
42
43
  /**
43
44
  * GrpcServerFactory - Create and run gRPC servers easily
44
45
  *
@@ -123,7 +124,27 @@ class GrpcServerFactory {
123
124
  const methodName = handler.name.charAt(0).toLowerCase() + handler.name.slice(1);
124
125
  implementations[methodName] = async (call, callback) => {
125
126
  try {
126
- const result = await handler.handler(call.request);
127
+ let request = call.request;
128
+ // Introspect Request for Struct fields and unwrap to JSON
129
+ const methodDef = ServiceConstructor.service[handler.name];
130
+ if (methodDef && methodDef.requestType && methodDef.requestType.format === 'Protocol Buffer 3 DescriptorProto') {
131
+ for (const field of methodDef.requestType.type.field) {
132
+ if (field.typeName === 'google.protobuf.Struct' && request[field.name]) {
133
+ // Convert Struct -> JSON for the handler
134
+ request[field.name] = (0, struct_utils_1.structToJson)(request[field.name]);
135
+ }
136
+ }
137
+ }
138
+ const result = await handler.handler(request);
139
+ // Introspect Response for Struct fields and wrap JSON to Struct
140
+ if (result && typeof result === 'object' && methodDef && methodDef.responseType && methodDef.responseType.format === 'Protocol Buffer 3 DescriptorProto') {
141
+ for (const field of methodDef.responseType.type.field) {
142
+ if (field.typeName === 'google.protobuf.Struct' && result[field.name]) {
143
+ // Convert JSON -> Struct for the callback
144
+ result[field.name] = (0, struct_utils_1.jsonToStruct)(result[field.name]);
145
+ }
146
+ }
147
+ }
127
148
  callback(null, result);
128
149
  }
129
150
  catch (error) {
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Utilities for converting between JSON/JS Objects and google.protobuf.Struct
3
+ */
4
+ /**
5
+ * Convert a plain JS object/value to google.protobuf.Value
6
+ */
7
+ export declare function jsonToValue(val: any): any;
8
+ /**
9
+ * Convert a plain JS object to google.protobuf.Struct
10
+ */
11
+ export declare function jsonToStruct(json: any): any;
12
+ /**
13
+ * Convert google.protobuf.Value to JS value
14
+ */
15
+ export declare function valueToJson(val: any): any;
16
+ /**
17
+ * Convert google.protobuf.Struct to plain JS object
18
+ */
19
+ export declare function structToJson(struct: any): any;
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ /**
3
+ * Utilities for converting between JSON/JS Objects and google.protobuf.Struct
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.jsonToValue = jsonToValue;
7
+ exports.jsonToStruct = jsonToStruct;
8
+ exports.valueToJson = valueToJson;
9
+ exports.structToJson = structToJson;
10
+ /**
11
+ * Convert a plain JS object/value to google.protobuf.Value
12
+ */
13
+ function jsonToValue(val) {
14
+ if (val === null || val === undefined) {
15
+ return { nullValue: 0 };
16
+ }
17
+ if (typeof val === 'number') {
18
+ return { numberValue: val };
19
+ }
20
+ if (typeof val === 'string') {
21
+ return { stringValue: val };
22
+ }
23
+ if (typeof val === 'boolean') {
24
+ return { boolValue: val };
25
+ }
26
+ if (Array.isArray(val)) {
27
+ return { listValue: { values: val.map(jsonToValue) } };
28
+ }
29
+ if (typeof val === 'object') {
30
+ return { structValue: jsonToStruct(val) };
31
+ }
32
+ throw new Error(`Unsupported type for Struct conversion: ${typeof val}`);
33
+ }
34
+ /**
35
+ * Convert a plain JS object to google.protobuf.Struct
36
+ */
37
+ function jsonToStruct(json) {
38
+ const fields = {};
39
+ for (const k in json) {
40
+ if (Object.prototype.hasOwnProperty.call(json, k)) {
41
+ fields[k] = jsonToValue(json[k]);
42
+ }
43
+ }
44
+ return { fields };
45
+ }
46
+ /**
47
+ * Convert google.protobuf.Value to JS value
48
+ */
49
+ function valueToJson(val) {
50
+ if (!val)
51
+ return null;
52
+ if ('nullValue' in val)
53
+ return null;
54
+ if ('numberValue' in val)
55
+ return val.numberValue;
56
+ if ('stringValue' in val)
57
+ return val.stringValue;
58
+ if ('boolValue' in val)
59
+ return val.boolValue;
60
+ if ('listValue' in val) {
61
+ return (val.listValue.values || []).map(valueToJson);
62
+ }
63
+ if ('structValue' in val) {
64
+ return structToJson(val.structValue);
65
+ }
66
+ // Fallback if 'kind' oneof logic is different in some implementations,
67
+ // but usually keys are explicit.
68
+ return null;
69
+ }
70
+ /**
71
+ * Convert google.protobuf.Struct to plain JS object
72
+ */
73
+ function structToJson(struct) {
74
+ if (!struct || !struct.fields)
75
+ return {};
76
+ const json = {};
77
+ for (const k in struct.fields) {
78
+ json[k] = valueToJson(struct.fields[k]);
79
+ }
80
+ return json;
81
+ }
@@ -45,7 +45,7 @@ const path = __importStar(require("path"));
45
45
  * @example
46
46
  * requestSample: () => ({ id: '', data: AnyType })
47
47
  */
48
- exports.AnyType = Symbol('google.protobuf.Any');
48
+ exports.AnyType = Symbol('google.protobuf.Struct');
49
49
  /**
50
50
  * Generate a complete .proto file from method definitions
51
51
  *
@@ -83,8 +83,8 @@ function generateProtoFromMethods(methods, options = {}) {
83
83
  let rule = undefined;
84
84
  const valueType = typeof value;
85
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";
86
+ if (enableAnyType && (value === exports.AnyType || (typeof value === 'symbol' && value.description === 'google.protobuf.Any') || (typeof value === 'symbol' && value.description === 'google.protobuf.Struct'))) {
87
+ type = "google.protobuf.Struct";
88
88
  usesAnyType = true;
89
89
  }
90
90
  else if (value === null || value === undefined) {
@@ -155,9 +155,9 @@ function generateProtoFromMethods(methods, options = {}) {
155
155
  if (packageName) {
156
156
  lines.push(`package ${packageName};`, '');
157
157
  }
158
- // Add google.protobuf.Any import if needed
158
+ // Add google.protobuf.Struct import if needed
159
159
  if (usesAnyType) {
160
- lines.push('import "google/protobuf/any.proto";', '');
160
+ lines.push('import "google/protobuf/struct.proto";', '');
161
161
  }
162
162
  // Service definition
163
163
  lines.push(`// ${serviceName} - Auto-generated gRPC service`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@themainstack/communication",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
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",
@@ -1,6 +1,7 @@
1
1
  import * as grpc from '@grpc/grpc-js';
2
2
  import * as protoLoader from '@grpc/proto-loader';
3
3
  import { GrpcClientOptions } from './types';
4
+ import { jsonToStruct, structToJson } from './struct-utils';
4
5
 
5
6
  export class GrpcClientFactory {
6
7
  static createClient<T extends grpc.Client>(options: GrpcClientOptions): T {
@@ -39,10 +40,82 @@ export class GrpcClientFactory {
39
40
 
40
41
  const ServiceClient = serviceDef[options.serviceName];
41
42
 
42
- return new ServiceClient(
43
+ const client = new ServiceClient(
43
44
  options.url,
44
45
  options.credentials || grpc.credentials.createInsecure(),
45
46
  options.channelOptions
46
47
  ) as T;
48
+
49
+ // Wrap the client to intercept methods and handle Struct conversion automatically
50
+ const wrapper = new Proxy(client, {
51
+ get(target: any, prop: string | symbol) {
52
+ const value = target[prop];
53
+
54
+ // If accessing a method function, wrap it
55
+ if (typeof prop === 'string' && typeof value === 'function') {
56
+ // Find the method definition in the proto package definition
57
+ // packageDefinition uses flattened keys: 'package.Service.Method' or 'Service.Method' if in root
58
+ const methodKey = packageName
59
+ ? `${packageName}.${options.serviceName}`
60
+ : options.serviceName;
61
+
62
+ // We need to look up the method definition to get request type
63
+ // The loaded packageDefinition is a flat map of FQN -> type definition
64
+ // But we don't have easy link from method name to request FQN here without traversing.
65
+ // Fortunately, ServiceClient.service (available on constructor) has the method definitions!
66
+
67
+ const serviceDefinition = ServiceClient.service;
68
+ const methodDef = serviceDefinition[prop];
69
+
70
+ if (methodDef && !methodDef.requestStream && !methodDef.responseStream) {
71
+ return (...args: any[]) => {
72
+ const request = args[0];
73
+ if (request && typeof request === 'object') {
74
+ // Introspect and convert Struct fields
75
+ const requestType = methodDef.requestType; // This contains the type definition structure
76
+ if (requestType && requestType.format === 'Protocol Buffer 3 DescriptorProto') {
77
+ // With @grpc/grpc-js and proto-loader, type info is attached
78
+ // traverse fields to find google.protobuf.Struct
79
+ for (const field of requestType.type.field) {
80
+ if (field.typeName === 'google.protobuf.Struct' && request[field.name]) {
81
+ // Auto-convert JSON to Struct
82
+ request[field.name] = jsonToStruct(request[field.name]);
83
+ }
84
+ }
85
+ }
86
+ }
87
+
88
+ // Intercept callback to unwrap Response Structs
89
+ const originalCallback = typeof args[args.length - 1] === 'function'
90
+ ? args[args.length - 1]
91
+ : undefined;
92
+
93
+ if (originalCallback) {
94
+ args[args.length - 1] = (err: any, response: any) => {
95
+ if (response && typeof response === 'object') {
96
+ const responseType = methodDef.responseType;
97
+ if (responseType && responseType.format === 'Protocol Buffer 3 DescriptorProto') {
98
+ for (const field of responseType.type.field) {
99
+ if (field.typeName === 'google.protobuf.Struct' && response[field.name]) {
100
+ // Auto-convert Struct -> JSON
101
+ response[field.name] = structToJson(response[field.name]);
102
+ }
103
+ }
104
+ }
105
+ }
106
+ originalCallback(err, response);
107
+ };
108
+ }
109
+
110
+ return value.apply(target, args);
111
+ };
112
+ }
113
+ }
114
+
115
+ return value;
116
+ }
117
+ });
118
+
119
+ return wrapper as T;
47
120
  }
48
121
  }
@@ -3,6 +3,7 @@ import * as protoLoader from '@grpc/proto-loader';
3
3
  import * as path from 'path';
4
4
  import * as fs from 'fs';
5
5
  import { generateProtoFromMethods, MethodDefinition } from '../proto-generator';
6
+ import { jsonToStruct, structToJson } from './struct-utils';
6
7
 
7
8
  /**
8
9
  * Options for creating a gRPC server
@@ -148,7 +149,31 @@ export class GrpcServerFactory {
148
149
  callback: grpc.sendUnaryData<any>
149
150
  ) => {
150
151
  try {
151
- const result = await handler.handler(call.request);
152
+ let request = call.request;
153
+
154
+ // Introspect Request for Struct fields and unwrap to JSON
155
+ const methodDef = ServiceConstructor.service[handler.name];
156
+ if (methodDef && methodDef.requestType && methodDef.requestType.format === 'Protocol Buffer 3 DescriptorProto') {
157
+ for (const field of methodDef.requestType.type.field) {
158
+ if (field.typeName === 'google.protobuf.Struct' && request[field.name]) {
159
+ // Convert Struct -> JSON for the handler
160
+ request[field.name] = structToJson(request[field.name]);
161
+ }
162
+ }
163
+ }
164
+
165
+ const result = await handler.handler(request);
166
+
167
+ // Introspect Response for Struct fields and wrap JSON to Struct
168
+ if (result && typeof result === 'object' && methodDef && methodDef.responseType && methodDef.responseType.format === 'Protocol Buffer 3 DescriptorProto') {
169
+ for (const field of methodDef.responseType.type.field) {
170
+ if (field.typeName === 'google.protobuf.Struct' && result[field.name]) {
171
+ // Convert JSON -> Struct for the callback
172
+ result[field.name] = jsonToStruct(result[field.name]);
173
+ }
174
+ }
175
+ }
176
+
152
177
  callback(null, result);
153
178
  } catch (error: any) {
154
179
  console.error(`gRPC Error in ${handler.name}:`, error);
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Utilities for converting between JSON/JS Objects and google.protobuf.Struct
3
+ */
4
+
5
+ /**
6
+ * Convert a plain JS object/value to google.protobuf.Value
7
+ */
8
+ export function jsonToValue(val: any): any {
9
+ if (val === null || val === undefined) {
10
+ return { nullValue: 0 };
11
+ }
12
+ if (typeof val === 'number') {
13
+ return { numberValue: val };
14
+ }
15
+ if (typeof val === 'string') {
16
+ return { stringValue: val };
17
+ }
18
+ if (typeof val === 'boolean') {
19
+ return { boolValue: val };
20
+ }
21
+ if (Array.isArray(val)) {
22
+ return { listValue: { values: val.map(jsonToValue) } };
23
+ }
24
+ if (typeof val === 'object') {
25
+ return { structValue: jsonToStruct(val) };
26
+ }
27
+ throw new Error(`Unsupported type for Struct conversion: ${typeof val}`);
28
+ }
29
+
30
+ /**
31
+ * Convert a plain JS object to google.protobuf.Struct
32
+ */
33
+ export function jsonToStruct(json: any): any {
34
+ const fields: Record<string, any> = {};
35
+ for (const k in json) {
36
+ if (Object.prototype.hasOwnProperty.call(json, k)) {
37
+ fields[k] = jsonToValue(json[k]);
38
+ }
39
+ }
40
+ return { fields };
41
+ }
42
+
43
+ /**
44
+ * Convert google.protobuf.Value to JS value
45
+ */
46
+ export function valueToJson(val: any): any {
47
+ if (!val) return null;
48
+ if ('nullValue' in val) return null;
49
+ if ('numberValue' in val) return val.numberValue;
50
+ if ('stringValue' in val) return val.stringValue;
51
+ if ('boolValue' in val) return val.boolValue;
52
+ if ('listValue' in val) {
53
+ return (val.listValue.values || []).map(valueToJson);
54
+ }
55
+ if ('structValue' in val) {
56
+ return structToJson(val.structValue);
57
+ }
58
+ // Fallback if 'kind' oneof logic is different in some implementations,
59
+ // but usually keys are explicit.
60
+ return null;
61
+ }
62
+
63
+ /**
64
+ * Convert google.protobuf.Struct to plain JS object
65
+ */
66
+ export function structToJson(struct: any): any {
67
+ if (!struct || !struct.fields) return {};
68
+ const json: Record<string, any> = {};
69
+ for (const k in struct.fields) {
70
+ json[k] = valueToJson(struct.fields[k]);
71
+ }
72
+ return json;
73
+ }
@@ -8,12 +8,12 @@ import * as path from 'path';
8
8
  * @example
9
9
  * requestSample: () => ({ id: '', data: AnyType })
10
10
  */
11
- export const AnyType = Symbol('google.protobuf.Any');
11
+ export const AnyType = Symbol('google.protobuf.Struct');
12
12
 
13
13
  /**
14
14
  * Maps JavaScript/TypeScript runtime types to Protobuf types.
15
15
  */
16
- type ProtoType = "double" | "float" | "int32" | "int64" | "bool" | "string" | "bytes" | "google.protobuf.Any" | string;
16
+ type ProtoType = "double" | "float" | "int32" | "int64" | "bool" | "string" | "bytes" | "google.protobuf.Struct" | string;
17
17
 
18
18
  interface ProtoField {
19
19
  name: string;
@@ -109,8 +109,8 @@ export function generateProtoFromMethods(
109
109
  const valueType = typeof value;
110
110
 
111
111
  // Check for AnyType marker symbol
112
- if (enableAnyType && (value === AnyType || (typeof value === 'symbol' && value.description === 'google.protobuf.Any'))) {
113
- type = "google.protobuf.Any";
112
+ if (enableAnyType && (value === AnyType || (typeof value === 'symbol' && value.description === 'google.protobuf.Any') || (typeof value === 'symbol' && value.description === 'google.protobuf.Struct'))) {
113
+ type = "google.protobuf.Struct";
114
114
  usesAnyType = true;
115
115
  } else if (value === null || value === undefined) {
116
116
  type = "string";
@@ -183,9 +183,9 @@ export function generateProtoFromMethods(
183
183
  lines.push(`package ${packageName};`, '');
184
184
  }
185
185
 
186
- // Add google.protobuf.Any import if needed
186
+ // Add google.protobuf.Struct import if needed
187
187
  if (usesAnyType) {
188
- lines.push('import "google/protobuf/any.proto";', '');
188
+ lines.push('import "google/protobuf/struct.proto";', '');
189
189
  }
190
190
 
191
191
  // Service definition
@@ -1,14 +1,14 @@
1
1
  import { describe, it, expect } from 'vitest';
2
2
  import { generateProtoFromMethods, AnyType } from '../src/index';
3
3
 
4
- describe('google.protobuf.Any support', () => {
5
- it('should export AnyType symbol', () => {
4
+ describe('google.protobuf.Struct support', () => {
5
+ it('should export AnyType symbol aliased to Struct', () => {
6
6
  expect(AnyType).toBeDefined();
7
7
  expect(typeof AnyType).toBe('symbol');
8
- expect(AnyType.description).toBe('google.protobuf.Any');
8
+ expect(AnyType.description).toBe('google.protobuf.Struct');
9
9
  });
10
10
 
11
- it('should generate proto with google.protobuf.Any for marked fields', () => {
11
+ it('should generate proto with google.protobuf.Struct for marked fields', () => {
12
12
  const proto = generateProtoFromMethods([
13
13
  {
14
14
  name: 'ProcessGenericData',
@@ -27,14 +27,14 @@ describe('google.protobuf.Any support', () => {
27
27
  });
28
28
 
29
29
  // Should include the import statement
30
- expect(proto).toContain('import "google/protobuf/any.proto";');
30
+ expect(proto).toContain('import "google/protobuf/struct.proto";');
31
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;');
32
+ // Should use google.protobuf.Struct type
33
+ expect(proto).toContain('google.protobuf.Struct data = 2;');
34
+ expect(proto).toContain('google.protobuf.Struct result = 2;');
35
35
  });
36
36
 
37
- it('should not include import if no Any types are used', () => {
37
+ it('should not include import if no Struct types are used', () => {
38
38
  const proto = generateProtoFromMethods([
39
39
  {
40
40
  name: 'SimpleMethod',
@@ -46,11 +46,11 @@ describe('google.protobuf.Any support', () => {
46
46
  serviceName: 'SimpleService',
47
47
  });
48
48
 
49
- expect(proto).not.toContain('import "google/protobuf/any.proto";');
50
- expect(proto).not.toContain('google.protobuf.Any');
49
+ expect(proto).not.toContain('import "google/protobuf/struct.proto";');
50
+ expect(proto).not.toContain('google.protobuf.Struct');
51
51
  });
52
52
 
53
- it('should handle mixed fields with some Any types', () => {
53
+ it('should handle mixed fields with some Struct types', () => {
54
54
  const proto = generateProtoFromMethods([
55
55
  {
56
56
  name: 'MixedMethod',
@@ -70,10 +70,10 @@ describe('google.protobuf.Any support', () => {
70
70
  serviceName: 'MixedService',
71
71
  });
72
72
 
73
- expect(proto).toContain('import "google/protobuf/any.proto";');
73
+ expect(proto).toContain('import "google/protobuf/struct.proto";');
74
74
  expect(proto).toContain('string id = 1;');
75
75
  expect(proto).toContain('string name = 2;');
76
- expect(proto).toContain('google.protobuf.Any metadata = 3;');
76
+ expect(proto).toContain('google.protobuf.Struct metadata = 3;');
77
77
  expect(proto).toContain('int32 count = 4;');
78
78
  });
79
79
 
@@ -94,7 +94,7 @@ describe('google.protobuf.Any support', () => {
94
94
  });
95
95
 
96
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');
97
+ expect(proto).not.toContain('import "google/protobuf/struct.proto";');
98
+ expect(proto).not.toContain('google.protobuf.Struct');
99
99
  });
100
100
  });