@krak-stack/registry 0.1.38 → 0.1.40

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 (38) hide show
  1. package/README.md +106 -29
  2. package/dist/components/ui/app-brand.js +17 -17
  3. package/dist/components/ui/code-block.js +4 -4
  4. package/dist/components/ui/copy-button.js +2 -2
  5. package/dist/components/ui/data-table.js +55 -55
  6. package/dist/components/ui/editing-locale-switcher.js +8 -8
  7. package/dist/components/ui/effect-form.js +12 -12
  8. package/dist/components/ui/error-component.js +6 -6
  9. package/dist/components/ui/file-picker.js +2 -2
  10. package/dist/components/ui/form.js +24 -24
  11. package/dist/components/ui/icon-input.js +5 -5
  12. package/dist/components/ui/locale-switcher.js +2 -2
  13. package/dist/components/ui/search-menu.js +2 -2
  14. package/dist/components/ui/sidebar-layout.js +1 -1
  15. package/dist/components/ui/theme-switcher.js +3 -3
  16. package/dist/lib/docs.js +52 -111
  17. package/dist/lib/docs.server.js +0 -28
  18. package/dist/lib/documentation-toolkit.js +0 -28
  19. package/dist/lib/httpapi-adapter.d.ts +73 -0
  20. package/dist/lib/httpapi-adapter.js +189 -0
  21. package/dist/lib/httpapi-cli.d.ts +4 -22
  22. package/dist/lib/httpapi-cli.js +199 -313
  23. package/dist/lib/httpapi-toolkit.d.ts +7 -16
  24. package/dist/lib/httpapi-toolkit.js +158 -214
  25. package/dist/lib/query.d.ts +30 -3
  26. package/dist/lib/query.js +13 -3
  27. package/dist/lib/webfetch-toolkit.d.ts +1 -1
  28. package/dist/lib/webfetch-toolkit.js +48 -50
  29. package/dist/oxlint/anti-slop/index.js +2 -2
  30. package/dist/services/agent/client/index.js +6 -6
  31. package/dist/services/agent/index.js +2 -2
  32. package/package.json +4 -12
  33. package/dist/lib/httpapi-client.d.ts +0 -34
  34. package/dist/lib/httpapi-client.js +0 -122
  35. package/dist/lib/httpapi-helpers.d.ts +0 -79
  36. package/dist/lib/httpapi-helpers.js +0 -130
  37. package/dist/lib/httpapi-mcp.d.ts +0 -25
  38. package/dist/lib/httpapi-mcp.js +0 -321
@@ -0,0 +1,73 @@
1
+ import { Context, Effect, JsonSchema, Layer, Schema } from "effect";
2
+ import type { Json } from "effect/Schema";
3
+ import { HttpClient } from "effect/http";
4
+ import { HttpApi, HttpApiGroup, OpenApi } from "effect/http-api";
5
+ export type HttpApiMethod = "get" | "post" | "put" | "patch" | "delete";
6
+ declare const HttpApiOperation: Schema.Struct<{
7
+ readonly operationId: Schema.optional<Schema.String>;
8
+ readonly summary: Schema.optional<Schema.String>;
9
+ readonly description: Schema.optional<Schema.String>;
10
+ readonly tags: Schema.optional<Schema.$Array<Schema.String>>;
11
+ readonly parameters: Schema.optional<Schema.$Array<Schema.Struct<{
12
+ readonly name: Schema.String;
13
+ readonly in: Schema.Literals<readonly ["path", "query", "header", "cookie"]>;
14
+ readonly required: Schema.optional<Schema.Boolean>;
15
+ readonly description: Schema.optional<Schema.String>;
16
+ readonly schema: Schema.optional<Schema.Codec<Json, Json, never, never>>;
17
+ }>>>;
18
+ readonly requestBody: Schema.optional<Schema.Struct<{
19
+ readonly required: Schema.optional<Schema.Boolean>;
20
+ readonly content: Schema.optional<Schema.$Record<Schema.String, Schema.Struct<{
21
+ readonly schema: Schema.optional<Schema.Codec<Json, Json, never, never>>;
22
+ }>>>;
23
+ }>>;
24
+ }>;
25
+ export type HttpApiOperation = typeof HttpApiOperation.Type;
26
+ export type HttpApiOperationEntry = {
27
+ readonly method: HttpApiMethod;
28
+ readonly path: string;
29
+ readonly operation: HttpApiOperation;
30
+ };
31
+ export type HttpApiOperationInputValues = Readonly<Record<string, unknown>>;
32
+ export type HttpApiOperationInput = {
33
+ readonly body?: unknown;
34
+ readonly headers: HttpApiOperationInputValues;
35
+ readonly params: HttpApiOperationInputValues;
36
+ readonly query: HttpApiOperationInputValues;
37
+ };
38
+ export type HttpApiOperationDefinition = HttpApiOperationEntry & {
39
+ readonly name: string;
40
+ readonly groupIdentifier: string;
41
+ readonly endpointIdentifier: string;
42
+ readonly topLevel: boolean;
43
+ readonly inputSchema: Schema.Codec<Partial<HttpApiOperationInput>, Json>;
44
+ readonly inputJsonSchema: JsonSchema.JsonSchema;
45
+ readonly successSchema?: Schema.Codec<unknown, unknown>;
46
+ readonly readOnly: boolean;
47
+ readonly destructive: boolean;
48
+ readonly idempotent: boolean;
49
+ };
50
+ export type HttpApiAdapterConfig<Id extends string, Groups extends HttpApiGroup.Constraint> = {
51
+ readonly api: HttpApi.HttpApi<Id, Groups>;
52
+ readonly baseUrl: string;
53
+ readonly methods?: ReadonlyArray<HttpApiMethod>;
54
+ readonly include?: (operation: HttpApiOperationEntry) => boolean;
55
+ readonly encodeResult?: (result: unknown, operation: HttpApiOperationDefinition) => Effect.Effect<Json, Error>;
56
+ };
57
+ export type HttpApiAdapterExecuteOptions = {
58
+ readonly operation: HttpApiOperationDefinition;
59
+ readonly input: Partial<HttpApiOperationInput>;
60
+ };
61
+ export type HttpApiAdapterService = {
62
+ readonly info: ReturnType<typeof OpenApi.fromApi>["info"];
63
+ readonly operations: ReadonlyArray<HttpApiOperationDefinition>;
64
+ readonly execute: (options: HttpApiAdapterExecuteOptions) => Effect.Effect<unknown, Error>;
65
+ readonly encodeResult: (result: unknown, operation: HttpApiOperationDefinition) => Effect.Effect<Json, Error>;
66
+ };
67
+ export declare const encodeHttpApiOperationResult: (result: unknown) => Effect.Effect<string | number | boolean | Schema.JsonArray | Schema.JsonObject | null, Error, never>;
68
+ declare const HttpApiAdapter_base: Context.ServiceClass<HttpApiAdapter, "@krak-stack/registry/HttpApiAdapter", HttpApiAdapterService>;
69
+ export declare class HttpApiAdapter extends HttpApiAdapter_base {
70
+ static readonly make: <Id extends string, Groups extends HttpApiGroup.Constraint>(config: HttpApiAdapterConfig<Id, Groups>) => Effect.Effect<HttpApiAdapterService, Error, HttpClient.HttpClient | import("effect/http-api/HttpApiMiddleware").MiddlewareClient<import("effect/http-api/HttpApiEndpoint").Middleware<HttpApiGroup.Endpoints<Groups>>>>;
71
+ static readonly layer: <Id extends string, Groups extends HttpApiGroup.Constraint>(config: HttpApiAdapterConfig<Id, Groups>) => Layer.Layer<HttpApiAdapter, Error, HttpClient.HttpClient | Exclude<import("effect/http-api/HttpApiMiddleware").MiddlewareClient<import("effect/http-api/HttpApiEndpoint").Middleware<HttpApiGroup.Endpoints<Groups>>>, import("effect/Scope").Scope>>;
72
+ }
73
+ export {};
@@ -0,0 +1,189 @@
1
+ // ../../src/lib/httpapi-adapter.ts
2
+ import {
3
+ Context,
4
+ Effect,
5
+ Layer,
6
+ Option,
7
+ Schema,
8
+ SchemaTransformation
9
+ } from "effect";
10
+ import { HttpClient } from "effect/http";
11
+ import { HttpApi, HttpApiClient, OpenApi } from "effect/http-api";
12
+ var HttpApiMethods = [
13
+ "get",
14
+ "post",
15
+ "put",
16
+ "patch",
17
+ "delete"
18
+ ];
19
+ var HttpApiOperation = Schema.Struct({
20
+ operationId: Schema.optional(Schema.String),
21
+ summary: Schema.optional(Schema.String),
22
+ description: Schema.optional(Schema.String),
23
+ tags: Schema.optional(Schema.Array(Schema.String)),
24
+ parameters: Schema.optional(Schema.Array(Schema.Struct({
25
+ name: Schema.String,
26
+ in: Schema.Literals(["path", "query", "header", "cookie"]),
27
+ required: Schema.optional(Schema.Boolean),
28
+ description: Schema.optional(Schema.String),
29
+ schema: Schema.optional(Schema.Json)
30
+ }))),
31
+ requestBody: Schema.optional(Schema.Struct({
32
+ required: Schema.optional(Schema.Boolean),
33
+ content: Schema.optional(Schema.Record(Schema.String, Schema.Struct({
34
+ schema: Schema.optional(Schema.Json)
35
+ })))
36
+ }))
37
+ }).annotate({ identifier: "HttpApiOperation" });
38
+ var UndefinedFromNull = Schema.Null.pipe(Schema.decodeTo(Schema.Undefined, SchemaTransformation.transform({
39
+ decode: () => {
40
+ return;
41
+ },
42
+ encode: () => null
43
+ })));
44
+ var HttpApiOperationResultValue = Schema.suspend(() => Schema.Union([
45
+ Schema.Null,
46
+ UndefinedFromNull,
47
+ Schema.String,
48
+ Schema.Number,
49
+ Schema.Boolean,
50
+ Schema.DateFromString,
51
+ Schema.Uint8ArrayFromBase64,
52
+ Schema.Array(HttpApiOperationResultValue),
53
+ Schema.Record(Schema.String, HttpApiOperationResultValue)
54
+ ]));
55
+ var HttpApiOperationResult = Schema.Union([
56
+ HttpApiOperationResultValue,
57
+ Schema.Undefined
58
+ ]).annotate({ identifier: "HttpApiOperationResult" });
59
+ var encodeHttpApiOperationResult = Effect.fn("HttpApiAdapter.encodeOperationResult")((result) => Schema.encodeUnknownEffect(HttpApiOperationResult)(result).pipe(Effect.map((encoded) => encoded ?? null), Effect.mapError((cause) => new Error("HTTP API result is not serializable", { cause }))));
60
+ var encodeOperationResult = Effect.fn("HttpApiAdapter.encodeResult")((result, operation) => operation.successSchema ? Schema.encodeUnknownEffect(operation.successSchema)(result).pipe(Effect.flatMap(encodeHttpApiOperationResult), Effect.mapError((cause) => new Error("HTTP API result does not match its success schema", {
61
+ cause
62
+ }))) : encodeHttpApiOperationResult(result));
63
+ var reflectedSchema = (schema) => Schema.make(schema.ast);
64
+ var sanitizeHttpName = (name) => name.replace(/[^a-zA-Z0-9_-]/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "");
65
+ var httpApiToolName = (entry) => (entry.operation.operationId || `${entry.method}_${entry.path.replace(/^\/api\//, "").replace(/[/:{}]/g, "_")}`).replace(/[^a-zA-Z0-9_-]/g, "_").replace(/_+/g, "_").slice(0, 64);
66
+ var makeCatalogue = (api, methods, include) => Effect.try({
67
+ try: () => {
68
+ if (!HttpApi.isHttpApi(api))
69
+ throw new Error("HttpApiAdapter requires a valid HttpApi");
70
+ const spec = OpenApi.fromApi(api);
71
+ const reflected = new Map;
72
+ HttpApi.reflect(api, {
73
+ onGroup: () => {
74
+ return;
75
+ },
76
+ onEndpoint: ({ endpoint, group, successes }) => {
77
+ const operationId = Context.getOrElse(endpoint.annotations, OpenApi.Identifier, () => group.topLevel ? endpoint.identifier : `${group.identifier}.${endpoint.identifier}`);
78
+ if (reflected.has(operationId))
79
+ throw new Error(`Duplicate HTTP API operation ID: ${operationId}`);
80
+ const fields = {};
81
+ if (endpoint.params)
82
+ fields.params = Schema.toType(reflectedSchema(endpoint.params));
83
+ if (endpoint.query)
84
+ fields.query = Schema.optionalKey(Schema.toType(reflectedSchema(endpoint.query)));
85
+ if (endpoint.headers)
86
+ fields.headers = Schema.optionalKey(Schema.toType(reflectedSchema(endpoint.headers)));
87
+ const payloads = Array.from(endpoint.payload.values()).flatMap(({ schemas }) => schemas.map(reflectedSchema));
88
+ if (payloads.length === 1 && payloads[0])
89
+ fields.body = payloads[0];
90
+ else if (payloads.length > 1)
91
+ fields.body = Schema.Union(payloads);
92
+ const input = Object.keys(fields).length === 0 ? Schema.Record(Schema.String, Schema.Never) : Schema.Struct(fields);
93
+ const inputSchema = Schema.make(Schema.toCodecJson(input).ast).annotate({
94
+ identifier: `${sanitizeHttpName(operationId)}ToolInput`
95
+ });
96
+ const successSchemas = Array.from(successes.values()).flat().map(reflectedSchema);
97
+ reflected.set(operationId, {
98
+ groupIdentifier: group.identifier,
99
+ endpointIdentifier: endpoint.identifier,
100
+ topLevel: group.topLevel,
101
+ inputSchema,
102
+ successSchema: successSchemas.length === 1 ? successSchemas[0] : successSchemas.length > 1 ? Schema.Union(successSchemas) : undefined
103
+ });
104
+ }
105
+ });
106
+ const names = new Set;
107
+ const operations = [];
108
+ for (const [path, pathItem] of Object.entries(spec.paths)) {
109
+ for (const method of methods) {
110
+ const decoded = Schema.decodeUnknownOption(HttpApiOperation)(pathItem[method]);
111
+ if (Option.isNone(decoded))
112
+ continue;
113
+ const entry = { method, path, operation: decoded.value };
114
+ if (include && !include(entry))
115
+ continue;
116
+ const metadata = entry.operation.operationId ? reflected.get(entry.operation.operationId) : undefined;
117
+ if (!metadata)
118
+ throw new Error(`Missing endpoint schema for ${entry.operation.operationId}`);
119
+ const name = httpApiToolName(entry);
120
+ if (!name || names.has(name))
121
+ throw new Error(`Duplicate or empty HTTP API tool name: ${name}`);
122
+ names.add(name);
123
+ const document = Schema.toJsonSchemaDocument(metadata.inputSchema.annotate({ identifier: undefined }));
124
+ operations.push({
125
+ ...entry,
126
+ ...metadata,
127
+ name,
128
+ inputJsonSchema: {
129
+ ...document.schema,
130
+ $defs: document.definitions
131
+ },
132
+ readOnly: method === "get",
133
+ destructive: method === "delete",
134
+ idempotent: method === "get" || method === "put" || method === "delete"
135
+ });
136
+ }
137
+ }
138
+ return { info: spec.info, operations };
139
+ },
140
+ catch: (cause) => new Error("Failed to build HTTP API adapter catalogue", { cause })
141
+ });
142
+ var GeneratedOperation = Schema.declare((value) => value instanceof Function).annotate({ identifier: "GeneratedOperation" });
143
+ var GeneratedOperationEffect = Schema.declare((value) => Effect.isEffect(value)).annotate({ identifier: "GeneratedOperationEffect" });
144
+ var executeGeneratedOperation = Effect.fn("HttpApiAdapter.executeGeneratedOperation")(function* (client, { operation, input }) {
145
+ const group = operation.topLevel ? client : Object.entries(Object(client)).find(([name]) => name === operation.groupIdentifier)?.[1];
146
+ const candidate = Object.entries(Object(group)).find(([name]) => name === operation.endpointIdentifier)?.[1];
147
+ const endpoint = Schema.decodeUnknownOption(GeneratedOperation)(candidate);
148
+ if (Option.isNone(endpoint))
149
+ return yield* Effect.fail(new Error(`No generated API client operation for ${operation.operation.operationId}`));
150
+ const result = Schema.decodeUnknownOption(GeneratedOperationEffect)(endpoint.value({
151
+ headers: input.headers ?? {},
152
+ params: input.params ?? {},
153
+ query: input.query ?? {},
154
+ payload: input.body
155
+ }));
156
+ if (Option.isNone(result))
157
+ return yield* Effect.fail(new Error(`Generated API client operation ${operation.operation.operationId} is invalid`));
158
+ return yield* result.value;
159
+ });
160
+
161
+ class HttpApiAdapter extends Context.Service()("@krak-stack/registry/HttpApiAdapter") {
162
+ static make = Effect.fn("HttpApiAdapter.make")(function* (config) {
163
+ const catalogue = yield* makeCatalogue(config.api, config.methods ?? HttpApiMethods, config.include);
164
+ const httpClient = yield* HttpClient.HttpClient;
165
+ const client = yield* HttpApiClient.makeWith(config.api, {
166
+ baseUrl: config.baseUrl,
167
+ httpClient
168
+ });
169
+ return HttpApiAdapter.of({
170
+ ...catalogue,
171
+ encodeResult: config.encodeResult ?? encodeOperationResult,
172
+ execute: Effect.fn("HttpApiAdapter.execute")(function* (options) {
173
+ const operation = catalogue.operations.find((entry) => entry.method === options.operation.method && entry.path === options.operation.path && entry.operation.operationId === options.operation.operation.operationId);
174
+ if (!operation) {
175
+ return yield* Effect.fail(new Error("Operation is not in this HTTP API adapter catalogue"));
176
+ }
177
+ return yield* executeGeneratedOperation(client, {
178
+ operation,
179
+ input: options.input
180
+ });
181
+ })
182
+ });
183
+ });
184
+ static layer = (config) => Layer.effect(this, this.make(config));
185
+ }
186
+ export {
187
+ HttpApiAdapter,
188
+ encodeHttpApiOperationResult
189
+ };
@@ -1,25 +1,7 @@
1
- import { Cause, Context, Effect, FileSystem, Layer, Path, Stdio, Terminal } from "effect";
1
+ import { Effect } from "effect";
2
2
  import { Command } from "effect/cli";
3
- import { ChildProcessSpawner } from "effect/process/ChildProcessSpawner";
4
- import { ApiClient, type ApiClientService } from "./httpapi-client.js";
5
- import { HttpApiSpec, type HttpApiOperationEntry } from "./httpapi-helpers.js";
6
- declare const HttpApiCli_base: Context.ServiceClass<HttpApiCli, "HttpApiCli", {
3
+ import { HttpApiAdapter } from "./httpapi-adapter.js";
4
+ export declare const makeHttpApiCli: () => Effect.Effect<{
7
5
  command: Command.Command<string, {}, {}, unknown, never>;
8
6
  run: (args: ReadonlyArray<string>) => Effect.Effect<void, unknown, Command.Environment>;
9
- }> & {
10
- readonly make: () => Effect.Effect<{
11
- command: Command.Command<string, {}, {}, unknown, never>;
12
- run: (args: ReadonlyArray<string>) => Effect.Effect<void, unknown, Command.Environment>;
13
- }, Error, ApiClient | HttpApiSpec>;
14
- };
15
- export declare class HttpApiCli extends HttpApiCli_base {
16
- static readonly layer: Layer.Layer<HttpApiCli, Error, ApiClient | HttpApiSpec>;
17
- }
18
- export declare const toHttpApiCliName: (value: string) => string;
19
- export declare const printHttpApiCliResult: (response: unknown, operation: HttpApiOperationEntry, client: ApiClientService) => Effect.Effect<void, unknown, never>;
20
- export declare const makeHttpApiCliCommand: () => Effect.Effect<Command.Command<string, {}, {}, unknown, never>, Error, ApiClient | HttpApiSpec>;
21
- export declare const httpApiCliEnvironmentLayer: (args: ReadonlyArray<string>) => Layer.Layer<ChildProcessSpawner | FileSystem.FileSystem | Path.Path | Stdio.Stdio | Terminal.Terminal, never, never>;
22
- export declare const httpApiCli: (args?: string[]) => Effect.Effect<void, unknown, HttpApiCli | Command.Environment>;
23
- export declare const formatHttpApiCliCause: (cause: Cause.Cause<unknown>) => string;
24
- export declare const runHttpApiCli: <E>(layer: Layer.Layer<HttpApiCli, E>, args?: string[]) => void;
25
- export {};
7
+ }, Error, HttpApiAdapter>;