@krak-stack/registry 0.1.37 → 0.1.39

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 +131 -7
  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 +56 -56
  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 +1 -29
  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 +227 -533
  23. package/dist/lib/httpapi-toolkit.d.ts +15 -12
  24. package/dist/lib/httpapi-toolkit.js +175 -381
  25. package/dist/lib/query.d.ts +2 -2
  26. package/dist/lib/query.js +18 -5
  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 +3 -3
  32. package/package.json +5 -13
  33. package/dist/lib/httpapi-client.d.ts +0 -30
  34. package/dist/lib/httpapi-client.js +0 -112
  35. package/dist/lib/httpapi-helpers.d.ts +0 -101
  36. package/dist/lib/httpapi-helpers.js +0 -286
  37. package/dist/lib/httpapi-mcp.d.ts +0 -20
  38. package/dist/lib/httpapi-mcp.js +0 -477
package/dist/lib/query.js CHANGED
@@ -1,5 +1,12 @@
1
1
  // ../../src/lib/query.ts
2
- import { Effect, Schema, SchemaIssue, SchemaTransformation } from "effect";
2
+ import {
3
+ Effect,
4
+ Option,
5
+ Schema,
6
+ SchemaGetter,
7
+ SchemaIssue,
8
+ SchemaTransformation
9
+ } from "effect";
3
10
  var parseSortParam = (sort) => {
4
11
  const id = sort.startsWith("-") ? sort.slice(1) : sort;
5
12
  if (!id || id.includes(",") || id.includes(":")) {
@@ -74,8 +81,14 @@ var SortParams = Schema.declare(Schema.is(SortParamsArray), {
74
81
  toCodecStringTree: () => Schema.link()(SortParamsFromString, SchemaTransformation.passthrough())
75
82
  });
76
83
  var Query = Schema.Struct({
77
- page: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)).pipe(Schema.withDecodingDefaultKey(Effect.succeed(0))),
78
- pageSize: Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 100 })).pipe(Schema.withDecodingDefaultKey(Effect.succeed(10))),
84
+ page: Schema.optionalKey(Schema.Union([Schema.Number, Schema.NumberFromString]).check(Schema.isInt(), Schema.isGreaterThanOrEqualTo(0))).pipe(Schema.decodeTo(Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)), {
85
+ decode: SchemaGetter.withDefault(Effect.succeed(0)),
86
+ encode: SchemaGetter.transformOptional(Option.filter((page) => page !== 0))
87
+ })),
88
+ pageSize: Schema.optionalKey(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
+ decode: SchemaGetter.withDefault(Effect.succeed(20)),
90
+ encode: SchemaGetter.transformOptional(Option.filter((pageSize) => pageSize !== 20))
91
+ })),
79
92
  globalFilter: Schema.optional(Schema.String),
80
93
  sort: Schema.optional(SortParams)
81
94
  }).annotate({
@@ -85,7 +98,7 @@ var Query = Schema.Struct({
85
98
  examples: [
86
99
  {
87
100
  page: 0,
88
- pageSize: 10,
101
+ pageSize: 20,
89
102
  globalFilter: "housing",
90
103
  sort: [
91
104
  { id: "publicName", direction: "desc" },
@@ -104,7 +117,7 @@ var PaginationMeta = Schema.Struct({
104
117
  identifier: "PaginationMeta",
105
118
  title: "Pagination Metadata",
106
119
  description: "Pagination metadata returned with a paginated list response.",
107
- examples: [{ page: 0, pageSize: 10, total: 125, pageCount: 13 }]
120
+ examples: [{ page: 0, pageSize: 20, total: 125, pageCount: 7 }]
108
121
  }));
109
122
  var PaginatedResponse = (items) => Schema.Struct({
110
123
  data: Schema.Array(items),
@@ -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)
@@ -227,7 +227,7 @@ function CopyButton({
227
227
  valueDescription,
228
228
  copyVariant = "default",
229
229
  locale: localeOverride,
230
- messages: messages2,
230
+ messages,
231
231
  onCopied,
232
232
  onCopyError,
233
233
  resetDelay = 1500,
@@ -239,7 +239,7 @@ function CopyButton({
239
239
  const locale = useKrakstackLocale(localeOverride);
240
240
  const [copyState, setCopyState] = useState("idle");
241
241
  const copyTimeout = useRef(undefined);
242
- const labels = copyButtonMessages(locale, messages2);
242
+ const labels = copyButtonMessages(locale, messages);
243
243
  const accessibleLabel = ariaLabel ?? (valueDescription ? `${labels.copy} ${valueDescription}` : labels.copy);
244
244
  const isLarge = copyVariant === "large";
245
245
  const defaultSize = copyVariant === "sm" ? "icon-xs" : isLarge ? "sm" : "icon-sm";
@@ -341,12 +341,12 @@ function CodeBlock({
341
341
  code,
342
342
  language = "text",
343
343
  locale: localeOverride,
344
- messages: messages3
344
+ messages
345
345
  }) {
346
346
  const locale = useKrakstackLocale2(localeOverride);
347
347
  const normalizedLanguage = language.toLowerCase() || "text";
348
348
  const highlighted = highlight(code, { lang: normalizedLanguage });
349
- const labels = codeBlockMessages(locale, messages3);
349
+ const labels = codeBlockMessages(locale, messages);
350
350
  return /* @__PURE__ */ jsxs2("div", {
351
351
  className: "not-prose bg-muted overflow-hidden rounded-md border text-[var(--th-token)]",
352
352
  "data-code-theme": true,
@@ -385,7 +385,7 @@ var MarkdownContent = ({
385
385
  codeBlocks,
386
386
  html,
387
387
  locale,
388
- messages: messages3
388
+ messages
389
389
  }) => {
390
390
  const content = [];
391
391
  let remainingHtml = html;
@@ -404,7 +404,7 @@ var MarkdownContent = ({
404
404
  code: block.code,
405
405
  language: block.language,
406
406
  locale,
407
- messages: messages3
407
+ messages
408
408
  })
409
409
  }, `code-${index}`));
410
410
  remainingHtml = remainingHtml.slice(markerIndex + marker.length);
@@ -43,7 +43,7 @@ var compileMarkdown = (source) => {
43
43
  codeBlocks.push({ code, language });
44
44
  return `<markdown-code-block data-index="${index}"></markdown-code-block>`;
45
45
  },
46
- codespan: (children) => `<code data-inline-code>${escapeHtml(children)}</code>`,
46
+ codespan: (children) => `<code data-inline-code>${children}</code>`,
47
47
  emphasis: (children) => `<em>${children}</em>`,
48
48
  heading: (children, { id, level }) => {
49
49
  const headingId = escapeHtml(id ?? "");
@@ -282,8 +282,8 @@ class AgentService extends Context.Service()("AgentService", {
282
282
  }));
283
283
  });
284
284
  const complete = Stream.fromEffect(Effect.gen(function* () {
285
- const history2 = yield* conversation.exportJson;
286
- return { type: "history", value: history2 };
285
+ const history = yield* conversation.exportJson;
286
+ return { type: "history", value: history };
287
287
  })).pipe(Stream.concat(Stream.succeed({ type: "finish" })));
288
288
  const response = Stream.concat(renderedRounds, complete).pipe(Stream.provideService(LanguageModel.LanguageModel, model), Stream.catch((error) => Stream.fromEffect(Effect.logError("Agent stream failed", streamErrorDetails(error))).pipe(Stream.drain, Stream.concat(Stream.make({
289
289
  type: "error",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@krak-stack/registry",
3
- "version": "0.1.37",
3
+ "version": "0.1.39",
4
4
  "description": "Tree-shakable KrakStack components and Effect services.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -29,7 +29,7 @@
29
29
  "types": "./dist/services/agent/schema.d.ts",
30
30
  "import": "./dist/services/agent/schema.js"
31
31
  },
32
- "./httpapi-toolkit": {
32
+ "./httpapi/toolkit": {
33
33
  "types": "./dist/lib/httpapi-toolkit.d.ts",
34
34
  "import": "./dist/lib/httpapi-toolkit.js"
35
35
  },
@@ -37,17 +37,9 @@
37
37
  "types": "./dist/lib/httpapi-cli.d.ts",
38
38
  "import": "./dist/lib/httpapi-cli.js"
39
39
  },
40
- "./httpapi/client": {
41
- "types": "./dist/lib/httpapi-client.d.ts",
42
- "import": "./dist/lib/httpapi-client.js"
43
- },
44
- "./httpapi/helpers": {
45
- "types": "./dist/lib/httpapi-helpers.d.ts",
46
- "import": "./dist/lib/httpapi-helpers.js"
47
- },
48
- "./httpapi/mcp": {
49
- "types": "./dist/lib/httpapi-mcp.d.ts",
50
- "import": "./dist/lib/httpapi-mcp.js"
40
+ "./httpapi/adapter": {
41
+ "types": "./dist/lib/httpapi-adapter.d.ts",
42
+ "import": "./dist/lib/httpapi-adapter.js"
51
43
  },
52
44
  "./opentelemetry/api": {
53
45
  "types": "./dist/services/opentelemetry/api.d.ts",
@@ -1,30 +0,0 @@
1
- import { Context, Effect, Layer, Schema } from "effect";
2
- import { HttpClient } from "effect/http";
3
- import { HttpApi, HttpApiGroup } from "effect/http-api";
4
- import type { HttpApiOperationEntry, HttpApiOperationInput } from "./httpapi-helpers.js";
5
- import type { Json } from "effect/Schema";
6
- export type ApiClientConfig<Id extends string, Groups extends HttpApiGroup.Constraint> = {
7
- readonly api: HttpApi.HttpApi<Id, Groups>;
8
- readonly baseUrl: string;
9
- readonly encodeResult?: (result: ErrorOptions["cause"], operation: HttpApiOperationEntry) => Effect.Effect<Json, Error>;
10
- };
11
- export type ApiClientExecuteOptions = {
12
- readonly operation: HttpApiOperationEntry;
13
- readonly input: HttpApiOperationInput;
14
- };
15
- export type HttpApiOperationResultValue = null | undefined | string | number | boolean | Date | Uint8Array | ReadonlyArray<HttpApiOperationResultValue> | {
16
- readonly [key: string]: HttpApiOperationResultValue;
17
- };
18
- export declare const HttpApiOperationResult: Schema.Union<readonly [Schema.Codec<HttpApiOperationResultValue, Json, never, never>, Schema.Undefined]>;
19
- export type HttpApiOperationResult = typeof HttpApiOperationResult.Type;
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>;
22
- export type ApiClientService = {
23
- readonly encodeResult: (result: ErrorOptions["cause"], operation: HttpApiOperationEntry) => Effect.Effect<Json, Error>;
24
- readonly execute: (options: ApiClientExecuteOptions) => Effect.Effect<ErrorOptions["cause"], Error>;
25
- };
26
- declare const ApiClient_base: Context.ServiceClass<ApiClient, "ApiClient", ApiClientService>;
27
- export declare class ApiClient extends ApiClient_base {
28
- static readonly layer: <Id extends string, Groups extends HttpApiGroup.Constraint>(config: ApiClientConfig<Id, Groups>) => Layer.Layer<ApiClient, never, HttpClient.HttpClient | Exclude<import("effect/http-api/HttpApiMiddleware").MiddlewareClient<import("effect/http-api/HttpApiEndpoint").Middleware<HttpApiGroup.Endpoints<Groups>>>, import("effect/Scope").Scope>>;
29
- }
30
- export {};
@@ -1,112 +0,0 @@
1
- // ../../src/lib/httpapi-client.ts
2
- import { Context, Effect, Layer, Schema, SchemaTransformation } from "effect";
3
- import { HttpClient } from "effect/http";
4
- import {
5
- HttpApi,
6
- HttpApiClient as EffectHttpApiClient,
7
- OpenApi
8
- } from "effect/http-api";
9
- var UndefinedFromNull = Schema.Null.pipe(Schema.decodeTo(Schema.Undefined, SchemaTransformation.transform({
10
- decode: () => {
11
- return;
12
- },
13
- encode: () => null
14
- })));
15
- var HttpApiOperationResultValue = Schema.suspend(() => Schema.Union([
16
- Schema.Null,
17
- UndefinedFromNull,
18
- Schema.String,
19
- Schema.Number,
20
- Schema.Boolean,
21
- Schema.DateFromString,
22
- Schema.Uint8ArrayFromBase64,
23
- Schema.Array(HttpApiOperationResultValue),
24
- Schema.Record(Schema.String, HttpApiOperationResultValue)
25
- ]));
26
- var HttpApiOperationResult = Schema.Union([
27
- HttpApiOperationResultValue,
28
- Schema.Undefined
29
- ]).annotate({ identifier: "HttpApiOperationResult" });
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
- };
62
- var GeneratedOperation = Schema.declare((value) => value instanceof Function).annotate({ identifier: "GeneratedOperation" });
63
- var GeneratedOperationEffect = Schema.declare((value) => Effect.isEffect(value)).annotate({ identifier: "GeneratedOperationEffect" });
64
- var makeGeneratedClient = (api, http, baseUrl) => EffectHttpApiClient.makeWith(api, {
65
- baseUrl,
66
- httpClient: http
67
- });
68
- var executeGeneratedOperation = Effect.fn("HttpApiClient.executeGeneratedOperation")(function* (client, { input, operation: entry }) {
69
- const operationId = entry.operation.operationId;
70
- if (!operationId) {
71
- return yield* Effect.fail(new Error(`No generated API client operation for ${entry.method} ${entry.path}`));
72
- }
73
- const target = Object(client);
74
- const groupName = Object.keys(target).filter((name) => operationId.startsWith(`${name}.`)).sort((a, b) => b.length - a.length)[0];
75
- const group = groupName ? Object.entries(target).find(([name]) => name === groupName)?.[1] : target;
76
- const endpointName = groupName ? operationId.slice(groupName.length + 1) : operationId;
77
- const endpointCandidate = group instanceof Function ? undefined : Object.entries(Object(group)).find(([name]) => name === endpointName)?.[1];
78
- const endpoint = Schema.decodeUnknownOption(GeneratedOperation)(endpointCandidate);
79
- if (endpoint._tag === "None") {
80
- return yield* Effect.fail(new Error(`No generated API client operation for ${operationId}`));
81
- }
82
- const result = Schema.decodeUnknownOption(GeneratedOperationEffect)(endpoint.value({
83
- headers: input.headers,
84
- params: input.params,
85
- query: input.query,
86
- payload: input.body
87
- }));
88
- if (result._tag === "None") {
89
- return yield* Effect.fail(new Error(`Generated API client operation ${operationId} is invalid`));
90
- }
91
- return yield* result.value;
92
- });
93
-
94
- class ApiClient extends Context.Service()("ApiClient") {
95
- static layer = (config) => Layer.effect(this, Effect.gen(function* () {
96
- const http = yield* HttpClient.HttpClient;
97
- const encodeResult = makeHttpApiOperationResultEncoder(config.api);
98
- const client = yield* makeGeneratedClient(config.api, http, config.baseUrl);
99
- return {
100
- encodeResult: config.encodeResult ?? ((result, operation) => encodeResult(result, operation)),
101
- execute: Effect.fn("ApiClient.execute")(function* (options) {
102
- return yield* executeGeneratedOperation(client, options);
103
- })
104
- };
105
- }));
106
- }
107
- export {
108
- ApiClient,
109
- HttpApiOperationResult,
110
- encodeHttpApiOperationResult,
111
- makeHttpApiOperationResultEncoder
112
- };
@@ -1,101 +0,0 @@
1
- import { Context, Effect, JsonSchema, Layer, Schema } from "effect";
2
- import type { Json } from "effect/Schema";
3
- import { HttpApi, OpenApi } from "effect/http-api";
4
- export declare const JsonObjectSchema: Schema.$Record<Schema.String, Schema.Codec<Json, Json, never, never>>;
5
- export type JsonObject = typeof JsonObjectSchema.Type;
6
- type HttpBoundaryError = ErrorOptions["cause"];
7
- export type HttpApiDocument = ReturnType<typeof OpenApi.fromApi>;
8
- export type HttpApiMethod = "get" | "post" | "put" | "patch" | "delete";
9
- export declare const HttpApiMethods: ReadonlyArray<HttpApiMethod>;
10
- export type HttpApiParameter = {
11
- readonly name: string;
12
- readonly in: "path" | "query" | "header" | "cookie";
13
- readonly required?: boolean;
14
- readonly description?: string;
15
- readonly schema?: JsonSchema.JsonSchema;
16
- };
17
- export type HttpApiOperation = {
18
- readonly operationId?: string;
19
- readonly summary?: string;
20
- readonly description?: string;
21
- readonly parameters?: ReadonlyArray<HttpApiParameter>;
22
- readonly requestBody?: {
23
- readonly required?: boolean;
24
- readonly content?: Record<string, {
25
- readonly schema?: JsonSchema.JsonSchema;
26
- }>;
27
- };
28
- readonly tags?: ReadonlyArray<string>;
29
- };
30
- export type HttpApiOperationEntry = {
31
- readonly method: HttpApiMethod;
32
- readonly path: string;
33
- readonly operation: HttpApiOperation;
34
- };
35
- export type HttpApiOperationInputValue = ErrorOptions["cause"];
36
- export type HttpApiOperationInputValues = Readonly<Record<string, HttpApiOperationInputValue>>;
37
- export type HttpApiOperationInput = {
38
- readonly body?: HttpApiOperationInputValue;
39
- readonly headers: HttpApiOperationInputValues;
40
- readonly params: HttpApiOperationInputValues;
41
- readonly query: HttpApiOperationInputValues;
42
- };
43
- export type HttpApiSpecConfig = {
44
- readonly api: HttpApi.Constraint;
45
- readonly methods?: ReadonlyArray<HttpApiMethod>;
46
- readonly include?: (operation: HttpApiOperationEntry) => boolean;
47
- };
48
- export declare const toHttpError: (message: string, error: HttpBoundaryError) => Error;
49
- export declare const sanitizeHttpName: (name: string) => string;
50
- export declare const httpApiToolName: (method: string, path: string, operation: HttpApiOperation) => string;
51
- export declare const httpApiOperations: ({ spec, methods, }: {
52
- readonly spec: HttpApiDocument;
53
- readonly methods?: ReadonlyArray<HttpApiMethod>;
54
- }) => ReadonlyArray<HttpApiOperationEntry>;
55
- export declare const httpApiToolEntries: (operations: readonly HttpApiOperationEntry[]) => Effect.Effect<{
56
- method: HttpApiMethod;
57
- path: string;
58
- operation: HttpApiOperation;
59
- name: string;
60
- }[], Error, never>;
61
- export declare const httpApiOperationInputSchema: (operation: HttpApiOperation) => JsonSchema.JsonSchema;
62
- export declare const decodeHttpApiOperationInput: (input: Json, operation: HttpApiOperation) => Effect.Effect<{
63
- body?: Json | undefined;
64
- headers: any;
65
- params: any;
66
- query: any;
67
- }, Error, never>;
68
- export declare const parseJsonObject: (value: string | undefined, label: string) => Effect.Effect<{
69
- readonly [x: string]: Json;
70
- }, Error, never>;
71
- export declare const parseJsonValue: (value: string | undefined, label: string) => Effect.Effect<Json | undefined, Error, never>;
72
- declare const HttpApiSpec_base: Context.ServiceClass<HttpApiSpec, "HttpApiSpec", {
73
- info: OpenApi.OpenAPISpecInfo;
74
- operations: HttpApiOperationEntry[];
75
- decodeOperationInput: (input: Json, operation: HttpApiOperation) => Effect.Effect<{
76
- body?: Json | undefined;
77
- headers: any;
78
- params: any;
79
- query: any;
80
- }, Error, never>;
81
- operationJsonSchema: (operation: HttpApiOperation) => JsonSchema.JsonSchema;
82
- operationSchema: (operation: HttpApiOperation) => Schema.Codec<unknown, unknown, never, never>;
83
- }> & {
84
- readonly make: (config: HttpApiSpecConfig) => Effect.Effect<{
85
- info: OpenApi.OpenAPISpecInfo;
86
- operations: HttpApiOperationEntry[];
87
- decodeOperationInput: (input: Json, operation: HttpApiOperation) => Effect.Effect<{
88
- body?: Json | undefined;
89
- headers: any;
90
- params: any;
91
- query: any;
92
- }, Error, never>;
93
- operationJsonSchema: (operation: HttpApiOperation) => JsonSchema.JsonSchema;
94
- operationSchema: (operation: HttpApiOperation) => Schema.Codec<unknown, unknown, never, never>;
95
- }, Error, never>;
96
- };
97
- export declare class HttpApiSpec extends HttpApiSpec_base {
98
- static readonly layer: (config: HttpApiSpecConfig) => Layer.Layer<HttpApiSpec, Error, never>;
99
- }
100
- export type HttpApiSpecService = typeof HttpApiSpec.Service;
101
- export {};