@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
@@ -1,24 +1,44 @@
1
1
  // ../../src/lib/httpapi-toolkit.ts
2
- import { Effect as Effect3, Layer as Layer3, Schema as Schema3 } from "effect";
2
+ import { Effect as Effect2, Schema as Schema2 } from "effect";
3
3
  import { Tool, Toolkit } from "effect/ai";
4
4
 
5
- // ../../src/lib/httpapi-client.ts
6
- import { Context, Effect, Layer, Schema, SchemaTransformation } from "effect";
7
- import { HttpClient } from "effect/http";
5
+ // ../../src/lib/httpapi-adapter.ts
8
6
  import {
9
- HttpApi,
10
- HttpApiClient as EffectHttpApiClient,
11
- OpenApi
12
- } from "effect/http-api";
13
- var executeHttpApiOperation = Effect.fn("HttpApiClient.executeOperation")((options, client) => client.execute({
14
- operation: options.operation,
15
- input: {
16
- body: options.input.body,
17
- headers: options.input.headers ?? {},
18
- params: options.input.params ?? {},
19
- query: options.input.query ?? {}
20
- }
21
- }));
7
+ Context,
8
+ Effect,
9
+ Layer,
10
+ Option,
11
+ Schema,
12
+ SchemaTransformation
13
+ } from "effect";
14
+ import { HttpClient } from "effect/http";
15
+ import { HttpApi, HttpApiClient, OpenApi } from "effect/http-api";
16
+ var HttpApiMethods = [
17
+ "get",
18
+ "post",
19
+ "put",
20
+ "patch",
21
+ "delete"
22
+ ];
23
+ var HttpApiOperation = Schema.Struct({
24
+ operationId: Schema.optional(Schema.String),
25
+ summary: Schema.optional(Schema.String),
26
+ description: Schema.optional(Schema.String),
27
+ tags: Schema.optional(Schema.Array(Schema.String)),
28
+ parameters: Schema.optional(Schema.Array(Schema.Struct({
29
+ name: Schema.String,
30
+ in: Schema.Literals(["path", "query", "header", "cookie"]),
31
+ required: Schema.optional(Schema.Boolean),
32
+ description: Schema.optional(Schema.String),
33
+ schema: Schema.optional(Schema.Json)
34
+ }))),
35
+ requestBody: Schema.optional(Schema.Struct({
36
+ required: Schema.optional(Schema.Boolean),
37
+ content: Schema.optional(Schema.Record(Schema.String, Schema.Struct({
38
+ schema: Schema.optional(Schema.Json)
39
+ })))
40
+ }))
41
+ }).annotate({ identifier: "HttpApiOperation" });
22
42
  var UndefinedFromNull = Schema.Null.pipe(Schema.decodeTo(Schema.Undefined, SchemaTransformation.transform({
23
43
  decode: () => {
24
44
  return;
@@ -40,202 +60,132 @@ var HttpApiOperationResult = Schema.Union([
40
60
  HttpApiOperationResultValue,
41
61
  Schema.Undefined
42
62
  ]).annotate({ identifier: "HttpApiOperationResult" });
43
- 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 }))));
63
+ 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 }))));
64
+ 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", {
65
+ cause
66
+ }))) : encodeHttpApiOperationResult(result));
44
67
  var reflectedSchema = (schema) => Schema.make(schema.ast);
45
- var operationResultSchemas = (api) => {
46
- const schemas = new Map;
47
- HttpApi.reflect(api, {
48
- onGroup: () => {
49
- return;
50
- },
51
- onEndpoint: ({ endpoint, group, successes }) => {
52
- const operationId = Context.getOrElse(endpoint.annotations, OpenApi.Identifier, () => group.topLevel ? endpoint.identifier : `${group.identifier}.${endpoint.identifier}`);
53
- const operationSchemas = Array.from(successes.values()).flat().map(reflectedSchema);
54
- if (operationSchemas.length === 1 && operationSchemas[0]) {
55
- schemas.set(operationId, operationSchemas[0]);
56
- } else if (operationSchemas.length > 1) {
57
- schemas.set(operationId, Schema.Union(operationSchemas));
68
+ var sanitizeHttpName = (name) => name.replace(/[^a-zA-Z0-9_-]/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "");
69
+ 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);
70
+ var makeCatalogue = (api, methods, include) => Effect.try({
71
+ try: () => {
72
+ if (!HttpApi.isHttpApi(api))
73
+ throw new Error("HttpApiAdapter requires a valid HttpApi");
74
+ const spec = OpenApi.fromApi(api);
75
+ const reflected = new Map;
76
+ HttpApi.reflect(api, {
77
+ onGroup: () => {
78
+ return;
79
+ },
80
+ onEndpoint: ({ endpoint, group, successes }) => {
81
+ const operationId = Context.getOrElse(endpoint.annotations, OpenApi.Identifier, () => group.topLevel ? endpoint.identifier : `${group.identifier}.${endpoint.identifier}`);
82
+ if (reflected.has(operationId))
83
+ throw new Error(`Duplicate HTTP API operation ID: ${operationId}`);
84
+ const fields = {};
85
+ if (endpoint.params)
86
+ fields.params = Schema.toType(reflectedSchema(endpoint.params));
87
+ if (endpoint.query)
88
+ fields.query = Schema.optionalKey(Schema.toType(reflectedSchema(endpoint.query)));
89
+ if (endpoint.headers)
90
+ fields.headers = Schema.optionalKey(Schema.toType(reflectedSchema(endpoint.headers)));
91
+ const payloads = Array.from(endpoint.payload.values()).flatMap(({ schemas }) => schemas.map(reflectedSchema));
92
+ if (payloads.length === 1 && payloads[0])
93
+ fields.body = payloads[0];
94
+ else if (payloads.length > 1)
95
+ fields.body = Schema.Union(payloads);
96
+ const input = Object.keys(fields).length === 0 ? Schema.Record(Schema.String, Schema.Never) : Schema.Struct(fields);
97
+ const inputSchema = Schema.make(Schema.toCodecJson(input).ast).annotate({
98
+ identifier: `${sanitizeHttpName(operationId)}ToolInput`
99
+ });
100
+ const successSchemas = Array.from(successes.values()).flat().map(reflectedSchema);
101
+ reflected.set(operationId, {
102
+ groupIdentifier: group.identifier,
103
+ endpointIdentifier: endpoint.identifier,
104
+ topLevel: group.topLevel,
105
+ inputSchema,
106
+ successSchema: successSchemas.length === 1 ? successSchemas[0] : successSchemas.length > 1 ? Schema.Union(successSchemas) : undefined
107
+ });
108
+ }
109
+ });
110
+ const names = new Set;
111
+ const operations = [];
112
+ for (const [path, pathItem] of Object.entries(spec.paths)) {
113
+ for (const method of methods) {
114
+ const decoded = Schema.decodeUnknownOption(HttpApiOperation)(pathItem[method]);
115
+ if (Option.isNone(decoded))
116
+ continue;
117
+ const entry = { method, path, operation: decoded.value };
118
+ if (include && !include(entry))
119
+ continue;
120
+ const metadata = entry.operation.operationId ? reflected.get(entry.operation.operationId) : undefined;
121
+ if (!metadata)
122
+ throw new Error(`Missing endpoint schema for ${entry.operation.operationId}`);
123
+ const name = httpApiToolName(entry);
124
+ if (!name || names.has(name))
125
+ throw new Error(`Duplicate or empty HTTP API tool name: ${name}`);
126
+ names.add(name);
127
+ const document = Schema.toJsonSchemaDocument(metadata.inputSchema.annotate({ identifier: undefined }));
128
+ operations.push({
129
+ ...entry,
130
+ ...metadata,
131
+ name,
132
+ inputJsonSchema: {
133
+ ...document.schema,
134
+ $defs: document.definitions
135
+ },
136
+ readOnly: method === "get",
137
+ destructive: method === "delete",
138
+ idempotent: method === "get" || method === "put" || method === "delete"
139
+ });
58
140
  }
59
141
  }
60
- });
61
- return schemas;
62
- };
63
- var makeHttpApiOperationResultEncoder = (api) => {
64
- const schemas = operationResultSchemas(api);
65
- return Effect.fn("HttpApiClient.encodeOperationResultWithSchema")((result, operation) => {
66
- const operationId = operation.operation.operationId;
67
- const schema = operationId ? schemas.get(operationId) : undefined;
68
- if (!schema)
69
- return encodeHttpApiOperationResult(result);
70
- return Schema.encodeUnknownEffect(schema)(result).pipe(Effect.flatMap(encodeHttpApiOperationResult), Effect.mapError((cause) => new Error("HTTP API result does not match its success schema", {
71
- cause
72
- })));
73
- });
74
- };
142
+ return { info: spec.info, operations };
143
+ },
144
+ catch: (cause) => new Error("Failed to build HTTP API adapter catalogue", { cause })
145
+ });
75
146
  var GeneratedOperation = Schema.declare((value) => value instanceof Function).annotate({ identifier: "GeneratedOperation" });
76
147
  var GeneratedOperationEffect = Schema.declare((value) => Effect.isEffect(value)).annotate({ identifier: "GeneratedOperationEffect" });
77
- var makeGeneratedClient = (api, http, baseUrl) => EffectHttpApiClient.makeWith(api, {
78
- baseUrl,
79
- httpClient: http
80
- });
81
- var executeGeneratedOperation = Effect.fn("HttpApiClient.executeGeneratedOperation")(function* (client, { input, operation: entry }) {
82
- const operationId = entry.operation.operationId;
83
- if (!operationId) {
84
- return yield* Effect.fail(new Error(`No generated API client operation for ${entry.method} ${entry.path}`));
85
- }
86
- const target = Object(client);
87
- const groupName = Object.keys(target).filter((name) => operationId.startsWith(`${name}.`)).sort((a, b) => b.length - a.length)[0];
88
- const group = groupName ? Object.entries(target).find(([name]) => name === groupName)?.[1] : target;
89
- const endpointName = groupName ? operationId.slice(groupName.length + 1) : operationId;
90
- const endpointCandidate = group instanceof Function ? undefined : Object.entries(Object(group)).find(([name]) => name === endpointName)?.[1];
91
- const endpoint = Schema.decodeUnknownOption(GeneratedOperation)(endpointCandidate);
92
- if (endpoint._tag === "None") {
93
- return yield* Effect.fail(new Error(`No generated API client operation for ${operationId}`));
94
- }
148
+ var executeGeneratedOperation = Effect.fn("HttpApiAdapter.executeGeneratedOperation")(function* (client, { operation, input }) {
149
+ const group = operation.topLevel ? client : Object.entries(Object(client)).find(([name]) => name === operation.groupIdentifier)?.[1];
150
+ const candidate = Object.entries(Object(group)).find(([name]) => name === operation.endpointIdentifier)?.[1];
151
+ const endpoint = Schema.decodeUnknownOption(GeneratedOperation)(candidate);
152
+ if (Option.isNone(endpoint))
153
+ return yield* Effect.fail(new Error(`No generated API client operation for ${operation.operation.operationId}`));
95
154
  const result = Schema.decodeUnknownOption(GeneratedOperationEffect)(endpoint.value({
96
- headers: input.headers,
97
- params: input.params,
98
- query: input.query,
155
+ headers: input.headers ?? {},
156
+ params: input.params ?? {},
157
+ query: input.query ?? {},
99
158
  payload: input.body
100
159
  }));
101
- if (result._tag === "None") {
102
- return yield* Effect.fail(new Error(`Generated API client operation ${operationId} is invalid`));
103
- }
160
+ if (Option.isNone(result))
161
+ return yield* Effect.fail(new Error(`Generated API client operation ${operation.operation.operationId} is invalid`));
104
162
  return yield* result.value;
105
163
  });
106
164
 
107
- class ApiClient extends Context.Service()("ApiClient") {
108
- static layer = (config) => Layer.effect(this, Effect.gen(function* () {
109
- const http = yield* HttpClient.HttpClient;
110
- const encodeResult = makeHttpApiOperationResultEncoder(config.api);
111
- const client = yield* makeGeneratedClient(config.api, http, config.baseUrl);
112
- return {
113
- encodeResult: config.encodeResult ?? ((result, operation) => encodeResult(result, operation)),
114
- execute: Effect.fn("ApiClient.execute")(function* (options) {
115
- return yield* executeGeneratedOperation(client, options);
165
+ class HttpApiAdapter extends Context.Service()("@krak-stack/registry/HttpApiAdapter") {
166
+ static make = Effect.fn("HttpApiAdapter.make")(function* (config) {
167
+ const catalogue = yield* makeCatalogue(config.api, config.methods ?? HttpApiMethods, config.include);
168
+ const httpClient = yield* HttpClient.HttpClient;
169
+ const client = yield* HttpApiClient.makeWith(config.api, {
170
+ baseUrl: config.baseUrl,
171
+ httpClient
172
+ });
173
+ return HttpApiAdapter.of({
174
+ ...catalogue,
175
+ encodeResult: config.encodeResult ?? encodeOperationResult,
176
+ execute: Effect.fn("HttpApiAdapter.execute")(function* (options) {
177
+ const operation = catalogue.operations.find((entry) => entry.method === options.operation.method && entry.path === options.operation.path && entry.operation.operationId === options.operation.operation.operationId);
178
+ if (!operation) {
179
+ return yield* Effect.fail(new Error("Operation is not in this HTTP API adapter catalogue"));
180
+ }
181
+ return yield* executeGeneratedOperation(client, {
182
+ operation,
183
+ input: options.input
184
+ });
116
185
  })
117
- };
118
- }));
119
- }
120
-
121
- // ../../src/lib/httpapi-helpers.tsx
122
- import { Context as Context2, Effect as Effect2, Layer as Layer2, Option, Schema as Schema2 } from "effect";
123
- import { HttpApi as HttpApi2, OpenApi as OpenApi2 } from "effect/http-api";
124
- var JsonObjectSchema = Schema2.Record(Schema2.String, Schema2.Json).annotate({
125
- identifier: "HttpJsonObject",
126
- title: "HTTP JSON object",
127
- description: "A JSON object passed to an HTTP API operation.",
128
- examples: [{ id: "example-id" }]
129
- });
130
- var JsonObjectFromString = Schema2.fromJsonString(JsonObjectSchema);
131
- var JsonValueFromString = Schema2.fromJsonString(Schema2.Json);
132
- var HttpApiMethods = [
133
- "get",
134
- "post",
135
- "put",
136
- "patch",
137
- "delete"
138
- ];
139
- var HttpApiOperationSchema = Schema2.declare((value) => Schema2.is(JsonObjectSchema)(value)).annotate({ identifier: "HttpApiOperation" });
140
- var decodeHttpApiOperation = Schema2.decodeUnknownOption(HttpApiOperationSchema);
141
- var toHttpError = (message, error) => new Error(message, { cause: error });
142
- var sanitizeHttpName = (name) => name.replace(/[^a-zA-Z0-9_-]/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "");
143
- var httpApiToolName = (method, path, operation) => {
144
- const fallback = `${method}_${path.replace(/^\/api\//, "").replace(/[/:{}]/g, "_")}`;
145
- return (operation.operationId || fallback).replace(/[^a-zA-Z0-9_-]/g, "_").replace(/_+/g, "_").slice(0, 64);
146
- };
147
- var httpApiOperations = ({
148
- spec,
149
- methods = HttpApiMethods
150
- }) => {
151
- const operations = [];
152
- for (const [path, pathItem] of Object.entries(spec.paths)) {
153
- for (const method of methods) {
154
- const operation = decodeHttpApiOperation(pathItem[method]);
155
- if (Option.isSome(operation))
156
- operations.push({ method, path, operation: operation.value });
157
- }
158
- }
159
- return operations;
160
- };
161
- var reflectedSchema2 = (schema) => Schema2.make(schema.ast);
162
- var reflectedOperationInputSchemas = (api) => {
163
- const schemas = new Map;
164
- HttpApi2.reflect(api, {
165
- onGroup: () => {
166
- return;
167
- },
168
- onEndpoint: ({ endpoint, group }) => {
169
- const operationId = Context2.getOrElse(endpoint.annotations, OpenApi2.Identifier, () => group.topLevel ? endpoint.identifier : `${group.identifier}.${endpoint.identifier}`);
170
- const fields = {};
171
- if (endpoint.params)
172
- fields.params = Schema2.toType(reflectedSchema2(endpoint.params));
173
- if (endpoint.query)
174
- fields.query = Schema2.optionalKey(Schema2.toType(reflectedSchema2(endpoint.query)));
175
- if (endpoint.headers)
176
- fields.headers = Schema2.optionalKey(Schema2.toType(reflectedSchema2(endpoint.headers)));
177
- const payloads = Array.from(endpoint.payload.values()).flatMap(({ schemas: schemas2 }) => schemas2.map(reflectedSchema2));
178
- if (payloads.length === 1 && payloads[0])
179
- fields.body = payloads[0];
180
- else if (payloads.length > 1)
181
- fields.body = Schema2.Union(payloads);
182
- const input = Object.keys(fields).length === 0 ? Schema2.Record(Schema2.String, Schema2.Never) : Schema2.Struct(fields);
183
- schemas.set(operationId, Schema2.make(Schema2.toCodecJson(input).ast).annotate({ identifier: `${sanitizeHttpName(operationId)}ToolInput` }));
184
- }
186
+ });
185
187
  });
186
- return schemas;
187
- };
188
- var parseJsonObject = Effect2.fn("Http.parseJsonObject")(function* (value, label) {
189
- if (!value)
190
- return {};
191
- return yield* Schema2.decodeUnknownEffect(JsonObjectFromString)(value).pipe(Effect2.mapError(() => new Error(`${label} must be a JSON object`)));
192
- });
193
- var parseJsonValue = Effect2.fn("Http.parseJsonValue")(function* (value, label) {
194
- if (!value)
195
- return;
196
- return yield* Schema2.decodeUnknownEffect(JsonValueFromString)(value).pipe(Effect2.mapError(() => new Error(`${label} must be valid JSON`)));
197
- });
198
-
199
- class HttpApiSpec extends Context2.Service()("HttpApiSpec", {
200
- make: (config) => Effect2.try({
201
- try: () => {
202
- const api = config.api;
203
- if (!HttpApi2.isHttpApi(api))
204
- throw new Error("HttpApiSpec requires a valid HttpApi");
205
- const spec = OpenApi2.fromApi(api);
206
- const schemas = reflectedOperationInputSchemas(api);
207
- const names = new Set;
208
- const operations = httpApiOperations({
209
- spec,
210
- methods: config.methods
211
- }).filter((entry) => config.include?.(entry) ?? true).map((entry) => {
212
- const name = httpApiToolName(entry.method, entry.path, entry.operation);
213
- if (!name || names.has(name))
214
- throw new Error(`Duplicate or empty HTTP API tool name: ${name}`);
215
- names.add(name);
216
- const inputSchema = entry.operation.operationId ? schemas.get(entry.operation.operationId) : undefined;
217
- if (!inputSchema)
218
- throw new Error(`Missing endpoint schema for ${entry.operation.operationId}`);
219
- const document = Schema2.toJsonSchemaDocument(inputSchema.annotate({ identifier: undefined }));
220
- return {
221
- ...entry,
222
- name,
223
- inputSchema,
224
- inputJsonSchema: {
225
- ...document.schema,
226
- $defs: document.definitions
227
- },
228
- readOnly: entry.method === "get",
229
- destructive: entry.method === "delete",
230
- idempotent: entry.method === "get" || entry.method === "put" || entry.method === "delete"
231
- };
232
- });
233
- return { info: spec.info, operations };
234
- },
235
- catch: (error) => toHttpError("Failed to build HTTP API spec", error)
236
- })
237
- }) {
238
- static layer = (config) => Layer2.effect(this, this.make(config));
188
+ static layer = (config) => Layer.effect(this, this.make(config));
239
189
  }
240
190
 
241
191
  // ../../src/lib/httpapi-toolkit.ts
@@ -250,8 +200,8 @@ var makeOperationTool = (entry, config) => {
250
200
 
251
201
  ${guidance}` : guidance,
252
202
  parameters: entry.inputSchema,
253
- success: Schema3.Json,
254
- failure: Schema3.String,
203
+ success: Schema2.Json,
204
+ failure: Schema2.String,
255
205
  failureMode: "return",
256
206
  needsApproval: config.needsApproval?.(entry) ?? !readOnly
257
207
  }).annotate(Tool.Title, operation.summary ?? operation.operationId ?? entry.name).annotate(Tool.Strict, strict).annotate(Tool.Readonly, readOnly).annotate(Tool.Destructive, entry.destructive).annotate(Tool.Idempotent, entry.idempotent).annotate(Tool.OpenWorld, false).annotate(Tool.Meta, {
@@ -261,29 +211,23 @@ ${guidance}` : guidance,
261
211
  }
262
212
  });
263
213
  };
264
- var makeHttpApiToolkit = Effect3.fn("HttpApiToolkit.make")(function* (config) {
265
- const spec = yield* HttpApiSpec;
214
+ var makeHttpApiToolkit = Effect2.fn("HttpApiToolkit.make")(function* (config = {}) {
215
+ const spec = yield* HttpApiAdapter;
266
216
  const entries = spec.operations.map((operation) => ({
267
217
  operation,
268
218
  tool: makeOperationTool(operation, config)
269
219
  }));
270
220
  const toolkit = Toolkit.make(...entries.map(({ tool }) => tool));
271
- const handlers = toolkit.toLayer(Effect3.map(ApiClient, (client) => Object.fromEntries(entries.map(({ operation: entry, tool }) => [
221
+ const handlers = toolkit.toLayer(Effect2.map(HttpApiAdapter, (client) => Object.fromEntries(entries.map(({ operation: entry, tool }) => [
272
222
  tool.name,
273
- (input) => Effect3.gen(function* () {
274
- const result = yield* executeHttpApiOperation({ operation: entry, input }, client);
223
+ (input) => Effect2.gen(function* () {
224
+ const result = yield* client.execute({ operation: entry, input });
275
225
  const encodedResult = yield* client.encodeResult(result, entry);
276
226
  return config.transformResult?.(entry, encodedResult) ?? encodedResult;
277
- }).pipe(Effect3.mapError((error) => error instanceof Error ? error.message : String(error)))
227
+ }).pipe(Effect2.mapError((error) => error instanceof Error ? error.message : String(error)))
278
228
  ]))));
279
229
  return { toolkit, handlers };
280
230
  });
281
- var HttpApiToolkit = Effect3.fn("HttpApiToolkit")(function* (config) {
282
- return (yield* makeHttpApiToolkit(config)).toolkit;
283
- });
284
- var HttpApiToolkitLayer = (config) => Layer3.unwrap(makeHttpApiToolkit(config).pipe(Effect3.map(({ handlers }) => handlers)));
285
231
  export {
286
- HttpApiToolkit,
287
- HttpApiToolkitLayer,
288
232
  makeHttpApiToolkit
289
233
  };
@@ -29,8 +29,8 @@ export declare const SortParams: Schema.declare<readonly {
29
29
  readonly direction: "asc" | "desc";
30
30
  }[]>;
31
31
  export declare const Query: Schema.Struct<{
32
- readonly page: Schema.decodeTo<Schema.Int, Schema.optionalKey<Schema.Int>, never, never>;
33
- readonly pageSize: Schema.decodeTo<Schema.Int, Schema.optionalKey<Schema.Int>, never, never>;
32
+ readonly page: Schema.decodeTo<Schema.Int, Schema.optional<Schema.Union<readonly [Schema.Number, Schema.NumberFromString]>>, never, never>;
33
+ readonly pageSize: Schema.decodeTo<Schema.Int, Schema.optional<Schema.Union<readonly [Schema.Number, Schema.NumberFromString]>>, never, never>;
34
34
  readonly globalFilter: Schema.optional<Schema.String>;
35
35
  readonly sort: Schema.optional<Schema.declare<readonly {
36
36
  readonly id: string;
@@ -42,7 +42,34 @@ export declare const Query: Schema.Struct<{
42
42
  }>;
43
43
  export type QueryType = typeof Query.Type;
44
44
  export type QueryEncoded = typeof Query.Encoded;
45
- export declare const QueryStandard: ReturnType<typeof Schema.toStandardSchemaV1<typeof Query>>;
45
+ export declare const QueryStandard: import("effect/StandardSchema").StandardSchemaV1<{
46
+ readonly globalFilter?: string | undefined;
47
+ readonly sort?: readonly {
48
+ readonly id: string;
49
+ readonly direction: "asc" | "desc";
50
+ }[] | undefined;
51
+ readonly page?: string | number | undefined;
52
+ readonly pageSize?: string | number | undefined;
53
+ }, {
54
+ readonly globalFilter?: string | undefined;
55
+ readonly sort?: readonly {
56
+ readonly id: string;
57
+ readonly direction: "asc" | "desc";
58
+ }[] | undefined;
59
+ readonly page?: number | undefined;
60
+ readonly pageSize?: number | undefined;
61
+ }> & Schema.Struct<{
62
+ readonly globalFilter: Schema.optional<Schema.String>;
63
+ readonly sort: Schema.optional<Schema.declare<readonly {
64
+ readonly id: string;
65
+ readonly direction: "asc" | "desc";
66
+ }[], readonly {
67
+ readonly id: string;
68
+ readonly direction: "asc" | "desc";
69
+ }[]>>;
70
+ readonly page: Schema.decodeTo<Schema.optional<Schema.Int>, Schema.decodeTo<Schema.Int, Schema.optional<Schema.Union<readonly [Schema.Number, Schema.NumberFromString]>>, never, never>, never, never>;
71
+ readonly pageSize: Schema.decodeTo<Schema.optional<Schema.Int>, Schema.decodeTo<Schema.Int, Schema.optional<Schema.Union<readonly [Schema.Number, Schema.NumberFromString]>>, never, never>, never, never>;
72
+ }>;
46
73
  export declare const PaginationMeta: Schema.Struct<{
47
74
  readonly page: Schema.Int;
48
75
  readonly pageSize: Schema.Int;
package/dist/lib/query.js CHANGED
@@ -81,11 +81,11 @@ var SortParams = Schema.declare(Schema.is(SortParamsArray), {
81
81
  toCodecStringTree: () => Schema.link()(SortParamsFromString, SchemaTransformation.passthrough())
82
82
  });
83
83
  var Query = Schema.Struct({
84
- page: Schema.optionalKey(Schema.Int.check(Schema.isGreaterThanOrEqualTo(0))).pipe(Schema.decodeTo(Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)), {
84
+ page: Schema.optional(Schema.Union([Schema.Number, Schema.NumberFromString]).check(Schema.isInt(), Schema.isGreaterThanOrEqualTo(0))).pipe(Schema.decodeTo(Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)), {
85
85
  decode: SchemaGetter.withDefault(Effect.succeed(0)),
86
86
  encode: SchemaGetter.transformOptional(Option.filter((page) => page !== 0))
87
87
  })),
88
- pageSize: Schema.optionalKey(Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 100 }))).pipe(Schema.decodeTo(Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 100 })), {
88
+ pageSize: Schema.optional(Schema.Union([Schema.Number, Schema.NumberFromString]).check(Schema.isInt(), Schema.isBetween({ minimum: 1, maximum: 100 }))).pipe(Schema.decodeTo(Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 100 })), {
89
89
  decode: SchemaGetter.withDefault(Effect.succeed(20)),
90
90
  encode: SchemaGetter.transformOptional(Option.filter((pageSize) => pageSize !== 20))
91
91
  })),
@@ -107,7 +107,17 @@ var Query = Schema.Struct({
107
107
  }
108
108
  ]
109
109
  });
110
- var QueryStandard = Schema.toStandardSchemaV1(Query);
110
+ var QueryStandard = Schema.toStandardSchemaV1(Schema.Struct({
111
+ ...Query.fields,
112
+ page: Query.fields.page.pipe(Schema.decodeTo(Schema.optional(Schema.Int), {
113
+ decode: SchemaGetter.transform((page) => page === 0 ? undefined : page),
114
+ encode: SchemaGetter.transform((page) => page ?? 0)
115
+ })),
116
+ pageSize: Query.fields.pageSize.pipe(Schema.decodeTo(Schema.optional(Schema.Int), {
117
+ decode: SchemaGetter.transform((pageSize) => pageSize === 20 ? undefined : pageSize),
118
+ encode: SchemaGetter.transform((pageSize) => pageSize ?? 20)
119
+ }))
120
+ }).annotate({ identifier: "QuerySearch" }));
111
121
  var PaginationMeta = Schema.Struct({
112
122
  page: Schema.Int,
113
123
  pageSize: Schema.Int,
@@ -42,4 +42,4 @@ export declare const WebFetchToolkit: Toolkit.Toolkit<{
42
42
  readonly failureMode: "return";
43
43
  }, never>;
44
44
  }>;
45
- export declare const WebFetchToolkitLayer: (options?: Partial<WebFetchToolkitOptions>) => import("effect/Layer").Layer<Tool.Handler<"webFetch">, never, FileExtractionService | HttpClient.HttpClient>;
45
+ export declare const WebFetchToolkitLayer: (options?: Partial<WebFetchToolkitOptions>) => import("effect/Layer").Layer<Tool.Handler<"webFetch">, Schema.SchemaError, FileExtractionService | HttpClient.HttpClient>;
@@ -127,7 +127,7 @@ var defaultWebFetchToolkitOptions = {
127
127
  maxResponseBytes: 2 * 1024 * 1024,
128
128
  maxContentCharacters: 30000
129
129
  };
130
- var decodeOptions = Schema2.decodeUnknownSync(WebFetchToolkitOptions);
130
+ var decodeOptions = Schema2.decodeUnknownEffect(WebFetchToolkitOptions);
131
131
  var isPublicHttpsUrl = Schema2.makeFilter((value) => {
132
132
  try {
133
133
  const url = new URL(value);
@@ -213,60 +213,58 @@ var WebFetchTool = Tool.make("webFetch", {
213
213
  failureMode: "return"
214
214
  }).annotate(Tool.Title, "Read web page").annotate(Tool.Readonly, true).annotate(Tool.Destructive, false).annotate(Tool.Idempotent, true).annotate(Tool.OpenWorld, true);
215
215
  var WebFetchToolkit = Toolkit.make(WebFetchTool);
216
- var WebFetchToolkitLayer = (options = {}) => {
217
- const resolved = decodeOptions({
216
+ var WebFetchToolkitLayer = (options = {}) => WebFetchToolkit.toLayer(Effect2.gen(function* () {
217
+ const resolved = yield* decodeOptions({
218
218
  ...defaultWebFetchToolkitOptions,
219
219
  ...options
220
220
  });
221
- return WebFetchToolkit.toLayer(Effect2.gen(function* () {
222
- const http = yield* HttpClient.HttpClient;
223
- const extraction = yield* FileExtractionService;
224
- return WebFetchToolkit.of({
225
- webFetch: Effect2.fn("WebFetchToolkit.webFetch")(function* ({
226
- url
227
- }) {
228
- const request = HttpClientRequest.get(url).pipe(HttpClientRequest.setHeaders({
229
- accept: "text/markdown, text/plain;q=0.9, text/html;q=0.8, application/xhtml+xml;q=0.7, application/pdf;q=0.6, application/json;q=0.5",
230
- "user-agent": "krak-stack-webfetch/1.0"
231
- }));
232
- const response = yield* HttpClient.filterStatusOk(http).execute(request).pipe(Effect2.mapError(() => failure("unavailable", "The web page could not be fetched")), Effect2.timeoutOrElse({
233
- duration: "20 seconds",
234
- orElse: () => Effect2.fail(failure("unavailable", "The web page request timed out"))
235
- }));
236
- const contentLength = response.headers["content-length"];
237
- if (contentLength !== undefined) {
238
- const decodedContentLength = decodeContentLength(contentLength);
239
- if (Option.isNone(decodedContentLength) || decodedContentLength.value > resolved.maxResponseBytes) {
240
- return yield* Effect2.fail(failure("too-large", "The web page exceeds the response size limit"));
241
- }
242
- }
243
- const mediaType = response.headers["content-type"]?.split(";", 1)[0]?.trim().toLowerCase();
244
- const decodedMediaType = decodeMediaType(mediaType);
245
- if (Option.isNone(decodedMediaType)) {
246
- return yield* Effect2.fail(failure("unsupported-content", "The web page has an unsupported content type"));
247
- }
248
- const arrayBuffer = yield* response.arrayBuffer.pipe(Effect2.mapError(() => failure("invalid-response", "The web page body could not be read")));
249
- if (arrayBuffer.byteLength > resolved.maxResponseBytes) {
221
+ const http = yield* HttpClient.HttpClient;
222
+ const extraction = yield* FileExtractionService;
223
+ return WebFetchToolkit.of({
224
+ webFetch: Effect2.fn("WebFetchToolkit.webFetch")(function* ({
225
+ url
226
+ }) {
227
+ const request = HttpClientRequest.get(url).pipe(HttpClientRequest.setHeaders({
228
+ accept: "text/markdown, text/plain;q=0.9, text/html;q=0.8, application/xhtml+xml;q=0.7, application/pdf;q=0.6, application/json;q=0.5",
229
+ "user-agent": "krak-stack-webfetch/1.0"
230
+ }));
231
+ const response = yield* HttpClient.filterStatusOk(http).execute(request).pipe(Effect2.mapError(() => failure("unavailable", "The web page could not be fetched")), Effect2.timeoutOrElse({
232
+ duration: "20 seconds",
233
+ orElse: () => Effect2.fail(failure("unavailable", "The web page request timed out"))
234
+ }));
235
+ const contentLength = response.headers["content-length"];
236
+ if (contentLength !== undefined) {
237
+ const decodedContentLength = decodeContentLength(contentLength);
238
+ if (Option.isNone(decodedContentLength) || decodedContentLength.value > resolved.maxResponseBytes) {
250
239
  return yield* Effect2.fail(failure("too-large", "The web page exceeds the response size limit"));
251
240
  }
252
- const parsedUrl = new URL(url);
253
- const filename = parsedUrl.pathname.split("/").at(-1) || "page.html";
254
- const extracted = yield* extraction.markdown({
255
- bytes: new Uint8Array(arrayBuffer),
256
- filename,
257
- mimeType: decodedMediaType.value
258
- }).pipe(Effect2.mapError(() => failure("invalid-response", "The web page did not contain readable content")));
259
- const bounded = truncateContent(extracted.content, resolved.maxContentCharacters);
260
- return {
261
- url,
262
- contentType: decodedMediaType.value,
263
- content: bounded.content,
264
- truncated: extracted.truncated || bounded.truncated
265
- };
266
- })
267
- });
268
- }));
269
- };
241
+ }
242
+ const mediaType = response.headers["content-type"]?.split(";", 1)[0]?.trim().toLowerCase();
243
+ const decodedMediaType = decodeMediaType(mediaType);
244
+ if (Option.isNone(decodedMediaType)) {
245
+ return yield* Effect2.fail(failure("unsupported-content", "The web page has an unsupported content type"));
246
+ }
247
+ const arrayBuffer = yield* response.arrayBuffer.pipe(Effect2.mapError(() => failure("invalid-response", "The web page body could not be read")));
248
+ if (arrayBuffer.byteLength > resolved.maxResponseBytes) {
249
+ return yield* Effect2.fail(failure("too-large", "The web page exceeds the response size limit"));
250
+ }
251
+ const parsedUrl = new URL(url);
252
+ const filename = parsedUrl.pathname.split("/").at(-1) || "page.html";
253
+ const extracted = yield* extraction.markdown({
254
+ bytes: new Uint8Array(arrayBuffer),
255
+ filename,
256
+ mimeType: decodedMediaType.value
257
+ }).pipe(Effect2.mapError(() => failure("invalid-response", "The web page did not contain readable content")));
258
+ const bounded = truncateContent(extracted.content, resolved.maxContentCharacters);
259
+ return {
260
+ url,
261
+ contentType: decodedMediaType.value,
262
+ content: bounded.content,
263
+ truncated: extracted.truncated || bounded.truncated
264
+ };
265
+ })
266
+ });
267
+ }));
270
268
  export {
271
269
  WebFetchFailure,
272
270
  WebFetchRequest,
@@ -349,8 +349,8 @@ function classifyWideningTarget(type, environment) {
349
349
  if (alias === undefined)
350
350
  return null;
351
351
  if ((alias.typeParameters?.params.length ?? 0) > 0) {
352
- const substitutions2 = aliasSubstitution(alias, unwrapped, new Map);
353
- return substitutions2 !== null && resolvesToDictionary(alias.typeAnnotation, environment, substitutions2, new Set([name])) ? { kind: "generic container" } : null;
352
+ const substitutions = aliasSubstitution(alias, unwrapped, new Map);
353
+ return substitutions !== null && resolvesToDictionary(alias.typeAnnotation, environment, substitutions, new Set([name])) ? { kind: "generic container" } : null;
354
354
  }
355
355
  const substitutions = aliasSubstitution(alias, unwrapped, new Map);
356
356
  if (substitutions === null)