@globalart/zod-to-proto 1.0.6 → 1.0.7
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 +189 -17
- package/package.json +12 -1
package/README.md
CHANGED
|
@@ -56,6 +56,52 @@ message Message {
|
|
|
56
56
|
|
|
57
57
|
### Generating gRPC Services
|
|
58
58
|
|
|
59
|
+
There are two ways to define gRPC services:
|
|
60
|
+
|
|
61
|
+
#### Option 1: Using Zod Schemas with Functions (Recommended)
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
import { zodToProtobuf } from "@globalart/zod-to-proto";
|
|
65
|
+
import { z } from "zod";
|
|
66
|
+
|
|
67
|
+
// Define request/response schemas
|
|
68
|
+
const getUserByIdRequestSchema = z.object({
|
|
69
|
+
id: z.number().int(),
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const userSchema = z.object({
|
|
73
|
+
id: z.number().int(),
|
|
74
|
+
name: z.string(),
|
|
75
|
+
email: z.string(),
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// Define service using z.function()
|
|
79
|
+
const userServiceSchema = z.object({
|
|
80
|
+
getUserById: z.function({
|
|
81
|
+
input: [getUserByIdRequestSchema],
|
|
82
|
+
output: userSchema,
|
|
83
|
+
}),
|
|
84
|
+
createUser: z.function({
|
|
85
|
+
input: [userSchema],
|
|
86
|
+
output: z.object({
|
|
87
|
+
id: z.number().int(),
|
|
88
|
+
success: z.boolean(),
|
|
89
|
+
}),
|
|
90
|
+
}),
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const protoDefinition = zodToProtobuf(z.object(), {
|
|
94
|
+
packageName: "user.service",
|
|
95
|
+
services: {
|
|
96
|
+
UserService: userServiceSchema,
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
console.log(protoDefinition);
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
#### Option 2: Using Service Definitions Array
|
|
104
|
+
|
|
59
105
|
```typescript
|
|
60
106
|
import { zodToProtobuf } from "@globalart/zod-to-proto";
|
|
61
107
|
import { z } from "zod";
|
|
@@ -97,36 +143,36 @@ const protoDefinition = zodToProtobuf(z.object(), {
|
|
|
97
143
|
console.log(protoDefinition);
|
|
98
144
|
```
|
|
99
145
|
|
|
100
|
-
|
|
146
|
+
Both approaches produce the same output:
|
|
101
147
|
|
|
102
148
|
```protobuf
|
|
103
149
|
syntax = "proto3";
|
|
104
150
|
package user.service;
|
|
105
151
|
|
|
106
|
-
message
|
|
107
|
-
|
|
152
|
+
message GetUserByIdRequest {
|
|
153
|
+
int32 id = 1;
|
|
108
154
|
}
|
|
109
155
|
|
|
110
|
-
message
|
|
111
|
-
|
|
112
|
-
|
|
156
|
+
message GetUserByIdResponse {
|
|
157
|
+
int32 id = 1;
|
|
158
|
+
string name = 2;
|
|
113
159
|
string email = 3;
|
|
114
160
|
}
|
|
115
161
|
|
|
116
162
|
message CreateUserRequest {
|
|
117
|
-
|
|
118
|
-
|
|
163
|
+
int32 id = 1;
|
|
164
|
+
string name = 2;
|
|
119
165
|
string email = 3;
|
|
120
166
|
}
|
|
121
167
|
|
|
122
168
|
message CreateUserResponse {
|
|
123
|
-
|
|
169
|
+
int32 id = 1;
|
|
124
170
|
bool success = 2;
|
|
125
171
|
}
|
|
126
172
|
|
|
127
173
|
service UserService {
|
|
128
|
-
rpc
|
|
129
|
-
rpc
|
|
174
|
+
rpc GetUserById(GetUserByIdRequest) returns (GetUserByIdResponse);
|
|
175
|
+
rpc CreateUser(CreateUserRequest) returns (CreateUserResponse);
|
|
130
176
|
}
|
|
131
177
|
```
|
|
132
178
|
|
|
@@ -145,16 +191,41 @@ Converts a Zod schema to a Protobuf definition.
|
|
|
145
191
|
|
|
146
192
|
```typescript
|
|
147
193
|
interface ZodToProtobufOptions {
|
|
148
|
-
packageName?: string;
|
|
149
|
-
rootMessageName?: string;
|
|
150
|
-
typePrefix?: string;
|
|
151
|
-
services?:
|
|
152
|
-
skipRootMessage?: boolean;
|
|
194
|
+
packageName?: string; // Protobuf package name (default: "default")
|
|
195
|
+
rootMessageName?: string; // Root message name (default: "Message")
|
|
196
|
+
typePrefix?: string; // Prefix for message and enum types
|
|
197
|
+
services?: ServicesInput; // gRPC service definitions
|
|
198
|
+
skipRootMessage?: boolean; // Skip root message generation
|
|
153
199
|
}
|
|
200
|
+
|
|
201
|
+
type ServicesInput = ServiceDefinition[] | Record<string, ZodObject<any>>;
|
|
154
202
|
```
|
|
155
203
|
|
|
156
204
|
#### Service Definition
|
|
157
205
|
|
|
206
|
+
You can define services in two ways:
|
|
207
|
+
|
|
208
|
+
**Option 1: Using Zod Schemas (Recommended)**
|
|
209
|
+
|
|
210
|
+
```typescript
|
|
211
|
+
const serviceSchema = z.object({
|
|
212
|
+
methodName: z.function({
|
|
213
|
+
input: [requestSchema],
|
|
214
|
+
output: responseSchema,
|
|
215
|
+
}),
|
|
216
|
+
// ... more methods
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
// Use in options
|
|
220
|
+
const proto = zodToProtobuf(z.object(), {
|
|
221
|
+
services: {
|
|
222
|
+
ServiceName: serviceSchema,
|
|
223
|
+
},
|
|
224
|
+
});
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
**Option 2: Using Service Definitions Array**
|
|
228
|
+
|
|
158
229
|
```typescript
|
|
159
230
|
interface ServiceDefinition {
|
|
160
231
|
name: string; // Service name
|
|
@@ -183,7 +254,7 @@ interface ServiceMethod {
|
|
|
183
254
|
|
|
184
255
|
- `z.array()` → `repeated`
|
|
185
256
|
- `z.set()` → `repeated`
|
|
186
|
-
- `z.map()` → `map<keyType, valueType>`
|
|
257
|
+
- `z.map()` → `map<keyType, valueType>` (key must be int32, int64, string, or bool)
|
|
187
258
|
- `z.tuple()` → nested message
|
|
188
259
|
|
|
189
260
|
### Complex Types
|
|
@@ -282,12 +353,113 @@ const protoDefinition = zodToProtobuf(schema, {
|
|
|
282
353
|
});
|
|
283
354
|
```
|
|
284
355
|
|
|
356
|
+
## Advanced Usage
|
|
357
|
+
|
|
358
|
+
### Working with Maps
|
|
359
|
+
|
|
360
|
+
Protobuf maps have strict key type requirements. Only integral types, strings, and booleans are allowed as keys:
|
|
361
|
+
|
|
362
|
+
```typescript
|
|
363
|
+
const schema = z.object({
|
|
364
|
+
// ✅ Valid map keys
|
|
365
|
+
usersByStringId: z.map(z.string(), userSchema),
|
|
366
|
+
usersByIntId: z.map(z.number().int(), userSchema),
|
|
367
|
+
flagsMap: z.map(z.boolean(), z.string()),
|
|
368
|
+
|
|
369
|
+
// ❌ Invalid - double is not allowed as map key
|
|
370
|
+
invalidMap: z.map(z.number(), userSchema), // Use .int() instead!
|
|
371
|
+
});
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
### Type-Safe Service Definitions
|
|
375
|
+
|
|
376
|
+
When using Zod schemas for services, you get full TypeScript type safety:
|
|
377
|
+
|
|
378
|
+
```typescript
|
|
379
|
+
const userServiceSchema = z.object({
|
|
380
|
+
getUser: z.function({
|
|
381
|
+
input: [z.object({ id: z.number().int() })],
|
|
382
|
+
output: userSchema,
|
|
383
|
+
}),
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
type UserService = z.infer<typeof userServiceSchema>;
|
|
387
|
+
|
|
388
|
+
// Implementation with type checking
|
|
389
|
+
class UserServiceImpl implements UserService {
|
|
390
|
+
async getUser({ id }: { id: number }) {
|
|
391
|
+
// TypeScript knows the shape of input and output
|
|
392
|
+
return { id, name: "John", email: "john@example.com" };
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
### Avoiding Circular Dependencies
|
|
398
|
+
|
|
399
|
+
**Important:** Avoid circular dependencies between schema files. Circular imports will cause types to become `undefined` during schema construction.
|
|
400
|
+
|
|
401
|
+
❌ **Bad Example:**
|
|
402
|
+
```typescript
|
|
403
|
+
// user.schema.ts
|
|
404
|
+
import { getUserByIdResponseSchema } from "./get-user-by-id.schema";
|
|
405
|
+
|
|
406
|
+
export const userSchema = z.object({ ... });
|
|
407
|
+
|
|
408
|
+
export const userServiceSchema = z.object({
|
|
409
|
+
getUserById: z.function({
|
|
410
|
+
input: [...],
|
|
411
|
+
output: getUserByIdResponseSchema, // ❌ Circular dependency
|
|
412
|
+
}),
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
// get-user-by-id.schema.ts
|
|
416
|
+
import { userSchema } from "./user.schema"; // ❌ Circular dependency
|
|
417
|
+
|
|
418
|
+
export const getUserByIdResponseSchema = userSchema;
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
✅ **Good Example:**
|
|
422
|
+
```typescript
|
|
423
|
+
// user.schema.ts
|
|
424
|
+
import { getUserByIdRequestSchema } from "./get-user-by-id.schema";
|
|
425
|
+
|
|
426
|
+
export const userSchema = z.object({ ... });
|
|
427
|
+
|
|
428
|
+
export const userServiceSchema = z.object({
|
|
429
|
+
getUserById: z.function({
|
|
430
|
+
input: [getUserByIdRequestSchema],
|
|
431
|
+
output: userSchema, // ✅ Direct reference, no circular dependency
|
|
432
|
+
}),
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
// get-user-by-id.schema.ts
|
|
436
|
+
export const getUserByIdRequestSchema = z.object({ id: z.number().int() });
|
|
437
|
+
// No import of userSchema needed
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
### Multiple Services
|
|
441
|
+
|
|
442
|
+
You can define multiple services in a single protobuf file:
|
|
443
|
+
|
|
444
|
+
```typescript
|
|
445
|
+
const protoDefinition = zodToProtobuf(z.object(), {
|
|
446
|
+
packageName: "api.v1",
|
|
447
|
+
services: {
|
|
448
|
+
UserService: userServiceSchema,
|
|
449
|
+
AuthService: authServiceSchema,
|
|
450
|
+
ProductService: productServiceSchema,
|
|
451
|
+
},
|
|
452
|
+
});
|
|
453
|
+
```
|
|
454
|
+
|
|
285
455
|
## Limitations
|
|
286
456
|
|
|
287
457
|
- Only the types listed above are supported
|
|
288
458
|
- Unsupported types will throw `UnsupportedTypeException`
|
|
289
459
|
- Nested objects are automatically converted to separate messages
|
|
290
460
|
- Enum values are converted to numbers starting from 0
|
|
461
|
+
- Map keys must be integral types (int32, int64, etc.), strings, or booleans - **not** doubles or floats
|
|
462
|
+
- Avoid circular dependencies between schema files
|
|
291
463
|
|
|
292
464
|
## License
|
|
293
465
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@globalart/zod-to-proto",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.7",
|
|
4
4
|
"author": {
|
|
5
5
|
"name": "GlobalArt, Inc"
|
|
6
6
|
},
|
|
@@ -26,6 +26,17 @@
|
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
},
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "git+https://github.com/GlobalArtInc/ecosystem.git#main"
|
|
32
|
+
},
|
|
33
|
+
"keywords": [
|
|
34
|
+
"zod",
|
|
35
|
+
"protobuf",
|
|
36
|
+
"grpc",
|
|
37
|
+
"protobuf-schema",
|
|
38
|
+
"protobuf-generator"
|
|
39
|
+
],
|
|
29
40
|
"scripts": {
|
|
30
41
|
"format": "prettier --write \"**/*.ts\"",
|
|
31
42
|
"test": "jest --runInBand --passWithNoTests",
|