@krak-stack/registry 0.1.2 → 0.1.4

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.
Files changed (50) hide show
  1. package/README.md +17 -1
  2. package/dist/components/ui/alert.d.ts +10 -0
  3. package/dist/components/ui/app-brand.js +20 -20
  4. package/dist/components/ui/bubble.d.ts +16 -0
  5. package/dist/components/ui/code-block.js +38 -38
  6. package/dist/components/ui/collapsible.d.ts +5 -0
  7. package/dist/components/ui/copy-button.js +16 -16
  8. package/dist/components/ui/data-table.js +687 -687
  9. package/dist/components/ui/editing-locale-switcher.js +54 -54
  10. package/dist/components/ui/effect-form.js +490 -490
  11. package/dist/components/ui/empty.d.ts +11 -0
  12. package/dist/components/ui/file-picker.js +96 -96
  13. package/dist/components/ui/form.js +418 -418
  14. package/dist/components/ui/google-map.js +27 -27
  15. package/dist/components/ui/icon-input.js +93 -93
  16. package/dist/components/ui/loading.js +5 -5
  17. package/dist/components/ui/locale-switcher.js +48 -48
  18. package/dist/components/ui/marker.d.ts +10 -0
  19. package/dist/components/ui/message-scroller.d.ts +10 -0
  20. package/dist/components/ui/message.d.ts +10 -0
  21. package/dist/components/ui/pagination.js +92 -92
  22. package/dist/components/ui/search-menu.js +93 -93
  23. package/dist/components/ui/sidebar-layout.js +156 -156
  24. package/dist/components/ui/stats-card.js +28 -28
  25. package/dist/components/ui/theme-switcher.js +64 -64
  26. package/dist/components/ui/virtualized-combobox.js +66 -66
  27. package/dist/lib/docs-ai.d.ts +136 -0
  28. package/dist/lib/docs-ai.js +310 -0
  29. package/dist/lib/docs-core.d.ts +681 -0
  30. package/dist/lib/docs-core.js +2571 -0
  31. package/dist/lib/httpapi-ai.d.ts +54 -0
  32. package/dist/lib/httpapi-ai.js +361 -0
  33. package/dist/lib/httpapi-cli.d.ts +22 -0
  34. package/dist/lib/httpapi-cli.js +412 -0
  35. package/dist/lib/httpapi-client.d.ts +20 -0
  36. package/dist/lib/httpapi-client.js +50 -0
  37. package/dist/lib/httpapi-helpers.d.ts +105 -0
  38. package/dist/lib/httpapi-helpers.js +237 -0
  39. package/dist/lib/httpapi-mcp.d.ts +20 -0
  40. package/dist/lib/httpapi-mcp.js +366 -0
  41. package/dist/lib/query.js +128 -0
  42. package/dist/services/agent/client/atom.d.ts +56 -0
  43. package/dist/services/agent/client/index.d.ts +2 -0
  44. package/dist/services/agent/client/index.js +2239 -0
  45. package/dist/services/agent/client/widget.d.ts +52 -0
  46. package/dist/services/agent/index.d.ts +111 -0
  47. package/dist/services/agent/index.js +190 -0
  48. package/dist/services/agent/schema.d.ts +161 -0
  49. package/dist/services/agent/schema.js +135 -0
  50. package/package.json +59 -3
@@ -0,0 +1,412 @@
1
+ // ../../src/lib/httpapi-cli.ts
2
+ import {
3
+ Console,
4
+ Context as Context3,
5
+ Effect as Effect3,
6
+ FileSystem,
7
+ Layer as Layer3,
8
+ Path,
9
+ Stdio,
10
+ Stream,
11
+ Terminal
12
+ } from "effect";
13
+ import { Command, Flag } from "effect/unstable/cli";
14
+ import { ChildProcessSpawner } from "effect/unstable/process/ChildProcessSpawner";
15
+
16
+ // ../../src/lib/httpapi-client.ts
17
+ import { Context, Effect, Layer } from "effect";
18
+ import { HttpClient } from "effect/unstable/http";
19
+ import {
20
+ HttpApiClient as EffectHttpApiClient
21
+ } from "effect/unstable/httpapi";
22
+ var makeGeneratedClient = (api, http, baseUrl) => EffectHttpApiClient.makeWith(api, {
23
+ baseUrl,
24
+ httpClient: http
25
+ });
26
+ var isClientEffect = (value) => Effect.isEffect(value);
27
+ var executeGeneratedOperation = Effect.fn("HttpApiClient.executeGeneratedOperation")(function* (client, { input, operation: entry }) {
28
+ const operationId = entry.operation.operationId;
29
+ if (!operationId) {
30
+ return yield* Effect.fail(new Error(`No generated API client operation for ${entry.method} ${entry.path}`));
31
+ }
32
+ const target = Object(client);
33
+ const groupName = Object.keys(target).filter((name) => operationId.startsWith(`${name}.`)).sort((a, b) => b.length - a.length)[0];
34
+ const group = groupName ? Reflect.get(target, groupName) : target;
35
+ const endpointName = groupName ? operationId.slice(groupName.length + 1) : operationId;
36
+ const endpoint = Reflect.get(Object(group), endpointName);
37
+ if (typeof endpoint !== "function") {
38
+ return yield* Effect.fail(new Error(`No generated API client operation for ${operationId}`));
39
+ }
40
+ const result = endpoint({
41
+ headers: input.headers,
42
+ params: input.params,
43
+ query: input.query,
44
+ payload: input.body
45
+ });
46
+ if (!isClientEffect(result)) {
47
+ return yield* Effect.fail(new Error(`Generated API client operation ${operationId} is invalid`));
48
+ }
49
+ return yield* result;
50
+ });
51
+
52
+ class ApiClient extends Context.Service()("ApiClient") {
53
+ static layer = (config) => Layer.effect(this, Effect.gen(function* () {
54
+ const http = yield* HttpClient.HttpClient;
55
+ const client = yield* makeGeneratedClient(config.api, http, config.baseUrl);
56
+ return {
57
+ execute: Effect.fn("ApiClient.execute")(function* (options) {
58
+ return yield* executeGeneratedOperation(client, options);
59
+ })
60
+ };
61
+ }));
62
+ }
63
+
64
+ // ../../src/lib/httpapi-helpers.tsx
65
+ import {
66
+ Context as Context2,
67
+ Effect as Effect2,
68
+ JsonSchema,
69
+ Layer as Layer2,
70
+ Option,
71
+ Schema,
72
+ SchemaRepresentation
73
+ } from "effect";
74
+ import { HttpApi as HttpApi2, OpenApi } from "effect/unstable/httpapi";
75
+ var JsonObjectSchema = Schema.Record(Schema.String, Schema.Unknown).annotate({
76
+ identifier: "HttpJsonObject",
77
+ title: "HTTP JSON object",
78
+ description: "A JSON object passed to an HTTP API operation.",
79
+ examples: [{ id: "example-id" }]
80
+ });
81
+ var JsonObjectFromString = Schema.fromJsonString(JsonObjectSchema);
82
+ var JsonValueFromString = Schema.fromJsonString(Schema.Unknown);
83
+ var JsonSchemaAnnotations = Schema.Struct({
84
+ title: Schema.optional(Schema.String),
85
+ description: Schema.optional(Schema.String),
86
+ examples: Schema.optional(Schema.Array(Schema.Unknown))
87
+ }).annotate({
88
+ identifier: "HttpJsonSchemaAnnotations",
89
+ title: "HTTP JSON Schema annotations",
90
+ description: "JSON Schema annotations surfaced on generated tool inputs."
91
+ });
92
+ var HttpApiToolInputSchema = Schema.Struct({
93
+ body: Schema.optional(Schema.Unknown)
94
+ }).annotate({
95
+ identifier: "HttpApiToolInput",
96
+ title: "HTTP API tool input",
97
+ description: "Input accepted by an HTTP API-backed tool.",
98
+ examples: [{ body: { id: "example-id" } }]
99
+ });
100
+ var HttpApiMethods = [
101
+ "get",
102
+ "post",
103
+ "put",
104
+ "patch",
105
+ "delete"
106
+ ];
107
+ var toHttpError = (message, error) => new Error(message, { cause: error });
108
+ var sanitizeHttpName = (name) => name.replace(/[^a-zA-Z0-9_-]/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "");
109
+ var httpApiToolName = (method, path, operation) => {
110
+ const fallback = `${method}_${path.replace(/^\/api\//, "").replace(/[/:{}]/g, "_")}`;
111
+ return (operation.operationId || fallback).replace(/[^a-zA-Z0-9_-]/g, "_").replace(/_+/g, "_").slice(0, 64);
112
+ };
113
+ var httpApiOperations = ({
114
+ spec,
115
+ methods = HttpApiMethods
116
+ }) => {
117
+ const operations = [];
118
+ for (const [path, pathItem] of Object.entries(spec.paths)) {
119
+ for (const method of methods) {
120
+ const operation = pathItem[method];
121
+ if (operation)
122
+ operations.push({ method, path, operation });
123
+ }
124
+ }
125
+ return operations;
126
+ };
127
+ var httpApiToolEntries = Effect2.fn("Http.toolEntries")(function* (operations) {
128
+ return yield* Effect2.try({
129
+ try: () => {
130
+ const names = new Set;
131
+ return operations.map((entry) => {
132
+ const name = httpApiToolName(entry.method, entry.path, entry.operation);
133
+ if (!name || names.has(name)) {
134
+ throw new Error(`Duplicate or empty HTTP API tool name: ${name}`);
135
+ }
136
+ names.add(name);
137
+ return { ...entry, name };
138
+ });
139
+ },
140
+ catch: (error) => error instanceof Error ? error : new Error(String(error))
141
+ });
142
+ });
143
+ var decodeAnnotations = Schema.decodeUnknownOption(JsonSchemaAnnotations);
144
+ var schemaWithVisibleAnnotations = (schema) => {
145
+ const directAnnotations = decodeAnnotations(schema).pipe(Option.getOrElse(() => ({})));
146
+ const allOf = Array.isArray(schema.allOf) ? schema.allOf : [];
147
+ const annotations = allOf.reduce((acc, item) => ({
148
+ ...acc,
149
+ ...decodeAnnotations(item).pipe(Option.getOrElse(() => ({})))
150
+ }), directAnnotations);
151
+ return {
152
+ ...schema,
153
+ ..."title" in annotations && !("title" in schema) ? { title: annotations.title } : {},
154
+ ..."description" in annotations && !("description" in schema) ? { description: annotations.description } : {},
155
+ ..."examples" in annotations && !("examples" in schema) ? { examples: annotations.examples } : {}
156
+ };
157
+ };
158
+ var referencedDefinitions = (schema, definitions) => {
159
+ const names = new Set;
160
+ const pending = [schema];
161
+ while (pending.length > 0) {
162
+ const current = pending.pop();
163
+ if (!current || typeof current !== "object")
164
+ continue;
165
+ if (Array.isArray(current)) {
166
+ pending.push(...current);
167
+ continue;
168
+ }
169
+ for (const [key, value] of Object.entries(current)) {
170
+ if (key === "$ref" && typeof value === "string") {
171
+ const name = value.match(/^#\/(?:\$defs|components\/schemas)\/(.+)$/)?.[1];
172
+ if (name && !names.has(name) && definitions[name]) {
173
+ names.add(name);
174
+ pending.push(definitions[name]);
175
+ }
176
+ } else if (key !== "$defs") {
177
+ pending.push(value);
178
+ }
179
+ }
180
+ }
181
+ return Object.fromEntries([...names].map((name) => [name, definitions[name]]));
182
+ };
183
+ var operationParameters = (parameters, location) => parameters.filter((parameter) => parameter.in === location);
184
+ var httpApiOperationInputSchema = (operation) => {
185
+ const parameters = operation.parameters ?? [];
186
+ const pathParameters = operationParameters(parameters, "path");
187
+ const queryParameters = operationParameters(parameters, "query");
188
+ const headerParameters = operationParameters(parameters, "header");
189
+ const properties = {};
190
+ const required = [];
191
+ const body = operation.requestBody?.content?.["application/json"]?.schema;
192
+ for (const parameter of [
193
+ ...pathParameters,
194
+ ...queryParameters,
195
+ ...headerParameters
196
+ ]) {
197
+ properties[parameter.name] = {
198
+ ...parameter.schema ? schemaWithVisibleAnnotations(parameter.schema) : { type: "string" },
199
+ ...parameter.description ? { description: parameter.description } : {}
200
+ };
201
+ if (parameter.required)
202
+ required.push(parameter.name);
203
+ }
204
+ if (body) {
205
+ properties.body = body;
206
+ if (operation.requestBody?.required)
207
+ required.push("body");
208
+ }
209
+ return {
210
+ type: "object",
211
+ properties,
212
+ required,
213
+ additionalProperties: false
214
+ };
215
+ };
216
+ var decodeJsonObject = Schema.decodeUnknownOption(JsonObjectSchema);
217
+ var decodeHttpApiOperationInput = Effect2.fn("Http.decodeApiOperationInput")(function* (input, operation) {
218
+ const payload = yield* Schema.decodeUnknownEffect(JsonObjectSchema)(input ?? {}).pipe(Effect2.mapError(() => new Error("Tool input must be a JSON object")));
219
+ const decoded = yield* Schema.decodeUnknownEffect(HttpApiToolInputSchema)(payload).pipe(Effect2.mapError(() => new Error("Tool input must be a JSON object")));
220
+ const parameters = operation.parameters ?? [];
221
+ const pickParameters = (location) => {
222
+ const nestedKey = location === "path" ? "params" : location;
223
+ const nested = decodeJsonObject(payload[nestedKey]).pipe(Option.getOrElse(() => ({})));
224
+ return Object.fromEntries(operationParameters(parameters, location).map((parameter) => [
225
+ parameter.name,
226
+ nested[parameter.name] ?? payload[parameter.name]
227
+ ]).filter(([, value]) => value !== undefined));
228
+ };
229
+ return {
230
+ ...decoded,
231
+ headers: pickParameters("header"),
232
+ params: pickParameters("path"),
233
+ query: pickParameters("query")
234
+ };
235
+ });
236
+ var parseJsonObject = Effect2.fn("Http.parseJsonObject")(function* (value, label) {
237
+ if (!value)
238
+ return {};
239
+ return yield* Schema.decodeUnknownEffect(JsonObjectFromString)(value).pipe(Effect2.mapError(() => new Error(`${label} must be a JSON object`)));
240
+ });
241
+ var parseJsonValue = Effect2.fn("Http.parseJsonValue")(function* (value, label) {
242
+ if (!value)
243
+ return;
244
+ return yield* Schema.decodeUnknownEffect(JsonValueFromString)(value).pipe(Effect2.mapError(() => new Error(`${label} must be valid JSON`)));
245
+ });
246
+
247
+ class HttpApiSpec extends Context2.Service()("HttpApiSpec", {
248
+ make: (config) => Effect2.try({
249
+ try: () => {
250
+ if (!HttpApi2.isHttpApi(config.api)) {
251
+ throw new Error("HttpApiSpec requires a valid HttpApi");
252
+ }
253
+ const spec = OpenApi.fromApi(config.api);
254
+ const operations = httpApiOperations({
255
+ spec,
256
+ methods: config.methods
257
+ }).filter((operation) => config.include?.(operation) ?? true);
258
+ const operationJsonSchema = (operation) => {
259
+ const schema = httpApiOperationInputSchema(operation);
260
+ const document = JsonSchema.fromSchemaOpenApi3_1({
261
+ ...schema,
262
+ $defs: spec.components?.schemas
263
+ });
264
+ const definitions = document.definitions ?? {};
265
+ const usedDefinitions = referencedDefinitions(document.schema, definitions);
266
+ return {
267
+ ...document.schema,
268
+ ...Object.keys(usedDefinitions).length > 0 ? { $defs: usedDefinitions } : {}
269
+ };
270
+ };
271
+ return {
272
+ info: spec.info,
273
+ operations,
274
+ decodeOperationInput: decodeHttpApiOperationInput,
275
+ operationJsonSchema,
276
+ operationSchema: (operation) => {
277
+ const document = JsonSchema.fromSchemaOpenApi3_1(operationJsonSchema(operation));
278
+ return SchemaRepresentation.toSchema(SchemaRepresentation.fromJsonSchemaDocument(document));
279
+ }
280
+ };
281
+ },
282
+ catch: (error) => toHttpError("Failed to build HTTP API spec", error)
283
+ })
284
+ }) {
285
+ static layer = (config) => Layer2.effect(this, this.make(config));
286
+ }
287
+
288
+ // ../../src/lib/httpapi-cli.ts
289
+ class HttpApiCli extends Context3.Service()("HttpApiCli", {
290
+ make: () => Effect3.gen(function* () {
291
+ const spec = yield* HttpApiSpec;
292
+ const command = yield* makeHttpApiCliCommand();
293
+ return {
294
+ command,
295
+ run: (args) => Command.runWith(command, { version: spec.info.version })(args)
296
+ };
297
+ })
298
+ }) {
299
+ static layer = Layer3.effect(this, this.make());
300
+ }
301
+ var fallbackName = (value, fallback) => sanitizeHttpName(value) || fallback;
302
+ var operationIdParts = (operation) => operation.operationId?.split(".").filter(Boolean) ?? [];
303
+ var operationGroupName = (operation) => fallbackName(operationIdParts(operation)[0] ?? operation.tags?.[0] ?? "default", "default");
304
+ var operationGroupTitle = (operation) => operation.tags?.[0] ?? operationGroupName(operation);
305
+ var operationName = (method, path, operation) => fallbackName(operationIdParts(operation).at(-1) ?? `${method}_${path.replace(/^\/api\//, "").replace(/[/:{}]/g, "_")}`, `${method}_operation`);
306
+ var toCliOperation = ({
307
+ method,
308
+ operation,
309
+ path
310
+ }) => ({
311
+ groupName: operationGroupName(operation),
312
+ groupTitle: operationGroupTitle(operation),
313
+ name: operationName(method, path, operation),
314
+ method,
315
+ path,
316
+ summary: operation.summary ?? operation.description ?? "",
317
+ operation
318
+ });
319
+ var httpApiCliOperationGroups = (operations) => {
320
+ const groups = new Map;
321
+ for (const operation of operations) {
322
+ const group = groups.get(operation.groupName);
323
+ if (group) {
324
+ group.operations.push(operation);
325
+ } else {
326
+ groups.set(operation.groupName, {
327
+ name: operation.groupName,
328
+ title: operation.groupTitle,
329
+ operations: [operation]
330
+ });
331
+ }
332
+ }
333
+ return Array.from(groups.values()).map((group) => ({
334
+ ...group,
335
+ operations: Array.from(group.operations).sort((a, b) => a.name.localeCompare(b.name))
336
+ })).sort((a, b) => a.name.localeCompare(b.name));
337
+ };
338
+ var print = (value) => Console.log(value);
339
+ var formatOperations = (operations) => operations.map((operation) => `${operation.groupName} ${operation.name} ${operation.method.toUpperCase()} ${operation.path} ${operation.summary}`).join(`
340
+ `);
341
+ var listOperations = (operations) => print(formatOperations(operations));
342
+ var callOperation = (operation, callConfig, client) => Effect3.gen(function* () {
343
+ const body = yield* parseJsonValue(callConfig.body, "--body");
344
+ const headers = yield* parseJsonObject(callConfig.headers, "--headers");
345
+ const params = yield* parseJsonObject(callConfig.params, "--params");
346
+ const query = yield* parseJsonObject(callConfig.query, "--query");
347
+ const response = yield* client.execute({
348
+ operation: {
349
+ method: operation.method,
350
+ path: operation.path,
351
+ operation: operation.operation
352
+ },
353
+ input: { body, headers, params, query }
354
+ });
355
+ const formatted = JSON.stringify(response, null, 2) ?? "null";
356
+ return yield* print(formatted);
357
+ });
358
+ var listCommand = (groups) => Command.make("list", {}, () => print(groups.map((group) => `${group.name} ${group.title} ${group.operations.length}`).join(`
359
+ `))).pipe(Command.withDescription("List command groups"));
360
+ var groupListCommand = (group) => Command.make("list", {}, () => listOperations(group.operations)).pipe(Command.withDescription(`List ${group.title} operations`));
361
+ var operationCommand = (operation, client) => Command.make(operation.name, {
362
+ body: Flag.string("body").pipe(Flag.withDefault(""), Flag.withDescription("JSON request body")),
363
+ headers: Flag.string("headers").pipe(Flag.withDefault("{}"), Flag.withDescription("JSON object for request headers")),
364
+ params: Flag.string("params").pipe(Flag.withDefault("{}"), Flag.withDescription("JSON object for path parameters")),
365
+ query: Flag.string("query").pipe(Flag.withDefault("{}"), Flag.withDescription("JSON object for query parameters"))
366
+ }, (callConfig) => callOperation(operation, callConfig, client)).pipe(Command.withDescription(operation.summary || `${operation.method.toUpperCase()} ${operation.path}`));
367
+ var groupCommand = (group, client) => Command.make(group.name).pipe(Command.withDescription(group.title), Command.withSubcommands([
368
+ groupListCommand(group),
369
+ ...group.operations.map((operation) => operationCommand(operation, client))
370
+ ]));
371
+ var makeHttpApiCliCommand = Effect3.fn("HttpApiCli.makeCommand")(function* () {
372
+ const spec = yield* HttpApiSpec;
373
+ const client = yield* ApiClient;
374
+ const name = sanitizeHttpName(spec.info.title);
375
+ const groups = httpApiCliOperationGroups(spec.operations.map(toCliOperation));
376
+ return Command.make(name).pipe(Command.withDescription(spec.info.description ?? spec.info.title), Command.withSubcommands([
377
+ listCommand(groups),
378
+ ...groups.map((group) => groupCommand(group, client))
379
+ ]));
380
+ });
381
+ var cliEnvironmentLayer = (args) => Layer3.mergeAll(FileSystem.layerNoop({}), Path.layer, Stdio.layerTest({ args: Effect3.succeed(Array.from(args)) }), Layer3.succeed(Terminal.Terminal, Terminal.make({
382
+ columns: Effect3.sync(() => process.stdout.columns ?? 80),
383
+ rows: Effect3.sync(() => process.stdout.rows ?? 24),
384
+ readInput: Effect3.die("Terminal input is not supported"),
385
+ readLine: Effect3.die("Terminal input is not supported"),
386
+ display: (text) => Effect3.sync(() => process.stdout.write(text))
387
+ })), Layer3.succeed(ChildProcessSpawner, ChildProcessSpawner.of({
388
+ spawn: () => Effect3.die("Child processes are not supported"),
389
+ exitCode: () => Effect3.die("Child processes are not supported"),
390
+ streamString: () => Stream.die("Child processes are not supported"),
391
+ streamLines: () => Stream.die("Child processes are not supported"),
392
+ lines: () => Effect3.die("Child processes are not supported"),
393
+ string: () => Effect3.die("Child processes are not supported")
394
+ })));
395
+ var httpApiCliEnvironmentLayer = (args) => cliEnvironmentLayer(args);
396
+ var httpApiCli = (args = process.argv.slice(2)) => Effect3.gen(function* () {
397
+ const cli = yield* HttpApiCli;
398
+ return yield* cli.run(args);
399
+ });
400
+ var runHttpApiCli = (layer, args = process.argv.slice(2)) => {
401
+ Effect3.runPromise(httpApiCli(args).pipe(Effect3.provide(layer), Effect3.provide(httpApiCliEnvironmentLayer(args)))).catch((error) => {
402
+ console.error(error instanceof Error ? error.message : error);
403
+ process.exit(1);
404
+ });
405
+ };
406
+ export {
407
+ runHttpApiCli,
408
+ makeHttpApiCliCommand,
409
+ httpApiCliEnvironmentLayer,
410
+ httpApiCli,
411
+ HttpApiCli
412
+ };
@@ -0,0 +1,20 @@
1
+ import { Context, Effect, Layer } from "effect";
2
+ import { HttpClient } from "effect/unstable/http";
3
+ import { HttpApi, HttpApiGroup } from "effect/unstable/httpapi";
4
+ import type { HttpApiOperationEntry, HttpApiOperationInput } from "./httpapi-helpers.js";
5
+ export type ApiClientConfig<Id extends string, Groups extends HttpApiGroup.Constraint> = {
6
+ readonly api: HttpApi.HttpApi<Id, Groups>;
7
+ readonly baseUrl: string;
8
+ };
9
+ export type ApiClientExecuteOptions = {
10
+ readonly operation: HttpApiOperationEntry;
11
+ readonly input: HttpApiOperationInput;
12
+ };
13
+ export type ApiClientService = {
14
+ readonly execute: (options: ApiClientExecuteOptions) => Effect.Effect<unknown, unknown>;
15
+ };
16
+ declare const ApiClient_base: Context.ServiceClass<ApiClient, "ApiClient", ApiClientService>;
17
+ export declare class ApiClient extends ApiClient_base {
18
+ static readonly layer: <Id extends string, Groups extends HttpApiGroup.Constraint>(config: ApiClientConfig<Id, Groups>) => Layer.Layer<ApiClient, never, HttpClient.HttpClient | Exclude<import("effect/unstable/httpapi/HttpApiMiddleware").MiddlewareClient<import("effect/unstable/httpapi/HttpApiEndpoint").Middleware<HttpApiGroup.Endpoints<Groups>>>, import("effect/Scope").Scope>>;
19
+ }
20
+ export {};
@@ -0,0 +1,50 @@
1
+ // ../../src/lib/httpapi-client.ts
2
+ import { Context, Effect, Layer } from "effect";
3
+ import { HttpClient } from "effect/unstable/http";
4
+ import {
5
+ HttpApiClient as EffectHttpApiClient
6
+ } from "effect/unstable/httpapi";
7
+ var makeGeneratedClient = (api, http, baseUrl) => EffectHttpApiClient.makeWith(api, {
8
+ baseUrl,
9
+ httpClient: http
10
+ });
11
+ var isClientEffect = (value) => Effect.isEffect(value);
12
+ var executeGeneratedOperation = Effect.fn("HttpApiClient.executeGeneratedOperation")(function* (client, { input, operation: entry }) {
13
+ const operationId = entry.operation.operationId;
14
+ if (!operationId) {
15
+ return yield* Effect.fail(new Error(`No generated API client operation for ${entry.method} ${entry.path}`));
16
+ }
17
+ const target = Object(client);
18
+ const groupName = Object.keys(target).filter((name) => operationId.startsWith(`${name}.`)).sort((a, b) => b.length - a.length)[0];
19
+ const group = groupName ? Reflect.get(target, groupName) : target;
20
+ const endpointName = groupName ? operationId.slice(groupName.length + 1) : operationId;
21
+ const endpoint = Reflect.get(Object(group), endpointName);
22
+ if (typeof endpoint !== "function") {
23
+ return yield* Effect.fail(new Error(`No generated API client operation for ${operationId}`));
24
+ }
25
+ const result = endpoint({
26
+ headers: input.headers,
27
+ params: input.params,
28
+ query: input.query,
29
+ payload: input.body
30
+ });
31
+ if (!isClientEffect(result)) {
32
+ return yield* Effect.fail(new Error(`Generated API client operation ${operationId} is invalid`));
33
+ }
34
+ return yield* result;
35
+ });
36
+
37
+ class ApiClient extends Context.Service()("ApiClient") {
38
+ static layer = (config) => Layer.effect(this, Effect.gen(function* () {
39
+ const http = yield* HttpClient.HttpClient;
40
+ const client = yield* makeGeneratedClient(config.api, http, config.baseUrl);
41
+ return {
42
+ execute: Effect.fn("ApiClient.execute")(function* (options) {
43
+ return yield* executeGeneratedOperation(client, options);
44
+ })
45
+ };
46
+ }));
47
+ }
48
+ export {
49
+ ApiClient
50
+ };
@@ -0,0 +1,105 @@
1
+ import { Context, Effect, JsonSchema, Layer, Schema } from "effect";
2
+ import { HttpApi, OpenApi } from "effect/unstable/httpapi";
3
+ export declare const JsonObjectSchema: Schema.$Record<Schema.String, Schema.Unknown>;
4
+ export type JsonObject = typeof JsonObjectSchema.Type;
5
+ export type HttpApiDocument = ReturnType<typeof OpenApi.fromApi>;
6
+ export type HttpApiMethod = "get" | "post" | "put" | "patch" | "delete";
7
+ export declare const HttpApiMethods: ReadonlyArray<HttpApiMethod>;
8
+ export type HttpApiParameter = {
9
+ readonly name: string;
10
+ readonly in: "path" | "query" | "header" | "cookie";
11
+ readonly required?: boolean;
12
+ readonly description?: string;
13
+ readonly schema?: JsonSchema.JsonSchema;
14
+ };
15
+ export type HttpApiOperation = {
16
+ readonly operationId?: string;
17
+ readonly summary?: string;
18
+ readonly description?: string;
19
+ readonly parameters?: ReadonlyArray<HttpApiParameter>;
20
+ readonly requestBody?: {
21
+ readonly required?: boolean;
22
+ readonly content?: Record<string, {
23
+ readonly schema?: JsonSchema.JsonSchema;
24
+ }>;
25
+ };
26
+ readonly tags?: ReadonlyArray<string>;
27
+ };
28
+ export type HttpApiOperationEntry = {
29
+ readonly method: HttpApiMethod;
30
+ readonly path: string;
31
+ readonly operation: HttpApiOperation;
32
+ };
33
+ export type HttpApiOperationInput = {
34
+ readonly body?: unknown;
35
+ readonly headers: JsonObject;
36
+ readonly params: JsonObject;
37
+ readonly query: JsonObject;
38
+ };
39
+ export type HttpApiSpecConfig = {
40
+ readonly api: HttpApi.Constraint;
41
+ readonly methods?: ReadonlyArray<HttpApiMethod>;
42
+ readonly include?: (operation: HttpApiOperationEntry) => boolean;
43
+ };
44
+ export declare const toHttpError: (message: string, error: unknown) => Error;
45
+ export declare const sanitizeHttpName: (name: string) => string;
46
+ export declare const httpApiToolName: (method: string, path: string, operation: HttpApiOperation) => string;
47
+ export declare const httpApiOperations: ({ spec, methods, }: {
48
+ readonly spec: HttpApiDocument;
49
+ readonly methods?: ReadonlyArray<HttpApiMethod>;
50
+ }) => ReadonlyArray<HttpApiOperationEntry>;
51
+ export declare const httpApiToolEntries: (operations: readonly HttpApiOperationEntry[]) => Effect.Effect<{
52
+ method: HttpApiMethod;
53
+ path: string;
54
+ operation: HttpApiOperation;
55
+ name: string;
56
+ }[], Error, never>;
57
+ export declare const httpApiOperationInputSchema: (operation: HttpApiOperation) => JsonSchema.JsonSchema;
58
+ export declare const decodeHttpApiOperationInput: (input: unknown, operation: HttpApiOperation) => Effect.Effect<{
59
+ body?: unknown;
60
+ headers: any;
61
+ params: any;
62
+ query: any;
63
+ }, Error, never>;
64
+ export declare const parseJsonObject: (value: string | undefined, label: string) => Effect.Effect<{
65
+ readonly [x: string]: unknown;
66
+ }, Error, never>;
67
+ export declare const parseJsonValue: (value: string | undefined, label: string) => Effect.Effect<unknown, Error, never>;
68
+ declare const HttpApiSpec_base: Context.ServiceClass<HttpApiSpec, "HttpApiSpec", {
69
+ info: OpenApi.OpenAPISpecInfo;
70
+ operations: HttpApiOperationEntry[];
71
+ decodeOperationInput: (input: unknown, operation: HttpApiOperation) => Effect.Effect<{
72
+ body?: unknown;
73
+ headers: any;
74
+ params: any;
75
+ query: any;
76
+ }, Error, never>;
77
+ operationJsonSchema: (operation: HttpApiOperation) => {
78
+ $defs?: {
79
+ [k: string]: JsonSchema.JsonSchema;
80
+ } | undefined;
81
+ };
82
+ operationSchema: (operation: HttpApiOperation) => Schema.Top;
83
+ }> & {
84
+ readonly make: (config: HttpApiSpecConfig) => Effect.Effect<{
85
+ info: OpenApi.OpenAPISpecInfo;
86
+ operations: HttpApiOperationEntry[];
87
+ decodeOperationInput: (input: unknown, operation: HttpApiOperation) => Effect.Effect<{
88
+ body?: unknown;
89
+ headers: any;
90
+ params: any;
91
+ query: any;
92
+ }, Error, never>;
93
+ operationJsonSchema: (operation: HttpApiOperation) => {
94
+ $defs?: {
95
+ [k: string]: JsonSchema.JsonSchema;
96
+ } | undefined;
97
+ };
98
+ operationSchema: (operation: HttpApiOperation) => Schema.Top;
99
+ }, Error, never>;
100
+ };
101
+ export declare class HttpApiSpec extends HttpApiSpec_base {
102
+ static readonly layer: (config: HttpApiSpecConfig) => Layer.Layer<HttpApiSpec, Error, never>;
103
+ }
104
+ export type HttpApiSpecService = typeof HttpApiSpec.Service;
105
+ export {};