@krak-stack/registry 0.1.16 → 0.1.18

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.
@@ -1,22 +1,24 @@
1
- import { Context, Effect, FileSystem, Layer, Path, Stdio, Terminal } from "effect";
1
+ import { Cause, Context, Effect, FileSystem, Layer, Path, Stdio, Terminal } from "effect";
2
2
  import { Command } from "effect/unstable/cli";
3
3
  import { ChildProcessSpawner } from "effect/unstable/process/ChildProcessSpawner";
4
- import { ApiClient } from "./httpapi-client.js";
5
- import { HttpApiSpec } from "./httpapi-helpers.js";
4
+ import { ApiClient, type ApiClientService } from "./httpapi-client.js";
5
+ import { HttpApiSpec, type HttpApiOperationEntry } from "./httpapi-helpers.js";
6
6
  declare const HttpApiCli_base: Context.ServiceClass<HttpApiCli, "HttpApiCli", {
7
- command: Command.Command<string, {}, {}, Error, never>;
8
- run: (args: ReadonlyArray<string>) => Effect.Effect<void, Error | import("effect/unstable/cli/CliError").CliError, Command.Environment>;
7
+ command: Command.Command<string, {}, {}, unknown, never>;
8
+ run: (args: ReadonlyArray<string>) => Effect.Effect<void, unknown, Command.Environment>;
9
9
  }> & {
10
10
  readonly make: () => Effect.Effect<{
11
- command: Command.Command<string, {}, {}, Error, never>;
12
- run: (args: ReadonlyArray<string>) => Effect.Effect<void, Error | import("effect/unstable/cli/CliError").CliError, Command.Environment>;
11
+ command: Command.Command<string, {}, {}, unknown, never>;
12
+ run: (args: ReadonlyArray<string>) => Effect.Effect<void, unknown, Command.Environment>;
13
13
  }, never, ApiClient | HttpApiSpec>;
14
14
  };
15
15
  export declare class HttpApiCli extends HttpApiCli_base {
16
16
  static readonly layer: Layer.Layer<HttpApiCli, never, ApiClient | HttpApiSpec>;
17
17
  }
18
- export declare const makeHttpApiCliCommand: () => Effect.Effect<Command.Command<string, {}, {}, Error, never>, never, ApiClient | HttpApiSpec>;
18
+ export declare const printHttpApiCliResult: (response: unknown, operation: HttpApiOperationEntry, client: ApiClientService) => Effect.Effect<void, unknown, never>;
19
+ export declare const makeHttpApiCliCommand: () => Effect.Effect<Command.Command<string, {}, {}, unknown, never>, never, ApiClient | HttpApiSpec>;
19
20
  export declare const httpApiCliEnvironmentLayer: (args: ReadonlyArray<string>) => Layer.Layer<ChildProcessSpawner | FileSystem.FileSystem | Path.Path | Stdio.Stdio | Terminal.Terminal, never, never>;
20
- export declare const httpApiCli: (args?: string[]) => Effect.Effect<void, import("effect/unstable/cli/CliError").DuplicateOption | Error | import("effect/unstable/cli/CliError").InvalidValue | import("effect/unstable/cli/CliError").MissingArgument | import("effect/unstable/cli/CliError").MissingOption | import("effect/unstable/cli/CliError").ShowHelp | import("effect/unstable/cli/CliError").UnknownSubcommand | import("effect/unstable/cli/CliError").UnrecognizedOption, HttpApiCli | Command.Environment>;
21
+ export declare const httpApiCli: (args?: string[]) => Effect.Effect<void, unknown, HttpApiCli | Command.Environment>;
22
+ export declare const formatHttpApiCliCause: <E>(cause: Cause.Cause<E>) => string;
21
23
  export declare const runHttpApiCli: <E>(layer: Layer.Layer<HttpApiCli, E>, args?: string[]) => void;
22
24
  export {};
@@ -1,11 +1,14 @@
1
1
  // ../../src/lib/httpapi-cli.ts
2
2
  import {
3
+ Cause,
3
4
  Console,
4
5
  Context as Context3,
5
6
  Effect as Effect3,
7
+ Exit,
6
8
  FileSystem,
7
9
  Layer as Layer3,
8
10
  Path,
11
+ Schema as Schema3,
9
12
  Stdio,
10
13
  Stream,
11
14
  Terminal
@@ -14,13 +17,22 @@ import { Command, Flag } from "effect/unstable/cli";
14
17
  import { ChildProcessSpawner } from "effect/unstable/process/ChildProcessSpawner";
15
18
 
16
19
  // ../../src/lib/httpapi-client.ts
17
- import { Context, Effect, Layer, Schema } from "effect";
20
+ import { Context, Effect, Layer, Schema, SchemaTransformation } from "effect";
18
21
  import { HttpClient } from "effect/unstable/http";
19
22
  import {
20
- HttpApiClient as EffectHttpApiClient
23
+ HttpApi,
24
+ HttpApiClient as EffectHttpApiClient,
25
+ OpenApi
21
26
  } from "effect/unstable/httpapi";
27
+ var UndefinedFromNull = Schema.Null.pipe(Schema.decodeTo(Schema.Undefined, SchemaTransformation.transform({
28
+ decode: () => {
29
+ return;
30
+ },
31
+ encode: () => null
32
+ })));
22
33
  var HttpApiOperationResultValue = Schema.suspend(() => Schema.Union([
23
34
  Schema.Null,
35
+ UndefinedFromNull,
24
36
  Schema.String,
25
37
  Schema.Number,
26
38
  Schema.Boolean,
@@ -34,6 +46,37 @@ var HttpApiOperationResult = Schema.Union([
34
46
  Schema.Undefined
35
47
  ]).annotate({ identifier: "HttpApiOperationResult" });
36
48
  var encodeHttpApiOperationResult = Effect.fn("HttpApiClient.encodeOperationResult")((result) => Schema.encodeUnknownEffect(HttpApiOperationResult)(result).pipe(Effect.map((encoded) => encoded ?? null), Effect.mapError((cause) => new Error("HTTP API result is not serializable", { cause }))));
49
+ var reflectedSchema = (schema) => Schema.make(schema.ast);
50
+ var operationResultSchemas = (api) => {
51
+ const schemas = new Map;
52
+ HttpApi.reflect(api, {
53
+ onGroup: () => {
54
+ return;
55
+ },
56
+ onEndpoint: ({ endpoint, group, successes }) => {
57
+ const operationId = Context.getOrElse(endpoint.annotations, OpenApi.Identifier, () => group.topLevel ? endpoint.identifier : `${group.identifier}.${endpoint.identifier}`);
58
+ const operationSchemas = Array.from(successes.values()).flat().map(reflectedSchema);
59
+ if (operationSchemas.length === 1 && operationSchemas[0]) {
60
+ schemas.set(operationId, operationSchemas[0]);
61
+ } else if (operationSchemas.length > 1) {
62
+ schemas.set(operationId, Schema.Union(operationSchemas));
63
+ }
64
+ }
65
+ });
66
+ return schemas;
67
+ };
68
+ var makeHttpApiOperationResultEncoder = (api) => {
69
+ const schemas = operationResultSchemas(api);
70
+ return Effect.fn("HttpApiClient.encodeOperationResultWithSchema")((result, operation) => {
71
+ const operationId = operation.operation.operationId;
72
+ const schema = operationId ? schemas.get(operationId) : undefined;
73
+ if (!schema)
74
+ return encodeHttpApiOperationResult(result);
75
+ return Schema.encodeUnknownEffect(schema)(result).pipe(Effect.flatMap(encodeHttpApiOperationResult), Effect.mapError((cause) => new Error("HTTP API result does not match its success schema", {
76
+ cause
77
+ })));
78
+ });
79
+ };
37
80
  var GeneratedOperation = Schema.declare((value) => value instanceof Function).annotate({ identifier: "GeneratedOperation" });
38
81
  var GeneratedOperationEffect = Schema.declare((value) => Effect.isEffect(value)).annotate({ identifier: "GeneratedOperationEffect" });
39
82
  var makeGeneratedClient = (api, http, baseUrl) => EffectHttpApiClient.makeWith(api, {
@@ -69,9 +112,10 @@ var executeGeneratedOperation = Effect.fn("HttpApiClient.executeGeneratedOperati
69
112
  class ApiClient extends Context.Service()("ApiClient") {
70
113
  static layer = (config) => Layer.effect(this, Effect.gen(function* () {
71
114
  const http = yield* HttpClient.HttpClient;
115
+ const encodeResult = makeHttpApiOperationResultEncoder(config.api);
72
116
  const client = yield* makeGeneratedClient(config.api, http, config.baseUrl);
73
117
  return {
74
- encodeResult: config.encodeResult ?? ((result) => encodeHttpApiOperationResult(result)),
118
+ encodeResult: config.encodeResult ?? ((result, operation) => encodeResult(result, operation)),
75
119
  execute: Effect.fn("ApiClient.execute")(function* (options) {
76
120
  return yield* executeGeneratedOperation(client, options);
77
121
  })
@@ -89,7 +133,7 @@ import {
89
133
  Schema as Schema2,
90
134
  SchemaRepresentation
91
135
  } from "effect";
92
- import { HttpApi as HttpApi2, OpenApi } from "effect/unstable/httpapi";
136
+ import { HttpApi as HttpApi2, OpenApi as OpenApi2 } from "effect/unstable/httpapi";
93
137
  var JsonObjectSchema = Schema2.Record(Schema2.String, Schema2.Json).annotate({
94
138
  identifier: "HttpJsonObject",
95
139
  title: "HTTP JSON object",
@@ -262,7 +306,7 @@ var decodeHttpApiOperationInput = Effect2.fn("Http.decodeApiOperationInput")(fun
262
306
  query: pickParameters("query")
263
307
  };
264
308
  });
265
- var reflectedSchema = (schema) => Schema2.make(schema.ast);
309
+ var reflectedSchema2 = (schema) => Schema2.make(schema.ast);
266
310
  var reflectedOperationInputSchemas = (api) => {
267
311
  const schemas = new Map;
268
312
  HttpApi2.reflect(api, {
@@ -270,17 +314,17 @@ var reflectedOperationInputSchemas = (api) => {
270
314
  return;
271
315
  },
272
316
  onEndpoint: ({ endpoint, group }) => {
273
- const operationId = Context2.getOrElse(endpoint.annotations, OpenApi.Identifier, () => group.topLevel ? endpoint.identifier : `${group.identifier}.${endpoint.identifier}`);
317
+ const operationId = Context2.getOrElse(endpoint.annotations, OpenApi2.Identifier, () => group.topLevel ? endpoint.identifier : `${group.identifier}.${endpoint.identifier}`);
274
318
  const fields = {};
275
319
  if (endpoint.params)
276
- fields.params = reflectedSchema(endpoint.params);
320
+ fields.params = reflectedSchema2(endpoint.params);
277
321
  if (endpoint.query) {
278
- fields.query = Schema2.optionalKey(reflectedSchema(endpoint.query));
322
+ fields.query = Schema2.optionalKey(reflectedSchema2(endpoint.query));
279
323
  }
280
324
  if (endpoint.headers) {
281
- fields.headers = Schema2.optionalKey(reflectedSchema(endpoint.headers));
325
+ fields.headers = Schema2.optionalKey(reflectedSchema2(endpoint.headers));
282
326
  }
283
- const payloadSchemas = Array.from(endpoint.payload.values()).flatMap(({ schemas: schemas2 }) => schemas2.map(reflectedSchema));
327
+ const payloadSchemas = Array.from(endpoint.payload.values()).flatMap(({ schemas: schemas2 }) => schemas2.map(reflectedSchema2));
284
328
  if (payloadSchemas.length === 1 && payloadSchemas[0]) {
285
329
  fields.body = payloadSchemas[0];
286
330
  } else if (payloadSchemas.length > 1) {
@@ -312,7 +356,7 @@ class HttpApiSpec extends Context2.Service()("HttpApiSpec", {
312
356
  if (!HttpApi2.isHttpApi(api)) {
313
357
  throw new Error("HttpApiSpec requires a valid HttpApi");
314
358
  }
315
- const spec = OpenApi.fromApi(api);
359
+ const spec = OpenApi2.fromApi(api);
316
360
  const reflectedSchemas = reflectedOperationInputSchemas(api);
317
361
  const operations = httpApiOperations({
318
362
  spec,
@@ -406,6 +450,15 @@ var print = (value) => Console.log(value);
406
450
  var formatOperations = (operations) => operations.map((operation) => `${operation.groupName} ${operation.name} ${operation.method.toUpperCase()} ${operation.path} ${operation.summary}`).join(`
407
451
  `);
408
452
  var listOperations = (operations) => print(formatOperations(operations));
453
+ var HttpApiCliResultStream = Schema3.declare((value) => Stream.isStream(value)).annotate({ identifier: "HttpApiCliResultStream" });
454
+ var printHttpApiCliResult = Effect3.fn("HttpApiCli.printResult")(function* (response, operation, client) {
455
+ const stream = Schema3.decodeUnknownOption(HttpApiCliResultStream)(response);
456
+ if (stream._tag === "Some") {
457
+ return yield* stream.value.pipe(Stream.mapEffect((event) => client.encodeResult(event, operation)), Stream.runForEach((event) => print(JSON.stringify(event))));
458
+ }
459
+ const encoded = yield* client.encodeResult(response, operation);
460
+ return yield* print(JSON.stringify(encoded, null, 2) ?? "null");
461
+ });
409
462
  var callOperation = (operation, callConfig, client) => Effect3.gen(function* () {
410
463
  const body = yield* parseJsonValue(callConfig.body, "--body");
411
464
  const headers = yield* parseJsonObject(callConfig.headers, "--headers");
@@ -419,13 +472,11 @@ var callOperation = (operation, callConfig, client) => Effect3.gen(function* ()
419
472
  },
420
473
  input: { body, headers, params, query }
421
474
  });
422
- const encoded = yield* client.encodeResult(response, {
475
+ return yield* printHttpApiCliResult(response, {
423
476
  method: operation.method,
424
477
  path: operation.path,
425
478
  operation: operation.operation
426
- });
427
- const formatted = JSON.stringify(encoded, null, 2) ?? "null";
428
- return yield* print(formatted);
479
+ }, client);
429
480
  });
430
481
  var listCommand = (groups) => Command.make("list", {}, () => print(groups.map((group) => `${group.name} ${group.title} ${group.operations.length}`).join(`
431
482
  `))).pipe(Command.withDescription("List command groups"));
@@ -469,16 +520,24 @@ var httpApiCli = (args = process.argv.slice(2)) => Effect3.gen(function* () {
469
520
  const cli = yield* HttpApiCli;
470
521
  return yield* cli.run(args);
471
522
  });
523
+ var formatHttpApiCliCause = Cause.pretty;
472
524
  var runHttpApiCli = (layer, args = process.argv.slice(2)) => {
473
- Effect3.runPromise(httpApiCli(args).pipe(Effect3.provide(layer), Effect3.provide(httpApiCliEnvironmentLayer(args)))).catch((error) => {
474
- console.error(error instanceof Error ? error.message : error);
475
- process.exit(1);
476
- });
525
+ Effect3.runPromiseExit(httpApiCli(args).pipe(Effect3.provide(layer), Effect3.provide(httpApiCliEnvironmentLayer(args)))).then(Exit.match({
526
+ onSuccess: () => {
527
+ return;
528
+ },
529
+ onFailure: (cause) => {
530
+ console.error(formatHttpApiCliCause(cause));
531
+ process.exitCode = 1;
532
+ }
533
+ }));
477
534
  };
478
535
  export {
479
536
  runHttpApiCli,
537
+ printHttpApiCliResult,
480
538
  makeHttpApiCliCommand,
481
539
  httpApiCliEnvironmentLayer,
482
540
  httpApiCli,
541
+ formatHttpApiCliCause,
483
542
  HttpApiCli
484
543
  };
@@ -12,12 +12,13 @@ export type ApiClientExecuteOptions = {
12
12
  readonly operation: HttpApiOperationEntry;
13
13
  readonly input: HttpApiOperationInput;
14
14
  };
15
- export type HttpApiOperationResultValue = null | string | number | boolean | Date | Uint8Array | ReadonlyArray<HttpApiOperationResultValue> | {
15
+ export type HttpApiOperationResultValue = null | undefined | string | number | boolean | Date | Uint8Array | ReadonlyArray<HttpApiOperationResultValue> | {
16
16
  readonly [key: string]: HttpApiOperationResultValue;
17
17
  };
18
18
  export declare const HttpApiOperationResult: Schema.Union<readonly [Schema.Codec<HttpApiOperationResultValue, Json, never, never>, Schema.Undefined]>;
19
19
  export type HttpApiOperationResult = typeof HttpApiOperationResult.Type;
20
20
  export declare const encodeHttpApiOperationResult: (result: unknown) => Effect.Effect<string | number | boolean | Schema.JsonArray | Schema.JsonObject | null, Error, never>;
21
+ export declare const makeHttpApiOperationResultEncoder: <Id extends string, Groups extends HttpApiGroup.Constraint>(api: HttpApi.HttpApi<Id, Groups>) => (result: unknown, operation: HttpApiOperationEntry) => Effect.Effect<string | number | boolean | Schema.JsonArray | Schema.JsonObject | null, Error, never>;
21
22
  export type ApiClientService = {
22
23
  readonly encodeResult: (result: ErrorOptions["cause"], operation: HttpApiOperationEntry) => Effect.Effect<Json, Error>;
23
24
  readonly execute: (options: ApiClientExecuteOptions) => Effect.Effect<ErrorOptions["cause"], Error>;
@@ -1,11 +1,20 @@
1
1
  // ../../src/lib/httpapi-client.ts
2
- import { Context, Effect, Layer, Schema } from "effect";
2
+ import { Context, Effect, Layer, Schema, SchemaTransformation } from "effect";
3
3
  import { HttpClient } from "effect/unstable/http";
4
4
  import {
5
- HttpApiClient as EffectHttpApiClient
5
+ HttpApi,
6
+ HttpApiClient as EffectHttpApiClient,
7
+ OpenApi
6
8
  } from "effect/unstable/httpapi";
9
+ var UndefinedFromNull = Schema.Null.pipe(Schema.decodeTo(Schema.Undefined, SchemaTransformation.transform({
10
+ decode: () => {
11
+ return;
12
+ },
13
+ encode: () => null
14
+ })));
7
15
  var HttpApiOperationResultValue = Schema.suspend(() => Schema.Union([
8
16
  Schema.Null,
17
+ UndefinedFromNull,
9
18
  Schema.String,
10
19
  Schema.Number,
11
20
  Schema.Boolean,
@@ -19,6 +28,37 @@ var HttpApiOperationResult = Schema.Union([
19
28
  Schema.Undefined
20
29
  ]).annotate({ identifier: "HttpApiOperationResult" });
21
30
  var encodeHttpApiOperationResult = Effect.fn("HttpApiClient.encodeOperationResult")((result) => Schema.encodeUnknownEffect(HttpApiOperationResult)(result).pipe(Effect.map((encoded) => encoded ?? null), Effect.mapError((cause) => new Error("HTTP API result is not serializable", { cause }))));
31
+ var reflectedSchema = (schema) => Schema.make(schema.ast);
32
+ var operationResultSchemas = (api) => {
33
+ const schemas = new Map;
34
+ HttpApi.reflect(api, {
35
+ onGroup: () => {
36
+ return;
37
+ },
38
+ onEndpoint: ({ endpoint, group, successes }) => {
39
+ const operationId = Context.getOrElse(endpoint.annotations, OpenApi.Identifier, () => group.topLevel ? endpoint.identifier : `${group.identifier}.${endpoint.identifier}`);
40
+ const operationSchemas = Array.from(successes.values()).flat().map(reflectedSchema);
41
+ if (operationSchemas.length === 1 && operationSchemas[0]) {
42
+ schemas.set(operationId, operationSchemas[0]);
43
+ } else if (operationSchemas.length > 1) {
44
+ schemas.set(operationId, Schema.Union(operationSchemas));
45
+ }
46
+ }
47
+ });
48
+ return schemas;
49
+ };
50
+ var makeHttpApiOperationResultEncoder = (api) => {
51
+ const schemas = operationResultSchemas(api);
52
+ return Effect.fn("HttpApiClient.encodeOperationResultWithSchema")((result, operation) => {
53
+ const operationId = operation.operation.operationId;
54
+ const schema = operationId ? schemas.get(operationId) : undefined;
55
+ if (!schema)
56
+ return encodeHttpApiOperationResult(result);
57
+ return Schema.encodeUnknownEffect(schema)(result).pipe(Effect.flatMap(encodeHttpApiOperationResult), Effect.mapError((cause) => new Error("HTTP API result does not match its success schema", {
58
+ cause
59
+ })));
60
+ });
61
+ };
22
62
  var GeneratedOperation = Schema.declare((value) => value instanceof Function).annotate({ identifier: "GeneratedOperation" });
23
63
  var GeneratedOperationEffect = Schema.declare((value) => Effect.isEffect(value)).annotate({ identifier: "GeneratedOperationEffect" });
24
64
  var makeGeneratedClient = (api, http, baseUrl) => EffectHttpApiClient.makeWith(api, {
@@ -54,9 +94,10 @@ var executeGeneratedOperation = Effect.fn("HttpApiClient.executeGeneratedOperati
54
94
  class ApiClient extends Context.Service()("ApiClient") {
55
95
  static layer = (config) => Layer.effect(this, Effect.gen(function* () {
56
96
  const http = yield* HttpClient.HttpClient;
97
+ const encodeResult = makeHttpApiOperationResultEncoder(config.api);
57
98
  const client = yield* makeGeneratedClient(config.api, http, config.baseUrl);
58
99
  return {
59
- encodeResult: config.encodeResult ?? ((result) => encodeHttpApiOperationResult(result)),
100
+ encodeResult: config.encodeResult ?? ((result, operation) => encodeResult(result, operation)),
60
101
  execute: Effect.fn("ApiClient.execute")(function* (options) {
61
102
  return yield* executeGeneratedOperation(client, options);
62
103
  })
@@ -64,6 +105,7 @@ class ApiClient extends Context.Service()("ApiClient") {
64
105
  }));
65
106
  }
66
107
  export {
108
+ makeHttpApiOperationResultEncoder,
67
109
  encodeHttpApiOperationResult,
68
110
  HttpApiOperationResult,
69
111
  ApiClient
@@ -3,13 +3,22 @@ import { Context as Context3, Effect as Effect3, Layer as Layer3, Option as Opti
3
3
  import { McpSchema, McpServer } from "effect/unstable/ai";
4
4
 
5
5
  // ../../src/lib/httpapi-client.ts
6
- import { Context, Effect, Layer, Schema } from "effect";
6
+ import { Context, Effect, Layer, Schema, SchemaTransformation } from "effect";
7
7
  import { HttpClient } from "effect/unstable/http";
8
8
  import {
9
- HttpApiClient as EffectHttpApiClient
9
+ HttpApi,
10
+ HttpApiClient as EffectHttpApiClient,
11
+ OpenApi
10
12
  } from "effect/unstable/httpapi";
13
+ var UndefinedFromNull = Schema.Null.pipe(Schema.decodeTo(Schema.Undefined, SchemaTransformation.transform({
14
+ decode: () => {
15
+ return;
16
+ },
17
+ encode: () => null
18
+ })));
11
19
  var HttpApiOperationResultValue = Schema.suspend(() => Schema.Union([
12
20
  Schema.Null,
21
+ UndefinedFromNull,
13
22
  Schema.String,
14
23
  Schema.Number,
15
24
  Schema.Boolean,
@@ -23,6 +32,37 @@ var HttpApiOperationResult = Schema.Union([
23
32
  Schema.Undefined
24
33
  ]).annotate({ identifier: "HttpApiOperationResult" });
25
34
  var encodeHttpApiOperationResult = Effect.fn("HttpApiClient.encodeOperationResult")((result) => Schema.encodeUnknownEffect(HttpApiOperationResult)(result).pipe(Effect.map((encoded) => encoded ?? null), Effect.mapError((cause) => new Error("HTTP API result is not serializable", { cause }))));
35
+ var reflectedSchema = (schema) => Schema.make(schema.ast);
36
+ var operationResultSchemas = (api) => {
37
+ const schemas = new Map;
38
+ HttpApi.reflect(api, {
39
+ onGroup: () => {
40
+ return;
41
+ },
42
+ onEndpoint: ({ endpoint, group, successes }) => {
43
+ const operationId = Context.getOrElse(endpoint.annotations, OpenApi.Identifier, () => group.topLevel ? endpoint.identifier : `${group.identifier}.${endpoint.identifier}`);
44
+ const operationSchemas = Array.from(successes.values()).flat().map(reflectedSchema);
45
+ if (operationSchemas.length === 1 && operationSchemas[0]) {
46
+ schemas.set(operationId, operationSchemas[0]);
47
+ } else if (operationSchemas.length > 1) {
48
+ schemas.set(operationId, Schema.Union(operationSchemas));
49
+ }
50
+ }
51
+ });
52
+ return schemas;
53
+ };
54
+ var makeHttpApiOperationResultEncoder = (api) => {
55
+ const schemas = operationResultSchemas(api);
56
+ return Effect.fn("HttpApiClient.encodeOperationResultWithSchema")((result, operation) => {
57
+ const operationId = operation.operation.operationId;
58
+ const schema = operationId ? schemas.get(operationId) : undefined;
59
+ if (!schema)
60
+ return encodeHttpApiOperationResult(result);
61
+ return Schema.encodeUnknownEffect(schema)(result).pipe(Effect.flatMap(encodeHttpApiOperationResult), Effect.mapError((cause) => new Error("HTTP API result does not match its success schema", {
62
+ cause
63
+ })));
64
+ });
65
+ };
26
66
  var GeneratedOperation = Schema.declare((value) => value instanceof Function).annotate({ identifier: "GeneratedOperation" });
27
67
  var GeneratedOperationEffect = Schema.declare((value) => Effect.isEffect(value)).annotate({ identifier: "GeneratedOperationEffect" });
28
68
  var makeGeneratedClient = (api, http, baseUrl) => EffectHttpApiClient.makeWith(api, {
@@ -58,9 +98,10 @@ var executeGeneratedOperation = Effect.fn("HttpApiClient.executeGeneratedOperati
58
98
  class ApiClient extends Context.Service()("ApiClient") {
59
99
  static layer = (config) => Layer.effect(this, Effect.gen(function* () {
60
100
  const http = yield* HttpClient.HttpClient;
101
+ const encodeResult = makeHttpApiOperationResultEncoder(config.api);
61
102
  const client = yield* makeGeneratedClient(config.api, http, config.baseUrl);
62
103
  return {
63
- encodeResult: config.encodeResult ?? ((result) => encodeHttpApiOperationResult(result)),
104
+ encodeResult: config.encodeResult ?? ((result, operation) => encodeResult(result, operation)),
64
105
  execute: Effect.fn("ApiClient.execute")(function* (options) {
65
106
  return yield* executeGeneratedOperation(client, options);
66
107
  })
@@ -78,7 +119,7 @@ import {
78
119
  Schema as Schema2,
79
120
  SchemaRepresentation
80
121
  } from "effect";
81
- import { HttpApi as HttpApi2, OpenApi } from "effect/unstable/httpapi";
122
+ import { HttpApi as HttpApi2, OpenApi as OpenApi2 } from "effect/unstable/httpapi";
82
123
  var JsonObjectSchema = Schema2.Record(Schema2.String, Schema2.Json).annotate({
83
124
  identifier: "HttpJsonObject",
84
125
  title: "HTTP JSON object",
@@ -251,7 +292,7 @@ var decodeHttpApiOperationInput = Effect2.fn("Http.decodeApiOperationInput")(fun
251
292
  query: pickParameters("query")
252
293
  };
253
294
  });
254
- var reflectedSchema = (schema) => Schema2.make(schema.ast);
295
+ var reflectedSchema2 = (schema) => Schema2.make(schema.ast);
255
296
  var reflectedOperationInputSchemas = (api) => {
256
297
  const schemas = new Map;
257
298
  HttpApi2.reflect(api, {
@@ -259,17 +300,17 @@ var reflectedOperationInputSchemas = (api) => {
259
300
  return;
260
301
  },
261
302
  onEndpoint: ({ endpoint, group }) => {
262
- const operationId = Context2.getOrElse(endpoint.annotations, OpenApi.Identifier, () => group.topLevel ? endpoint.identifier : `${group.identifier}.${endpoint.identifier}`);
303
+ const operationId = Context2.getOrElse(endpoint.annotations, OpenApi2.Identifier, () => group.topLevel ? endpoint.identifier : `${group.identifier}.${endpoint.identifier}`);
263
304
  const fields = {};
264
305
  if (endpoint.params)
265
- fields.params = reflectedSchema(endpoint.params);
306
+ fields.params = reflectedSchema2(endpoint.params);
266
307
  if (endpoint.query) {
267
- fields.query = Schema2.optionalKey(reflectedSchema(endpoint.query));
308
+ fields.query = Schema2.optionalKey(reflectedSchema2(endpoint.query));
268
309
  }
269
310
  if (endpoint.headers) {
270
- fields.headers = Schema2.optionalKey(reflectedSchema(endpoint.headers));
311
+ fields.headers = Schema2.optionalKey(reflectedSchema2(endpoint.headers));
271
312
  }
272
- const payloadSchemas = Array.from(endpoint.payload.values()).flatMap(({ schemas: schemas2 }) => schemas2.map(reflectedSchema));
313
+ const payloadSchemas = Array.from(endpoint.payload.values()).flatMap(({ schemas: schemas2 }) => schemas2.map(reflectedSchema2));
273
314
  if (payloadSchemas.length === 1 && payloadSchemas[0]) {
274
315
  fields.body = payloadSchemas[0];
275
316
  } else if (payloadSchemas.length > 1) {
@@ -301,7 +342,7 @@ class HttpApiSpec extends Context2.Service()("HttpApiSpec", {
301
342
  if (!HttpApi2.isHttpApi(api)) {
302
343
  throw new Error("HttpApiSpec requires a valid HttpApi");
303
344
  }
304
- const spec = OpenApi.fromApi(api);
345
+ const spec = OpenApi2.fromApi(api);
305
346
  const reflectedSchemas = reflectedOperationInputSchemas(api);
306
347
  const operations = httpApiOperations({
307
348
  spec,
@@ -3,13 +3,22 @@ import { Effect as Effect3, Layer as Layer3, Schema as Schema3 } from "effect";
3
3
  import { Tool, Toolkit } from "effect/unstable/ai";
4
4
 
5
5
  // ../../src/lib/httpapi-client.ts
6
- import { Context, Effect, Layer, Schema } from "effect";
6
+ import { Context, Effect, Layer, Schema, SchemaTransformation } from "effect";
7
7
  import { HttpClient } from "effect/unstable/http";
8
8
  import {
9
- HttpApiClient as EffectHttpApiClient
9
+ HttpApi,
10
+ HttpApiClient as EffectHttpApiClient,
11
+ OpenApi
10
12
  } from "effect/unstable/httpapi";
13
+ var UndefinedFromNull = Schema.Null.pipe(Schema.decodeTo(Schema.Undefined, SchemaTransformation.transform({
14
+ decode: () => {
15
+ return;
16
+ },
17
+ encode: () => null
18
+ })));
11
19
  var HttpApiOperationResultValue = Schema.suspend(() => Schema.Union([
12
20
  Schema.Null,
21
+ UndefinedFromNull,
13
22
  Schema.String,
14
23
  Schema.Number,
15
24
  Schema.Boolean,
@@ -23,6 +32,37 @@ var HttpApiOperationResult = Schema.Union([
23
32
  Schema.Undefined
24
33
  ]).annotate({ identifier: "HttpApiOperationResult" });
25
34
  var encodeHttpApiOperationResult = Effect.fn("HttpApiClient.encodeOperationResult")((result) => Schema.encodeUnknownEffect(HttpApiOperationResult)(result).pipe(Effect.map((encoded) => encoded ?? null), Effect.mapError((cause) => new Error("HTTP API result is not serializable", { cause }))));
35
+ var reflectedSchema = (schema) => Schema.make(schema.ast);
36
+ var operationResultSchemas = (api) => {
37
+ const schemas = new Map;
38
+ HttpApi.reflect(api, {
39
+ onGroup: () => {
40
+ return;
41
+ },
42
+ onEndpoint: ({ endpoint, group, successes }) => {
43
+ const operationId = Context.getOrElse(endpoint.annotations, OpenApi.Identifier, () => group.topLevel ? endpoint.identifier : `${group.identifier}.${endpoint.identifier}`);
44
+ const operationSchemas = Array.from(successes.values()).flat().map(reflectedSchema);
45
+ if (operationSchemas.length === 1 && operationSchemas[0]) {
46
+ schemas.set(operationId, operationSchemas[0]);
47
+ } else if (operationSchemas.length > 1) {
48
+ schemas.set(operationId, Schema.Union(operationSchemas));
49
+ }
50
+ }
51
+ });
52
+ return schemas;
53
+ };
54
+ var makeHttpApiOperationResultEncoder = (api) => {
55
+ const schemas = operationResultSchemas(api);
56
+ return Effect.fn("HttpApiClient.encodeOperationResultWithSchema")((result, operation) => {
57
+ const operationId = operation.operation.operationId;
58
+ const schema = operationId ? schemas.get(operationId) : undefined;
59
+ if (!schema)
60
+ return encodeHttpApiOperationResult(result);
61
+ return Schema.encodeUnknownEffect(schema)(result).pipe(Effect.flatMap(encodeHttpApiOperationResult), Effect.mapError((cause) => new Error("HTTP API result does not match its success schema", {
62
+ cause
63
+ })));
64
+ });
65
+ };
26
66
  var GeneratedOperation = Schema.declare((value) => value instanceof Function).annotate({ identifier: "GeneratedOperation" });
27
67
  var GeneratedOperationEffect = Schema.declare((value) => Effect.isEffect(value)).annotate({ identifier: "GeneratedOperationEffect" });
28
68
  var makeGeneratedClient = (api, http, baseUrl) => EffectHttpApiClient.makeWith(api, {
@@ -58,9 +98,10 @@ var executeGeneratedOperation = Effect.fn("HttpApiClient.executeGeneratedOperati
58
98
  class ApiClient extends Context.Service()("ApiClient") {
59
99
  static layer = (config) => Layer.effect(this, Effect.gen(function* () {
60
100
  const http = yield* HttpClient.HttpClient;
101
+ const encodeResult = makeHttpApiOperationResultEncoder(config.api);
61
102
  const client = yield* makeGeneratedClient(config.api, http, config.baseUrl);
62
103
  return {
63
- encodeResult: config.encodeResult ?? ((result) => encodeHttpApiOperationResult(result)),
104
+ encodeResult: config.encodeResult ?? ((result, operation) => encodeResult(result, operation)),
64
105
  execute: Effect.fn("ApiClient.execute")(function* (options) {
65
106
  return yield* executeGeneratedOperation(client, options);
66
107
  })
@@ -78,7 +119,7 @@ import {
78
119
  Schema as Schema2,
79
120
  SchemaRepresentation
80
121
  } from "effect";
81
- import { HttpApi as HttpApi2, OpenApi } from "effect/unstable/httpapi";
122
+ import { HttpApi as HttpApi2, OpenApi as OpenApi2 } from "effect/unstable/httpapi";
82
123
  var JsonObjectSchema = Schema2.Record(Schema2.String, Schema2.Json).annotate({
83
124
  identifier: "HttpJsonObject",
84
125
  title: "HTTP JSON object",
@@ -251,7 +292,7 @@ var decodeHttpApiOperationInput = Effect2.fn("Http.decodeApiOperationInput")(fun
251
292
  query: pickParameters("query")
252
293
  };
253
294
  });
254
- var reflectedSchema = (schema) => Schema2.make(schema.ast);
295
+ var reflectedSchema2 = (schema) => Schema2.make(schema.ast);
255
296
  var reflectedOperationInputSchemas = (api) => {
256
297
  const schemas = new Map;
257
298
  HttpApi2.reflect(api, {
@@ -259,17 +300,17 @@ var reflectedOperationInputSchemas = (api) => {
259
300
  return;
260
301
  },
261
302
  onEndpoint: ({ endpoint, group }) => {
262
- const operationId = Context2.getOrElse(endpoint.annotations, OpenApi.Identifier, () => group.topLevel ? endpoint.identifier : `${group.identifier}.${endpoint.identifier}`);
303
+ const operationId = Context2.getOrElse(endpoint.annotations, OpenApi2.Identifier, () => group.topLevel ? endpoint.identifier : `${group.identifier}.${endpoint.identifier}`);
263
304
  const fields = {};
264
305
  if (endpoint.params)
265
- fields.params = reflectedSchema(endpoint.params);
306
+ fields.params = reflectedSchema2(endpoint.params);
266
307
  if (endpoint.query) {
267
- fields.query = Schema2.optionalKey(reflectedSchema(endpoint.query));
308
+ fields.query = Schema2.optionalKey(reflectedSchema2(endpoint.query));
268
309
  }
269
310
  if (endpoint.headers) {
270
- fields.headers = Schema2.optionalKey(reflectedSchema(endpoint.headers));
311
+ fields.headers = Schema2.optionalKey(reflectedSchema2(endpoint.headers));
271
312
  }
272
- const payloadSchemas = Array.from(endpoint.payload.values()).flatMap(({ schemas: schemas2 }) => schemas2.map(reflectedSchema));
313
+ const payloadSchemas = Array.from(endpoint.payload.values()).flatMap(({ schemas: schemas2 }) => schemas2.map(reflectedSchema2));
273
314
  if (payloadSchemas.length === 1 && payloadSchemas[0]) {
274
315
  fields.body = payloadSchemas[0];
275
316
  } else if (payloadSchemas.length > 1) {
@@ -301,7 +342,7 @@ class HttpApiSpec extends Context2.Service()("HttpApiSpec", {
301
342
  if (!HttpApi2.isHttpApi(api)) {
302
343
  throw new Error("HttpApiSpec requires a valid HttpApi");
303
344
  }
304
- const spec = OpenApi.fromApi(api);
345
+ const spec = OpenApi2.fromApi(api);
305
346
  const reflectedSchemas = reflectedOperationInputSchemas(api);
306
347
  const operations = httpApiOperations({
307
348
  spec,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@krak-stack/registry",
3
- "version": "0.1.16",
3
+ "version": "0.1.18",
4
4
  "description": "Tree-shakable KrakStack components and Effect services.",
5
5
  "license": "MIT",
6
6
  "repository": {