@dr_nikson/effect-grpc 3.0.0-alpha.0 → 3.0.0-alpha.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.
- package/README.md +139 -204
- package/dist/protoRuntime.d.ts +3 -3
- package/dist/protoRuntime.d.ts.map +1 -1
- package/dist/protoRuntime.internal.d.ts +5 -5
- package/dist/protoRuntime.internal.d.ts.map +1 -1
- package/dist/protoRuntime.internal.js +5 -5
- package/dist/protoRuntime.internal.js.map +1 -1
- package/dist/protocGenPlugin.js +357 -145
- package/dist/protocGenPlugin.js.map +1 -1
- package/dist/server.d.ts +3 -3
- package/dist/server.d.ts.map +1 -1
- package/dist/server.internal.d.ts +4 -4
- package/dist/server.internal.d.ts.map +1 -1
- package/dist/server.internal.js +2 -2
- package/dist/server.internal.js.map +1 -1
- package/dist/server.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -110,14 +110,8 @@ import { NodeRuntime } from "@effect/platform-node";
|
|
|
110
110
|
import * as effectProto from "./generated/example/v1/hello_effect.js";
|
|
111
111
|
import * as proto from "./generated/example/v1/hello_pb.js";
|
|
112
112
|
|
|
113
|
-
//
|
|
114
|
-
const
|
|
115
|
-
"HandlerContext"
|
|
116
|
-
);
|
|
117
|
-
type HelloServiceTag = Context.Tag.Identifier<typeof HelloServiceTag>;
|
|
118
|
-
|
|
119
|
-
// Implement the service
|
|
120
|
-
const HelloServiceLive: effectProto.HelloService<HandlerContext> = {
|
|
113
|
+
// Implement the service (ctx not used, so no need to specify type)
|
|
114
|
+
const HelloServiceLive: effectProto.HelloServiceService = {
|
|
121
115
|
sayHello(request: proto.HelloRequest) {
|
|
122
116
|
return Effect.succeed({
|
|
123
117
|
message: `Hello, ${request.name}!`
|
|
@@ -126,21 +120,22 @@ const HelloServiceLive: effectProto.HelloService<HandlerContext> = {
|
|
|
126
120
|
};
|
|
127
121
|
|
|
128
122
|
// Create the service layer
|
|
129
|
-
const helloServiceLayer = effectProto.
|
|
130
|
-
HelloServiceTag
|
|
123
|
+
const helloServiceLayer = effectProto.helloServiceLiveLayer(
|
|
124
|
+
effectProto.HelloServiceTag,
|
|
125
|
+
HelloServiceLive
|
|
131
126
|
);
|
|
132
127
|
|
|
133
128
|
// Build and run the gRPC server
|
|
134
129
|
const program = Effect.gen(function* () {
|
|
135
|
-
const helloService = yield* HelloServiceTag;
|
|
130
|
+
const helloService = yield* effectProto.HelloServiceTag;
|
|
136
131
|
|
|
137
|
-
const server: EffectGrpcServer.GrpcServer<"HelloService"> =
|
|
132
|
+
const server: EffectGrpcServer.GrpcServer<"HelloService"> =
|
|
138
133
|
EffectGrpcServer
|
|
139
134
|
.GrpcServerBuilder()
|
|
140
135
|
.withService(helloService)
|
|
141
136
|
.build();
|
|
142
137
|
|
|
143
|
-
return yield* server.run();
|
|
138
|
+
return yield* server.run({ host: "localhost", port: 8000 });
|
|
144
139
|
});
|
|
145
140
|
|
|
146
141
|
// Provide dependencies and run
|
|
@@ -162,19 +157,15 @@ import { NodeRuntime } from "@effect/platform-node";
|
|
|
162
157
|
|
|
163
158
|
import * as effectProto from "./generated/example/v1/hello_effect.js";
|
|
164
159
|
|
|
165
|
-
// Create a client tag
|
|
166
|
-
const HelloServiceClientTag = effectProto.HelloServiceClient.makeTag<object>("{}");
|
|
167
|
-
type HelloServiceClientTag = typeof HelloServiceClientTag;
|
|
168
|
-
|
|
169
160
|
// Create the client layer with configuration
|
|
170
|
-
const helloClientLayer = effectProto.
|
|
171
|
-
HelloServiceClientTag
|
|
161
|
+
const helloClientLayer = effectProto.helloServiceClientLiveLayer(
|
|
162
|
+
effectProto.HelloServiceClientTag
|
|
172
163
|
).pipe(
|
|
173
164
|
Layer.provideMerge(
|
|
174
165
|
Layer.succeed(
|
|
175
166
|
effectProto.HelloServiceConfigTag,
|
|
176
167
|
EffectGrpcClient.GrpcClientConfig({
|
|
177
|
-
baseUrl: "http://localhost:8000"
|
|
168
|
+
baseUrl: new URL("http://localhost:8000")
|
|
178
169
|
})
|
|
179
170
|
)
|
|
180
171
|
)
|
|
@@ -182,7 +173,7 @@ const helloClientLayer = effectProto.HelloServiceClient.liveLayer(
|
|
|
182
173
|
|
|
183
174
|
// Use the client
|
|
184
175
|
const program = Effect.gen(function* () {
|
|
185
|
-
const client = yield* HelloServiceClientTag;
|
|
176
|
+
const client = yield* effectProto.HelloServiceClientTag;
|
|
186
177
|
|
|
187
178
|
const response = yield* client.sayHello({
|
|
188
179
|
name: "World"
|
|
@@ -249,7 +240,7 @@ Represents a running gRPC server instance.
|
|
|
249
240
|
- `Services` - Union type of all service tags registered with this server
|
|
250
241
|
|
|
251
242
|
**Methods:**
|
|
252
|
-
- `run(): Effect.Effect<never, never, Scope.Scope>` - Starts the server and
|
|
243
|
+
- `run(options: { host: string; port: number }): Effect.Effect<never, never, Scope.Scope>` - Starts the server on the specified host and port. Returns an Effect that requires a Scope for resource management.
|
|
253
244
|
|
|
254
245
|
**Example:**
|
|
255
246
|
```typescript
|
|
@@ -260,7 +251,9 @@ const server: EffectGrpcServer.GrpcServer<"UserService" | "ProductService"> =
|
|
|
260
251
|
.build();
|
|
261
252
|
|
|
262
253
|
// Run with proper resource management
|
|
263
|
-
const program = Effect.scoped(
|
|
254
|
+
const program = Effect.scoped(
|
|
255
|
+
server.run({ host: "localhost", port: 8000 })
|
|
256
|
+
);
|
|
264
257
|
```
|
|
265
258
|
|
|
266
259
|
##### `GrpcServerBuilder<Ctx, Services>`
|
|
@@ -272,7 +265,7 @@ Fluent builder interface for constructing gRPC servers.
|
|
|
272
265
|
- `Services` - Union of currently registered service tags
|
|
273
266
|
|
|
274
267
|
**Methods:**
|
|
275
|
-
- `withContextTransformer<Ctx1>(f: (ctx: Ctx) => Effect.Effect<Ctx1>): GrpcServerBuilder<Ctx1, never>` - Transform the handler context (
|
|
268
|
+
- `withContextTransformer<Ctx1>(f: (originalCtx: HandlerContext, ctx: Ctx) => Effect.Effect<Ctx1>): GrpcServerBuilder<Ctx1, never>` - Transform the handler context. The first parameter is the original Connect-RPC HandlerContext, the second is the current context (defaults to `any`). Must be called before adding services.
|
|
276
269
|
- `withService<S>(service: S): GrpcServerBuilder<Ctx, Services | Tag<S>>` - Add a service (enforces unique tags)
|
|
277
270
|
- `build(): GrpcServer<Services>` - Build the server (requires at least one service)
|
|
278
271
|
|
|
@@ -290,81 +283,36 @@ interface AppContext {
|
|
|
290
283
|
}
|
|
291
284
|
|
|
292
285
|
const serverWithCtx = EffectGrpcServer.GrpcServerBuilder()
|
|
286
|
+
// Ctx is any here, so it is okay to omit second param
|
|
293
287
|
.withContextTransformer((handlerCtx: HandlerContext) =>
|
|
294
288
|
Effect.succeed({
|
|
295
|
-
userId: handlerCtx.requestHeader.get("user-id") ?? "anonymous",
|
|
296
289
|
requestId: crypto.randomUUID()
|
|
297
290
|
})
|
|
298
291
|
)
|
|
292
|
+
// Ctx has `requestId` field now, originalCtx is also available
|
|
293
|
+
.withContextTransformer((handlerCtx: HandlerContext, ctx) =>
|
|
294
|
+
Effect.succeed({
|
|
295
|
+
requestId: ctx.requestId,
|
|
296
|
+
userId: handlerCtx.requestHeader.get("user-id") ?? "anonymous",
|
|
297
|
+
})
|
|
298
|
+
)
|
|
299
299
|
.withService(myService)
|
|
300
300
|
.build();
|
|
301
301
|
```
|
|
302
302
|
|
|
303
|
-
##### `GrpcService<Tag, Proto, Ctx>`
|
|
304
|
-
|
|
305
|
-
Represents a gRPC service implementation bound to a specific Protocol Buffer definition.
|
|
306
|
-
|
|
307
|
-
**Type Parameters:**
|
|
308
|
-
- `Tag` - Unique identifier for this service (typically the fully-qualified protobuf name)
|
|
309
|
-
- `Proto` - The Protocol Buffer service definition from generated code
|
|
310
|
-
- `Ctx` - Context type available to service method handlers
|
|
311
|
-
|
|
312
|
-
**Note:** Instances are typically created by the `protoc-gen-effect` code generator.
|
|
313
|
-
|
|
314
|
-
**Example:**
|
|
315
|
-
```typescript
|
|
316
|
-
// Generated by protoc-gen-effect
|
|
317
|
-
const userService: EffectGrpcServer.GrpcService<
|
|
318
|
-
"com.example.UserService",
|
|
319
|
-
typeof UserServiceProto,
|
|
320
|
-
HandlerContext
|
|
321
|
-
> = EffectGrpcServer.GrpcService("com.example.UserService", UserServiceProto)(
|
|
322
|
-
(exec) => ({
|
|
323
|
-
getUser: (req, ctx) => exec.unary(req, ctx, (req, ctx) =>
|
|
324
|
-
Effect.succeed({ user: { id: req.userId, name: "John" } })
|
|
325
|
-
)
|
|
326
|
-
})
|
|
327
|
-
);
|
|
328
|
-
```
|
|
329
|
-
|
|
330
303
|
#### Factory Functions
|
|
331
304
|
|
|
332
305
|
##### `GrpcServerBuilder()`
|
|
333
306
|
|
|
334
|
-
Creates a new server builder instance with default
|
|
307
|
+
Creates a new server builder instance with default context.
|
|
335
308
|
|
|
336
|
-
**Returns:** `GrpcServerBuilder<
|
|
309
|
+
**Returns:** `GrpcServerBuilder<any, never>`
|
|
337
310
|
|
|
338
311
|
**Example:**
|
|
339
312
|
```typescript
|
|
340
313
|
const builder = EffectGrpcServer.GrpcServerBuilder();
|
|
341
314
|
```
|
|
342
315
|
|
|
343
|
-
##### `GrpcService(tag, definition)`
|
|
344
|
-
|
|
345
|
-
Creates a GrpcService factory (typically used by code generators).
|
|
346
|
-
|
|
347
|
-
**Parameters:**
|
|
348
|
-
- `tag` - Unique service identifier
|
|
349
|
-
- `definition` - Protocol Buffer service definition
|
|
350
|
-
|
|
351
|
-
**Returns:** Function that accepts implementation and returns `GrpcService`
|
|
352
|
-
|
|
353
|
-
**Example:**
|
|
354
|
-
```typescript
|
|
355
|
-
// This is typically generated, not written manually
|
|
356
|
-
const createService = EffectGrpcServer.GrpcService(
|
|
357
|
-
"com.example.MyService",
|
|
358
|
-
MyServiceProto
|
|
359
|
-
);
|
|
360
|
-
|
|
361
|
-
const service = createService<HandlerContext>((exec) => ({
|
|
362
|
-
myMethod: (req, ctx) => exec.unary(req, ctx, (req, ctx) =>
|
|
363
|
-
Effect.succeed({ result: "success" })
|
|
364
|
-
)
|
|
365
|
-
}));
|
|
366
|
-
```
|
|
367
|
-
|
|
368
316
|
---
|
|
369
317
|
|
|
370
318
|
### Client API (`EffectGrpcClient`)
|
|
@@ -373,31 +321,6 @@ The client API provides tools for making gRPC calls from Effect programs.
|
|
|
373
321
|
|
|
374
322
|
#### Core Types
|
|
375
323
|
|
|
376
|
-
##### `GrpcClientRuntime`
|
|
377
|
-
|
|
378
|
-
The runtime service that creates executors for invoking gRPC methods.
|
|
379
|
-
|
|
380
|
-
**Methods:**
|
|
381
|
-
- `makeExecutor<Shape>(serviceDefinition, methodNames, config): Effect.Effect<ClientExecutor<Shape>>` - Creates an executor for specified service methods
|
|
382
|
-
|
|
383
|
-
**Note:** This is primarily used by generated client code, not called directly by users.
|
|
384
|
-
|
|
385
|
-
**Example:**
|
|
386
|
-
```typescript
|
|
387
|
-
const program = Effect.gen(function* () {
|
|
388
|
-
const runtime = yield* EffectGrpcClient.GrpcClientRuntime;
|
|
389
|
-
const config = yield* MyServiceConfigTag;
|
|
390
|
-
|
|
391
|
-
const executor = yield* runtime.makeExecutor(
|
|
392
|
-
MyServiceProto,
|
|
393
|
-
["getUser", "listUsers"],
|
|
394
|
-
config
|
|
395
|
-
);
|
|
396
|
-
|
|
397
|
-
return executor;
|
|
398
|
-
});
|
|
399
|
-
```
|
|
400
|
-
|
|
401
324
|
##### `GrpcClientConfig<Service>`
|
|
402
325
|
|
|
403
326
|
Configuration for connecting to a gRPC service.
|
|
@@ -406,7 +329,7 @@ Configuration for connecting to a gRPC service.
|
|
|
406
329
|
- `Service` - The fully-qualified service name (e.g., "com.example.v1.UserService")
|
|
407
330
|
|
|
408
331
|
**Properties:**
|
|
409
|
-
- `baseUrl:
|
|
332
|
+
- `baseUrl: URL` - Base URL for gRPC requests (e.g., `new URL("http://localhost:8000")`)
|
|
410
333
|
- `binaryOptions?: Partial<BinaryReadOptions & BinaryWriteOptions>` - Protocol Buffer binary format options
|
|
411
334
|
- `acceptCompression?: Compression[]` - Accepted response compression algorithms (defaults to ["gzip", "br"])
|
|
412
335
|
- `sendCompression?: Compression` - Compression algorithm for request messages
|
|
@@ -416,7 +339,7 @@ Configuration for connecting to a gRPC service.
|
|
|
416
339
|
**Example:**
|
|
417
340
|
```typescript
|
|
418
341
|
const config = EffectGrpcClient.GrpcClientConfig({
|
|
419
|
-
baseUrl: "https://api.example.com",
|
|
342
|
+
baseUrl: new URL("https://api.example.com"),
|
|
420
343
|
defaultTimeoutMs: 5000,
|
|
421
344
|
acceptCompression: ["gzip", "br"],
|
|
422
345
|
sendCompression: "gzip",
|
|
@@ -456,20 +379,6 @@ const meta: EffectGrpcClient.RequestMeta = {
|
|
|
456
379
|
const response = yield* client.getUser({ userId: "123" }, meta);
|
|
457
380
|
```
|
|
458
381
|
|
|
459
|
-
#### Context Tags
|
|
460
|
-
|
|
461
|
-
##### `GrpcClientRuntime`
|
|
462
|
-
|
|
463
|
-
Tag for accessing the gRPC client runtime service.
|
|
464
|
-
|
|
465
|
-
**Usage:**
|
|
466
|
-
```typescript
|
|
467
|
-
const program = Effect.gen(function* () {
|
|
468
|
-
const runtime = yield* EffectGrpcClient.GrpcClientRuntime;
|
|
469
|
-
// runtime is now available
|
|
470
|
-
});
|
|
471
|
-
```
|
|
472
|
-
|
|
473
382
|
#### Factory Functions
|
|
474
383
|
|
|
475
384
|
##### `liveGrpcClientRuntimeLayer()`
|
|
@@ -497,7 +406,7 @@ Creates a client configuration object.
|
|
|
497
406
|
**Example:**
|
|
498
407
|
```typescript
|
|
499
408
|
const config = EffectGrpcClient.GrpcClientConfig({
|
|
500
|
-
baseUrl: "http://localhost:8000",
|
|
409
|
+
baseUrl: new URL("http://localhost:8000"),
|
|
501
410
|
defaultTimeoutMs: 5000
|
|
502
411
|
});
|
|
503
412
|
```
|
|
@@ -528,14 +437,14 @@ The `protoc-gen-effect` plugin generates TypeScript code from `.proto` files wit
|
|
|
528
437
|
|
|
529
438
|
For each service in your `.proto` file, the generator creates:
|
|
530
439
|
|
|
531
|
-
##### `{ServiceName}
|
|
440
|
+
##### `{ServiceName}ProtoId`
|
|
532
441
|
|
|
533
442
|
Constant and type for the service identifier.
|
|
534
443
|
|
|
535
444
|
**Example:**
|
|
536
445
|
```typescript
|
|
537
|
-
export const
|
|
538
|
-
export type
|
|
446
|
+
export const UserServiceProtoId = "com.example.v1.UserService" as const;
|
|
447
|
+
export type UserServiceProtoId = typeof UserServiceProtoId;
|
|
539
448
|
```
|
|
540
449
|
|
|
541
450
|
##### `{ServiceName}Service<Ctx>`
|
|
@@ -547,45 +456,54 @@ Interface defining the service implementation contract.
|
|
|
547
456
|
|
|
548
457
|
**Example:**
|
|
549
458
|
```typescript
|
|
550
|
-
export interface
|
|
459
|
+
export interface UserServiceService<Ctx = any> {
|
|
551
460
|
getUser(
|
|
552
461
|
request: GetUserRequest,
|
|
553
462
|
ctx: Ctx
|
|
554
|
-
): Effect.Effect<MessageInitShape<typeof GetUserResponseSchema
|
|
463
|
+
): Effect.Effect<MessageInitShape<typeof GetUserResponseSchema>, GrpcException>;
|
|
555
464
|
|
|
556
465
|
listUsers(
|
|
557
466
|
request: ListUsersRequest,
|
|
558
467
|
ctx: Ctx
|
|
559
|
-
): Effect.Effect<MessageInitShape<typeof ListUsersResponseSchema
|
|
468
|
+
): Effect.Effect<MessageInitShape<typeof ListUsersResponseSchema>, GrpcException>;
|
|
560
469
|
}
|
|
561
470
|
```
|
|
562
471
|
|
|
563
|
-
##### `{ServiceName}
|
|
472
|
+
##### `{ServiceName}ServiceTag`
|
|
564
473
|
|
|
565
|
-
|
|
474
|
+
Context tag for the service. Can be used as-is (default context) or called as a function to create a typed tag.
|
|
566
475
|
|
|
567
|
-
**
|
|
568
|
-
|
|
476
|
+
**Usage:**
|
|
477
|
+
```typescript
|
|
478
|
+
// Use default tag directly (when not using ctx parameter in implementation)
|
|
479
|
+
effectProto.UserServiceTag
|
|
569
480
|
|
|
570
|
-
|
|
481
|
+
// Create typed tag when you need to access ctx parameter
|
|
482
|
+
interface AppContext {
|
|
483
|
+
userId: string;
|
|
484
|
+
requestId: string;
|
|
485
|
+
}
|
|
486
|
+
const UserServiceAppCtxTag = effectProto.UserServiceTag<AppContext>("AppContext");
|
|
571
487
|
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
const
|
|
488
|
+
// With HandlerContext when you need access to request headers
|
|
489
|
+
import { HandlerContext } from "@connectrpc/connect";
|
|
490
|
+
const UserServiceHandlerCtxTag = effectProto.UserServiceTag<HandlerContext>("HandlerContext");
|
|
575
491
|
```
|
|
576
492
|
|
|
577
|
-
##### `{
|
|
493
|
+
##### `{serviceName}ServiceLiveLayer(tag, service)`
|
|
578
494
|
|
|
579
|
-
|
|
495
|
+
Function that creates a layer from a service implementation.
|
|
580
496
|
|
|
581
497
|
**Parameters:**
|
|
582
|
-
- `
|
|
498
|
+
- `tag` - Context tag for the service
|
|
499
|
+
- `service` - Implementation of the service interface
|
|
583
500
|
|
|
584
|
-
**Returns:**
|
|
501
|
+
**Returns:** `Layer` providing the gRPC service
|
|
585
502
|
|
|
586
503
|
**Example:**
|
|
587
504
|
```typescript
|
|
588
|
-
|
|
505
|
+
// If not using ctx, use default type and tag
|
|
506
|
+
const UserServiceLive: UserServiceService = {
|
|
589
507
|
getUser(request) {
|
|
590
508
|
return Effect.succeed({ user: { id: request.userId, name: "John" } });
|
|
591
509
|
},
|
|
@@ -594,17 +512,30 @@ const UserServiceLive: UserService<HandlerContext> = {
|
|
|
594
512
|
}
|
|
595
513
|
};
|
|
596
514
|
|
|
597
|
-
const
|
|
598
|
-
|
|
599
|
-
|
|
515
|
+
const userServiceLayer = userServiceLiveLayer(
|
|
516
|
+
effectProto.UserServiceTag,
|
|
517
|
+
UserServiceLive
|
|
518
|
+
);
|
|
600
519
|
|
|
601
|
-
|
|
520
|
+
// When you need to access ctx (e.g., HandlerContext for request headers)
|
|
521
|
+
import { HandlerContext } from "@connectrpc/connect";
|
|
602
522
|
|
|
603
|
-
|
|
523
|
+
const UserServiceWithCtx: UserServiceService<HandlerContext> = {
|
|
524
|
+
getUser(request, ctx) {
|
|
525
|
+
const authToken = ctx.requestHeader.get("authorization");
|
|
526
|
+
// ... use authToken in your logic
|
|
527
|
+
return Effect.succeed({ user: { id: request.userId, name: "John" } });
|
|
528
|
+
},
|
|
529
|
+
listUsers(request, ctx) {
|
|
530
|
+
return Effect.succeed({ users: [] });
|
|
531
|
+
}
|
|
532
|
+
};
|
|
604
533
|
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
534
|
+
const UserServiceHandlerCtxTag = effectProto.UserServiceTag<HandlerContext>("HandlerContext");
|
|
535
|
+
const userServiceLayerWithCtx = userServiceLiveLayer(
|
|
536
|
+
UserServiceHandlerCtxTag,
|
|
537
|
+
UserServiceWithCtx
|
|
538
|
+
);
|
|
608
539
|
```
|
|
609
540
|
|
|
610
541
|
#### Client Implementation
|
|
@@ -633,35 +564,37 @@ export interface UserServiceClient<Meta> {
|
|
|
633
564
|
}
|
|
634
565
|
```
|
|
635
566
|
|
|
636
|
-
##### `{ServiceName}
|
|
637
|
-
|
|
638
|
-
Creates a Context tag for the client.
|
|
639
|
-
|
|
640
|
-
**Parameters:**
|
|
641
|
-
- `metaKey` - String identifier for the metadata type
|
|
567
|
+
##### `{ServiceName}ClientTag`
|
|
642
568
|
|
|
643
|
-
|
|
569
|
+
Context tag for the client. Can be used as-is (default metadata) or called as a function to create a typed tag.
|
|
644
570
|
|
|
645
|
-
**
|
|
571
|
+
**Usage:**
|
|
646
572
|
```typescript
|
|
647
|
-
|
|
573
|
+
// Use default tag directly (any metadata)
|
|
574
|
+
effectProto.UserServiceClientTag
|
|
575
|
+
|
|
576
|
+
// Create typed tag with custom metadata
|
|
577
|
+
interface AuthMeta {
|
|
578
|
+
authToken: string;
|
|
579
|
+
}
|
|
580
|
+
const UserServiceAuthClientTag = effectProto.UserServiceClientTag<AuthMeta>("AuthMeta");
|
|
648
581
|
```
|
|
649
582
|
|
|
650
|
-
##### `{
|
|
583
|
+
##### `{serviceName}ClientLiveLayer(tag)` / `{serviceName}ClientLiveLayer(transformMeta, tag)`
|
|
651
584
|
|
|
652
|
-
|
|
585
|
+
Function that creates a client layer (two overloads).
|
|
653
586
|
|
|
654
587
|
**Overload 1: With metadata transformation**
|
|
655
588
|
```typescript
|
|
656
|
-
|
|
589
|
+
{serviceName}ClientLiveLayer<Tag extends {ServiceName}ClientTag<Meta>, Meta>(
|
|
657
590
|
transformMeta: (meta: Meta) => EffectGrpcClient.RequestMeta,
|
|
658
591
|
tag: Tag
|
|
659
592
|
): Layer.Layer<...>
|
|
660
593
|
```
|
|
661
594
|
|
|
662
|
-
**Overload 2: Default metadata
|
|
595
|
+
**Overload 2: Default metadata**
|
|
663
596
|
```typescript
|
|
664
|
-
|
|
597
|
+
{serviceName}ClientLiveLayer<Tag extends {ServiceName}ClientTag>(
|
|
665
598
|
tag: Tag
|
|
666
599
|
): Layer.Layer<...>
|
|
667
600
|
```
|
|
@@ -669,27 +602,28 @@ liveLayer<Tag extends {ServiceName}ClientTag<object>>(
|
|
|
669
602
|
**Example:**
|
|
670
603
|
```typescript
|
|
671
604
|
// With custom metadata transformation
|
|
672
|
-
interface
|
|
605
|
+
interface AuthMeta {
|
|
673
606
|
authToken: string;
|
|
674
607
|
}
|
|
675
608
|
|
|
676
|
-
const
|
|
677
|
-
|
|
609
|
+
const UserServiceAuthClientTag = effectProto.UserServiceClientTag<AuthMeta>("AuthMeta");
|
|
610
|
+
const userServiceAuthClientLayer = effectProto.userServiceClientLiveLayer(
|
|
611
|
+
(meta: AuthMeta) => ({
|
|
678
612
|
headers: new Headers({ "Authorization": `Bearer ${meta.authToken}` })
|
|
679
613
|
}),
|
|
680
|
-
|
|
614
|
+
UserServiceAuthClientTag
|
|
681
615
|
).pipe(
|
|
682
616
|
Layer.provideMerge(
|
|
683
|
-
Layer.succeed(UserServiceConfigTag, config)
|
|
617
|
+
Layer.succeed(effectProto.UserServiceConfigTag, config)
|
|
684
618
|
)
|
|
685
619
|
);
|
|
686
620
|
|
|
687
|
-
// With default
|
|
688
|
-
const
|
|
689
|
-
UserServiceClientTag
|
|
621
|
+
// With default metadata
|
|
622
|
+
const userServiceClientLayer = effectProto.userServiceClientLiveLayer(
|
|
623
|
+
effectProto.UserServiceClientTag
|
|
690
624
|
).pipe(
|
|
691
625
|
Layer.provideMerge(
|
|
692
|
-
Layer.succeed(UserServiceConfigTag, config)
|
|
626
|
+
Layer.succeed(effectProto.UserServiceConfigTag, config)
|
|
693
627
|
)
|
|
694
628
|
);
|
|
695
629
|
```
|
|
@@ -700,13 +634,13 @@ Pre-created config tag for the service.
|
|
|
700
634
|
|
|
701
635
|
**Example:**
|
|
702
636
|
```typescript
|
|
703
|
-
export const UserServiceConfigTag
|
|
704
|
-
EffectGrpcClient.GrpcClientConfig.makeTag(
|
|
637
|
+
export const UserServiceConfigTag =
|
|
638
|
+
EffectGrpcClient.GrpcClientConfig.makeTag(UserServiceProtoId);
|
|
705
639
|
|
|
706
640
|
// Use it to provide configuration
|
|
707
641
|
const configLayer = Layer.succeed(
|
|
708
642
|
UserServiceConfigTag,
|
|
709
|
-
EffectGrpcClient.GrpcClientConfig({ baseUrl: "http://localhost:8000" })
|
|
643
|
+
EffectGrpcClient.GrpcClientConfig({ baseUrl: new URL("http://localhost:8000") })
|
|
710
644
|
);
|
|
711
645
|
```
|
|
712
646
|
|
|
@@ -718,15 +652,14 @@ effect-grpc provides `GrpcException`, a typed error that extends Effect's `Data.
|
|
|
718
652
|
|
|
719
653
|
```typescript
|
|
720
654
|
import { Effect } from "effect";
|
|
721
|
-
import { HandlerContext } from "@connectrpc/connect";
|
|
722
655
|
import { GrpcException } from "@dr_nikson/effect-grpc";
|
|
723
656
|
import { Code } from "@connectrpc/connect";
|
|
724
657
|
|
|
725
658
|
import * as effectProto from "./generated/example/v1/user_effect.js";
|
|
726
659
|
import * as proto from "./generated/example/v1/user_pb.js";
|
|
727
660
|
|
|
728
|
-
// Implement the service with error handling
|
|
729
|
-
const UserServiceLive: effectProto.
|
|
661
|
+
// Implement the service with error handling (ctx not used, so use default)
|
|
662
|
+
const UserServiceLive: effectProto.UserServiceService = {
|
|
730
663
|
getUser(request: proto.GetUserRequest) {
|
|
731
664
|
return Effect.gen(function* () {
|
|
732
665
|
// Input validation with gRPC status codes
|
|
@@ -767,9 +700,14 @@ Leverage Effect's powerful dependency injection to compose your services with ex
|
|
|
767
700
|
|
|
768
701
|
```typescript
|
|
769
702
|
import { Context, Effect, Layer } from "effect";
|
|
770
|
-
import {
|
|
703
|
+
import { EffectGrpcServer } from "@dr_nikson/effect-grpc";
|
|
771
704
|
import * as effectProto from "./generated/user_effect.js";
|
|
772
705
|
|
|
706
|
+
interface User {
|
|
707
|
+
id: string;
|
|
708
|
+
name: string;
|
|
709
|
+
}
|
|
710
|
+
|
|
773
711
|
// Define a database service tag
|
|
774
712
|
class DatabaseService extends Context.Tag("DatabaseService")<
|
|
775
713
|
DatabaseService,
|
|
@@ -779,34 +717,31 @@ class DatabaseService extends Context.Tag("DatabaseService")<
|
|
|
779
717
|
}
|
|
780
718
|
>() {}
|
|
781
719
|
|
|
782
|
-
//
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
return Effect.gen(function* () {
|
|
786
|
-
// Access the database service from context
|
|
787
|
-
const db = yield* DatabaseService;
|
|
788
|
-
|
|
789
|
-
// Use it in your business logic
|
|
790
|
-
const user = yield* db.getUser(request.userId);
|
|
791
|
-
|
|
792
|
-
return { user };
|
|
793
|
-
});
|
|
794
|
-
},
|
|
795
|
-
|
|
796
|
-
updateUser(request) {
|
|
797
|
-
return Effect.gen(function* () {
|
|
798
|
-
const db = yield* DatabaseService;
|
|
720
|
+
// Service implementation class with constructor
|
|
721
|
+
class UserServiceLive implements effectProto.UserServiceService {
|
|
722
|
+
constructor(private readonly db: Context.Tag.Service<typeof DatabaseService>) {}
|
|
799
723
|
|
|
800
|
-
|
|
724
|
+
getUser(request: effectProto.GetUserRequest) {
|
|
725
|
+
return this.db.getUser(request.userId).pipe(
|
|
726
|
+
Effect.map(user => ({ user }))
|
|
727
|
+
);
|
|
728
|
+
}
|
|
801
729
|
|
|
802
|
-
|
|
803
|
-
|
|
730
|
+
updateUser(request: effectProto.UpdateUserRequest) {
|
|
731
|
+
return this.db.saveUser(request.user).pipe(
|
|
732
|
+
Effect.map(() => ({ success: true }))
|
|
733
|
+
);
|
|
804
734
|
}
|
|
805
|
-
}
|
|
735
|
+
}
|
|
806
736
|
|
|
807
|
-
//
|
|
808
|
-
const
|
|
809
|
-
|
|
737
|
+
// Wire dependencies through constructor
|
|
738
|
+
const userServiceLayer = Layer.unwrapEffect(
|
|
739
|
+
Effect.gen(function* () {
|
|
740
|
+
const db = yield* DatabaseService;
|
|
741
|
+
const serviceImpl = new UserServiceLive(db);
|
|
742
|
+
return effectProto.userServiceLiveLayer(effectProto.UserServiceTag, serviceImpl);
|
|
743
|
+
})
|
|
744
|
+
);
|
|
810
745
|
|
|
811
746
|
// Create a mock database layer for testing
|
|
812
747
|
const mockDatabaseLayer = Layer.succeed(DatabaseService, {
|
|
@@ -822,13 +757,13 @@ const appLayer = Layer.empty.pipe(
|
|
|
822
757
|
|
|
823
758
|
// Build and run your server with all dependencies
|
|
824
759
|
const program = Effect.gen(function* () {
|
|
825
|
-
const userService = yield* UserServiceTag;
|
|
760
|
+
const userService = yield* effectProto.UserServiceTag;
|
|
826
761
|
|
|
827
762
|
const server = EffectGrpcServer.GrpcServerBuilder()
|
|
828
763
|
.withService(userService)
|
|
829
764
|
.build();
|
|
830
765
|
|
|
831
|
-
return yield* server.run();
|
|
766
|
+
return yield* server.run({ host: "localhost", port: 8000 });
|
|
832
767
|
}).pipe(
|
|
833
768
|
Effect.provide(appLayer)
|
|
834
769
|
);
|
package/dist/protoRuntime.d.ts
CHANGED
|
@@ -73,14 +73,14 @@ export interface ServerExecutor<Ctx> {
|
|
|
73
73
|
unary<In, Out>(req: In, ctx: HandlerContext, prog: (req: In, ctx: Ctx) => Effect.Effect<Out, GrpcException.GrpcException>): Promise<Out>;
|
|
74
74
|
}
|
|
75
75
|
export declare const ServerExecutor: {
|
|
76
|
-
(runtime: Runtime.Runtime<never>): ServerExecutor<
|
|
76
|
+
(runtime: Runtime.Runtime<never>): ServerExecutor<any>;
|
|
77
77
|
};
|
|
78
78
|
export interface ServerExecutorTransformer<Ctx> {
|
|
79
79
|
readonly transformation: (underlying: ServerExecutor<HandlerContext>) => ServerExecutor<Ctx>;
|
|
80
|
-
transformContext<Ctx1>(f: (
|
|
80
|
+
transformContext<Ctx1>(f: (handlerCtx: HandlerContext) => Effect.Effect<Ctx1, GrpcException.GrpcException>): ServerExecutorTransformer<Ctx1>;
|
|
81
81
|
}
|
|
82
82
|
export declare const ServerExecutorTransformer: {
|
|
83
|
-
(): ServerExecutorTransformer<
|
|
83
|
+
(): ServerExecutorTransformer<any>;
|
|
84
84
|
};
|
|
85
85
|
export {};
|
|
86
86
|
//# sourceMappingURL=protoRuntime.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protoRuntime.d.ts","sourceRoot":"","sources":["../src/protoRuntime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEzC,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACtF,OAAO,KAAK,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAClF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,OAAO,KAAK,aAAa,MAAM,oBAAoB,CAAC;AAEpD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,MAAM,cAAc,CAAC,YAAY,SAAS,iBAAiB,IAAI;KAClE,CAAC,IAAI,MAAM,YAAY,GAAG,YAAY,CAAC,CAAC,CAAC,SAAS,CACjD;QAAE,UAAU,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;QAAC,MAAM,EAAE,UAAU,CAAC,MAAM,GAAG,CAAC,CAAA;KAAE,CACpF,GACC,qBAAqB,CAAC,UAAU,CAAC,EAAE,CAAC,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,GACtD,0CAA0C;CAC7C,CAAC;AAEF,KAAK,qBAAqB,CAAC,CAAC,SAAS,WAAW,EAAE,CAAC,SAAS,WAAW,IAAI,CACzE,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAC5B,IAAI,CAAC,EAAE,WAAW,KACf,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;AAEpC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,MAAM,WAAW,cAAc,CAAC,GAAG;IACjC,KAAK,CAAC,EAAE,EAAE,GAAG,EACX,GAAG,EAAE,EAAE,EACP,GAAG,EAAE,cAAc,EACnB,IAAI,EAAE,CAAC,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,KAAK,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,aAAa,CAAC,aAAa,CAAC,GAC3E,OAAO,CAAC,GAAG,CAAC,CAAC;CACjB;AACD,eAAO,MAAM,cAAc,EAAE;IAC3B,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,cAAc,CAAC,
|
|
1
|
+
{"version":3,"file":"protoRuntime.d.ts","sourceRoot":"","sources":["../src/protoRuntime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEzC,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACtF,OAAO,KAAK,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAClF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,OAAO,KAAK,aAAa,MAAM,oBAAoB,CAAC;AAEpD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,MAAM,cAAc,CAAC,YAAY,SAAS,iBAAiB,IAAI;KAClE,CAAC,IAAI,MAAM,YAAY,GAAG,YAAY,CAAC,CAAC,CAAC,SAAS,CACjD;QAAE,UAAU,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;QAAC,MAAM,EAAE,UAAU,CAAC,MAAM,GAAG,CAAC,CAAA;KAAE,CACpF,GACC,qBAAqB,CAAC,UAAU,CAAC,EAAE,CAAC,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,GACtD,0CAA0C;CAC7C,CAAC;AAEF,KAAK,qBAAqB,CAAC,CAAC,SAAS,WAAW,EAAE,CAAC,SAAS,WAAW,IAAI,CACzE,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAC5B,IAAI,CAAC,EAAE,WAAW,KACf,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;AAEpC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,MAAM,WAAW,cAAc,CAAC,GAAG;IACjC,KAAK,CAAC,EAAE,EAAE,GAAG,EACX,GAAG,EAAE,EAAE,EACP,GAAG,EAAE,cAAc,EACnB,IAAI,EAAE,CAAC,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,KAAK,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,aAAa,CAAC,aAAa,CAAC,GAC3E,OAAO,CAAC,GAAG,CAAC,CAAC;CACjB;AACD,eAAO,MAAM,cAAc,EAAE;IAC3B,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;CACrB,CAAC;AAErC,MAAM,WAAW,yBAAyB,CAAC,GAAG;IAC5C,QAAQ,CAAC,cAAc,EAAE,CAAC,UAAU,EAAE,cAAc,CAAC,cAAc,CAAC,KAAK,cAAc,CAAC,GAAG,CAAC,CAAC;IAE7F,gBAAgB,CAAC,IAAI,EACnB,CAAC,EAAE,CAAC,UAAU,EAAE,cAAc,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,aAAa,CAAC,aAAa,CAAC,GAClF,yBAAyB,CAAC,IAAI,CAAC,CAAC;CACpC;AACD,eAAO,MAAM,yBAAyB,EAAE;IACtC,IAAI,yBAAyB,CAAC,GAAG,CAAC,CAAC;CACW,CAAC"}
|
|
@@ -7,11 +7,11 @@ import type * as T from "./protoRuntime.js";
|
|
|
7
7
|
* Live implementation of the Executor interface using Effect's ManagedRuntime.
|
|
8
8
|
* Handles the execution of Effect programs within gRPC service handlers.
|
|
9
9
|
*/
|
|
10
|
-
export declare class ServerExecutorLive implements T.ServerExecutor<
|
|
10
|
+
export declare class ServerExecutorLive implements T.ServerExecutor<any> {
|
|
11
11
|
readonly runtime: Runtime.Runtime<never>;
|
|
12
12
|
constructor(runtime: Runtime.Runtime<never>);
|
|
13
|
-
static make(runtime: Runtime.Runtime<never>): T.ServerExecutor<
|
|
14
|
-
unary<In, Out>(req: In, ctx: HandlerContext, prog: (req: In, ctx:
|
|
13
|
+
static make(runtime: Runtime.Runtime<never>): T.ServerExecutor<any>;
|
|
14
|
+
unary<In, Out>(req: In, ctx: HandlerContext, prog: (req: In, ctx: any) => Effect.Effect<Out, GrpcException.GrpcException>): Promise<Out>;
|
|
15
15
|
}
|
|
16
16
|
/**
|
|
17
17
|
* @internal
|
|
@@ -21,7 +21,7 @@ export declare class ServerExecutorLive implements T.ServerExecutor<HandlerConte
|
|
|
21
21
|
export declare class ServerExecutorTransformerLive<Ctx> implements T.ServerExecutorTransformer<Ctx> {
|
|
22
22
|
readonly transformation: (underlying: T.ServerExecutor<HandlerContext>) => T.ServerExecutor<Ctx>;
|
|
23
23
|
constructor(transformation: (underlying: T.ServerExecutor<HandlerContext>) => T.ServerExecutor<Ctx>);
|
|
24
|
-
static empty(): ServerExecutorTransformerLive<
|
|
25
|
-
transformContext<Ctx1>(f: (
|
|
24
|
+
static empty(): ServerExecutorTransformerLive<any>;
|
|
25
|
+
transformContext<Ctx1>(f: (handlerCtx: HandlerContext) => Effect.Effect<Ctx1, GrpcException.GrpcException>): ServerExecutorTransformerLive<Ctx1>;
|
|
26
26
|
}
|
|
27
27
|
//# sourceMappingURL=protoRuntime.internal.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protoRuntime.internal.d.ts","sourceRoot":"","sources":["../src/protoRuntime.internal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,MAAM,EAAQ,OAAO,EAAE,MAAM,QAAQ,CAAC;AAGtD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,OAAO,KAAK,aAAa,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,KAAK,CAAC,MAAM,mBAAmB,CAAC;AAE5C;;;;GAIG;AACH,qBAAa,kBAAmB,YAAW,CAAC,CAAC,cAAc,CAAC,
|
|
1
|
+
{"version":3,"file":"protoRuntime.internal.d.ts","sourceRoot":"","sources":["../src/protoRuntime.internal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,MAAM,EAAQ,OAAO,EAAE,MAAM,QAAQ,CAAC;AAGtD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,OAAO,KAAK,aAAa,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,KAAK,CAAC,MAAM,mBAAmB,CAAC;AAE5C;;;;GAIG;AACH,qBAAa,kBAAmB,YAAW,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC;aAClC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC;gBAA/B,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC;IAE3D,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC;IAInE,KAAK,CAAC,EAAE,EAAE,GAAG,EACX,GAAG,EAAE,EAAE,EACP,GAAG,EAAE,cAAc,EACnB,IAAI,EAAE,CAAC,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,KAAK,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,aAAa,CAAC,aAAa,CAAC,GAC3E,OAAO,CAAC,GAAG,CAAC;CA2BhB;AAED;;;;GAIG;AACH,qBAAa,6BAA6B,CAAC,GAAG,CAAE,YAAW,CAAC,CAAC,yBAAyB,CAAC,GAAG,CAAC;aAEvE,cAAc,EAAE,CAC9B,UAAU,EAAE,CAAC,CAAC,cAAc,CAAC,cAAc,CAAC,KACzC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC;gBAFV,cAAc,EAAE,CAC9B,UAAU,EAAE,CAAC,CAAC,cAAc,CAAC,cAAc,CAAC,KACzC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC;IAG5B,MAAM,CAAC,KAAK,IAAI,6BAA6B,CAAC,GAAG,CAAC;IAIlD,gBAAgB,CAAC,IAAI,EACnB,CAAC,EAAE,CAAC,UAAU,EAAE,cAAc,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,aAAa,CAAC,aAAa,CAAC,GAClF,6BAA6B,CAAC,IAAI,CAAC;CAevC"}
|