@krak-stack/registry 0.1.17 → 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.
- package/dist/lib/httpapi-cli.d.ts +2 -1
- package/dist/lib/httpapi-cli.js +65 -15
- package/dist/lib/httpapi-client.d.ts +2 -1
- package/dist/lib/httpapi-client.js +45 -3
- package/dist/lib/httpapi-mcp.js +52 -11
- package/dist/lib/httpapi-toolkit.js +52 -11
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
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
4
|
import { ApiClient, type ApiClientService } from "./httpapi-client.js";
|
|
@@ -19,5 +19,6 @@ export declare const printHttpApiCliResult: (response: unknown, operation: HttpA
|
|
|
19
19
|
export declare const makeHttpApiCliCommand: () => Effect.Effect<Command.Command<string, {}, {}, unknown, never>, never, ApiClient | HttpApiSpec>;
|
|
20
20
|
export declare const httpApiCliEnvironmentLayer: (args: ReadonlyArray<string>) => Layer.Layer<ChildProcessSpawner | FileSystem.FileSystem | Path.Path | Stdio.Stdio | Terminal.Terminal, never, never>;
|
|
21
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;
|
|
22
23
|
export declare const runHttpApiCli: <E>(layer: Layer.Layer<HttpApiCli, E>, args?: string[]) => void;
|
|
23
24
|
export {};
|
package/dist/lib/httpapi-cli.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
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,
|
|
@@ -15,13 +17,22 @@ import { Command, Flag } from "effect/unstable/cli";
|
|
|
15
17
|
import { ChildProcessSpawner } from "effect/unstable/process/ChildProcessSpawner";
|
|
16
18
|
|
|
17
19
|
// ../../src/lib/httpapi-client.ts
|
|
18
|
-
import { Context, Effect, Layer, Schema } from "effect";
|
|
20
|
+
import { Context, Effect, Layer, Schema, SchemaTransformation } from "effect";
|
|
19
21
|
import { HttpClient } from "effect/unstable/http";
|
|
20
22
|
import {
|
|
21
|
-
|
|
23
|
+
HttpApi,
|
|
24
|
+
HttpApiClient as EffectHttpApiClient,
|
|
25
|
+
OpenApi
|
|
22
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
|
+
})));
|
|
23
33
|
var HttpApiOperationResultValue = Schema.suspend(() => Schema.Union([
|
|
24
34
|
Schema.Null,
|
|
35
|
+
UndefinedFromNull,
|
|
25
36
|
Schema.String,
|
|
26
37
|
Schema.Number,
|
|
27
38
|
Schema.Boolean,
|
|
@@ -35,6 +46,37 @@ var HttpApiOperationResult = Schema.Union([
|
|
|
35
46
|
Schema.Undefined
|
|
36
47
|
]).annotate({ identifier: "HttpApiOperationResult" });
|
|
37
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
|
+
};
|
|
38
80
|
var GeneratedOperation = Schema.declare((value) => value instanceof Function).annotate({ identifier: "GeneratedOperation" });
|
|
39
81
|
var GeneratedOperationEffect = Schema.declare((value) => Effect.isEffect(value)).annotate({ identifier: "GeneratedOperationEffect" });
|
|
40
82
|
var makeGeneratedClient = (api, http, baseUrl) => EffectHttpApiClient.makeWith(api, {
|
|
@@ -70,9 +112,10 @@ var executeGeneratedOperation = Effect.fn("HttpApiClient.executeGeneratedOperati
|
|
|
70
112
|
class ApiClient extends Context.Service()("ApiClient") {
|
|
71
113
|
static layer = (config) => Layer.effect(this, Effect.gen(function* () {
|
|
72
114
|
const http = yield* HttpClient.HttpClient;
|
|
115
|
+
const encodeResult = makeHttpApiOperationResultEncoder(config.api);
|
|
73
116
|
const client = yield* makeGeneratedClient(config.api, http, config.baseUrl);
|
|
74
117
|
return {
|
|
75
|
-
encodeResult: config.encodeResult ?? ((result) =>
|
|
118
|
+
encodeResult: config.encodeResult ?? ((result, operation) => encodeResult(result, operation)),
|
|
76
119
|
execute: Effect.fn("ApiClient.execute")(function* (options) {
|
|
77
120
|
return yield* executeGeneratedOperation(client, options);
|
|
78
121
|
})
|
|
@@ -90,7 +133,7 @@ import {
|
|
|
90
133
|
Schema as Schema2,
|
|
91
134
|
SchemaRepresentation
|
|
92
135
|
} from "effect";
|
|
93
|
-
import { HttpApi as HttpApi2, OpenApi } from "effect/unstable/httpapi";
|
|
136
|
+
import { HttpApi as HttpApi2, OpenApi as OpenApi2 } from "effect/unstable/httpapi";
|
|
94
137
|
var JsonObjectSchema = Schema2.Record(Schema2.String, Schema2.Json).annotate({
|
|
95
138
|
identifier: "HttpJsonObject",
|
|
96
139
|
title: "HTTP JSON object",
|
|
@@ -263,7 +306,7 @@ var decodeHttpApiOperationInput = Effect2.fn("Http.decodeApiOperationInput")(fun
|
|
|
263
306
|
query: pickParameters("query")
|
|
264
307
|
};
|
|
265
308
|
});
|
|
266
|
-
var
|
|
309
|
+
var reflectedSchema2 = (schema) => Schema2.make(schema.ast);
|
|
267
310
|
var reflectedOperationInputSchemas = (api) => {
|
|
268
311
|
const schemas = new Map;
|
|
269
312
|
HttpApi2.reflect(api, {
|
|
@@ -271,17 +314,17 @@ var reflectedOperationInputSchemas = (api) => {
|
|
|
271
314
|
return;
|
|
272
315
|
},
|
|
273
316
|
onEndpoint: ({ endpoint, group }) => {
|
|
274
|
-
const operationId = Context2.getOrElse(endpoint.annotations,
|
|
317
|
+
const operationId = Context2.getOrElse(endpoint.annotations, OpenApi2.Identifier, () => group.topLevel ? endpoint.identifier : `${group.identifier}.${endpoint.identifier}`);
|
|
275
318
|
const fields = {};
|
|
276
319
|
if (endpoint.params)
|
|
277
|
-
fields.params =
|
|
320
|
+
fields.params = reflectedSchema2(endpoint.params);
|
|
278
321
|
if (endpoint.query) {
|
|
279
|
-
fields.query = Schema2.optionalKey(
|
|
322
|
+
fields.query = Schema2.optionalKey(reflectedSchema2(endpoint.query));
|
|
280
323
|
}
|
|
281
324
|
if (endpoint.headers) {
|
|
282
|
-
fields.headers = Schema2.optionalKey(
|
|
325
|
+
fields.headers = Schema2.optionalKey(reflectedSchema2(endpoint.headers));
|
|
283
326
|
}
|
|
284
|
-
const payloadSchemas = Array.from(endpoint.payload.values()).flatMap(({ schemas: schemas2 }) => schemas2.map(
|
|
327
|
+
const payloadSchemas = Array.from(endpoint.payload.values()).flatMap(({ schemas: schemas2 }) => schemas2.map(reflectedSchema2));
|
|
285
328
|
if (payloadSchemas.length === 1 && payloadSchemas[0]) {
|
|
286
329
|
fields.body = payloadSchemas[0];
|
|
287
330
|
} else if (payloadSchemas.length > 1) {
|
|
@@ -313,7 +356,7 @@ class HttpApiSpec extends Context2.Service()("HttpApiSpec", {
|
|
|
313
356
|
if (!HttpApi2.isHttpApi(api)) {
|
|
314
357
|
throw new Error("HttpApiSpec requires a valid HttpApi");
|
|
315
358
|
}
|
|
316
|
-
const spec =
|
|
359
|
+
const spec = OpenApi2.fromApi(api);
|
|
317
360
|
const reflectedSchemas = reflectedOperationInputSchemas(api);
|
|
318
361
|
const operations = httpApiOperations({
|
|
319
362
|
spec,
|
|
@@ -477,11 +520,17 @@ var httpApiCli = (args = process.argv.slice(2)) => Effect3.gen(function* () {
|
|
|
477
520
|
const cli = yield* HttpApiCli;
|
|
478
521
|
return yield* cli.run(args);
|
|
479
522
|
});
|
|
523
|
+
var formatHttpApiCliCause = Cause.pretty;
|
|
480
524
|
var runHttpApiCli = (layer, args = process.argv.slice(2)) => {
|
|
481
|
-
Effect3.
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
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
|
+
}));
|
|
485
534
|
};
|
|
486
535
|
export {
|
|
487
536
|
runHttpApiCli,
|
|
@@ -489,5 +538,6 @@ export {
|
|
|
489
538
|
makeHttpApiCliCommand,
|
|
490
539
|
httpApiCliEnvironmentLayer,
|
|
491
540
|
httpApiCli,
|
|
541
|
+
formatHttpApiCliCause,
|
|
492
542
|
HttpApiCli
|
|
493
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
|
-
|
|
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) =>
|
|
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
|
package/dist/lib/httpapi-mcp.js
CHANGED
|
@@ -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
|
-
|
|
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) =>
|
|
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
|
|
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,
|
|
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 =
|
|
306
|
+
fields.params = reflectedSchema2(endpoint.params);
|
|
266
307
|
if (endpoint.query) {
|
|
267
|
-
fields.query = Schema2.optionalKey(
|
|
308
|
+
fields.query = Schema2.optionalKey(reflectedSchema2(endpoint.query));
|
|
268
309
|
}
|
|
269
310
|
if (endpoint.headers) {
|
|
270
|
-
fields.headers = Schema2.optionalKey(
|
|
311
|
+
fields.headers = Schema2.optionalKey(reflectedSchema2(endpoint.headers));
|
|
271
312
|
}
|
|
272
|
-
const payloadSchemas = Array.from(endpoint.payload.values()).flatMap(({ schemas: schemas2 }) => schemas2.map(
|
|
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 =
|
|
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
|
-
|
|
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) =>
|
|
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
|
|
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,
|
|
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 =
|
|
306
|
+
fields.params = reflectedSchema2(endpoint.params);
|
|
266
307
|
if (endpoint.query) {
|
|
267
|
-
fields.query = Schema2.optionalKey(
|
|
308
|
+
fields.query = Schema2.optionalKey(reflectedSchema2(endpoint.query));
|
|
268
309
|
}
|
|
269
310
|
if (endpoint.headers) {
|
|
270
|
-
fields.headers = Schema2.optionalKey(
|
|
311
|
+
fields.headers = Schema2.optionalKey(reflectedSchema2(endpoint.headers));
|
|
271
312
|
}
|
|
272
|
-
const payloadSchemas = Array.from(endpoint.payload.values()).flatMap(({ schemas: schemas2 }) => schemas2.map(
|
|
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 =
|
|
345
|
+
const spec = OpenApi2.fromApi(api);
|
|
305
346
|
const reflectedSchemas = reflectedOperationInputSchemas(api);
|
|
306
347
|
const operations = httpApiOperations({
|
|
307
348
|
spec,
|