@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.
@@ -15,7 +15,8 @@ export class ServerExecutorLive {
15
15
  return new ServerExecutorLive(runtime);
16
16
  }
17
17
  unary(req, ctx, prog) {
18
- return Runtime.runPromiseExit(this.runtime, prog(req, ctx), { signal: ctx.signal }).then(Exit.match({
18
+ // Pass undefined as the context since the default is 'any' and no transformation has been applied
19
+ return Runtime.runPromiseExit(this.runtime, prog(req, undefined), { signal: ctx.signal }).then(Exit.match({
19
20
  onFailure: (cause) => {
20
21
  throw Cause.match(cause, {
21
22
  onEmpty: new ConnectError("Unknown error", Code.Unknown),
@@ -45,11 +46,10 @@ export class ServerExecutorTransformerLive {
45
46
  }
46
47
  transformContext(f) {
47
48
  return new ServerExecutorTransformerLive((underlying) => {
48
- const executor = this.transformation(underlying);
49
49
  return {
50
- unary(req, ctx, prog) {
51
- return executor.unary(req, ctx, (req, ctx0) => {
52
- return Effect.flatMap(f(ctx0), (ctx1) => prog(req, ctx1));
50
+ unary(req, handlerCtx, prog) {
51
+ return underlying.unary(req, handlerCtx, (req) => {
52
+ return Effect.flatMap(f(handlerCtx), (ctx1) => prog(req, ctx1));
53
53
  });
54
54
  },
55
55
  };
@@ -1 +1 @@
1
- {"version":3,"file":"protoRuntime.internal.js","sourceRoot":"","sources":["../src/protoRuntime.internal.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"protoRuntime.internal.js","sourceRoot":"","sources":["../src/protoRuntime.internal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEtD,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGzD,OAAO,KAAK,aAAa,MAAM,oBAAoB,CAAC;AAGpD;;;;GAIG;AACH,MAAM,OAAO,kBAAkB;IACD;IAA5B,YAA4B,OAA+B;QAA/B,YAAO,GAAP,OAAO,CAAwB;IAAG,CAAC;IAE/D,MAAM,CAAC,IAAI,CAAC,OAA+B;QACzC,OAAO,IAAI,kBAAkB,CAAC,OAAO,CAAC,CAAC;IACzC,CAAC;IAED,KAAK,CACH,GAAO,EACP,GAAmB,EACnB,IAA4E;QAE5E,kGAAkG;QAClG,OAAO,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAC5F,IAAI,CAAC,KAAK,CAAC;YACT,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE;gBACnB,MAAM,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE;oBACvB,OAAO,EAAE,IAAI,YAAY,CAAC,eAAe,EAAE,IAAI,CAAC,OAAO,CAAC;oBACxD,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,aAAa,CAAC,cAAc,CAAC,KAAK,CAAC;oBACtD,KAAK,EAAE,CAAC,MAAM,EAAE,EAAE,CAChB,IAAI,YAAY,CACd,uBAAuB,EACvB,IAAI,CAAC,QAAQ,EACb,SAAS,EACT,SAAS,EACT,MAAM,CACP;oBACH,WAAW,EAAE,GAAG,EAAE,CAAC,IAAI,YAAY,CAAC,sBAAsB,EAAE,IAAI,CAAC,OAAO,CAAC;oBACzE,YAAY,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAC5B,IAAI,YAAY,CAAC,GAAG,IAAI,CAAC,UAAU,KAAK,KAAK,CAAC,UAAU,EAAE,EAAE,IAAI,CAAC,QAAQ,CAAC;oBAC5E,UAAU,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAC1B,IAAI,YAAY,CAAC,GAAG,IAAI,CAAC,UAAU,MAAM,KAAK,CAAC,UAAU,EAAE,EAAE,IAAI,CAAC,QAAQ,CAAC;iBAC9E,CAAC,CAAC;YACL,CAAC;YACD,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK;SAC5B,CAAC,CACH,CAAC;IACJ,CAAC;CACF;AAED;;;;GAIG;AACH,MAAM,OAAO,6BAA6B;IAEtB;IADlB,YACkB,cAEU;QAFV,mBAAc,GAAd,cAAc,CAEJ;IACzB,CAAC;IAEJ,MAAM,CAAC,KAAK;QACV,OAAO,IAAI,6BAA6B,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC;IACvE,CAAC;IAED,gBAAgB,CACd,CAAmF;QAEnF,OAAO,IAAI,6BAA6B,CAAO,CAAC,UAAU,EAAE,EAAE;YAC5D,OAAO;gBACL,KAAK,CACH,GAAO,EACP,UAA0B,EAC1B,IAA6E;oBAE7E,OAAO,UAAU,CAAC,KAAK,CAAC,GAAG,EAAE,UAAU,EAAE,CAAC,GAAG,EAAE,EAAE;wBAC/C,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC;oBAClE,CAAC,CAAC,CAAC;gBACL,CAAC;aACwB,CAAC;QAC9B,CAAC,CAAC,CAAC;IACL,CAAC;CACF"}
@@ -9,7 +9,9 @@ function generateTs(schema) {
9
9
  for (const file of schema.files) {
10
10
  const f = schema.generateFile(file.name + "_effect.ts");
11
11
  f.preamble(file);
12
- file.services.forEach(service => generateEffectService(f, service));
12
+ // Extract basename from file path for import examples
13
+ const fileBasename = file.name.split('/').pop() || file.name;
14
+ file.services.forEach(service => generateEffectService(f, service, fileBasename));
13
15
  /*
14
16
  for (const service of file.services) {
15
17
  f.print(f.jsDoc(service));
@@ -60,208 +62,418 @@ function generateTs(schema) {
60
62
  }*/
61
63
  }
62
64
  }
63
- function generateEffectService(f, service) {
65
+ function generateEffectService(f, service, fileBasename) {
64
66
  const importEffect = f.import("Effect", "effect");
65
67
  const importContext = f.import("Context", "effect");
66
68
  const importLayer = f.import("Layer", "effect");
67
69
  const importScope = f.import("Scope", "effect");
68
- const importHandlerContext = f.import("HandlerContext", "@connectrpc/connect", true);
69
70
  const importEffectGrpcService = f.import("EffectGrpcServer", packageJson.name);
70
71
  const importGrpcException = f.import("GrpcException", packageJson.name);
71
72
  const importService = f.importSchema(service);
72
73
  const serviceId = service.typeName;
73
- const serviceIdSymbol = safeIdentifier(service.name + "Id");
74
+ const serviceIdSymbol = safeIdentifier(service.name + "ProtoId");
74
75
  const serviceSymbol = safeIdentifier(service.name + "Service");
75
76
  const grpcServiceSymbol = safeIdentifier(service.name + "GrpcService");
76
- const serviceTagSymbol = safeIdentifier(service.name + "Tag");
77
+ const serviceTagSymbol = safeIdentifier(service.name + "ServiceTag");
78
+ const serviceLiveLayerSymbol = safeIdentifier(service.name.charAt(0).toLowerCase() + service.name.slice(1) + "ServiceLiveLayer");
77
79
  const makeTagSymbol = safeIdentifier("make" + service.name + "ServiceTag");
78
- const makeLiveLayerSymbol = safeIdentifier("make" + service.name + "LiveLayer");
80
+ const makeLiveLayerSymbol = safeIdentifier("make" + service.name + "ServiceLiveLayer");
81
+ // Generate service ID constant with JSDoc
82
+ f.print("/**");
83
+ f.print(" * Unique identifier for the ", service.name, " gRPC service.");
84
+ f.print(" *");
85
+ f.print(" * This constant represents the fully qualified service name from the Protocol Buffer definition.");
86
+ f.print(" * It's used to identify and wire gRPC dependencies.");
87
+ f.print(" *");
88
+ f.print(" * @generated from service ", service.typeName);
89
+ f.print(" */");
79
90
  f.print(f.export("const", serviceIdSymbol), " = ", f.string(serviceId), " as const;");
80
91
  f.print(f.export("type", serviceIdSymbol), " = typeof ", serviceIdSymbol, ";");
81
92
  f.print();
82
- f.print(f.jsDoc(service));
83
- f.print(f.export("interface", serviceSymbol), "<Ctx> {");
93
+ // Generate comprehensive JSDoc for service interface
94
+ f.print("/**");
95
+ f.print(" * gRPC service interface.");
96
+ f.print(" *");
97
+ f.print(" * @typeParam Ctx - The type of context passed to service methods. Use this to inject");
98
+ f.print(" * dependencies or pass request-scoped data (e.g., authentication info)");
99
+ f.print(" *");
100
+ f.print(" * @example");
101
+ f.print(" * ```typescript");
102
+ f.print(" * import { Effect } from \"effect\";");
103
+ f.print(" * import * as effectProto from \"./" + fileBasename + "_effect.js\";");
104
+ f.print(" *");
105
+ f.print(" * // Simple implementation with default context");
106
+ f.print(" * const service: effectProto.", serviceSymbol, " = {");
107
+ if (service.methods.length > 0 && service.methods[0] !== undefined) {
108
+ const firstMethod = service.methods[0];
109
+ f.print(" * ", firstMethod.localName, ": (request) =>");
110
+ f.print(" * Effect.succeed({})");
111
+ }
112
+ f.print(" * };");
113
+ f.print(" * ```");
114
+ f.print(" *");
115
+ f.print(" * @generated from service ", service.typeName);
116
+ f.print(" */");
117
+ f.print(f.export("interface", serviceSymbol), "<Ctx = any> {");
84
118
  service.methods.forEach(generateServerMethod);
85
119
  f.print("}");
86
- /**
87
- * @example
88
- * ```typescript
89
- * export const DebugAPIService: {
90
- * makeTag<Ctx>(ctxKey: string): DebugAPITag<Ctx>;
91
- *
92
- * liveLayer<Ctx>(service: DebugAPIService<Ctx>):
93
- * <Tag extends DebugAPITag<Ctx>>(tag: Tag) => Layer.Layer<Context.Tag.Identifier<Tag>, never, never>;
94
- * } = {
95
- * makeTag: makeDebugAPIServiceTag,
96
- * liveLayer: makeDebugApiLiveLayer
97
- * };
98
- * ```
99
- */
100
- f.print(f.export("const", serviceSymbol), ": {");
101
- f.print(" makeTag<Ctx>(ctxKey: string): ", serviceTagSymbol, "<Ctx>;");
102
120
  f.print();
103
- f.print(" liveLayer<Ctx>(");
104
- f.print(" service: ", serviceSymbol, "<Ctx>");
105
- f.print(" ): <Tag extends ", serviceTagSymbol, "<Ctx>>(tag: Tag) => ", importLayer, ".Layer<", importContext, ".Tag.Identifier<Tag>, never, never>;");
106
- f.print("} = {");
107
- f.print(" makeTag: ", makeTagSymbol, ",");
108
- f.print(" liveLayer: ", makeLiveLayerSymbol);
109
- f.print("};");
121
+ // Generate direct exported layer function with JSDoc
122
+ f.print("/**");
123
+ f.print(" * Creates a Layer that provides a gRPC service implementation.");
124
+ f.print(" *");
125
+ f.print(" * This function takes your service implementation and wraps it in a Layer that can be");
126
+ f.print(" * composed with other layers to build your application. The returned function accepts");
127
+ f.print(" * a Context.Tag to identify the service in the Effect context.");
128
+ f.print(" *");
129
+ f.print(" * @typeParam Ctx - The context type used by your service implementation");
130
+ f.print(" *");
131
+ f.print(" * @param tag - Context tag to identify the service");
132
+ f.print(" * @param service - Your implementation of the ", serviceSymbol, " interface");
133
+ f.print(" * @returns A Layer providing the gRPC service");
134
+ f.print(" *");
135
+ f.print(" * @example");
136
+ f.print(" * ```typescript");
137
+ f.print(" * import { Effect, Layer } from \"effect\";");
138
+ f.print(" * import * as effectProto from \"./" + fileBasename + "_effect.js\";");
139
+ f.print(" *");
140
+ f.print(" * // Define your service implementation");
141
+ f.print(" * const myService: effectProto.", serviceSymbol, " = {");
142
+ if (service.methods.length > 0 && service.methods[0] !== undefined) {
143
+ const firstMethod = service.methods[0];
144
+ f.print(" * ", firstMethod.localName, ": (request) =>");
145
+ f.print(" * Effect.succeed({})");
146
+ }
147
+ f.print(" * };");
148
+ f.print(" *");
149
+ f.print(" * // Create the service layer");
150
+ f.print(" * const ServiceLayer = effectProto.", serviceLiveLayerSymbol, "(effectProto.", serviceTagSymbol, ", myService);");
151
+ f.print(" * ```");
152
+ f.print(" *");
153
+ f.print(" * @generated from service ", service.typeName);
154
+ f.print(" */");
155
+ f.print(f.export("const", serviceLiveLayerSymbol), ": {");
156
+ f.print(" <Tag extends ", serviceTagSymbol, "<Ctx>, Ctx>(");
157
+ f.print(" tag: Tag,");
158
+ f.print(" service: ", serviceSymbol, "<Ctx>,");
159
+ f.print(" ): ", importLayer, ".Layer<", importContext, ".Tag.Identifier<Tag>>;");
160
+ f.print("} = ", makeLiveLayerSymbol, ";");
161
+ f.print();
162
+ // Generate type aliases with JSDoc
163
+ f.print("/**");
164
+ f.print(" * Type alias for the wrapped gRPC service.");
165
+ f.print(" *");
166
+ f.print(" * This represents the Effect-wrapped version of your service implementation,");
167
+ f.print(" * ready to be registered with a gRPC server.");
168
+ f.print(" *");
169
+ f.print(" * @typeParam Ctx - The context type used by the service");
170
+ f.print(" *");
171
+ f.print(" * @generated from service ", service.typeName);
172
+ f.print(" */");
173
+ f.print(f.export("type", grpcServiceSymbol), "<Ctx = any>", " = ", importEffectGrpcService, ".GrpcService<", serviceIdSymbol, ", typeof ", importService, ", Ctx>");
174
+ f.print();
175
+ // export type DebugAPIServiceTag<Ctx = any> = Context.Tag<DebugAPIGrpcService<Ctx>, DebugAPIGrpcService<Ctx>>
176
+ f.print("/**");
177
+ f.print(" * Type alias for the service Context.Tag.");
178
+ f.print(" *");
179
+ f.print(" * Used to identify and retrieve the service from the Effect context.");
180
+ f.print(" *");
181
+ f.print(" * @typeParam Ctx - The context type used by the service");
182
+ f.print(" *");
183
+ f.print(" * @generated from service ", service.typeName);
184
+ f.print(" */");
185
+ f.print(f.export("type", serviceTagSymbol), "<Ctx = any>", " = ", importContext, ".Tag<", grpcServiceSymbol, "<Ctx>, ", grpcServiceSymbol, "<Ctx>>");
186
+ f.print();
187
+ // Generate ServiceTag constant with comprehensive JSDoc
188
+ f.print("/**");
189
+ f.print(" * Context.Tag for identifying the ", service.name, " service implementation.");
190
+ f.print(" *");
191
+ f.print(" * This tag is used to provide and retrieve the service from the Effect context.");
192
+ f.print(" * It supports both default (any) context and typed context via the function overload.");
193
+ f.print(" *");
194
+ f.print(" * @example");
195
+ f.print(" * ```typescript");
196
+ f.print(" * import { Effect } from \"effect\";");
197
+ f.print(" * import * as effectProto from \"./" + fileBasename + "_effect.js\";");
198
+ f.print(" *");
199
+ f.print(" * // Use default context tag");
200
+ f.print(" * const myService = {");
201
+ if (service.methods.length > 0 && service.methods[0] !== undefined) {
202
+ const firstMethod = service.methods[0];
203
+ f.print(" * ", firstMethod.localName, ": (request) => Effect.succeed({})");
204
+ }
205
+ f.print(" * };");
206
+ f.print(" * const ServiceLayer = effectProto.", serviceLiveLayerSymbol, "(effectProto.", serviceTagSymbol, ", myService);");
207
+ f.print(" * ```");
208
+ f.print(" *");
209
+ f.print(" * @example");
210
+ f.print(" * ```typescript");
211
+ f.print(" * import { Effect } from \"effect\";");
212
+ f.print(" * import * as effectProto from \"./" + fileBasename + "_effect.js\";");
213
+ f.print(" *");
214
+ f.print(" * // Create a typed context tag");
215
+ f.print(" * interface MyContext {");
216
+ f.print(" * userId: string;");
217
+ f.print(" * }");
218
+ f.print(" *");
219
+ f.print(" * const TypedServiceTag = effectProto.", serviceTagSymbol, "<MyContext>(\"MyContext\");");
220
+ f.print(" * ```");
221
+ f.print(" *");
222
+ f.print(" * @generated from service ", service.typeName);
223
+ f.print(" */");
224
+ f.print(f.export("const", serviceTagSymbol), ": ", serviceTagSymbol, " & {");
225
+ f.print(" <Ctx>(ctxKey: string): ", serviceTagSymbol, "<Ctx>;");
226
+ f.print("} = Object.assign(", makeTagSymbol, "(), ", makeTagSymbol, ");");
110
227
  f.print();
111
- // export type DebugAPIGrpcService<Ctx = HandlerContext> = EffectGrpcServer.GrpcService<"DebugAPI", typeof proto.DebugAPI, Ctx>
112
- f.print(f.export("type", grpcServiceSymbol), "<Ctx = ", importHandlerContext, ">", " = ", importEffectGrpcService, `.GrpcService<"`, service.typeName, `", typeof `, importService, ", Ctx>");
113
- // export type DebugAPITag<Ctx> = Context.Tag<DebugAPIGrpcService<Ctx>, DebugAPIGrpcService<Ctx>>
114
- f.print(f.export("type", serviceTagSymbol), "<Ctx>", " = ", importContext, ".Tag<", grpcServiceSymbol, "<Ctx>, ", grpcServiceSymbol, "<Ctx>>");
115
228
  /**
116
229
  * @example
117
230
  * ```typescript
118
- * function makeDebugAPIServiceTag<Ctx>(ctxKey: string & keyof Ctx): DebugAPITag<Ctx> {
119
- * return Context.GenericTag<DebugAPIGrpcService<Ctx>, DebugAPIGrpcService<Ctx>>(`${proto.DebugAPI.typeName}<${ctxKey}}>`);
231
+ * function makeDebugAPIServiceTag<Ctx = any>(ctxKey: string = "any"): DebugAPITag<Ctx> {
232
+ * return Context.GenericTag<DebugAPIGrpcService<Ctx>>(`${proto.DebugAPI.typeName}<${ctxKey}}>`);
120
233
  * }
121
234
  * ```
122
235
  */
123
- f.print("function ", makeTagSymbol, "<Ctx>(ctxKey: string): ", serviceTagSymbol, "<Ctx> {");
236
+ f.print("function ", makeTagSymbol, "<Ctx = any>(ctxKey: string = ", f.string("any"), "): ", serviceTagSymbol, "<Ctx> {");
124
237
  f.print(" return ", importContext, ".GenericTag<", grpcServiceSymbol, "<Ctx>>(`", service.typeName, "<${ctxKey}>`);");
125
238
  f.print("}");
126
239
  f.print();
127
- /**
128
- * @example
129
- * ```typescript
130
- * function makeDebugApiLiveLayer<Ctx>(service: DebugAPIService<Ctx>) {
131
- * return <Tag extends DebugAPITag<Ctx>>(tag: Tag) => {
132
- * type Proto = typeof proto.DebugAPI;
133
- *
134
- * const instance: DebugAPIGrpcService<Ctx> = EffectGrpcServer.GrpcService("DebugAPI" as const, proto.DebugAPI)(
135
- * (executor: EffectGrpcServer.Executor<Ctx>): ServiceImpl<Proto> => {
136
- * return {
137
- * getDebugInfo: (req: proto.GetDebugInfoRequest, ctx: HandlerContext) => {
138
- * return executor.unary(
139
- * req,
140
- * ctx,
141
- * (req, ctx) => service.getDebugInfo(req, ctx)
142
- * );
143
- * }
144
- * } as ServiceImpl<Proto>;
145
- * }
146
- * );
147
- *
148
- * return Layer.succeed(tag, instance);
149
- *
150
- * }
151
- * }
152
- * ```
153
- */
154
- f.print("function ", makeLiveLayerSymbol, "<Ctx>(service: ", serviceSymbol, "<Ctx>) {");
155
- f.print(" return <Tag extends ", serviceTagSymbol, "<Ctx>>(tag: Tag) => {");
156
- f.print();
157
- f.print(" const instance: ", grpcServiceSymbol, "<Ctx> = ", importEffectGrpcService, '.GrpcService("', service.typeName, '" as const, ', importService, ")(");
158
- f.print(" (executor) => ({");
240
+ // Generate implementation function
241
+ f.print("function ", makeLiveLayerSymbol, "<Tag extends ", serviceTagSymbol, "<Ctx>, Ctx>(");
242
+ f.print(" tag: Tag,");
243
+ f.print(" service: ", serviceSymbol, "<Ctx>,");
244
+ f.print("): ", importLayer, ".Layer<", importContext, ".Tag.Identifier<Tag>> {");
245
+ f.print(" const instance: ", grpcServiceSymbol, "<Ctx> = ", importEffectGrpcService, ".GrpcService(");
246
+ f.print(" ", serviceIdSymbol, ",");
247
+ f.print(" ", importService, ",");
248
+ f.print(" )((executor) => ({");
159
249
  service.methods.forEach((method) => {
160
250
  if (method.methodKind === "unary") {
161
- f.print(" ", method.localName, ": (req, ctx) => executor.unary(req, ctx, (req, ctx) => service.", method.localName, "(req, ctx))", ",");
251
+ f.print(" ", method.localName, ": (req, ctx) =>");
252
+ f.print(" executor.unary(req, ctx, (req, ctx) => service.", method.localName, "(req, ctx)),");
162
253
  }
163
254
  });
164
- f.print(" })");
165
- f.print(" );");
255
+ f.print(" }));");
166
256
  f.print();
167
- f.print(" return ", importLayer, ".succeed(tag, instance);");
168
- f.print(" };");
257
+ f.print(" return ", importLayer, ".succeed(tag, instance);");
169
258
  f.print("}");
170
259
  f.print();
171
260
  const clientSymbol = safeIdentifier(service.name + "Client");
172
- /**
173
- * @example
174
- * ```typescript
175
- * export interface DebugAPIClient<Meta> {
176
- * getDebugInfo(
177
- * request: MessageInitShape<typeof proto.GetDebugInfoRequestSchema>,
178
- * meta: Meta,
179
- * ): Effect.Effect<proto.GetDebugInfoResponse>
180
- * }
181
- * ```
182
- */
183
- f.print(f.jsDoc(service));
184
- f.print(f.export("interface", clientSymbol), "<Meta> {");
185
- service.methods.forEach(generateClientMethod);
186
- f.print("}");
187
- /**
188
- * @example
189
- * ```typescript
190
- * export const DebugAPIClient: {
191
- * makeTag<Meta>(metaKey: string): DebugAPIClientTag<Meta>
192
- *
193
- * liveLayer<Meta>(transformMeta: (meta: Meta) => RequestMeta):
194
- * <Tag extends DebugAPIClientTag<Meta>>(tag: Tag) => Layer.Layer<Context.Tag.Identifier<Tag>, never, EffectGrpcClient.GrpcClient>
195
- * } = {
196
- * makeTag: makeDebugAPIClientTag,
197
- * liveLayer: makeDebugApiClientLiveLayer,
198
- * }
199
- * ```
200
- */
201
261
  const importEffectGrpcClient = f.import("EffectGrpcClient", packageJson.name);
202
262
  const clientTagSymbol = safeIdentifier(service.name + "ClientTag");
263
+ const clientLiveLayerSymbol = safeIdentifier(service.name.charAt(0).toLowerCase() + service.name.slice(1) + "ClientLiveLayer");
203
264
  const configTagSymbol = safeIdentifier(service.name + "ConfigTag");
204
265
  const makeClientTagSymbol = safeIdentifier("make" + service.name + "ClientTag");
205
266
  const makeClientLiveLayerSymbol = safeIdentifier("make" + service.name + "ClientLiveLayer");
206
- f.print(f.export("const", clientSymbol), ": {");
207
- f.print(" makeTag<Meta>(metaKey: string): ", clientTagSymbol, "<Meta>;");
267
+ // Generate comprehensive JSDoc for client interface
268
+ f.print("/**");
269
+ f.print(" * Client interface for making gRPC calls to ", service.name, " service.");
270
+ f.print(" *");
271
+ f.print(" * This interface defines the client-side methods for calling the gRPC service.");
272
+ f.print(" * Each method accepts a request message and metadata, and returns an Effect that");
273
+ f.print(" * produces the response or fails with an error.");
274
+ f.print(" *");
275
+ f.print(" * @typeParam Meta - The type of metadata to pass with each request. This can be used");
276
+ f.print(" * for authentication tokens, tracing headers, or other per-request data.");
277
+ f.print(" *");
278
+ f.print(" * @example");
279
+ f.print(" * ```typescript");
280
+ f.print(" * import { Effect } from \"effect\";");
281
+ f.print(" * import * as effectProto from \"./" + fileBasename + "_effect.js\";");
282
+ f.print(" *");
283
+ f.print(" * // Use the client in an Effect");
284
+ f.print(" * const program = Effect.gen(function* () {");
285
+ f.print(" * const client = yield* effectProto.", clientTagSymbol, ";");
286
+ if (service.methods.length > 0 && service.methods[0] !== undefined) {
287
+ const firstMethod = service.methods[0];
288
+ f.print(" * const response = yield* client.", firstMethod.localName, "({}, {});");
289
+ f.print(" * return response;");
290
+ }
291
+ f.print(" * });");
292
+ f.print(" * ```");
293
+ f.print(" *");
294
+ f.print(" * @generated from service ", service.typeName);
295
+ f.print(" */");
296
+ f.print(f.export("interface", clientSymbol), "<Meta> {");
297
+ service.methods.forEach(generateClientMethod);
298
+ f.print("}");
299
+ f.print();
300
+ // Generate ClientTag type with JSDoc
301
+ f.print("/**");
302
+ f.print(" * Type alias for the client Context.Tag.");
303
+ f.print(" *");
304
+ f.print(" * Used to identify and retrieve the client from the Effect context.");
305
+ f.print(" *");
306
+ f.print(" * @typeParam Meta - The metadata type used by the client");
307
+ f.print(" *");
308
+ f.print(" * @generated from service ", service.typeName);
309
+ f.print(" */");
310
+ f.print(f.export("type", clientTagSymbol), "<Meta = any>", " = ", importContext, ".Tag<", clientSymbol, "<Meta>, ", clientSymbol, "<Meta>>");
311
+ f.print();
312
+ // Generate ClientTag constant with comprehensive JSDoc
313
+ f.print("/**");
314
+ f.print(" * Context.Tag for identifying the ", service.name, " client.");
315
+ f.print(" *");
316
+ f.print(" * This tag is used to provide and retrieve the gRPC client from the Effect context.");
317
+ f.print(" * It supports both default (any) metadata and typed metadata via the function overload.");
318
+ f.print(" *");
319
+ f.print(" * @example");
320
+ f.print(" * ```typescript");
321
+ f.print(" * import { Effect, Layer } from \"effect\";");
322
+ f.print(" * import * as effectProto from \"./" + fileBasename + "_effect.js\";");
323
+ f.print(" * import { EffectGrpcClient } from \"@dr_nikson/effect-grpc\";");
324
+ f.print(" *");
325
+ f.print(" * // Use default metadata type");
326
+ f.print(" * const ClientLayer = effectProto.", clientLiveLayerSymbol, "(effectProto.", clientTagSymbol, ");");
327
+ f.print(" *");
328
+ f.print(" * // Use the client");
329
+ f.print(" * const program = Effect.gen(function* () {");
330
+ f.print(" * const client = yield* effectProto.", clientTagSymbol, ";");
331
+ if (service.methods.length > 0 && service.methods[0] !== undefined) {
332
+ const firstMethod = service.methods[0];
333
+ f.print(" * return yield* client.", firstMethod.localName, "({}, {});");
334
+ }
335
+ f.print(" * });");
336
+ f.print(" * ```");
337
+ f.print(" *");
338
+ f.print(" * @example");
339
+ f.print(" * ```typescript");
340
+ f.print(" * import { Effect, Layer } from \"effect\";");
341
+ f.print(" * import * as effectProto from \"./" + fileBasename + "_effect.js\";");
342
+ f.print(" *");
343
+ f.print(" * // Create a typed metadata tag");
344
+ f.print(" * interface RequestMeta {");
345
+ f.print(" * userId: string;");
346
+ f.print(" * traceId: string;");
347
+ f.print(" * }");
348
+ f.print(" *");
349
+ f.print(" * const TypedClientTag = effectProto.", clientTagSymbol, "<RequestMeta>(\"RequestMeta\");");
350
+ f.print(" * ```");
351
+ f.print(" *");
352
+ f.print(" * @generated from service ", service.typeName);
353
+ f.print(" */");
354
+ f.print(f.export("const", clientTagSymbol), ": ", clientTagSymbol, " & {");
355
+ f.print(" <Meta>(metaKey: string): ", clientTagSymbol, "<Meta>;");
356
+ f.print("} = Object.assign(", makeClientTagSymbol, "<any>(", f.string("any"), "), ", makeClientTagSymbol, ");");
208
357
  f.print();
209
- f.print(" liveLayer<Tag extends ", clientTagSymbol, "<Meta>, Meta>(");
358
+ // Generate clientLiveLayer function with comprehensive JSDoc
359
+ f.print("/**");
360
+ f.print(" * Creates a Layer that provides a gRPC client for the ", service.name, " service.");
361
+ f.print(" *");
362
+ f.print(" * This function creates a client that can make gRPC calls to the service.");
363
+ f.print(" * It has two overloads:");
364
+ f.print(" * 1. Simple version: Just pass the tag (uses default empty metadata)");
365
+ f.print(" * 2. Advanced version: Pass a metadata transformer function and the tag");
366
+ f.print(" *");
367
+ f.print(" * The client layer requires:");
368
+ f.print(" * - ", configTagSymbol, ": Configuration with the server URL");
369
+ f.print(" * - EffectGrpcClient.GrpcClientRuntime: The gRPC runtime");
370
+ f.print(" * - Scope.Scope: For resource management");
371
+ f.print(" *");
372
+ f.print(" * @example");
373
+ f.print(" * ```typescript");
374
+ f.print(" * import { Effect, Layer } from \"effect\";");
375
+ f.print(" * import * as effectProto from \"./" + fileBasename + "_effect.js\";");
376
+ f.print(" * import { EffectGrpcClient } from \"@dr_nikson/effect-grpc\";");
377
+ f.print(" *");
378
+ f.print(" * // Simple usage with default metadata");
379
+ f.print(" * const ClientLayer = effectProto.", clientLiveLayerSymbol, "(effectProto.", clientTagSymbol, ");");
380
+ f.print(" *");
381
+ f.print(" * // Configuration layer");
382
+ f.print(" * const ConfigLayer = Layer.succeed(");
383
+ f.print(" * effectProto.", configTagSymbol, ",");
384
+ f.print(" * { baseUrl: new URL(\"http://localhost:50051\") }");
385
+ f.print(" * );");
386
+ f.print(" * ```");
387
+ f.print(" *");
388
+ f.print(" * @example");
389
+ f.print(" * ```typescript");
390
+ f.print(" * import { Effect } from \"effect\";");
391
+ f.print(" * import * as effectProto from \"./" + fileBasename + "_effect.js\";");
392
+ f.print(" *");
393
+ f.print(" * // Advanced usage with metadata transformation");
394
+ f.print(" * interface AppMeta {");
395
+ f.print(" * userId: string;");
396
+ f.print(" * authToken: string;");
397
+ f.print(" * }");
398
+ f.print(" *");
399
+ f.print(" * const AppClientTag = effectProto.", clientTagSymbol, "<AppMeta>(\"AppMeta\");");
400
+ f.print(" *");
401
+ f.print(" * // Transform app metadata to gRPC headers");
402
+ f.print(" * const ClientLayer = effectProto.", clientLiveLayerSymbol, "(");
403
+ f.print(" * (meta: AppMeta) => ({");
404
+ f.print(" * headers: {");
405
+ f.print(" * \"authorization\": `Bearer ${meta.authToken}`,");
406
+ f.print(" * \"x-user-id\": meta.userId");
407
+ f.print(" * }");
408
+ f.print(" * }),");
409
+ f.print(" * AppClientTag");
410
+ f.print(" * );");
411
+ f.print(" * ```");
412
+ f.print(" *");
413
+ f.print(" * @generated from service ", service.typeName);
414
+ f.print(" */");
415
+ f.print(f.export("const", clientLiveLayerSymbol), ": {");
416
+ f.print(" <Tag extends ", clientTagSymbol, "<Meta>, Meta>(");
210
417
  f.print(" transformMeta: (meta: Meta) => ", importEffectGrpcClient, ".RequestMeta,");
211
- f.print(" tag: Tag");
418
+ f.print(" tag: Tag,");
212
419
  f.print(" ): ", importLayer, ".Layer<");
213
420
  f.print(" ", importContext, ".Tag.Identifier<Tag>,");
214
421
  f.print(" never,");
215
- f.print(" ", importContext, ".Tag.Identifier<", configTagSymbol, "> | ", importEffectGrpcClient, ".GrpcClientRuntime | ", importScope, ".Scope");
422
+ f.print(" ", configTagSymbol, "[\"Identifier\"] | ", importEffectGrpcClient, ".GrpcClientRuntime | ", importScope, ".Scope");
216
423
  f.print(" >;");
217
424
  f.print();
218
- f.print(" liveLayer<Tag extends ", clientTagSymbol, "<object>>(");
219
- f.print(" tag: Tag");
425
+ f.print(" <Tag extends ", clientTagSymbol, ">(");
426
+ f.print(" tag: Tag,");
220
427
  f.print(" ): ", importLayer, ".Layer<");
221
428
  f.print(" ", importContext, ".Tag.Identifier<Tag>,");
222
429
  f.print(" never,");
223
- f.print(" ", importContext, ".Tag.Identifier<", configTagSymbol, "> | ", importEffectGrpcClient, ".GrpcClientRuntime | ", importScope, ".Scope");
430
+ f.print(" ", configTagSymbol, "[\"Identifier\"] | ", importEffectGrpcClient, ".GrpcClientRuntime | ", importScope, ".Scope");
224
431
  f.print(" >;");
225
- f.print("} = {");
226
- f.print(" makeTag: ", makeClientTagSymbol, ",");
227
- f.print(" liveLayer: ", makeClientLiveLayerSymbol, ",");
228
- f.print("};");
229
- f.print();
230
- // export type DebugAPIClientTag<Meta> = Context.Tag<DebugAPIClient<Meta>, DebugAPIClient<Meta>>
231
- f.print(f.export("type", clientTagSymbol), "<Meta>", " = ", importContext, ".Tag<", clientSymbol, "<Meta>, ", clientSymbol, "<Meta>>");
432
+ f.print("} = ", makeClientLiveLayerSymbol, ";");
232
433
  f.print();
233
- // export type HelloWorldAPIConfigTag = Context.Tag<EffectGrpcClient.GrpcClientConfig<HelloWorldAPIId>, EffectGrpcClient.GrpcClientConfig<HelloWorldAPIId>>
434
+ // Generate ConfigTag type with JSDoc
435
+ f.print("/**");
436
+ f.print(" * Type alias for the client configuration Context.Tag.");
437
+ f.print(" *");
438
+ f.print(" * This tag provides the configuration required by the gRPC client,");
439
+ f.print(" * such as the server URL and connection options.");
440
+ f.print(" *");
441
+ f.print(" * @generated from service ", service.typeName);
442
+ f.print(" */");
234
443
  f.print(f.export("type", configTagSymbol), " = ", importContext, ".Tag<", importEffectGrpcClient, ".GrpcClientConfig<", serviceIdSymbol, ">, ", importEffectGrpcClient, ".GrpcClientConfig<", serviceIdSymbol, ">>");
235
- // export const HelloWorldAPIConfigTag: HelloWorldAPIConfigTag = EffectGrpcClient.GrpcClientConfig.makeTag(HelloWorldAPIId);
444
+ f.print();
445
+ // Generate ConfigTag constant with comprehensive JSDoc
446
+ f.print("/**");
447
+ f.print(" * Context.Tag for the ", service.name, " client configuration.");
448
+ f.print(" *");
449
+ f.print(" * This tag is used to provide the gRPC client configuration, which includes:");
450
+ f.print(" * - baseUrl: The URL of the gRPC server (e.g., \"http://localhost:50051\")");
451
+ f.print(" * - Additional connection options (timeouts, interceptors, etc.)");
452
+ f.print(" *");
453
+ f.print(" * You must provide this configuration as a Layer when using the client.");
454
+ f.print(" *");
455
+ f.print(" * @example");
456
+ f.print(" * ```typescript");
457
+ f.print(" * import { Layer } from \"effect\";");
458
+ f.print(" * import * as effectProto from \"./" + fileBasename + "_effect.js\";");
459
+ f.print(" *");
460
+ f.print(" * // Simple configuration with just the base URL");
461
+ f.print(" * const ConfigLayer = Layer.succeed(");
462
+ f.print(" * effectProto.", configTagSymbol, ",");
463
+ f.print(" * { baseUrl: new URL(\"http://localhost:50051\") }");
464
+ f.print(" * );");
465
+ f.print(" * ```");
466
+ f.print(" *");
467
+ f.print(" * @generated from service ", service.typeName);
468
+ f.print(" */");
236
469
  f.print(f.export("const", configTagSymbol), ": ", configTagSymbol, " = ", importEffectGrpcClient, ".GrpcClientConfig.makeTag(", serviceIdSymbol, ");");
237
470
  f.print();
238
- // function makeDebugAPIClientTag<Meta>(metaKey: string): DebugAPIClientTag<Meta>
471
+ // Generate makeClientTag helper function
239
472
  f.print("function ", makeClientTagSymbol, "<Meta>(metaKey: string): ", clientTagSymbol, "<Meta> {");
240
- f.print(" return ", importContext, ".GenericTag<", clientSymbol, "<Meta>>(`", service.typeName, "Client<${metaKey}>`);");
473
+ f.print(" return ", importContext, ".GenericTag<", clientSymbol, "<Meta>>(`${", serviceIdSymbol, "}<${metaKey}>`);");
241
474
  f.print("}");
242
475
  f.print();
243
- /**
244
- * @example
245
- * ```typescript
246
- * function makeDebugApiClientLiveLayer<Meta>(transformMeta: (meta: Meta) => RequestMeta) {
247
- * return <Tag extends DebugAPIClientTag<Meta>>(tag: Tag) => {
248
- * const prog = Effect.gen(function* () {
249
- * const grpcService = yield* EffectGrpcClient.GrpcClient
250
- * const executor = grpcService.makeExecutor(proto.DebugAPI, ["getDebugInfo"]);
251
- *
252
- * return {
253
- * getDebugInfo(req, meta) {
254
- * return executor.getDebugInfo(req, meta ?? transformMeta(meta));
255
- * },
256
- * } as DebugAPIClient<Meta>;
257
- * });
258
- *
259
- * return Layer.effect(tag, prog);
260
- * }
261
- * }
262
- * ```
263
- */
264
- // function makeDebugAPIClientLiveLayer<Tag extends DebugAPIClientTag<Meta>, Meta = object>(...args: readonly [(meta: Meta) => RequestMeta, Tag] | readonly [Tag])
476
+ // Generate client implementation function with overload handling
265
477
  f.print("function ", makeClientLiveLayerSymbol, "<Tag extends ", clientTagSymbol, "<Meta>, Meta = object>(");
266
478
  f.print(" ...args: readonly [(meta: Meta) => ", importEffectGrpcClient, ".RequestMeta, Tag] | readonly [Tag]");
267
479
  f.print(") {");