@iflow-ai/search-core 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.
- package/LICENSE +21 -0
- package/README.md +49 -0
- package/dist/client.d.ts +21 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +200 -0
- package/dist/client.js.map +1 -0
- package/dist/config.d.ts +17 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +28 -0
- package/dist/config.js.map +1 -0
- package/dist/errors.d.ts +26 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +66 -0
- package/dist/errors.js.map +1 -0
- package/dist/headers.d.ts +25 -0
- package/dist/headers.d.ts.map +1 -0
- package/dist/headers.js +29 -0
- package/dist/headers.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/normalize.d.ts +45 -0
- package/dist/normalize.d.ts.map +1 -0
- package/dist/normalize.js +69 -0
- package/dist/normalize.js.map +1 -0
- package/dist/types.d.ts +75 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -0
- package/package.json +52 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 iFlow AI
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# @iflow-ai/search-core
|
|
2
|
+
|
|
3
|
+
Framework-agnostic SDK for the [iFlow Search API](https://platform.iflow.cn/docs/) — web search, image search, web fetch.
|
|
4
|
+
|
|
5
|
+
- Zero runtime dependencies
|
|
6
|
+
- Node ≥ 18 (uses global `fetch`)
|
|
7
|
+
- Injectable `fetch` for tests
|
|
8
|
+
- Per-request timeout + external `AbortSignal`
|
|
9
|
+
- Plain-object result envelope; never throws on API errors
|
|
10
|
+
- Attribution headers built in (every request advertises which integration sent it)
|
|
11
|
+
|
|
12
|
+
This package is the shared core consumed by:
|
|
13
|
+
|
|
14
|
+
- `@iflow-ai/search-langchain` — LangChain JS tool adapter
|
|
15
|
+
- `@iflow-ai/search-mcp` — MCP server
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm i @iflow-ai/search-core
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Quick start
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import { createIFlowSearchClient } from "@iflow-ai/search-core";
|
|
27
|
+
|
|
28
|
+
const client = createIFlowSearchClient({
|
|
29
|
+
apiKey: process.env.IFLOW_API_KEY!,
|
|
30
|
+
source: "core",
|
|
31
|
+
integrationName: "my-app",
|
|
32
|
+
integrationVersion: "1.0.0",
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const result = await client.webSearch({ query: "flash attention", count: 5 });
|
|
36
|
+
if (!result.ok) {
|
|
37
|
+
console.error(result.error.code, result.error.message);
|
|
38
|
+
} else {
|
|
39
|
+
for (const r of result.data.results) console.log(r.title, r.url);
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## API
|
|
44
|
+
|
|
45
|
+
See [`src/index.ts`](./src/index.ts) for the full public surface.
|
|
46
|
+
|
|
47
|
+
## License
|
|
48
|
+
|
|
49
|
+
MIT
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IFlowSearchClient — Bearer-authenticated POST client for iFlow Search.
|
|
3
|
+
*
|
|
4
|
+
* - global fetch (Node ≥18), injectable for tests
|
|
5
|
+
* - per-request timeout via AbortController; external signal forwarded
|
|
6
|
+
* - never throws on API errors; returns IFlowResult<T>
|
|
7
|
+
* - never logs the API key
|
|
8
|
+
* - no retry, no cache (adapters add those when needed)
|
|
9
|
+
*/
|
|
10
|
+
import type { IFlowResult, IFlowSearchClientOptions, ImageSearchParams, NormalizedImageSearch, NormalizedWebFetch, NormalizedWebSearch, WebFetchParams, WebSearchParams } from "./types.js";
|
|
11
|
+
export declare class IFlowSearchClient {
|
|
12
|
+
private readonly config;
|
|
13
|
+
constructor(opts: IFlowSearchClientOptions);
|
|
14
|
+
webSearch(params: WebSearchParams, signal?: AbortSignal): Promise<IFlowResult<NormalizedWebSearch>>;
|
|
15
|
+
imageSearch(params: ImageSearchParams, signal?: AbortSignal): Promise<IFlowResult<NormalizedImageSearch>>;
|
|
16
|
+
webFetch(params: WebFetchParams, signal?: AbortSignal): Promise<IFlowResult<NormalizedWebFetch>>;
|
|
17
|
+
private checkApiKey;
|
|
18
|
+
private call;
|
|
19
|
+
}
|
|
20
|
+
export declare function createIFlowSearchClient(opts: IFlowSearchClientOptions): IFlowSearchClient;
|
|
21
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA8BH,OAAO,KAAK,EACV,WAAW,EACX,wBAAwB,EACxB,iBAAiB,EACjB,qBAAqB,EACrB,kBAAkB,EAClB,mBAAmB,EACnB,cAAc,EACd,eAAe,EAChB,MAAM,YAAY,CAAC;AA4CpB,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAuB;gBAElC,IAAI,EAAE,wBAAwB;IAIpC,SAAS,CACb,MAAM,EAAE,eAAe,EACvB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,WAAW,CAAC,mBAAmB,CAAC,CAAC;IAwBtC,WAAW,CACf,MAAM,EAAE,iBAAiB,EACzB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,WAAW,CAAC,qBAAqB,CAAC,CAAC;IAwBxC,QAAQ,CACZ,MAAM,EAAE,cAAc,EACtB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,WAAW,CAAC,kBAAkB,CAAC,CAAC;IAoB3C,OAAO,CAAC,WAAW;YAIL,IAAI;CAoFnB;AAkBD,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,wBAAwB,GAAG,iBAAiB,CAEzF"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IFlowSearchClient — Bearer-authenticated POST client for iFlow Search.
|
|
3
|
+
*
|
|
4
|
+
* - global fetch (Node ≥18), injectable for tests
|
|
5
|
+
* - per-request timeout via AbortController; external signal forwarded
|
|
6
|
+
* - never throws on API errors; returns IFlowResult<T>
|
|
7
|
+
* - never logs the API key
|
|
8
|
+
* - no retry, no cache (adapters add those when needed)
|
|
9
|
+
*/
|
|
10
|
+
import { DEFAULT_TIMEOUT_MS, IMAGE_SEARCH_DEFAULT_COUNT, IMAGE_SEARCH_MAX_COUNT, WEB_SEARCH_DEFAULT_COUNT, WEB_SEARCH_MAX_COUNT, normalizeBaseUrl, } from "./config.js";
|
|
11
|
+
import { apiBusinessError, apiHttpError, invalidParamError, missingApiKeyError, missingParamError, networkError, networkTimeoutError, } from "./errors.js";
|
|
12
|
+
import { buildAttributionHeaders } from "./headers.js";
|
|
13
|
+
import { normalizeImageSearch, normalizeWebFetch, normalizeWebSearch, } from "./normalize.js";
|
|
14
|
+
const ENDPOINTS = {
|
|
15
|
+
webSearch: "/api/search/webSearch",
|
|
16
|
+
imageSearch: "/api/search/imageSearch",
|
|
17
|
+
webFetch: "/api/search/webFetch",
|
|
18
|
+
};
|
|
19
|
+
function resolveOptions(opts) {
|
|
20
|
+
const fetchImpl = opts.fetch ?? globalThis.fetch;
|
|
21
|
+
if (typeof fetchImpl !== "function") {
|
|
22
|
+
throw new Error("IFlowSearchClient: global fetch is not available; pass `fetch` explicitly (Node <18 or non-standard runtime).");
|
|
23
|
+
}
|
|
24
|
+
const timeoutMs = typeof opts.timeoutMs === "number" && Number.isFinite(opts.timeoutMs) && opts.timeoutMs > 0
|
|
25
|
+
? opts.timeoutMs
|
|
26
|
+
: DEFAULT_TIMEOUT_MS;
|
|
27
|
+
return {
|
|
28
|
+
apiKey: typeof opts.apiKey === "string" ? opts.apiKey : "",
|
|
29
|
+
baseUrl: normalizeBaseUrl(opts.baseUrl),
|
|
30
|
+
timeoutMs,
|
|
31
|
+
fetchImpl,
|
|
32
|
+
attributionHeaders: buildAttributionHeaders({
|
|
33
|
+
source: opts.source,
|
|
34
|
+
integrationName: opts.integrationName,
|
|
35
|
+
integrationVersion: opts.integrationVersion,
|
|
36
|
+
}),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export class IFlowSearchClient {
|
|
40
|
+
config;
|
|
41
|
+
constructor(opts) {
|
|
42
|
+
this.config = resolveOptions(opts);
|
|
43
|
+
}
|
|
44
|
+
async webSearch(params, signal) {
|
|
45
|
+
const keyMissing = this.checkApiKey();
|
|
46
|
+
if (keyMissing)
|
|
47
|
+
return { ok: false, error: keyMissing };
|
|
48
|
+
const query = (params?.query ?? "").trim();
|
|
49
|
+
if (!query)
|
|
50
|
+
return { ok: false, error: missingParamError("query") };
|
|
51
|
+
const count = params.count ?? WEB_SEARCH_DEFAULT_COUNT;
|
|
52
|
+
const countError = validateCount(count, WEB_SEARCH_MAX_COUNT);
|
|
53
|
+
if (countError)
|
|
54
|
+
return { ok: false, error: countError };
|
|
55
|
+
const started = Date.now();
|
|
56
|
+
const httpResult = await this.call("webSearch", { keywords: query, num: count }, signal);
|
|
57
|
+
if (!httpResult.ok)
|
|
58
|
+
return httpResult;
|
|
59
|
+
return {
|
|
60
|
+
ok: true,
|
|
61
|
+
data: normalizeWebSearch(httpResult.data, query, Date.now() - started),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
async imageSearch(params, signal) {
|
|
65
|
+
const keyMissing = this.checkApiKey();
|
|
66
|
+
if (keyMissing)
|
|
67
|
+
return { ok: false, error: keyMissing };
|
|
68
|
+
const query = (params?.query ?? "").trim();
|
|
69
|
+
if (!query)
|
|
70
|
+
return { ok: false, error: missingParamError("query") };
|
|
71
|
+
const count = params.count ?? IMAGE_SEARCH_DEFAULT_COUNT;
|
|
72
|
+
const countError = validateCount(count, IMAGE_SEARCH_MAX_COUNT);
|
|
73
|
+
if (countError)
|
|
74
|
+
return { ok: false, error: countError };
|
|
75
|
+
const started = Date.now();
|
|
76
|
+
const httpResult = await this.call("imageSearch", { keywords: query, num: count }, signal);
|
|
77
|
+
if (!httpResult.ok)
|
|
78
|
+
return httpResult;
|
|
79
|
+
return {
|
|
80
|
+
ok: true,
|
|
81
|
+
data: normalizeImageSearch(httpResult.data, query, Date.now() - started),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
async webFetch(params, signal) {
|
|
85
|
+
const keyMissing = this.checkApiKey();
|
|
86
|
+
if (keyMissing)
|
|
87
|
+
return { ok: false, error: keyMissing };
|
|
88
|
+
const url = (params?.url ?? "").trim();
|
|
89
|
+
if (!url)
|
|
90
|
+
return { ok: false, error: missingParamError("url") };
|
|
91
|
+
const started = Date.now();
|
|
92
|
+
const httpResult = await this.call("webFetch", { url }, signal);
|
|
93
|
+
if (!httpResult.ok)
|
|
94
|
+
return httpResult;
|
|
95
|
+
return {
|
|
96
|
+
ok: true,
|
|
97
|
+
data: normalizeWebFetch(httpResult.data, url, Date.now() - started),
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
checkApiKey() {
|
|
101
|
+
return this.config.apiKey ? null : missingApiKeyError();
|
|
102
|
+
}
|
|
103
|
+
async call(endpoint, body, externalSignal) {
|
|
104
|
+
const { baseUrl, timeoutMs, fetchImpl, apiKey, attributionHeaders } = this.config;
|
|
105
|
+
const url = `${baseUrl}${ENDPOINTS[endpoint]}`;
|
|
106
|
+
const controller = new AbortController();
|
|
107
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
108
|
+
if (externalSignal) {
|
|
109
|
+
if (externalSignal.aborted) {
|
|
110
|
+
controller.abort();
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
externalSignal.addEventListener("abort", () => controller.abort(), { once: true });
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
let response;
|
|
117
|
+
try {
|
|
118
|
+
response = await fetchImpl(url, {
|
|
119
|
+
method: "POST",
|
|
120
|
+
headers: {
|
|
121
|
+
...attributionHeaders,
|
|
122
|
+
Authorization: `Bearer ${apiKey}`,
|
|
123
|
+
"Content-Type": "application/json",
|
|
124
|
+
Accept: "application/json",
|
|
125
|
+
},
|
|
126
|
+
body: JSON.stringify(body),
|
|
127
|
+
signal: controller.signal,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
catch (err) {
|
|
131
|
+
const e = err;
|
|
132
|
+
if (e?.name === "AbortError") {
|
|
133
|
+
return { ok: false, error: networkTimeoutError(timeoutMs) };
|
|
134
|
+
}
|
|
135
|
+
return { ok: false, error: networkError(e?.message ?? String(err)) };
|
|
136
|
+
}
|
|
137
|
+
finally {
|
|
138
|
+
clearTimeout(timer);
|
|
139
|
+
}
|
|
140
|
+
if (!response.ok) {
|
|
141
|
+
let detail = "";
|
|
142
|
+
try {
|
|
143
|
+
detail = (await response.text()).slice(0, 500);
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
// ignore
|
|
147
|
+
}
|
|
148
|
+
return { ok: false, error: apiHttpError(response.status, detail || response.statusText) };
|
|
149
|
+
}
|
|
150
|
+
let parsed;
|
|
151
|
+
try {
|
|
152
|
+
parsed = await response.json();
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
return {
|
|
156
|
+
ok: false,
|
|
157
|
+
error: {
|
|
158
|
+
code: "api_error",
|
|
159
|
+
message: "iFlow returned a non-JSON response.",
|
|
160
|
+
status: response.status,
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
const envelope = parsed;
|
|
165
|
+
if (envelope?.success !== true) {
|
|
166
|
+
const dataObj = envelope?.data && typeof envelope.data === "object" && !Array.isArray(envelope.data)
|
|
167
|
+
? envelope.data
|
|
168
|
+
: undefined;
|
|
169
|
+
return {
|
|
170
|
+
ok: false,
|
|
171
|
+
error: apiBusinessError({
|
|
172
|
+
code: envelope?.code ?? null,
|
|
173
|
+
message: envelope?.message ?? null,
|
|
174
|
+
errorMsg: dataObj?.errorMsg ?? null,
|
|
175
|
+
errorCode: dataObj?.errorCode ?? null,
|
|
176
|
+
}),
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
return { ok: true, data: parsed };
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
function validateCount(count, max) {
|
|
183
|
+
if (typeof count !== "number" || !Number.isFinite(count)) {
|
|
184
|
+
return invalidParamError("count", "must be a finite number");
|
|
185
|
+
}
|
|
186
|
+
if (!Number.isInteger(count)) {
|
|
187
|
+
return invalidParamError("count", "must be an integer");
|
|
188
|
+
}
|
|
189
|
+
if (count < 1) {
|
|
190
|
+
return invalidParamError("count", "must be ≥ 1");
|
|
191
|
+
}
|
|
192
|
+
if (count > max) {
|
|
193
|
+
return invalidParamError("count", `must be ≤ ${max}`);
|
|
194
|
+
}
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
export function createIFlowSearchClient(opts) {
|
|
198
|
+
return new IFlowSearchClient(opts);
|
|
199
|
+
}
|
|
200
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Defaults and the env-var name for the iFlow API key. Adapters that want
|
|
3
|
+
* the env fallback can read it themselves — the core client requires an
|
|
4
|
+
* explicit apiKey to avoid surprising production behavior.
|
|
5
|
+
*/
|
|
6
|
+
export declare const DEFAULT_BASE_URL = "https://platform.iflow.cn";
|
|
7
|
+
export declare const DEFAULT_TIMEOUT_MS = 30000;
|
|
8
|
+
export declare const ENV_API_KEY = "IFLOW_API_KEY";
|
|
9
|
+
export declare const WEB_SEARCH_MAX_COUNT = 20;
|
|
10
|
+
export declare const WEB_SEARCH_DEFAULT_COUNT = 10;
|
|
11
|
+
export declare const IMAGE_SEARCH_MAX_COUNT = 20;
|
|
12
|
+
export declare const IMAGE_SEARCH_DEFAULT_COUNT = 10;
|
|
13
|
+
/** Strip trailing slashes so concatenating "/api/..." never double-slashes. */
|
|
14
|
+
export declare function normalizeBaseUrl(raw: string | undefined): string;
|
|
15
|
+
/** Mask an API key for logs. Adapters should use this; core never logs keys. */
|
|
16
|
+
export declare function redactApiKey(key: string | undefined): string;
|
|
17
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,eAAO,MAAM,gBAAgB,8BAA8B,CAAC;AAC5D,eAAO,MAAM,kBAAkB,QAAS,CAAC;AACzC,eAAO,MAAM,WAAW,kBAAkB,CAAC;AAE3C,eAAO,MAAM,oBAAoB,KAAK,CAAC;AACvC,eAAO,MAAM,wBAAwB,KAAK,CAAC;AAC3C,eAAO,MAAM,sBAAsB,KAAK,CAAC;AACzC,eAAO,MAAM,0BAA0B,KAAK,CAAC;AAE7C,+EAA+E;AAC/E,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAIhE;AAED,gFAAgF;AAChF,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAI5D"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Defaults and the env-var name for the iFlow API key. Adapters that want
|
|
3
|
+
* the env fallback can read it themselves — the core client requires an
|
|
4
|
+
* explicit apiKey to avoid surprising production behavior.
|
|
5
|
+
*/
|
|
6
|
+
export const DEFAULT_BASE_URL = "https://platform.iflow.cn";
|
|
7
|
+
export const DEFAULT_TIMEOUT_MS = 30_000;
|
|
8
|
+
export const ENV_API_KEY = "IFLOW_API_KEY";
|
|
9
|
+
export const WEB_SEARCH_MAX_COUNT = 20;
|
|
10
|
+
export const WEB_SEARCH_DEFAULT_COUNT = 10;
|
|
11
|
+
export const IMAGE_SEARCH_MAX_COUNT = 20;
|
|
12
|
+
export const IMAGE_SEARCH_DEFAULT_COUNT = 10;
|
|
13
|
+
/** Strip trailing slashes so concatenating "/api/..." never double-slashes. */
|
|
14
|
+
export function normalizeBaseUrl(raw) {
|
|
15
|
+
const value = (raw ?? DEFAULT_BASE_URL).trim();
|
|
16
|
+
if (!value)
|
|
17
|
+
return DEFAULT_BASE_URL;
|
|
18
|
+
return value.replace(/\/+$/u, "") || DEFAULT_BASE_URL;
|
|
19
|
+
}
|
|
20
|
+
/** Mask an API key for logs. Adapters should use this; core never logs keys. */
|
|
21
|
+
export function redactApiKey(key) {
|
|
22
|
+
if (!key)
|
|
23
|
+
return "<unset>";
|
|
24
|
+
if (key.length <= 8)
|
|
25
|
+
return "***";
|
|
26
|
+
return `${key.slice(0, 4)}***${key.slice(-2)}`;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,CAAC,MAAM,gBAAgB,GAAG,2BAA2B,CAAC;AAC5D,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC;AACzC,MAAM,CAAC,MAAM,WAAW,GAAG,eAAe,CAAC;AAE3C,MAAM,CAAC,MAAM,oBAAoB,GAAG,EAAE,CAAC;AACvC,MAAM,CAAC,MAAM,wBAAwB,GAAG,EAAE,CAAC;AAC3C,MAAM,CAAC,MAAM,sBAAsB,GAAG,EAAE,CAAC;AACzC,MAAM,CAAC,MAAM,0BAA0B,GAAG,EAAE,CAAC;AAE7C,+EAA+E;AAC/E,MAAM,UAAU,gBAAgB,CAAC,GAAuB;IACtD,MAAM,KAAK,GAAG,CAAC,GAAG,IAAI,gBAAgB,CAAC,CAAC,IAAI,EAAE,CAAC;IAC/C,IAAI,CAAC,KAAK;QAAE,OAAO,gBAAgB,CAAC;IACpC,OAAO,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,gBAAgB,CAAC;AACxD,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,YAAY,CAAC,GAAuB;IAClD,IAAI,CAAC,GAAG;QAAE,OAAO,SAAS,CAAC;IAC3B,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IAClC,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACjD,CAAC"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error taxonomy. Plain objects, never Error subclasses, so adapters can
|
|
3
|
+
* serialize them straight to JSON without losing fields.
|
|
4
|
+
*/
|
|
5
|
+
export type IFlowErrorCode = "missing_api_key" | "missing_param" | "invalid_param" | "network_timeout" | "network_error" | "api_error" | "api_business_error";
|
|
6
|
+
export interface IFlowError {
|
|
7
|
+
code: IFlowErrorCode;
|
|
8
|
+
message: string;
|
|
9
|
+
status?: number;
|
|
10
|
+
detail?: unknown;
|
|
11
|
+
}
|
|
12
|
+
export declare function isIFlowError(value: unknown): value is IFlowError;
|
|
13
|
+
export declare function missingApiKeyError(): IFlowError;
|
|
14
|
+
export declare function missingParamError(name: string): IFlowError;
|
|
15
|
+
export declare function invalidParamError(name: string, detail: string): IFlowError;
|
|
16
|
+
export declare function networkTimeoutError(timeoutMs: number): IFlowError;
|
|
17
|
+
export declare function networkError(detail: string): IFlowError;
|
|
18
|
+
export declare function apiHttpError(status: number, detailText: string): IFlowError;
|
|
19
|
+
export interface BusinessErrorInput {
|
|
20
|
+
code?: string | number | null;
|
|
21
|
+
message?: string | null;
|
|
22
|
+
errorMsg?: string | null;
|
|
23
|
+
errorCode?: string | number | null;
|
|
24
|
+
}
|
|
25
|
+
export declare function apiBusinessError(input: BusinessErrorInput): IFlowError;
|
|
26
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,cAAc,GACtB,iBAAiB,GACjB,eAAe,GACf,eAAe,GACf,iBAAiB,GACjB,eAAe,GACf,WAAW,GACX,oBAAoB,CAAC;AAEzB,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,cAAc,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,UAAU,CAIhE;AAED,wBAAgB,kBAAkB,IAAI,UAAU,CAO/C;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAE1D;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,UAAU,CAK1E;AAED,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,UAAU,CAKjE;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAKvD;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,UAAU,CAM3E;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC9B,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;CACpC;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,kBAAkB,GAAG,UAAU,CAetE"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error taxonomy. Plain objects, never Error subclasses, so adapters can
|
|
3
|
+
* serialize them straight to JSON without losing fields.
|
|
4
|
+
*/
|
|
5
|
+
export function isIFlowError(value) {
|
|
6
|
+
if (typeof value !== "object" || value === null)
|
|
7
|
+
return false;
|
|
8
|
+
const v = value;
|
|
9
|
+
return typeof v.code === "string" && typeof v.message === "string";
|
|
10
|
+
}
|
|
11
|
+
export function missingApiKeyError() {
|
|
12
|
+
return {
|
|
13
|
+
code: "missing_api_key",
|
|
14
|
+
message: "iFlow Search needs an API key. Set IFLOW_API_KEY in the environment, " +
|
|
15
|
+
"or pass apiKey when constructing the client.",
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export function missingParamError(name) {
|
|
19
|
+
return { code: "missing_param", message: `Parameter "${name}" is required.` };
|
|
20
|
+
}
|
|
21
|
+
export function invalidParamError(name, detail) {
|
|
22
|
+
return {
|
|
23
|
+
code: "invalid_param",
|
|
24
|
+
message: `Parameter "${name}" is invalid: ${detail}`,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export function networkTimeoutError(timeoutMs) {
|
|
28
|
+
return {
|
|
29
|
+
code: "network_timeout",
|
|
30
|
+
message: `Request to iFlow timed out after ${Math.round(timeoutMs)}ms.`,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export function networkError(detail) {
|
|
34
|
+
return {
|
|
35
|
+
code: "network_error",
|
|
36
|
+
message: `Network error talking to iFlow: ${detail}`,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export function apiHttpError(status, detailText) {
|
|
40
|
+
let message = detailText || `HTTP ${status}`;
|
|
41
|
+
if (status === 401)
|
|
42
|
+
message = "401 Unauthorized — iFlow API key missing or invalid.";
|
|
43
|
+
else if (status === 403)
|
|
44
|
+
message = "403 Forbidden — iFlow API key is not allowed for this endpoint.";
|
|
45
|
+
else if (status === 429)
|
|
46
|
+
message = "429 Too Many Requests — iFlow rate limit reached.";
|
|
47
|
+
return { code: "api_error", status, message, detail: detailText || undefined };
|
|
48
|
+
}
|
|
49
|
+
export function apiBusinessError(input) {
|
|
50
|
+
const parts = [];
|
|
51
|
+
if (input.message)
|
|
52
|
+
parts.push(String(input.message));
|
|
53
|
+
if (input.errorMsg && input.errorMsg !== input.message) {
|
|
54
|
+
parts.push(`detail: ${input.errorMsg}`);
|
|
55
|
+
}
|
|
56
|
+
const message = parts.join(" — ") || "iFlow API returned success=false without a message.";
|
|
57
|
+
return {
|
|
58
|
+
code: "api_business_error",
|
|
59
|
+
message,
|
|
60
|
+
detail: {
|
|
61
|
+
code: input.errorCode ?? input.code ?? null,
|
|
62
|
+
errorMsg: input.errorMsg ?? null,
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAkBH,MAAM,UAAU,YAAY,CAAC,KAAc;IACzC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC9D,MAAM,CAAC,GAAG,KAA8C,CAAC;IACzD,OAAO,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ,CAAC;AACrE,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,OAAO;QACL,IAAI,EAAE,iBAAiB;QACvB,OAAO,EACL,uEAAuE;YACvE,8CAA8C;KACjD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,cAAc,IAAI,gBAAgB,EAAE,CAAC;AAChF,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,IAAY,EAAE,MAAc;IAC5D,OAAO;QACL,IAAI,EAAE,eAAe;QACrB,OAAO,EAAE,cAAc,IAAI,iBAAiB,MAAM,EAAE;KACrD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,SAAiB;IACnD,OAAO;QACL,IAAI,EAAE,iBAAiB;QACvB,OAAO,EAAE,oCAAoC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK;KACxE,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,MAAc;IACzC,OAAO;QACL,IAAI,EAAE,eAAe;QACrB,OAAO,EAAE,mCAAmC,MAAM,EAAE;KACrD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,MAAc,EAAE,UAAkB;IAC7D,IAAI,OAAO,GAAG,UAAU,IAAI,QAAQ,MAAM,EAAE,CAAC;IAC7C,IAAI,MAAM,KAAK,GAAG;QAAE,OAAO,GAAG,sDAAsD,CAAC;SAChF,IAAI,MAAM,KAAK,GAAG;QAAE,OAAO,GAAG,iEAAiE,CAAC;SAChG,IAAI,MAAM,KAAK,GAAG;QAAE,OAAO,GAAG,mDAAmD,CAAC;IACvF,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,IAAI,SAAS,EAAE,CAAC;AACjF,CAAC;AASD,MAAM,UAAU,gBAAgB,CAAC,KAAyB;IACxD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,KAAK,CAAC,OAAO;QAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;IACrD,IAAI,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,QAAQ,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC;QACvD,KAAK,CAAC,IAAI,CAAC,WAAW,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC1C,CAAC;IACD,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,qDAAqD,CAAC;IAC3F,OAAO;QACL,IAAI,EAAE,oBAAoB;QAC1B,OAAO;QACP,MAAM,EAAE;YACN,IAAI,EAAE,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,IAAI,IAAI,IAAI;YAC3C,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,IAAI;SACjC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Attribution header builder.
|
|
3
|
+
*
|
|
4
|
+
* Every outbound iFlow Search request carries:
|
|
5
|
+
*
|
|
6
|
+
* IFlow-Source: who's calling (framework name, e.g. "langchain")
|
|
7
|
+
* IFlow-Integration: the npm package making the call
|
|
8
|
+
* IFlow-Integration-Version: that package's version
|
|
9
|
+
* User-Agent: "<integrationName>/<integrationVersion>"
|
|
10
|
+
*
|
|
11
|
+
* Caller supplies all three values — search-core does not hard-code a source.
|
|
12
|
+
*/
|
|
13
|
+
export interface AttributionInput {
|
|
14
|
+
source: string;
|
|
15
|
+
integrationName: string;
|
|
16
|
+
integrationVersion: string;
|
|
17
|
+
}
|
|
18
|
+
export interface AttributionHeaders {
|
|
19
|
+
"IFlow-Source": string;
|
|
20
|
+
"IFlow-Integration": string;
|
|
21
|
+
"IFlow-Integration-Version": string;
|
|
22
|
+
"User-Agent": string;
|
|
23
|
+
}
|
|
24
|
+
export declare function buildAttributionHeaders(input: AttributionInput): AttributionHeaders;
|
|
25
|
+
//# sourceMappingURL=headers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"headers.d.ts","sourceRoot":"","sources":["../src/headers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,MAAM,CAAC;IACxB,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,kBAAkB;IACjC,cAAc,EAAE,MAAM,CAAC;IACvB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,2BAA2B,EAAE,MAAM,CAAC;IACpC,YAAY,EAAE,MAAM,CAAC;CACtB;AAQD,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,gBAAgB,GAAG,kBAAkB,CAUnF"}
|
package/dist/headers.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Attribution header builder.
|
|
3
|
+
*
|
|
4
|
+
* Every outbound iFlow Search request carries:
|
|
5
|
+
*
|
|
6
|
+
* IFlow-Source: who's calling (framework name, e.g. "langchain")
|
|
7
|
+
* IFlow-Integration: the npm package making the call
|
|
8
|
+
* IFlow-Integration-Version: that package's version
|
|
9
|
+
* User-Agent: "<integrationName>/<integrationVersion>"
|
|
10
|
+
*
|
|
11
|
+
* Caller supplies all three values — search-core does not hard-code a source.
|
|
12
|
+
*/
|
|
13
|
+
function requireNonEmpty(name, value) {
|
|
14
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
15
|
+
throw new Error(`buildAttributionHeaders: "${name}" must be a non-empty string.`);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export function buildAttributionHeaders(input) {
|
|
19
|
+
requireNonEmpty("source", input.source);
|
|
20
|
+
requireNonEmpty("integrationName", input.integrationName);
|
|
21
|
+
requireNonEmpty("integrationVersion", input.integrationVersion);
|
|
22
|
+
return {
|
|
23
|
+
"IFlow-Source": input.source,
|
|
24
|
+
"IFlow-Integration": input.integrationName,
|
|
25
|
+
"IFlow-Integration-Version": input.integrationVersion,
|
|
26
|
+
"User-Agent": `${input.integrationName}/${input.integrationVersion}`,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=headers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"headers.js","sourceRoot":"","sources":["../src/headers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAeH,SAAS,eAAe,CAAC,IAAY,EAAE,KAAa;IAClD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpD,MAAM,IAAI,KAAK,CAAC,6BAA6B,IAAI,+BAA+B,CAAC,CAAC;IACpF,CAAC;AACH,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,KAAuB;IAC7D,eAAe,CAAC,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACxC,eAAe,CAAC,iBAAiB,EAAE,KAAK,CAAC,eAAe,CAAC,CAAC;IAC1D,eAAe,CAAC,oBAAoB,EAAE,KAAK,CAAC,kBAAkB,CAAC,CAAC;IAChE,OAAO;QACL,cAAc,EAAE,KAAK,CAAC,MAAM;QAC5B,mBAAmB,EAAE,KAAK,CAAC,eAAe;QAC1C,2BAA2B,EAAE,KAAK,CAAC,kBAAkB;QACrD,YAAY,EAAE,GAAG,KAAK,CAAC,eAAe,IAAI,KAAK,CAAC,kBAAkB,EAAE;KACrE,CAAC;AACJ,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @iflow-ai/search-core — framework-agnostic SDK for the iFlow Search API.
|
|
3
|
+
*
|
|
4
|
+
* See README.md for usage.
|
|
5
|
+
*/
|
|
6
|
+
export { IFlowSearchClient, createIFlowSearchClient, } from "./client.js";
|
|
7
|
+
export { buildAttributionHeaders, type AttributionHeaders, type AttributionInput, } from "./headers.js";
|
|
8
|
+
export { isIFlowError, type IFlowError, type IFlowErrorCode, } from "./errors.js";
|
|
9
|
+
export { normalizeImageSearch, normalizeWebFetch, normalizeWebSearch, type IFlowEnvelope, } from "./normalize.js";
|
|
10
|
+
export { DEFAULT_BASE_URL, DEFAULT_TIMEOUT_MS, ENV_API_KEY, IMAGE_SEARCH_DEFAULT_COUNT, IMAGE_SEARCH_MAX_COUNT, WEB_SEARCH_DEFAULT_COUNT, WEB_SEARCH_MAX_COUNT, redactApiKey, } from "./config.js";
|
|
11
|
+
export type { IFlowResult, IFlowSearchClientOptions, ImageSearchParams, NormalizedImage, NormalizedImageSearch, NormalizedWebFetch, NormalizedWebSearch, NormalizedWebSearchResult, WebFetchParams, WebSearchParams, } from "./types.js";
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,iBAAiB,EACjB,uBAAuB,GACxB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,uBAAuB,EACvB,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,GACtB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,YAAY,EACZ,KAAK,UAAU,EACf,KAAK,cAAc,GACpB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,oBAAoB,EACpB,iBAAiB,EACjB,kBAAkB,EAClB,KAAK,aAAa,GACnB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,WAAW,EACX,0BAA0B,EAC1B,sBAAsB,EACtB,wBAAwB,EACxB,oBAAoB,EACpB,YAAY,GACb,MAAM,aAAa,CAAC;AAErB,YAAY,EACV,WAAW,EACX,wBAAwB,EACxB,iBAAiB,EACjB,eAAe,EACf,qBAAqB,EACrB,kBAAkB,EAClB,mBAAmB,EACnB,yBAAyB,EACzB,cAAc,EACd,eAAe,GAChB,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @iflow-ai/search-core — framework-agnostic SDK for the iFlow Search API.
|
|
3
|
+
*
|
|
4
|
+
* See README.md for usage.
|
|
5
|
+
*/
|
|
6
|
+
export { IFlowSearchClient, createIFlowSearchClient, } from "./client.js";
|
|
7
|
+
export { buildAttributionHeaders, } from "./headers.js";
|
|
8
|
+
export { isIFlowError, } from "./errors.js";
|
|
9
|
+
export { normalizeImageSearch, normalizeWebFetch, normalizeWebSearch, } from "./normalize.js";
|
|
10
|
+
export { DEFAULT_BASE_URL, DEFAULT_TIMEOUT_MS, ENV_API_KEY, IMAGE_SEARCH_DEFAULT_COUNT, IMAGE_SEARCH_MAX_COUNT, WEB_SEARCH_DEFAULT_COUNT, WEB_SEARCH_MAX_COUNT, redactApiKey, } from "./config.js";
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,iBAAiB,EACjB,uBAAuB,GACxB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,uBAAuB,GAGxB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,YAAY,GAGb,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,oBAAoB,EACpB,iBAAiB,EACjB,kBAAkB,GAEnB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,WAAW,EACX,0BAA0B,EAC1B,sBAAsB,EACtB,wBAAwB,EACxB,oBAAoB,EACpB,YAAY,GACb,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Map raw iFlow API responses into framework-agnostic normalized shapes.
|
|
3
|
+
*
|
|
4
|
+
* Field mapping mirrors observed iFlow API responses (see openclaw plugin
|
|
5
|
+
* normalize.ts header comment for the schema reference). Defensive coercion
|
|
6
|
+
* keeps the LLM-facing payload predictable even when iFlow emits null or
|
|
7
|
+
* unexpected types.
|
|
8
|
+
*/
|
|
9
|
+
import type { NormalizedImageSearch, NormalizedWebFetch, NormalizedWebSearch } from "./types.js";
|
|
10
|
+
export interface IFlowEnvelope<T> {
|
|
11
|
+
success?: boolean;
|
|
12
|
+
code?: string | number;
|
|
13
|
+
message?: string;
|
|
14
|
+
data?: T;
|
|
15
|
+
}
|
|
16
|
+
export interface RawOrganicItem {
|
|
17
|
+
title?: unknown;
|
|
18
|
+
link?: unknown;
|
|
19
|
+
snippet?: unknown;
|
|
20
|
+
position?: unknown;
|
|
21
|
+
date?: unknown;
|
|
22
|
+
}
|
|
23
|
+
export interface RawWebSearchData {
|
|
24
|
+
query?: unknown;
|
|
25
|
+
organic?: RawOrganicItem[] | null;
|
|
26
|
+
}
|
|
27
|
+
export interface RawImageItem {
|
|
28
|
+
url?: unknown;
|
|
29
|
+
title?: unknown;
|
|
30
|
+
refUrl?: unknown;
|
|
31
|
+
width?: unknown;
|
|
32
|
+
height?: unknown;
|
|
33
|
+
position?: unknown;
|
|
34
|
+
}
|
|
35
|
+
export type RawImageSearchData = RawImageItem[];
|
|
36
|
+
export interface RawWebFetchData {
|
|
37
|
+
title?: unknown;
|
|
38
|
+
content?: unknown;
|
|
39
|
+
url?: unknown;
|
|
40
|
+
fromCache?: unknown;
|
|
41
|
+
}
|
|
42
|
+
export declare function normalizeWebSearch(raw: IFlowEnvelope<RawWebSearchData> | null | undefined, requestQuery: string, tookMs: number): NormalizedWebSearch;
|
|
43
|
+
export declare function normalizeImageSearch(raw: IFlowEnvelope<RawImageSearchData> | null | undefined, requestQuery: string, tookMs: number): NormalizedImageSearch;
|
|
44
|
+
export declare function normalizeWebFetch(raw: IFlowEnvelope<RawWebFetchData> | null | undefined, requestUrl: string, tookMs: number): NormalizedWebFetch;
|
|
45
|
+
//# sourceMappingURL=normalize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../src/normalize.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAEV,qBAAqB,EACrB,kBAAkB,EAClB,mBAAmB,EAEpB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,aAAa,CAAC,CAAC;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,CAAC,CAAC;CACV;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,cAAc,EAAE,GAAG,IAAI,CAAC;CACnC;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,MAAM,kBAAkB,GAAG,YAAY,EAAE,CAAC;AAEhD,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAcD,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,aAAa,CAAC,gBAAgB,CAAC,GAAG,IAAI,GAAG,SAAS,EACvD,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,GACb,mBAAmB,CAkBrB;AAED,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,aAAa,CAAC,kBAAkB,CAAC,GAAG,IAAI,GAAG,SAAS,EACzD,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,GACb,qBAAqB,CAoBvB;AAED,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,aAAa,CAAC,eAAe,CAAC,GAAG,IAAI,GAAG,SAAS,EACtD,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,GACb,kBAAkB,CAWpB"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Map raw iFlow API responses into framework-agnostic normalized shapes.
|
|
3
|
+
*
|
|
4
|
+
* Field mapping mirrors observed iFlow API responses (see openclaw plugin
|
|
5
|
+
* normalize.ts header comment for the schema reference). Defensive coercion
|
|
6
|
+
* keeps the LLM-facing payload predictable even when iFlow emits null or
|
|
7
|
+
* unexpected types.
|
|
8
|
+
*/
|
|
9
|
+
function asString(v, fallback = "") {
|
|
10
|
+
return typeof v === "string" ? v : fallback;
|
|
11
|
+
}
|
|
12
|
+
function asNullableString(v) {
|
|
13
|
+
return typeof v === "string" && v.length > 0 ? v : null;
|
|
14
|
+
}
|
|
15
|
+
function asNullableNumber(v) {
|
|
16
|
+
return typeof v === "number" && Number.isFinite(v) ? v : null;
|
|
17
|
+
}
|
|
18
|
+
export function normalizeWebSearch(raw, requestQuery, tookMs) {
|
|
19
|
+
const data = raw?.data;
|
|
20
|
+
const organic = Array.isArray(data?.organic) ? data.organic : [];
|
|
21
|
+
const results = organic
|
|
22
|
+
.filter((r) => r !== null && typeof r === "object")
|
|
23
|
+
.map((r) => ({
|
|
24
|
+
title: asString(r.title),
|
|
25
|
+
url: asString(r.link),
|
|
26
|
+
snippet: asString(r.snippet),
|
|
27
|
+
position: asNullableNumber(r.position),
|
|
28
|
+
date: asNullableString(r.date),
|
|
29
|
+
}));
|
|
30
|
+
return {
|
|
31
|
+
query: asString(data?.query, requestQuery),
|
|
32
|
+
count: results.length,
|
|
33
|
+
tookMs,
|
|
34
|
+
results,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export function normalizeImageSearch(raw, requestQuery, tookMs) {
|
|
38
|
+
const data = raw?.data;
|
|
39
|
+
const arr = Array.isArray(data) ? data : [];
|
|
40
|
+
const images = arr
|
|
41
|
+
.filter((r) => r !== null && typeof r === "object")
|
|
42
|
+
.map((r) => ({
|
|
43
|
+
imageUrl: asString(r.url),
|
|
44
|
+
title: asNullableString(r.title),
|
|
45
|
+
sourceUrl: asNullableString(r.refUrl),
|
|
46
|
+
width: asNullableNumber(r.width),
|
|
47
|
+
height: asNullableNumber(r.height),
|
|
48
|
+
position: asNullableNumber(r.position),
|
|
49
|
+
}))
|
|
50
|
+
.filter((img) => img.imageUrl.length > 0);
|
|
51
|
+
return {
|
|
52
|
+
query: requestQuery,
|
|
53
|
+
count: images.length,
|
|
54
|
+
tookMs,
|
|
55
|
+
images,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
export function normalizeWebFetch(raw, requestUrl, tookMs) {
|
|
59
|
+
const data = raw?.data;
|
|
60
|
+
const fromCache = typeof data?.fromCache === "boolean" ? data.fromCache : null;
|
|
61
|
+
return {
|
|
62
|
+
url: asString(data?.url, requestUrl),
|
|
63
|
+
title: asNullableString(data?.title),
|
|
64
|
+
content: asString(data?.content),
|
|
65
|
+
fromCache,
|
|
66
|
+
tookMs,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=normalize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"normalize.js","sourceRoot":"","sources":["../src/normalize.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public types for @iflow-ai/search-core.
|
|
3
|
+
*
|
|
4
|
+
* Plain objects only. No framework couplings.
|
|
5
|
+
*/
|
|
6
|
+
export interface WebSearchParams {
|
|
7
|
+
query: string;
|
|
8
|
+
/** Number of results. Default 10, range 1..20. */
|
|
9
|
+
count?: number;
|
|
10
|
+
}
|
|
11
|
+
export interface ImageSearchParams {
|
|
12
|
+
query: string;
|
|
13
|
+
count?: number;
|
|
14
|
+
}
|
|
15
|
+
export interface WebFetchParams {
|
|
16
|
+
url: string;
|
|
17
|
+
}
|
|
18
|
+
export interface NormalizedWebSearchResult {
|
|
19
|
+
title: string;
|
|
20
|
+
url: string;
|
|
21
|
+
snippet: string;
|
|
22
|
+
position: number | null;
|
|
23
|
+
date: string | null;
|
|
24
|
+
}
|
|
25
|
+
export interface NormalizedWebSearch {
|
|
26
|
+
query: string;
|
|
27
|
+
count: number;
|
|
28
|
+
tookMs: number;
|
|
29
|
+
results: NormalizedWebSearchResult[];
|
|
30
|
+
}
|
|
31
|
+
export interface NormalizedImage {
|
|
32
|
+
imageUrl: string;
|
|
33
|
+
title: string | null;
|
|
34
|
+
sourceUrl: string | null;
|
|
35
|
+
width: number | null;
|
|
36
|
+
height: number | null;
|
|
37
|
+
position: number | null;
|
|
38
|
+
}
|
|
39
|
+
export interface NormalizedImageSearch {
|
|
40
|
+
query: string;
|
|
41
|
+
count: number;
|
|
42
|
+
tookMs: number;
|
|
43
|
+
images: NormalizedImage[];
|
|
44
|
+
}
|
|
45
|
+
export interface NormalizedWebFetch {
|
|
46
|
+
url: string;
|
|
47
|
+
title: string | null;
|
|
48
|
+
content: string;
|
|
49
|
+
fromCache: boolean | null;
|
|
50
|
+
tookMs: number;
|
|
51
|
+
}
|
|
52
|
+
import type { IFlowError } from "./errors.js";
|
|
53
|
+
export type IFlowResult<T> = {
|
|
54
|
+
ok: true;
|
|
55
|
+
data: T;
|
|
56
|
+
} | {
|
|
57
|
+
ok: false;
|
|
58
|
+
error: IFlowError;
|
|
59
|
+
};
|
|
60
|
+
export interface IFlowSearchClientOptions {
|
|
61
|
+
apiKey: string;
|
|
62
|
+
/** Default https://platform.iflow.cn. Trailing slashes stripped. */
|
|
63
|
+
baseUrl?: string;
|
|
64
|
+
/** Per-request timeout in ms. Default 30000. */
|
|
65
|
+
timeoutMs?: number;
|
|
66
|
+
/** Injectable for tests. Falls back to global fetch (Node ≥18). */
|
|
67
|
+
fetch?: typeof fetch;
|
|
68
|
+
/** e.g. "langchain" | "mcp" | "openclaw" | "core". Required. */
|
|
69
|
+
source: string;
|
|
70
|
+
/** e.g. "@iflow-ai/search-langchain". Required. */
|
|
71
|
+
integrationName: string;
|
|
72
|
+
/** e.g. "1.2.3". Required. */
|
|
73
|
+
integrationVersion: string;
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,kDAAkD;IAClD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC;CACb;AAID,MAAM,WAAW,yBAAyB;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,yBAAyB,EAAE,CAAC;CACtC;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,eAAe,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,OAAO,GAAG,IAAI,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;CAChB;AAID,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,MAAM,WAAW,CAAC,CAAC,IACrB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,CAAC,CAAA;CAAE,GACrB;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,UAAU,CAAA;CAAE,CAAC;AAIrC,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,oEAAoE;IACpE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gDAAgD;IAChD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mEAAmE;IACnE,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,gEAAgE;IAChE,MAAM,EAAE,MAAM,CAAC;IACf,mDAAmD;IACnD,eAAe,EAAE,MAAM,CAAC;IACxB,8BAA8B;IAC9B,kBAAkB,EAAE,MAAM,CAAC;CAC5B"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@iflow-ai/search-core",
|
|
3
|
+
"version": "0.1.0-pre.0",
|
|
4
|
+
"description": "Framework-agnostic SDK for the iFlow Search API (web search, image search, web fetch). Zero runtime dependencies.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=18"
|
|
9
|
+
},
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/zhengyanglsun/iflow-search-js.git",
|
|
13
|
+
"directory": "packages/search-core"
|
|
14
|
+
},
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/zhengyanglsun/iflow-search-js/issues"
|
|
17
|
+
},
|
|
18
|
+
"homepage": "https://github.com/zhengyanglsun/iflow-search-js/tree/main/packages/search-core#readme",
|
|
19
|
+
"main": "./dist/index.js",
|
|
20
|
+
"types": "./dist/index.d.ts",
|
|
21
|
+
"exports": {
|
|
22
|
+
".": {
|
|
23
|
+
"types": "./dist/index.d.ts",
|
|
24
|
+
"default": "./dist/index.js"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"dist",
|
|
29
|
+
"README.md",
|
|
30
|
+
"LICENSE"
|
|
31
|
+
],
|
|
32
|
+
"keywords": [
|
|
33
|
+
"iflow",
|
|
34
|
+
"iflow-search",
|
|
35
|
+
"web-search",
|
|
36
|
+
"image-search",
|
|
37
|
+
"web-fetch",
|
|
38
|
+
"ai-search",
|
|
39
|
+
"search-sdk"
|
|
40
|
+
],
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@types/node": "^20.0.0",
|
|
43
|
+
"typescript": "^5.4.0",
|
|
44
|
+
"vitest": "^1.6.0"
|
|
45
|
+
},
|
|
46
|
+
"scripts": {
|
|
47
|
+
"build": "tsc -p tsconfig.json",
|
|
48
|
+
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
49
|
+
"test": "vitest run",
|
|
50
|
+
"test:watch": "vitest"
|
|
51
|
+
}
|
|
52
|
+
}
|