@dr_nikson/effect-grpc 3.0.0-alpha.0 → 3.0.0-alpha.2

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 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
- // Create a tag for dependency injection
114
- const HelloServiceTag = effectProto.HelloService.makeTag<HandlerContext>(
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.HelloService.liveLayer(HelloServiceLive)(
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.HelloServiceClient.liveLayer(
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 returns an Effect that requires a Scope
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(server.run());
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 (must be called before adding services)
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 `HandlerContext`.
307
+ Creates a new server builder instance with default context.
335
308
 
336
- **Returns:** `GrpcServerBuilder<HandlerContext, never>`
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: string` - Base URL for gRPC requests (e.g., "http://localhost:8000")
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}Id`
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 UserServiceId = "com.example.v1.UserService" as const;
538
- export type UserServiceId = typeof UserServiceId;
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 UserService<Ctx> {
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}Service.makeTag(ctxKey)`
472
+ ##### `{ServiceName}ServiceTag`
564
473
 
565
- Creates a Context tag for the service.
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
- **Parameters:**
568
- - `ctxKey` - String identifier for the context type (e.g., "HandlerContext")
476
+ **Usage:**
477
+ ```typescript
478
+ // Use default tag directly (when not using ctx parameter in implementation)
479
+ effectProto.UserServiceTag
569
480
 
570
- **Returns:** `Context.Tag<{ServiceName}GrpcService<Ctx>, {ServiceName}GrpcService<Ctx>>`
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
- **Example:**
573
- ```typescript
574
- const UserServiceTag = UserService.makeTag<HandlerContext>("HandlerContext");
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
- ##### `{ServiceName}Service.liveLayer(impl)`
493
+ ##### `{serviceName}ServiceLiveLayer(tag, service)`
578
494
 
579
- Creates a layer from a service implementation.
495
+ Function that creates a layer from a service implementation.
580
496
 
581
497
  **Parameters:**
582
- - `impl` - Implementation of the service interface
498
+ - `tag` - Context tag for the service
499
+ - `service` - Implementation of the service interface
583
500
 
584
- **Returns:** Function accepting a tag and returning a `Layer`
501
+ **Returns:** `Layer` providing the gRPC service
585
502
 
586
503
  **Example:**
587
504
  ```typescript
588
- const UserServiceLive: UserService<HandlerContext> = {
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 UserServiceTag = UserService.makeTag<HandlerContext>("HandlerContext");
598
- const layer = UserService.liveLayer(UserServiceLive)(UserServiceTag);
599
- ```
515
+ const userServiceLayer = userServiceLiveLayer(
516
+ effectProto.UserServiceTag,
517
+ UserServiceLive
518
+ );
600
519
 
601
- ##### `{ServiceName}GrpcService<Ctx>`
520
+ // When you need to access ctx (e.g., HandlerContext for request headers)
521
+ import { HandlerContext } from "@connectrpc/connect";
602
522
 
603
- Type alias for the complete gRPC service (used with server builder).
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
- **Example:**
606
- ```typescript
607
- type UserServiceGrpc = UserServiceGrpcService<HandlerContext>;
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}Client.makeTag(metaKey)`
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
- **Returns:** `Context.Tag<{ServiceName}Client<Meta>, {ServiceName}Client<Meta>>`
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
- **Example:**
571
+ **Usage:**
646
572
  ```typescript
647
- const UserServiceClientTag = UserServiceClient.makeTag<object>("{}");
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
- ##### `{ServiceName}Client.liveLayer(transformMeta, tag)` / `{ServiceName}Client.liveLayer(tag)`
583
+ ##### `{serviceName}ClientLiveLayer(tag)` / `{serviceName}ClientLiveLayer(transformMeta, tag)`
651
584
 
652
- Creates a layer for the client (two overloads).
585
+ Function that creates a client layer (two overloads).
653
586
 
654
587
  **Overload 1: With metadata transformation**
655
588
  ```typescript
656
- liveLayer<Tag extends {ServiceName}ClientTag<Meta>, Meta>(
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 (empty object)**
595
+ **Overload 2: Default metadata**
663
596
  ```typescript
664
- liveLayer<Tag extends {ServiceName}ClientTag<object>>(
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 MyMeta {
605
+ interface AuthMeta {
673
606
  authToken: string;
674
607
  }
675
608
 
676
- const clientLayerWithMeta = UserServiceClient.liveLayer(
677
- (meta: MyMeta) => ({
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
- UserServiceClientTag
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 empty metadata
688
- const clientLayer = UserServiceClient.liveLayer(
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: UserServiceConfigTag =
704
- EffectGrpcClient.GrpcClientConfig.makeTag(UserServiceId);
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.UserService<HandlerContext> = {
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 { HandlerContext } from "@connectrpc/connect";
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
- // Implement your gRPC service with database dependency
783
- const UserServiceLive: effectProto.UserService<HandlerContext> = {
784
- getUser(request) {
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
- yield* db.saveUser(request.user);
724
+ getUser(request: effectProto.GetUserRequest) {
725
+ return this.db.getUser(request.userId).pipe(
726
+ Effect.map(user => ({ user }))
727
+ );
728
+ }
801
729
 
802
- return { success: true };
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
- // Create service tag and layer
808
- const UserServiceTag = effectProto.UserService.makeTag<HandlerContext>("HandlerContext");
809
- const userServiceLayer = effectProto.UserService.liveLayer(UserServiceLive)(UserServiceTag);
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
  );
@@ -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<HandlerContext>;
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: (ctx: Ctx) => Effect.Effect<Ctx1, GrpcException.GrpcException>): ServerExecutorTransformer<Ctx1>;
80
+ transformContext<Ctx1>(f: (handlerCtx: HandlerContext) => Effect.Effect<Ctx1, GrpcException.GrpcException>): ServerExecutorTransformer<Ctx1>;
81
81
  }
82
82
  export declare const ServerExecutorTransformer: {
83
- (): ServerExecutorTransformer<HandlerContext>;
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,cAAc,CAAC,CAAC;CAChC,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,GAAG,EAAE,GAAG,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,aAAa,CAAC,aAAa,CAAC,GAChE,yBAAyB,CAAC,IAAI,CAAC,CAAC;CACpC;AACD,eAAO,MAAM,yBAAyB,EAAE;IACtC,IAAI,yBAAyB,CAAC,cAAc,CAAC,CAAC;CACA,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<HandlerContext> {
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<HandlerContext>;
14
- unary<In, Out>(req: In, ctx: HandlerContext, prog: (req: In, ctx: HandlerContext) => Effect.Effect<Out, GrpcException.GrpcException>): Promise<Out>;
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<HandlerContext>;
25
- transformContext<Ctx1>(f: (ctx: Ctx) => Effect.Effect<Ctx1, GrpcException.GrpcException>): ServerExecutorTransformerLive<Ctx1>;
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,cAAc,CAAC;aAC7C,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,cAAc,CAAC;IAI9E,KAAK,CAAC,EAAE,EAAE,GAAG,EACX,GAAG,EAAE,EAAE,EACP,GAAG,EAAE,cAAc,EACnB,IAAI,EAAE,CAAC,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,cAAc,KAAK,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,aAAa,CAAC,aAAa,CAAC,GACtF,OAAO,CAAC,GAAG,CAAC;CA0BhB;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,cAAc,CAAC;IAI7D,gBAAgB,CAAC,IAAI,EACnB,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,aAAa,CAAC,aAAa,CAAC,GAChE,6BAA6B,CAAC,IAAI,CAAC;CAiBvC"}
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"}