@iflow-ai/search-openapi 0.1.0-pre.0

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 (55) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +248 -0
  3. package/dist/auth.d.ts +22 -0
  4. package/dist/auth.d.ts.map +1 -0
  5. package/dist/auth.js +68 -0
  6. package/dist/auth.js.map +1 -0
  7. package/dist/bin.d.ts +24 -0
  8. package/dist/bin.d.ts.map +1 -0
  9. package/dist/bin.js +84 -0
  10. package/dist/bin.js.map +1 -0
  11. package/dist/config.d.ts +42 -0
  12. package/dist/config.d.ts.map +1 -0
  13. package/dist/config.js +70 -0
  14. package/dist/config.js.map +1 -0
  15. package/dist/errors.d.ts +27 -0
  16. package/dist/errors.d.ts.map +1 -0
  17. package/dist/errors.js +49 -0
  18. package/dist/errors.js.map +1 -0
  19. package/dist/handlers/image-search.d.ts +8 -0
  20. package/dist/handlers/image-search.d.ts.map +1 -0
  21. package/dist/handlers/image-search.js +53 -0
  22. package/dist/handlers/image-search.js.map +1 -0
  23. package/dist/handlers/index.d.ts +13 -0
  24. package/dist/handlers/index.d.ts.map +1 -0
  25. package/dist/handlers/index.js +15 -0
  26. package/dist/handlers/index.js.map +1 -0
  27. package/dist/handlers/types.d.ts +37 -0
  28. package/dist/handlers/types.d.ts.map +1 -0
  29. package/dist/handlers/types.js +13 -0
  30. package/dist/handlers/types.js.map +1 -0
  31. package/dist/handlers/web-fetch.d.ts +8 -0
  32. package/dist/handlers/web-fetch.d.ts.map +1 -0
  33. package/dist/handlers/web-fetch.js +41 -0
  34. package/dist/handlers/web-fetch.js.map +1 -0
  35. package/dist/handlers/web-search.d.ts +10 -0
  36. package/dist/handlers/web-search.d.ts.map +1 -0
  37. package/dist/handlers/web-search.js +55 -0
  38. package/dist/handlers/web-search.js.map +1 -0
  39. package/dist/index.d.ts +13 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +13 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/openapi.d.ts +19 -0
  44. package/dist/openapi.d.ts.map +1 -0
  45. package/dist/openapi.js +112 -0
  46. package/dist/openapi.js.map +1 -0
  47. package/dist/server.d.ts +31 -0
  48. package/dist/server.d.ts.map +1 -0
  49. package/dist/server.js +150 -0
  50. package/dist/server.js.map +1 -0
  51. package/dist/version.d.ts +4 -0
  52. package/dist/version.d.ts.map +1 -0
  53. package/dist/version.js +7 -0
  54. package/dist/version.js.map +1 -0
  55. package/package.json +61 -0
package/dist/errors.js ADDED
@@ -0,0 +1,49 @@
1
+ /**
2
+ * HTTP error JSON shape used by every endpoint. The OpenAPI spec
3
+ * advertises the same shape so Open WebUI / Coze and other OpenAPI
4
+ * tool hosts can render errors uniformly.
5
+ *
6
+ * iFlow errors come pre-shaped from @iflow-ai/search-core (stable codes
7
+ * + messages). This module never re-derives codes — it just maps to
8
+ * HTTP status codes and JSON output.
9
+ *
10
+ * For api_error specifically, iFlow's own HTTP status (when present on
11
+ * `IFlowError.status`) wins over the default — that preserves the
12
+ * upstream 401 / 403 / 429 signal to clients who key off status codes.
13
+ */
14
+ const STATUS_BY_CODE = {
15
+ missing_api_key: 401,
16
+ missing_param: 400,
17
+ invalid_param: 400,
18
+ network_timeout: 504,
19
+ network_error: 502,
20
+ api_error: 502,
21
+ api_business_error: 502,
22
+ };
23
+ export function statusForIFlowError(error) {
24
+ if (error.code === "api_error" &&
25
+ typeof error.status === "number" &&
26
+ error.status >= 400 &&
27
+ error.status <= 599) {
28
+ return error.status;
29
+ }
30
+ return STATUS_BY_CODE[error.code] ?? 500;
31
+ }
32
+ export function iflowErrorToBody(error) {
33
+ const body = {
34
+ ok: false,
35
+ error: {
36
+ code: error.code,
37
+ message: error.message,
38
+ },
39
+ };
40
+ if (typeof error.status === "number")
41
+ body.error.status = error.status;
42
+ if (error.detail !== undefined)
43
+ body.error.detail = error.detail;
44
+ return body;
45
+ }
46
+ export function genericErrorBody(code, message) {
47
+ return { ok: false, error: { code, message } };
48
+ }
49
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAcH,MAAM,cAAc,GAAmC;IACrD,eAAe,EAAE,GAAG;IACpB,aAAa,EAAE,GAAG;IAClB,aAAa,EAAE,GAAG;IAClB,eAAe,EAAE,GAAG;IACpB,aAAa,EAAE,GAAG;IAClB,SAAS,EAAE,GAAG;IACd,kBAAkB,EAAE,GAAG;CACxB,CAAC;AAEF,MAAM,UAAU,mBAAmB,CAAC,KAAiB;IACnD,IACE,KAAK,CAAC,IAAI,KAAK,WAAW;QAC1B,OAAO,KAAK,CAAC,MAAM,KAAK,QAAQ;QAChC,KAAK,CAAC,MAAM,IAAI,GAAG;QACnB,KAAK,CAAC,MAAM,IAAI,GAAG,EACnB,CAAC;QACD,OAAO,KAAK,CAAC,MAAM,CAAC;IACtB,CAAC;IACD,OAAO,cAAc,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,KAAiB;IAChD,MAAM,IAAI,GAAc;QACtB,EAAE,EAAE,KAAK;QACT,KAAK,EAAE;YACL,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,OAAO,EAAE,KAAK,CAAC,OAAO;SACvB;KACF,CAAC;IACF,IAAI,OAAO,KAAK,CAAC,MAAM,KAAK,QAAQ;QAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;IACvE,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS;QAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;IACjE,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,IAAY,EAAE,OAAe;IAC5D,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC;AACjD,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * POST /tools/iflow_image_search
3
+ *
4
+ * Pass-through to IFlowSearchClient.imageSearch.
5
+ */
6
+ import type { ToolHandler } from "./types.js";
7
+ export declare const imageSearchHandler: ToolHandler;
8
+ //# sourceMappingURL=image-search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-search.d.ts","sourceRoot":"","sources":["../../src/handlers/image-search.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAI9C,eAAO,MAAM,kBAAkB,EAAE,WA4ChC,CAAC"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * POST /tools/iflow_image_search
3
+ *
4
+ * Pass-through to IFlowSearchClient.imageSearch.
5
+ */
6
+ import { IMAGE_SEARCH_DEFAULT_COUNT, IMAGE_SEARCH_MAX_COUNT, } from "@iflow-ai/search-core";
7
+ import { iflowErrorToBody, statusForIFlowError } from "../errors.js";
8
+ const TOOL_NAME = "iflow_image_search";
9
+ export const imageSearchHandler = {
10
+ name: TOOL_NAME,
11
+ title: "iFlow Image Search",
12
+ description: "Search images with iFlow. Returns image URLs, titles, and the " +
13
+ "source pages they appear on.",
14
+ inputSchema: {
15
+ type: "object",
16
+ properties: {
17
+ query: {
18
+ type: "string",
19
+ minLength: 1,
20
+ description: "Image search query.",
21
+ },
22
+ count: {
23
+ type: "integer",
24
+ minimum: 1,
25
+ maximum: IMAGE_SEARCH_MAX_COUNT,
26
+ description: `Number of images (1–${IMAGE_SEARCH_MAX_COUNT}, default ${IMAGE_SEARCH_DEFAULT_COUNT}).`,
27
+ },
28
+ },
29
+ required: ["query"],
30
+ additionalProperties: false,
31
+ },
32
+ async handle(rawBody, client) {
33
+ const body = (rawBody ?? {});
34
+ const params = {
35
+ query: typeof body.query === "string" ? body.query : "",
36
+ };
37
+ if (body.count !== undefined) {
38
+ params.count = body.count;
39
+ }
40
+ const result = await client.imageSearch(params);
41
+ if (!result.ok) {
42
+ return {
43
+ status: statusForIFlowError(result.error),
44
+ body: iflowErrorToBody(result.error),
45
+ };
46
+ }
47
+ return {
48
+ status: 200,
49
+ body: { ok: true, data: result.data },
50
+ };
51
+ },
52
+ };
53
+ //# sourceMappingURL=image-search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-search.js","sourceRoot":"","sources":["../../src/handlers/image-search.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,0BAA0B,EAC1B,sBAAsB,GACvB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAGrE,MAAM,SAAS,GAAG,oBAAoB,CAAC;AAEvC,MAAM,CAAC,MAAM,kBAAkB,GAAgB;IAC7C,IAAI,EAAE,SAAS;IACf,KAAK,EAAE,oBAAoB;IAC3B,WAAW,EACT,gEAAgE;QAChE,8BAA8B;IAChC,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,KAAK,EAAE;gBACL,IAAI,EAAE,QAAQ;gBACd,SAAS,EAAE,CAAC;gBACZ,WAAW,EAAE,qBAAqB;aACnC;YACD,KAAK,EAAE;gBACL,IAAI,EAAE,SAAS;gBACf,OAAO,EAAE,CAAC;gBACV,OAAO,EAAE,sBAAsB;gBAC/B,WAAW,EAAE,uBAAuB,sBAAsB,aAAa,0BAA0B,IAAI;aACtG;SACF;QACD,QAAQ,EAAE,CAAC,OAAO,CAAC;QACnB,oBAAoB,EAAE,KAAK;KAC5B;IACD,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM;QAC1B,MAAM,IAAI,GAAG,CAAC,OAAO,IAAI,EAAE,CAAyC,CAAC;QACrE,MAAM,MAAM,GAAsC;YAChD,KAAK,EAAE,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;SACxD,CAAC;QACF,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;YAC7B,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,KAAe,CAAC;QACtC,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QAChD,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;YACf,OAAO;gBACL,MAAM,EAAE,mBAAmB,CAAC,MAAM,CAAC,KAAK,CAAC;gBACzC,IAAI,EAAE,gBAAgB,CAAC,MAAM,CAAC,KAAK,CAAC;aACrC,CAAC;QACJ,CAAC;QACD,OAAO;YACL,MAAM,EAAE,GAAG;YACX,IAAI,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE;SACtC,CAAC;IACJ,CAAC;CACF,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Ordered list of tool handlers. Order is the order they appear in
3
+ * /openapi.json so consumers (Open WebUI, Coze, …) get a stable
4
+ * tool catalog.
5
+ */
6
+ import { webSearchHandler } from "./web-search.js";
7
+ import { imageSearchHandler } from "./image-search.js";
8
+ import { webFetchHandler } from "./web-fetch.js";
9
+ import type { ToolHandler } from "./types.js";
10
+ export declare const TOOL_HANDLERS: readonly ToolHandler[];
11
+ export type { ToolHandler };
12
+ export { webSearchHandler, imageSearchHandler, webFetchHandler };
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/handlers/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,eAAO,MAAM,aAAa,EAAE,SAAS,WAAW,EAI/C,CAAC;AAEF,YAAY,EAAE,WAAW,EAAE,CAAC;AAC5B,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,eAAe,EAAE,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Ordered list of tool handlers. Order is the order they appear in
3
+ * /openapi.json so consumers (Open WebUI, Coze, …) get a stable
4
+ * tool catalog.
5
+ */
6
+ import { webSearchHandler } from "./web-search.js";
7
+ import { imageSearchHandler } from "./image-search.js";
8
+ import { webFetchHandler } from "./web-fetch.js";
9
+ export const TOOL_HANDLERS = [
10
+ webSearchHandler,
11
+ imageSearchHandler,
12
+ webFetchHandler,
13
+ ];
14
+ export { webSearchHandler, imageSearchHandler, webFetchHandler };
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/handlers/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAGjD,MAAM,CAAC,MAAM,aAAa,GAA2B;IACnD,gBAAgB;IAChB,kBAAkB;IAClB,eAAe;CAChB,CAAC;AAGF,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,eAAe,EAAE,CAAC"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Per-route handler shape shared by the three iFlow Search tool endpoints.
3
+ *
4
+ * Handlers are pure functions from a parsed JSON body to an HTTP response
5
+ * (status code + JSON body). They never throw across the HTTP boundary —
6
+ * all iFlow errors are surfaced as normalized error bodies built from
7
+ * the IFlowError returned by @iflow-ai/search-core.
8
+ *
9
+ * The inputSchema is JSON Schema, surfaced verbatim in /openapi.json as
10
+ * the requestBody schema for each tool route.
11
+ */
12
+ import type { IFlowSearchClient } from "@iflow-ai/search-core";
13
+ export interface ToolHandler {
14
+ /** Path segment under /tools, e.g. "iflow_web_search". */
15
+ name: string;
16
+ /** Short human label used in /openapi.json summary. */
17
+ title: string;
18
+ /** Description shown to LLMs and tool catalogs. */
19
+ description: string;
20
+ /** JSON Schema for the request body. */
21
+ inputSchema: {
22
+ type: "object";
23
+ properties: Record<string, unknown>;
24
+ required?: string[];
25
+ additionalProperties?: boolean;
26
+ };
27
+ /**
28
+ * Handle a parsed JSON request body. Returns the HTTP status and JSON
29
+ * body to send. Implementations delegate all iFlow logic to `client`
30
+ * and translate the IFlowResult envelope into the openapi response shape.
31
+ */
32
+ handle(rawBody: unknown, client: IFlowSearchClient): Promise<{
33
+ status: number;
34
+ body: object;
35
+ }>;
36
+ }
37
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/handlers/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE/D,MAAM,WAAW,WAAW;IAC1B,0DAA0D;IAC1D,IAAI,EAAE,MAAM,CAAC;IACb,uDAAuD;IACvD,KAAK,EAAE,MAAM,CAAC;IACd,mDAAmD;IACnD,WAAW,EAAE,MAAM,CAAC;IACpB,wCAAwC;IACxC,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ,CAAC;QACf,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACpC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;QACpB,oBAAoB,CAAC,EAAE,OAAO,CAAC;KAChC,CAAC;IACF;;;;OAIG;IACH,MAAM,CACJ,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,iBAAiB,GACxB,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC9C"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Per-route handler shape shared by the three iFlow Search tool endpoints.
3
+ *
4
+ * Handlers are pure functions from a parsed JSON body to an HTTP response
5
+ * (status code + JSON body). They never throw across the HTTP boundary —
6
+ * all iFlow errors are surfaced as normalized error bodies built from
7
+ * the IFlowError returned by @iflow-ai/search-core.
8
+ *
9
+ * The inputSchema is JSON Schema, surfaced verbatim in /openapi.json as
10
+ * the requestBody schema for each tool route.
11
+ */
12
+ export {};
13
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/handlers/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * POST /tools/iflow_web_fetch
3
+ *
4
+ * Pass-through to IFlowSearchClient.webFetch.
5
+ */
6
+ import type { ToolHandler } from "./types.js";
7
+ export declare const webFetchHandler: ToolHandler;
8
+ //# sourceMappingURL=web-fetch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-fetch.d.ts","sourceRoot":"","sources":["../../src/handlers/web-fetch.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAI9C,eAAO,MAAM,eAAe,EAAE,WAiC7B,CAAC"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * POST /tools/iflow_web_fetch
3
+ *
4
+ * Pass-through to IFlowSearchClient.webFetch.
5
+ */
6
+ import { iflowErrorToBody, statusForIFlowError } from "../errors.js";
7
+ const TOOL_NAME = "iflow_web_fetch";
8
+ export const webFetchHandler = {
9
+ name: TOOL_NAME,
10
+ title: "iFlow Web Fetch",
11
+ description: "Fetch the readable contents of a single URL via iFlow. Use after " +
12
+ "iflow_web_search picks a promising result and you want the full text.",
13
+ inputSchema: {
14
+ type: "object",
15
+ properties: {
16
+ url: {
17
+ type: "string",
18
+ minLength: 1,
19
+ description: "Absolute URL of the page to fetch.",
20
+ },
21
+ },
22
+ required: ["url"],
23
+ additionalProperties: false,
24
+ },
25
+ async handle(rawBody, client) {
26
+ const body = (rawBody ?? {});
27
+ const url = typeof body.url === "string" ? body.url : "";
28
+ const result = await client.webFetch({ url });
29
+ if (!result.ok) {
30
+ return {
31
+ status: statusForIFlowError(result.error),
32
+ body: iflowErrorToBody(result.error),
33
+ };
34
+ }
35
+ return {
36
+ status: 200,
37
+ body: { ok: true, data: result.data },
38
+ };
39
+ },
40
+ };
41
+ //# sourceMappingURL=web-fetch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-fetch.js","sourceRoot":"","sources":["../../src/handlers/web-fetch.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAGrE,MAAM,SAAS,GAAG,iBAAiB,CAAC;AAEpC,MAAM,CAAC,MAAM,eAAe,GAAgB;IAC1C,IAAI,EAAE,SAAS;IACf,KAAK,EAAE,iBAAiB;IACxB,WAAW,EACT,mEAAmE;QACnE,uEAAuE;IACzE,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,GAAG,EAAE;gBACH,IAAI,EAAE,QAAQ;gBACd,SAAS,EAAE,CAAC;gBACZ,WAAW,EAAE,oCAAoC;aAClD;SACF;QACD,QAAQ,EAAE,CAAC,KAAK,CAAC;QACjB,oBAAoB,EAAE,KAAK;KAC5B;IACD,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM;QAC1B,MAAM,IAAI,GAAG,CAAC,OAAO,IAAI,EAAE,CAAsB,CAAC;QAClD,MAAM,GAAG,GAAG,OAAO,IAAI,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QACzD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;QAC9C,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;YACf,OAAO;gBACL,MAAM,EAAE,mBAAmB,CAAC,MAAM,CAAC,KAAK,CAAC;gBACzC,IAAI,EAAE,gBAAgB,CAAC,MAAM,CAAC,KAAK,CAAC;aACrC,CAAC;QACJ,CAAC;QACD,OAAO;YACL,MAAM,EAAE,GAAG;YACX,IAAI,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE;SACtC,CAAC;IACJ,CAAC;CACF,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * POST /tools/iflow_web_search
3
+ *
4
+ * Thin pass-through to IFlowSearchClient.webSearch. search-core owns
5
+ * query / count validation and produces IFlowError on any rejection;
6
+ * this module just translates the envelope into the HTTP response shape.
7
+ */
8
+ import type { ToolHandler } from "./types.js";
9
+ export declare const webSearchHandler: ToolHandler;
10
+ //# sourceMappingURL=web-search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-search.d.ts","sourceRoot":"","sources":["../../src/handlers/web-search.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAOH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAI9C,eAAO,MAAM,gBAAgB,EAAE,WA4C9B,CAAC"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * POST /tools/iflow_web_search
3
+ *
4
+ * Thin pass-through to IFlowSearchClient.webSearch. search-core owns
5
+ * query / count validation and produces IFlowError on any rejection;
6
+ * this module just translates the envelope into the HTTP response shape.
7
+ */
8
+ import { WEB_SEARCH_DEFAULT_COUNT, WEB_SEARCH_MAX_COUNT, } from "@iflow-ai/search-core";
9
+ import { iflowErrorToBody, statusForIFlowError } from "../errors.js";
10
+ const TOOL_NAME = "iflow_web_search";
11
+ export const webSearchHandler = {
12
+ name: TOOL_NAME,
13
+ title: "iFlow Web Search",
14
+ description: "Search the web with iFlow. Use to find current information, news, " +
15
+ "papers, and reference pages. Returns titles, URLs, and snippets.",
16
+ inputSchema: {
17
+ type: "object",
18
+ properties: {
19
+ query: {
20
+ type: "string",
21
+ minLength: 1,
22
+ description: "Search query.",
23
+ },
24
+ count: {
25
+ type: "integer",
26
+ minimum: 1,
27
+ maximum: WEB_SEARCH_MAX_COUNT,
28
+ description: `Number of results (1–${WEB_SEARCH_MAX_COUNT}, default ${WEB_SEARCH_DEFAULT_COUNT}).`,
29
+ },
30
+ },
31
+ required: ["query"],
32
+ additionalProperties: false,
33
+ },
34
+ async handle(rawBody, client) {
35
+ const body = (rawBody ?? {});
36
+ const params = {
37
+ query: typeof body.query === "string" ? body.query : "",
38
+ };
39
+ if (body.count !== undefined) {
40
+ params.count = body.count;
41
+ }
42
+ const result = await client.webSearch(params);
43
+ if (!result.ok) {
44
+ return {
45
+ status: statusForIFlowError(result.error),
46
+ body: iflowErrorToBody(result.error),
47
+ };
48
+ }
49
+ return {
50
+ status: 200,
51
+ body: { ok: true, data: result.data },
52
+ };
53
+ },
54
+ };
55
+ //# sourceMappingURL=web-search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-search.js","sourceRoot":"","sources":["../../src/handlers/web-search.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACL,wBAAwB,EACxB,oBAAoB,GACrB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAGrE,MAAM,SAAS,GAAG,kBAAkB,CAAC;AAErC,MAAM,CAAC,MAAM,gBAAgB,GAAgB;IAC3C,IAAI,EAAE,SAAS;IACf,KAAK,EAAE,kBAAkB;IACzB,WAAW,EACT,oEAAoE;QACpE,kEAAkE;IACpE,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,KAAK,EAAE;gBACL,IAAI,EAAE,QAAQ;gBACd,SAAS,EAAE,CAAC;gBACZ,WAAW,EAAE,eAAe;aAC7B;YACD,KAAK,EAAE;gBACL,IAAI,EAAE,SAAS;gBACf,OAAO,EAAE,CAAC;gBACV,OAAO,EAAE,oBAAoB;gBAC7B,WAAW,EAAE,wBAAwB,oBAAoB,aAAa,wBAAwB,IAAI;aACnG;SACF;QACD,QAAQ,EAAE,CAAC,OAAO,CAAC;QACnB,oBAAoB,EAAE,KAAK;KAC5B;IACD,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM;QAC1B,MAAM,IAAI,GAAG,CAAC,OAAO,IAAI,EAAE,CAAyC,CAAC;QACrE,MAAM,MAAM,GAAsC;YAChD,KAAK,EAAE,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;SACxD,CAAC;QACF,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;YAC7B,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,KAAe,CAAC;QACtC,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAC9C,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;YACf,OAAO;gBACL,MAAM,EAAE,mBAAmB,CAAC,MAAM,CAAC,KAAK,CAAC;gBACzC,IAAI,EAAE,gBAAgB,CAAC,MAAM,CAAC,KAAK,CAAC;aACrC,CAAC;QACJ,CAAC;QACD,OAAO;YACL,MAAM,EAAE,GAAG;YACX,IAAI,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE;SACtC,CAAC;IACJ,CAAC;CACF,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * @iflow-ai/search-openapi — HTTP/OpenAPI tool server for the iFlow Search API.
3
+ *
4
+ * The package is primarily a CLI (`iflow-search-openapi`), but the request
5
+ * listener factory and config loader are exported so the server can be
6
+ * embedded in a larger HTTP app or driven by integration tests.
7
+ */
8
+ export { createApp, type AppOptions } from "./server.js";
9
+ export { loadConfig, ConfigError, DEFAULT_PORT, type ResolvedConfig, type EnvLike, } from "./config.js";
10
+ export { buildOpenApiDocument } from "./openapi.js";
11
+ export { TOOL_HANDLERS, webSearchHandler, imageSearchHandler, webFetchHandler, type ToolHandler, } from "./handlers/index.js";
12
+ export { INTEGRATION_NAME, SOURCE, VERSION } from "./version.js";
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,SAAS,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EACL,UAAU,EACV,WAAW,EACX,YAAY,EACZ,KAAK,cAAc,EACnB,KAAK,OAAO,GACb,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,kBAAkB,EAClB,eAAe,EACf,KAAK,WAAW,GACjB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,13 @@
1
+ /**
2
+ * @iflow-ai/search-openapi — HTTP/OpenAPI tool server for the iFlow Search API.
3
+ *
4
+ * The package is primarily a CLI (`iflow-search-openapi`), but the request
5
+ * listener factory and config loader are exported so the server can be
6
+ * embedded in a larger HTTP app or driven by integration tests.
7
+ */
8
+ export { createApp } from "./server.js";
9
+ export { loadConfig, ConfigError, DEFAULT_PORT, } from "./config.js";
10
+ export { buildOpenApiDocument } from "./openapi.js";
11
+ export { TOOL_HANDLERS, webSearchHandler, imageSearchHandler, webFetchHandler, } from "./handlers/index.js";
12
+ export { INTEGRATION_NAME, SOURCE, VERSION } from "./version.js";
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,SAAS,EAAmB,MAAM,aAAa,CAAC;AACzD,OAAO,EACL,UAAU,EACV,WAAW,EACX,YAAY,GAGb,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,kBAAkB,EAClB,eAAe,GAEhB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * OpenAPI 3.1 description served at /openapi.json.
3
+ *
4
+ * Open WebUI and Coze (and other OpenAPI 3.x tool hosts) read this
5
+ * document to populate their tool catalogs. The schema is generated
6
+ * from the canonical TOOL_HANDLERS list so the document and the routes
7
+ * can never drift.
8
+ *
9
+ * Auth: when `bearerAuth` is true, every operation declares the
10
+ * `BearerAuth` security scheme; consumers will require the user to
11
+ * paste a token. /health is intentionally excluded from this document
12
+ * — it's a private liveness check, not a tool.
13
+ */
14
+ export interface OpenApiDocumentOptions {
15
+ /** True when IFLOW_OPENAPI_AUTH_TOKEN is configured. */
16
+ bearerAuth: boolean;
17
+ }
18
+ export declare function buildOpenApiDocument(options: OpenApiDocumentOptions): object;
19
+ //# sourceMappingURL=openapi.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openapi.d.ts","sourceRoot":"","sources":["../src/openapi.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,MAAM,WAAW,sBAAsB;IACrC,wDAAwD;IACxD,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,sBAAsB,GAC9B,MAAM,CAqGR"}
@@ -0,0 +1,112 @@
1
+ /**
2
+ * OpenAPI 3.1 description served at /openapi.json.
3
+ *
4
+ * Open WebUI and Coze (and other OpenAPI 3.x tool hosts) read this
5
+ * document to populate their tool catalogs. The schema is generated
6
+ * from the canonical TOOL_HANDLERS list so the document and the routes
7
+ * can never drift.
8
+ *
9
+ * Auth: when `bearerAuth` is true, every operation declares the
10
+ * `BearerAuth` security scheme; consumers will require the user to
11
+ * paste a token. /health is intentionally excluded from this document
12
+ * — it's a private liveness check, not a tool.
13
+ */
14
+ import { TOOL_HANDLERS } from "./handlers/index.js";
15
+ import { VERSION } from "./version.js";
16
+ export function buildOpenApiDocument(options) {
17
+ const errorSchema = {
18
+ type: "object",
19
+ required: ["ok", "error"],
20
+ properties: {
21
+ ok: { type: "boolean", enum: [false] },
22
+ error: {
23
+ type: "object",
24
+ required: ["code", "message"],
25
+ properties: {
26
+ code: { type: "string" },
27
+ message: { type: "string" },
28
+ status: { type: "integer" },
29
+ detail: {},
30
+ },
31
+ },
32
+ },
33
+ };
34
+ const security = options.bearerAuth ? [{ BearerAuth: [] }] : [];
35
+ const paths = {};
36
+ for (const handler of TOOL_HANDLERS) {
37
+ paths[`/tools/${handler.name}`] = {
38
+ post: {
39
+ operationId: handler.name,
40
+ summary: handler.title,
41
+ description: handler.description,
42
+ ...(security.length > 0 ? { security } : {}),
43
+ requestBody: {
44
+ required: true,
45
+ content: {
46
+ "application/json": {
47
+ schema: handler.inputSchema,
48
+ },
49
+ },
50
+ },
51
+ responses: {
52
+ "200": {
53
+ description: "Successful tool invocation.",
54
+ content: {
55
+ "application/json": {
56
+ schema: {
57
+ type: "object",
58
+ required: ["ok", "data"],
59
+ properties: {
60
+ ok: { type: "boolean", enum: [true] },
61
+ data: { type: "object" },
62
+ },
63
+ },
64
+ },
65
+ },
66
+ },
67
+ "400": {
68
+ description: "Invalid input.",
69
+ content: {
70
+ "application/json": { schema: errorSchema },
71
+ },
72
+ },
73
+ "401": {
74
+ description: "Missing or invalid bearer token.",
75
+ content: {
76
+ "application/json": { schema: errorSchema },
77
+ },
78
+ },
79
+ "default": {
80
+ description: "Error.",
81
+ content: {
82
+ "application/json": { schema: errorSchema },
83
+ },
84
+ },
85
+ },
86
+ },
87
+ };
88
+ }
89
+ const document = {
90
+ openapi: "3.1.0",
91
+ info: {
92
+ title: "iFlow Search OpenAPI",
93
+ version: VERSION,
94
+ description: "HTTP/OpenAPI tool server for the iFlow Search API. " +
95
+ "Exposes iflow_web_search, iflow_image_search, and iflow_web_fetch " +
96
+ "as POST endpoints for Open WebUI / Coze and other OpenAPI 3.x tool hosts.",
97
+ },
98
+ paths,
99
+ };
100
+ if (options.bearerAuth) {
101
+ document.components = {
102
+ securitySchemes: {
103
+ BearerAuth: {
104
+ type: "http",
105
+ scheme: "bearer",
106
+ },
107
+ },
108
+ };
109
+ }
110
+ return document;
111
+ }
112
+ //# sourceMappingURL=openapi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openapi.js","sourceRoot":"","sources":["../src/openapi.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * HTTP request listener for the iFlow Search OpenAPI server.
3
+ *
4
+ * Routes:
5
+ * GET /health — liveness, never gated by bearer auth
6
+ * GET /openapi.json — OpenAPI 3.1 schema (bearer-gated when configured)
7
+ * POST /tools/iflow_web_search — search-core webSearch passthrough
8
+ * POST /tools/iflow_image_search — search-core imageSearch passthrough
9
+ * POST /tools/iflow_web_fetch — search-core webFetch passthrough
10
+ *
11
+ * Design notes:
12
+ * - The server is dependency-light: just the Node built-in `http` module
13
+ * plus search-core. No Express / Fastify / Koa.
14
+ * - All HTTP, Authorization, attribution headers, and iFlow error mapping
15
+ * live in @iflow-ai/search-core. This server only translates between
16
+ * JSON-over-HTTP and the typed search-core client.
17
+ * - The handler list is the single source of truth for both the routes
18
+ * and /openapi.json.
19
+ * - Body size is capped at MAX_BODY_BYTES to keep tool platforms from
20
+ * accidentally streaming megabytes into the server.
21
+ */
22
+ import type { RequestListener } from "node:http";
23
+ import type { IFlowSearchClient } from "@iflow-ai/search-core";
24
+ export interface AppOptions {
25
+ /** Authenticated iFlow client built from ResolvedConfig in bin.ts. */
26
+ client: IFlowSearchClient;
27
+ /** When set, every route except /health requires `Authorization: Bearer <token>`. */
28
+ authToken: string | undefined;
29
+ }
30
+ export declare function createApp(options: AppOptions): RequestListener;
31
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAmB,eAAe,EAAkB,MAAM,WAAW,CAAC;AAClF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAS/D,MAAM,WAAW,UAAU;IACzB,sEAAsE;IACtE,MAAM,EAAE,iBAAiB,CAAC;IAC1B,qFAAqF;IACrF,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;CAC/B;AAED,wBAAgB,SAAS,CAAC,OAAO,EAAE,UAAU,GAAG,eAAe,CA4E9D"}