@nickyzj2023/utils 1.0.69 → 1.0.71

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/dist/index.d.mts CHANGED
@@ -1,785 +1,789 @@
1
- //#region src/ai/chatCompletions/types.d.ts
2
- declare namespace ChatCompletions {
3
- type Model = {
4
- /** 模型名称(如果不传,会尝试从 /models 读取模型) */model?: string; /** API 基础地址 */
5
- baseUrl: string; /** API 密钥(本地模型可不传) */
6
- apiKey?: string;
7
- };
8
- type TextContent = {
9
- type: "text";
10
- text: string;
11
- };
12
- type ImageContent = {
13
- type: "image_url";
14
- image_url: {
15
- url: string;
16
- };
17
- };
18
- type AudioContent = {
19
- type: "input_audio";
20
- audio_url: {
21
- url: string;
22
- };
23
- };
24
- type VideoContent = {
25
- type: "video_url";
26
- video_url: {
27
- url: string;
28
- };
29
- };
30
- type ContentPart = TextContent | ImageContent | AudioContent | VideoContent;
31
- type Message = {
32
- role: "system" | "user" | "assistant" | "tool" | "function"; /** 字节的思考字段 */
33
- reasoning_content?: string | null; /** OpenRouter的思考字段 */
34
- reasoning?: string | null;
35
- content: string | ContentPart[];
36
- name?: string;
37
- tool_calls?: ToolCall[];
38
- tool_call_id?: string;
39
- };
40
- type ToolCall = {
41
- id: string;
42
- type: "function";
43
- function: {
44
- name: string;
45
- arguments: string;
46
- };
47
- };
48
- type ToolDefinition = {
49
- type: "function";
50
- function: {
51
- name: string;
52
- description?: string;
53
- parameters?: Record<string, any>;
54
- };
55
- };
56
- type Usage = {
57
- prompt_tokens: number;
58
- completion_tokens: number;
59
- total_tokens: number;
60
- };
61
- type Response = {
62
- id: string;
63
- object: "chat.completion";
64
- created: number;
65
- model: string;
66
- choices: Array<{
67
- index: number;
68
- message: Message;
69
- finish_reason: "stop" | "length" | "tool_calls" | "content_filter" | null;
70
- }>;
71
- usage: Usage;
72
- system_fingerprint?: string;
73
- };
74
- type ExtraBody = {
75
- /** 工具列表 */tools?: ToolDefinition[]; /** 工具调用函数表,key 为工具名,value 为函数 */
76
- toolHandlers?: Record<string, (args: any) => any | Promise<any>>; /** 是否使用流式传输,启用后函数返回异步迭代器 */
77
- stream?: boolean; /** 其他额外参数 */
78
- [key: string]: any;
79
- };
80
- type Result = {
81
- /** 模型的最终回复内容(多模态时取所有 text 拼接) */content: string; /** Token 消耗情况 */
82
- usage: Usage; /** 原始响应中的其他字段 */
83
- [key: string]: any;
84
- };
85
- /** 流式响应中的单个 SSE 数据块(OpenAI 原始格式) */
86
- type StreamResponse = {
87
- id: string;
88
- object: "chat.completion.chunk";
89
- created: number;
90
- model: string;
91
- choices: Array<{
92
- index: number;
93
- delta: {
94
- role?: Message["role"];
95
- content?: string | null; /** 字节的思考字段 */
96
- reasoning_content?: string | null; /** OpenRouter的思考字段 */
97
- reasoning?: string | null;
98
- tool_calls?: Array<{
99
- index: number;
100
- id?: string;
101
- type?: "function";
102
- function?: {
103
- name?: string;
104
- arguments?: string;
105
- };
106
- }>;
107
- };
108
- finish_reason: "stop" | "length" | "tool_calls" | "content_filter" | null;
109
- }>;
110
- usage?: Usage;
111
- };
112
- /** 流式调用 chatCompletions 时迭代器产出的数据块 */
113
- type StreamChunk = {
114
- /** 模型流式返回的思考内容增量(仅在生成过程中出现) */reasoningContent?: string; /** 模型流式返回的内容增量(仅在生成过程中出现) */
115
- content?: string; /** Token 消耗情况(仅在最后一帧出现) */
116
- usage?: Usage;
117
- };
118
- }
119
- //#endregion
120
- //#region src/ai/chatCompletions/index.d.ts
121
- /**
122
- * 兼容 OpenAI API 的聊天补全函数
123
- * - 自动处理工具调用
124
- * - 同时支持普通响应和流式响应
125
- *
126
- * @param model 模型配置,包含 model、baseUrl、apiKey
127
- * @param messages OpenAI API 兼容的消息数组
128
- * @param extraBody 可选的额外参数,如 tools、toolHandlers、temperature、stream 等
129
- * @returns 普通模式下返回 `{ content, usage, ... }`;`stream: true` 时返回异步迭代器
130
- *
131
- * @example
132
- * // 最简调用
133
- * // 未填写模型名,会自动使用/v1/models的第一个模型
134
- * const { content, usage } = await chatCompletions(
135
- * { baseUrl: "http://127.0.0.1:11434/v1" },
136
- * [{ role: "user", content: "你好" }],
137
- * );
138
- * console.log(content); // "你好!有什么我可以帮你的吗?"
139
- * console.log(usage); // { prompt_tokens: 13, completion_tokens: 9, total_tokens: 22 }
140
- *
141
- * @example
142
- * // 工具调用
143
- * const { content, usage } = await chatCompletions(
144
- * { baseUrl: "http://127.0.0.1:11434/v1", model: "model.gguf", apiKey: "sk-local-no-need-key" },
145
- * [{ role: "user", content: "查询上海天气" }],
146
- * {
147
- * tools: [{
148
- * type: "function",
149
- * function: {
150
- * name: "getWeather",
151
- * description: "查询城市天气情况",
152
- * parameters: { type: "object", properties: { city: { type: "string" } } },
153
- * },
154
- * }],
155
- * toolHandlers: {
156
- * getWeather: (args) => `${args.city}今日晴转多云,25°C`,
157
- * },
158
- * },
159
- * );
160
- *
161
- * @example
162
- * // 流式传输
163
- * const result = await chatCompletions(
164
- * { baseUrl: "http://127.0.0.1:11434/v1" },
165
- * [{ role: "user", content: "你好" }],
166
- * { stream: true },
167
- * );
168
- * for await (const { content, usage } of result) {
169
- * if (content) {
170
- * console.log("流式传输中:", content);
171
- * } else if (usage) {
172
- * console.log("对话结束,消耗:", usage);
173
- * }
174
- * }
175
- */
176
- declare function chatCompletions(model: ChatCompletions.Model, messages: ChatCompletions.Message[], extraBody: ChatCompletions.ExtraBody & {
177
- stream: true;
178
- }): Promise<AsyncGenerator<ChatCompletions.StreamChunk>>;
179
- declare function chatCompletions(model: ChatCompletions.Model, messages: ChatCompletions.Message[], extraBody?: ChatCompletions.ExtraBody): Promise<ChatCompletions.Result>;
180
- /**
181
- * 辅助定义一个 chatCompletions 支持的模型配置
182
- */
183
- declare const defineModel: (config: ChatCompletions.Model) => ChatCompletions.Model;
184
- //#endregion
185
- //#region src/dom/log.d.ts
186
- /**
187
- * log 配置选项
188
- */
189
- interface LogOptions {
190
- /**
191
- * 是否显示时间
192
- * @default true
193
- */
194
- time?: boolean;
195
- /**
196
- * 是否显示调用者文件名
197
- * @default true
198
- */
199
- fileName?: boolean;
200
- }
201
- /**
202
- * 带额外信息的 console.log
203
- * @param message - 日志消息,支持单条消息或消息数组
204
- * @param options - 配置选项
205
- *
206
- * @example
207
- * log("调试信息"); // "[14:30:00] [index.ts:15] 调试信息"
208
- * log("调试信息", { time: false }); // "[index.ts:15] 调试信息"
209
- * log("调试信息", { fileName: false }); // "[14:30:00] 调试信息"
210
- * log("调试信息", { time: false, fileName: false }); // "调试信息"
211
- * log(["消息1", "消息2"]); // "[14:30:00] [index.ts:15] 消息1 消息2"
212
- */
213
- declare const log: (message: any | any[], options?: LogOptions) => void;
214
- //#endregion
215
- //#region src/function/loop-until.d.ts
216
- /**
217
- * 循环执行函数,直到符合停止条件
218
- *
219
- * @example
220
- * // 循环请求大语言模型,直到其不再调用工具
221
- * loopUntil(
222
- * async () => {
223
- * const completion = await chatCompletions();
224
- * completion.tool_calls?.forEach(chooseAndHandleTool)
225
- * return completion;
226
- * },
227
- * {
228
- * shouldStop: (completion) => !completion.tool_calls,
229
- * },
230
- * ),
231
- *
232
- * @example
233
- * // 不传递 shouldStop,执行 3 次后正常返回最后结果
234
- * loopUntil(
235
- * () => {
236
- * return doSomething();
237
- * },
238
- * {
239
- * maxRetries: 3,
240
- * },
241
- * ),
242
- */
243
- declare const loopUntil: <T>(fn: (count: number) => T | Promise<T>, options?: {
244
- /**
245
- * 最大循环次数
246
- * @default 5
247
- */
248
- maxRetries?: number; /** 停止循环条件。如果未传递,则执行 maxRetries 次后退出并返回最后结果 */
249
- shouldStop?: (result: T) => boolean;
250
- }) => Promise<T>;
251
- //#endregion
252
- //#region src/hoc/with-cache.d.ts
253
- type SetTtl = (seconds: number) => void;
254
- /**
255
- * 创建一个带缓存的高阶函数
256
- *
257
- * @template Args 被包装函数的参数类型数组
258
- * @template Result 被包装函数的返回类型
259
- *
260
- * @param fn 需要被缓存的函数,参数里附带的 setTtl 方法用于根据具体情况改写过期时间
261
- * @param ttlSeconds 以秒为单位的过期时间,-1 表示永不过期,默认 -1,会被回调函数里的 setTtl() 覆盖
262
- *
263
- * @returns 返回包装后的函数,以及缓存相关的额外方法
264
- *
265
- * @example
266
- * // 异步函数示例
267
- * const fetchData = withCache(async function (url: string) {
268
- * const data = await fetch(url).then((res) => res.json());
269
- * this.setTtl(data.expiresIn); // 根据实际情况调整过期时间
270
- * return data;
271
- * });
272
- *
273
- * await fetchData(urlA);
274
- * await fetchData(urlA); // 使用缓存结果
275
- * await fetchData(urlB);
276
- * await fetchData(urlB); // 使用缓存结果
277
- *
278
- * fetchData.clear(); // 清除缓存
279
- * await fetchData(urlA); // 重新请求
280
- * await fetchData(urlB); // 重新请求
281
- *
282
- * // 缓存过期前
283
- * await sleep();
284
- * fetchData.updateTtl(180); // 更新 ttl 并为所有未过期的缓存续期
285
- * await fetchData(urlA); // 使用缓存结果
286
- * await fetchData(urlB); // 使用缓存结果
287
- */
288
- declare const withCache: <Args extends any[], Result>(fn: (this: {
289
- setTtl: SetTtl;
290
- }, ...args: Args) => Result, ttlSeconds?: number) => {
291
- (...args: Args): Result;
292
- clear(): void;
293
- updateTtl(seconds: number): void;
294
- };
295
- //#endregion
296
- //#region src/is/is-nil.d.ts
297
- /**
298
- * 检测传入的值是否为**空值**(null、undefined)
299
- *
300
- * @example
301
- * isNil(null); // true
302
- * isNil(undefined); // true
303
- * isNil(1); // false
304
- */
305
- declare const isNil: (value: any) => value is null | undefined;
306
- //#endregion
307
- //#region src/is/is-object.d.ts
308
- /**
309
- * 检测传入的值是否为**普通对象**
310
- *
311
- * @example
312
- * const obj = { a: 1 };
313
- * isObject(obj); // true
314
- */
315
- declare const isObject: (value: any) => value is Record<string, any>;
316
- //#endregion
317
- //#region src/is/is-primitive.d.ts
318
- type Primitive = number | string | boolean | symbol | bigint | undefined | null;
319
- /**
320
- * 检测传入的值是否为**原始值**(number、string、boolean、symbol、bigint、undefined、null)
321
- *
322
- * @example
323
- * isPrimitive(1); // true
324
- * isPrimitive([]); // false
325
- */
326
- declare const isPrimitive: (value: any) => value is Primitive;
327
- //#endregion
328
- //#region src/network/fetcher.d.ts
329
- type RequestInit = globalThis.RequestInit & {
330
- /**
331
- * searchParams 查询参数对象
332
- */
333
- params?: Record<string, any>;
334
- /**
335
- * 响应解析器,默认的解析方法为 response.json()
336
- */
337
- parser?: (response: Response) => Promise<any>;
338
- };
339
- /**
340
- * 基于 Fetch API 的请求实例
341
- * @param baseUrl 接口前缀
342
- * @param baseOptions 应用于整个实例的请求体,后续请求都会带上
343
- *
344
- * @remarks
345
- * 特性:
346
- * - 支持在创建实例、发出请求时合并相同的请求体(后者覆盖前者)
347
- * - 支持在 GET 的 params 请求体中传递对象
348
- * - 支持在 POST、PUT 的 body 请求体中传递对象
349
- * - 可选 to() 函数转换请求结果为 [Error, Response]
350
- * - 可选 withCache() 函数缓存请求结果
351
- *
352
- * @example
353
- * // 直接发请求
354
- * const res = await fetcher().get<Blog>("https://nickyzj.run:3030/blogs/hello-world", {
355
- * params: {
356
- * page: 2,
357
- * pageSize: 10,
358
- * }
359
- * });
360
- *
361
- * // 创建实例,发请求
362
- * const api = fetcher("https://nickyzj.run:3030", {
363
- * headers: {
364
- * Authorization: "Bearer token"
365
- * }
366
- * });
367
- * const res = await api.get<Blog>("/blogs/hello-world");
368
- *
369
- * // 安全返回请求结果,不抛异常
370
- * const [error, data] = await to(api.get<Blog>("/blogs/hello-world"));
371
- * if (error) {
372
- * // ...
373
- * }
374
- * // ...
375
- *
376
- * // 缓存请求结果
377
- * const getBlogs = withCache(api.get);
378
- * await getBlogs("/blogs");
379
- * await getBlogs("/blogs"); // 不发请求,使用缓存
380
- */
381
- declare const fetcher: (baseUrl?: string, baseOptions?: RequestInit) => {
382
- get: <T>(url: string, options?: Omit<RequestInit, "method">) => Promise<T>;
383
- post: <T>(url: string, body: any, options?: Omit<RequestInit, "method" | "body">) => Promise<T>;
384
- put: <T>(url: string, body: any, options?: Omit<RequestInit, "method" | "body">) => Promise<T>;
385
- delete: <T>(url: string, options?: Omit<RequestInit, "method" | "body">) => Promise<T>;
386
- };
387
- //#endregion
388
- //#region src/network/get-real-url.d.ts
389
- /** url 响应头获取真实链接 */
390
- declare const getRealURL: (originURL: string) => Promise<string>;
391
- //#endregion
392
- //#region src/network/image.d.ts
393
- /**
394
- * 图片压缩选项
395
- */
396
- type ImageCompressionOptions = {
397
- /** 压缩比率,默认 0.92 */quality?: number;
398
- /**
399
- * 自定义压缩函数,用于覆盖默认压缩行为
400
- * @param arrayBuffer 图片的 ArrayBuffer 数据
401
- * @param mime 图片的 MIME 类型
402
- * @param quality 压缩质量
403
- * @returns 压缩后的 base64 字符串
404
- */
405
- compressor?: (arrayBuffer: ArrayBuffer, mime: string, quality: number) => Promise<string> | string;
406
- /**
407
- * 自定义 fetch 函数,用于使用自己封装的请求库读取图片
408
- * 必须返回符合 Web 标准的 Response 对象
409
- * @param url 图片地址
410
- * @returns Promise<Response>
411
- */
412
- fetcher?: (url: string) => Promise<Response>;
413
- };
414
- /**
415
- * 图片地址转 base64 数据
416
- *
417
- * @param imageUrl 图片地址
418
- * @param options 可选配置
419
- * @param options.quality 压缩比率,默认 0.92
420
- * @param options.compressor 自定义压缩函数,用于覆盖默认压缩行为
421
- *
422
- * @example
423
- * // 基本用法(浏览器自动使用 Canvas 压缩,Node.js 自动检测并使用 sharp)
424
- * imageUrlToBase64("https://example.com/image.jpg");
425
- *
426
- * @example
427
- * // 使用自定义 fetch 函数(如 axios 封装)
428
- * imageUrlToBase64("https://example.com/image.jpg", {
429
- * fetcher: async (url) => {
430
- * // 使用 axios 或其他请求库,但必须返回 Response 对象
431
- * const response = await axios.get(url, { responseType: 'arraybuffer' });
432
- * return new Response(response.data, {
433
- * status: response.status,
434
- * statusText: response.statusText,
435
- * headers: response.headers
436
- * });
437
- * }
438
- * });
439
- *
440
- * @example
441
- * // 使用自定义压缩函数覆盖默认行为
442
- * imageUrlToBase64("https://example.com/image.jpg", {
443
- * quality: 0.8,
444
- * compressor: async (buffer, mime, quality) => {
445
- * // 自定义压缩逻辑
446
- * return `data:${mime};base64,...`;
447
- * }
448
- * });
449
- */
450
- declare const imageUrlToBase64: (imageUrl: string, options?: ImageCompressionOptions) => Promise<string>;
451
- //#endregion
452
- //#region src/network/to.d.ts
453
- /**
454
- * Go 语言风格的异步处理方式
455
- * @param promise 一个能被 await 的异步函数
456
- * @returns 如果成功,返回 [null, 异步函数结果],否则返回 [Error, undefined]
457
- *
458
- * @example
459
- * const [error, response] = await to(fetcher().get<Blog>("/blogs/hello-world"));
460
- */
461
- declare const to: <T, E = Error>(promise: Promise<T>) => Promise<[null, T] | [E, undefined]>;
462
- //#endregion
463
- //#region src/number/random-int.d.ts
464
- /**
465
- * 在指定闭区间内生成随机整数
466
- *
467
- * @example
468
- * randomInt(1, 10); // 1 <= x <= 10
469
- */
470
- declare const randomInt: (min: number, max: number) => number;
471
- //#endregion
472
- //#region src/object/map.d.ts
473
- type DeepMapKeys<T> = T extends Array<infer U> ? Array<DeepMapKeys<U>> : T extends object ? {
474
- [key: string]: DeepMapKeys<T[keyof T]>;
475
- } : T;
476
- /**
477
- * 递归处理对象里的 key
478
- *
479
- * @remarks
480
- * 无法完整推导出类型,只能做到有递归,key 全为 string,value 为同层级的所有类型的联合
481
- *
482
- * @template T 要转换的对象
483
- *
484
- * @example
485
- * const obj = { a: { b: 1 } };
486
- * const result = mapKeys(obj, (key) => key.toUpperCase());
487
- * console.log(result); // { A: { B: 1 } }
488
- */
489
- declare const mapKeys: <T>(obj: T, getNewKey: (key: string) => string) => DeepMapKeys<T>;
490
- type DeepMapValues<T, R> = T extends Array<infer U> ? Array<DeepMapValues<U, R>> : T extends object ? { [K in keyof T]: T[K] extends object ? DeepMapValues<T[K], R> : R } : R;
491
- /**
492
- * 递归处理对象里的 value
493
- *
494
- * @remarks
495
- * 无法完整推导出类型,所有 value 最终都会变为 any
496
- *
497
- * @template T 要转换的对象
498
- * @template R 转换后的值类型,为 any,无法进一步推导
499
- *
500
- * @example
501
- * const obj = { a: 1, b: { c: 2 } };
502
- * const result = mapValues(obj, (value, key) => isPrimitive(value) ? value + 1 : value);
503
- * console.log(result); // { a: 2, b: { c: 3 } }
504
- */
505
- declare const mapValues: <T, R = any>(obj: T, getNewValue: (value: any, key: string | number) => R, options?: {
506
- /** 过滤函数,返回 true 表示保留该字段 */filter?: (value: any, key: string | number) => boolean;
507
- }) => DeepMapValues<T, R>;
508
- //#endregion
509
- //#region src/object/merge.d.ts
510
- /**
511
- * 深度合并两个对象,规则如下:
512
- * 1. 原始值覆盖:如果两个值都是原始类型,则用后者覆盖;
513
- * 2. 数组拼接:如果两个值都是数组,则拼接为大数组;
514
- * 3. 对象递归合并:如果两个值都是对象,则进行递归深度合并;
515
- *
516
- * @template T 第一个对象
517
- * @template U 第二个对象
518
- * @param {T} obj1 要合并的第一个对象,相同字段会被 obj2 覆盖
519
- * @param {U} obj2 要合并的第二个对象
520
- */
521
- declare const mergeObjects: <T extends Record<string, any>, U extends Record<string, any>>(obj1: T, obj2: U) => T & U;
522
- //#endregion
523
- //#region src/object/omit.d.ts
524
- /**
525
- * 从对象中排除指定的键,返回不包含这些键的新对象
526
- *
527
- * @typeParam T - 源对象的类型
528
- * @typeParam K - 要排除的键,必须是源对象的键之一
529
- *
530
- * @param obj - 源对象
531
- * @param keys - 要排除的键名数组
532
- * @returns 不包含指定键的新对象
533
- *
534
- * @example
535
- * const user = {
536
- * id: 1,
537
- * name: "Alice",
538
- * age: 25,
539
- * password: "secret"
540
- * };
541
- * // { id: 1, name: "Alice", age: 25 }
542
- * const safeUser = omit(user, ["password"]);
543
- */
544
- declare const omit: <T extends Record<string, any>, K extends keyof T>(obj: T, keys: readonly K[]) => Omit<T, K>;
545
- /**
546
- * 从对象中排除满足条件的键值对,返回不包含这些键的新对象
547
- *
548
- * @typeParam T - 源对象的类型
549
- *
550
- * @param obj - 源对象
551
- * @param shouldOmit - 判断函数,接收键和值,返回 `true` 则排除该键值对
552
- * @returns 不包含满足条件的键值对的新对象
553
- *
554
- * @example
555
- * const user = {
556
- * id: 1,
557
- * name: "Alice",
558
- * age: 25,
559
- * password: "secret"
560
- * };
561
- * // { name: "Alice", password: "secret" }
562
- * const stringFields = omitBy(user, (key, value) => typeof value === "number");
563
- */
564
- declare const omitBy: <T extends Record<string, any>>(obj: T, shouldOmit: (key: keyof T, value: T[keyof T]) => boolean) => Partial<T>;
565
- //#endregion
566
- //#region src/object/pick.d.ts
567
- /**
568
- * 从对象中选取指定的键,返回仅包含这些键的新对象
569
- *
570
- * @typeParam T - 源对象的类型
571
- * @typeParam K - 要选取的键,必须是源对象的键之一
572
- *
573
- * @param obj - 源对象
574
- * @param keys - 要选取的键名数组
575
- * @returns 仅包含指定键的新对象
576
- *
577
- * @example
578
- * const user = {
579
- * id: 1,
580
- * name: "Alice",
581
- * age: 25,
582
- * password: "secret"
583
- * };
584
- * // { id: 1, name: "Alice", age: 25 }
585
- * const safeUser = pick(user, ["id", "name", "age"]);
586
- */
587
- declare const pick: <T extends Record<string, any>, K extends keyof T>(obj: T, keys: readonly K[]) => Pick<T, K>;
588
- /**
589
- * 从对象中选取满足条件的键值对,返回仅包含这些键的新对象
590
- *
591
- * @typeParam T - 源对象的类型
592
- *
593
- * @param obj - 源对象
594
- * @param shouldPick - 判断函数,返回 `true` 时保留该字段
595
- * @returns 仅包含满足条件的键值对的新对象
596
- *
597
- * @example
598
- * const user = {
599
- * id: 1,
600
- * name: "Alice",
601
- * age: 25,
602
- * password: "secret"
603
- * };
604
- * // { id: 1, age: 25 }
605
- * const numericFields = pickBy(user, (key, value) => typeof value === "number");
606
- */
607
- declare const pickBy: <T extends Record<string, any>>(obj: T, shouldPick: (key: keyof T, value: T[keyof T]) => boolean) => Partial<T>;
608
- //#endregion
609
- //#region src/string/case.d.ts
610
- type SnakeToCamel<S extends string> = S extends `${infer Before}_${infer After}` ? After extends `${infer First}${infer Rest}` ? `${Before}${Uppercase<First>}${SnakeToCamel<Rest>}` : Before : S;
611
- /**
612
- * 下划线命名法转为驼峰命名法
613
- *
614
- * @example
615
- * snakeToCamel("user_name") // "userName"
616
- */
617
- declare const snakeToCamel: <S extends string>(str: S) => SnakeToCamel<S>;
618
- type CamelToSnake<S extends string> = S extends `${infer First}${infer Rest}` ? Rest extends Uncapitalize<Rest> ? `${Lowercase<First>}${CamelToSnake<Rest>}` : `${Lowercase<First>}_${CamelToSnake<Rest>}` : Lowercase<S>;
619
- /**
620
- * 驼峰命名法转为下划线命名法
621
- *
622
- * @example
623
- * camelToSnake("shouldComponentUpdate") // "should_component_update"
624
- */
625
- declare const camelToSnake: <S extends string>(str: S) => CamelToSnake<S>;
626
- type Capitalize<S extends string> = S extends `${infer P1}${infer Rest}` ? P1 extends Capitalize<P1> ? S : `${Uppercase<P1>}${Rest}` : S;
627
- /**
628
- * 字符串首字母大写
629
- *
630
- * @example
631
- * capitalize("hello") // "Hello"
632
- */
633
- declare const capitalize: <S extends string>(s: S) => Capitalize<S>;
634
- type Decapitalize<S extends string> = S extends `${infer P1}${infer Rest}` ? P1 extends Lowercase<P1> ? P1 : `${Lowercase<P1>}${Rest}` : S;
635
- /**
636
- * 字符串首字母小写
637
- *
638
- * @example
639
- * decapitalize("Hello") // "hello"
640
- */
641
- declare const decapitalize: <S extends string>(s: S) => Decapitalize<S>;
642
- //#endregion
643
- //#region src/string/compact.d.ts
644
- /**
645
- * 将字符串压缩为单行精简格式
646
- *
647
- * @example
648
- * // "Hello\nworld"
649
- * compactStr(`Hello,
650
- *
651
- * world
652
- *
653
- * !`);
654
- *
655
- * @example
656
- * // "Hello...world"
657
- * compactStr("Hello, beautiful world!", { maxLength: 15 });
658
- */
659
- declare const compactStr: (text?: string, options?: {
660
- /**
661
- * 最大保留长度,超过该长度使用 "..." 替代
662
- @default Infinity
663
- */
664
- maxLength?: number;
665
- /**
666
- * 是否将换行符替换为字面量"\n"
667
- * @default false
668
- */
669
- disableNewLineReplace?: boolean;
670
- /**
671
- * 是否合并连续的换行符/制表符为单个
672
- * @default false
673
- */
674
- disableCollapse?: boolean;
675
- }) => string;
676
- //#endregion
677
- //#region src/string/extract-error-message.d.ts
678
- /** 从任意异常中提取类似 error.message 的可读文字 */
679
- declare const extractErrorMessage: (error: unknown) => string;
680
- //#endregion
681
- //#region src/string/qs.d.ts
682
- /**
683
- * 针对 URL 查询字符串的解析和序列化
684
- * @example
685
- * qs.parse("?a=1&b=2") // { a: 1, b: 2 }
686
- * qs.stringify({ a: 1, b: 2 }, { addQueryPrefix: true }) // "?a=1&b=2"
687
- */
688
- declare const qs: {
689
- /** queryString -> queryParams */parse: (queryString: string) => Record<string, any>;
690
- stringify: (params: Record<string, any>, options?: {
691
- /**
692
- * 是否在结果前添加“?”
693
- * @default false
694
- */
695
- addQueryPrefix: boolean;
696
- }) => string;
697
- };
698
- //#endregion
699
- //#region src/time/debounce.d.ts
700
- /**
701
- * 防抖:在指定时间内只执行最后一次调用
702
- * @param fn 要防抖的函数
703
- * @param delay 延迟时间,默认 300ms
704
- *
705
- * @remarks
706
- * 连续触发时,只有最后一次会执行。适合用于搜索框输入、窗口大小调整等场景。
707
- * 例如:用户输入"hello"过程中,不会触发搜索,只有停下来时才执行。
708
- *
709
- * 防抖 vs 节流:
710
- * - 防抖:等待触发停止后才执行(最后一次)
711
- * - 节流:按固定节奏执行(每隔多久执行一次)
712
- *
713
- * @example
714
- * const search = debounce((keyword: string) => {
715
- * console.log('搜索:', keyword);
716
- * });
717
- * search('hello'); // 300ms 后执行
718
- */
719
- declare const debounce: <T extends (...args: any[]) => any>(fn: T, delay?: number) => (...args: Parameters<T>) => void;
720
- //#endregion
721
- //#region src/time/lock-queue.d.ts
722
- /**
723
- * 排队锁
724
- *
725
- * @remarks
726
- * 使用场景如:同时给大模型发送多条消息,使其依次回复
727
- *
728
- * @example
729
- * const queue = new LockQueue();
730
- * const messages = [];
731
- *
732
- * const chatCompletions = async () => {
733
- * // 等待前一个队列释放
734
- * const release = await queue.waitInQueue();
735
- *
736
- * const message = await requestLLM();
737
- * messages.push(message);
738
- * sendMessage(message);
739
- *
740
- * // 释放队列
741
- * release();
742
- * };
743
- *
744
- * chatCompletions();
745
- * chatCompletions();
746
- * chatCompletions();
747
- */
748
- declare class LockQueue {
749
- queue: Promise<any>;
750
- constructor();
751
- waitInQueue(): Promise<(value?: any) => void>;
752
- }
753
- //#endregion
754
- //#region src/time/sleep.d.ts
755
- /**
756
- * 延迟一段时间再执行后续代码
757
- * @param time 延迟时间,默认 150ms
758
- * @example
759
- * await sleep(1000); // 等待 1 秒执行后续代码
760
- */
761
- declare const sleep: (time?: number) => Promise<unknown>;
762
- //#endregion
763
- //#region src/time/throttle.d.ts
764
- /**
765
- * 节流函数 - 在指定时间间隔内最多执行一次调用
766
- * @param fn 要节流的函数
767
- * @param delay 间隔时间,默认 300ms
768
- *
769
- * @remarks
770
- * 节流:连续触发时,按照固定间隔执行。适合用于滚动、拖拽等高频触发场景。
771
- * 例如:滚动页面时,每300ms最多执行一次回调,而不是每次滚动都执行。
772
- *
773
- * 防抖 vs 节流:
774
- * - 防抖:等待触发停止后才执行(最后一次)
775
- * - 节流:按固定节奏执行(每隔多久执行一次)
776
- *
777
- * @example
778
- * const handleScroll = throttle(() => {
779
- * console.log('滚动位置:', window.scrollY);
780
- * }, 200);
781
- * window.addEventListener('scroll', handleScroll);
782
- */
783
- declare const throttle: <T extends (...args: any[]) => any>(fn: T, delay?: number) => (this: any, ...args: Parameters<T>) => void;
784
- //#endregion
1
+ //#region src/ai/chatCompletions/types.d.ts
2
+ declare namespace ChatCompletions {
3
+ type Model = {
4
+ /** 模型名称(如果不传,会尝试从 /models 读取模型) */model?: string; /** API 基础地址 */
5
+ baseUrl: string; /** API 密钥(本地模型可不传) */
6
+ apiKey?: string;
7
+ };
8
+ type TextContent = {
9
+ type: "text";
10
+ text: string;
11
+ };
12
+ type ImageContent = {
13
+ type: "image_url";
14
+ image_url: {
15
+ url: string;
16
+ };
17
+ };
18
+ type AudioContent = {
19
+ type: "input_audio";
20
+ input_audio: {
21
+ /** 使用公网可访问的音频文件 URL */url?: string; /** 使用 base64 */
22
+ data?: string;
23
+ format: string;
24
+ };
25
+ };
26
+ type VideoContent = {
27
+ type: "video_url";
28
+ video_url: {
29
+ url: string;
30
+ };
31
+ };
32
+ type ContentPart = TextContent | ImageContent | AudioContent | VideoContent;
33
+ type Message = {
34
+ role: "system" | "user" | "assistant" | "tool" | "function"; /** 字节的思考字段 */
35
+ reasoning_content?: string | null; /** OpenRouter的思考字段 */
36
+ reasoning?: string | null;
37
+ content: string | ContentPart[];
38
+ name?: string;
39
+ tool_calls?: ToolCall[];
40
+ tool_call_id?: string;
41
+ };
42
+ type ToolCall = {
43
+ id: string;
44
+ type: "function";
45
+ function: {
46
+ name: string;
47
+ arguments: string;
48
+ };
49
+ };
50
+ type ToolDefinition = {
51
+ type: "function";
52
+ function: {
53
+ name: string;
54
+ description?: string;
55
+ parameters?: Record<string, any>;
56
+ };
57
+ };
58
+ type Usage = {
59
+ prompt_tokens: number;
60
+ completion_tokens: number;
61
+ total_tokens: number;
62
+ };
63
+ /** 请求非流式 /chat/completions 的响应结果 */
64
+ type Response = {
65
+ id: string;
66
+ object: "chat.completion";
67
+ created: number;
68
+ model: string;
69
+ choices: Array<{
70
+ index: number;
71
+ message: Message;
72
+ finish_reason: "stop" | "length" | "tool_calls" | "content_filter" | null;
73
+ }>;
74
+ usage: Usage;
75
+ system_fingerprint?: string;
76
+ };
77
+ type ExtraBody = {
78
+ /** 工具列表 */tools?: ToolDefinition[]; /** 工具调用函数表,key 为工具名,value 为函数 */
79
+ toolHandlers?: Record<string, (args: any) => any | Promise<any>>; /** 是否使用流式传输,启用后函数返回异步迭代器 */
80
+ stream?: boolean; /** 其他额外参数 */
81
+ [key: string]: any;
82
+ };
83
+ /** 调用 chatCompletions 返回的结果,流式/非流式通用 */
84
+ type Result = {
85
+ /** 模型的最终回复内容(多模态时取所有 text 拼接) */content: string; /** Token 消耗情况 */
86
+ usage: Usage; /** 原始响应中的其他字段 */
87
+ [key: string]: any;
88
+ };
89
+ /** 流式响应中的单个 SSE 数据块(OpenAI 原始格式) */
90
+ type StreamResponse = {
91
+ id: string;
92
+ object: "chat.completion.chunk";
93
+ created: number;
94
+ model: string;
95
+ choices: Array<{
96
+ index: number;
97
+ delta: {
98
+ role?: Message["role"];
99
+ content?: string | null; /** 字节的思考字段 */
100
+ reasoning_content?: string | null; /** OpenRouter的思考字段 */
101
+ reasoning?: string | null;
102
+ tool_calls?: Array<{
103
+ index: number;
104
+ id?: string;
105
+ type?: "function";
106
+ function?: {
107
+ name?: string;
108
+ arguments?: string;
109
+ };
110
+ }>;
111
+ };
112
+ finish_reason: "stop" | "length" | "tool_calls" | "content_filter" | null;
113
+ }>;
114
+ usage?: Usage;
115
+ };
116
+ /** 流式调用 chatCompletions 时迭代器产出的数据块 */
117
+ type StreamChunk = {
118
+ /** 模型流式返回的思考内容增量(仅在生成过程中出现) */reasoningContent?: string; /** 模型流式返回的内容增量(仅在生成过程中出现) */
119
+ content?: string; /** Token 消耗情况(仅在最后一帧出现) */
120
+ usage?: Usage;
121
+ };
122
+ }
123
+ //#endregion
124
+ //#region src/ai/chatCompletions/index.d.ts
125
+ /**
126
+ * 兼容 OpenAI API 的聊天补全函数
127
+ * - 自动处理工具调用
128
+ * - 同时支持普通响应和流式响应
129
+ *
130
+ * @param model 模型配置,包含 model、baseUrl、apiKey
131
+ * @param messages OpenAI API 兼容的消息数组
132
+ * @param extraBody 可选的额外参数,如 tools、toolHandlers、temperature、stream 等
133
+ * @returns 普通模式下返回 `{ content, usage, ... }`;`stream: true` 时返回异步迭代器
134
+ *
135
+ * @example
136
+ * // 最简调用
137
+ * // 未填写模型名,会自动使用/v1/models的第一个模型
138
+ * const { content, usage } = await chatCompletions(
139
+ * { baseUrl: "http://127.0.0.1:11434/v1" },
140
+ * [{ role: "user", content: "你好" }],
141
+ * );
142
+ * console.log(content); // "你好!有什么我可以帮你的吗?"
143
+ * console.log(usage); // { prompt_tokens: 13, completion_tokens: 9, total_tokens: 22 }
144
+ *
145
+ * @example
146
+ * // 工具调用
147
+ * const { content, usage } = await chatCompletions(
148
+ * { baseUrl: "http://127.0.0.1:11434/v1", model: "model.gguf", apiKey: "sk-local-no-need-key" },
149
+ * [{ role: "user", content: "查询上海天气" }],
150
+ * {
151
+ * tools: [{
152
+ * type: "function",
153
+ * function: {
154
+ * name: "getWeather",
155
+ * description: "查询城市天气情况",
156
+ * parameters: { type: "object", properties: { city: { type: "string" } } },
157
+ * },
158
+ * }],
159
+ * toolHandlers: {
160
+ * getWeather: (args) => `${args.city}今日晴转多云,25°C`,
161
+ * },
162
+ * },
163
+ * );
164
+ *
165
+ * @example
166
+ * // 流式传输
167
+ * const result = await chatCompletions(
168
+ * { baseUrl: "http://127.0.0.1:11434/v1" },
169
+ * [{ role: "user", content: "你好" }],
170
+ * { stream: true },
171
+ * );
172
+ * for await (const { content, usage } of result) {
173
+ * if (content) {
174
+ * console.log("流式传输中:", content);
175
+ * } else if (usage) {
176
+ * console.log("对话结束,消耗:", usage);
177
+ * }
178
+ * }
179
+ */
180
+ declare function chatCompletions(model: ChatCompletions.Model, messages: ChatCompletions.Message[], extraBody: ChatCompletions.ExtraBody & {
181
+ stream: true;
182
+ }): Promise<AsyncGenerator<ChatCompletions.StreamChunk>>;
183
+ declare function chatCompletions(model: ChatCompletions.Model, messages: ChatCompletions.Message[], extraBody?: ChatCompletions.ExtraBody): Promise<ChatCompletions.Result>;
184
+ /**
185
+ * 辅助定义一个 chatCompletions 支持的模型配置
186
+ */
187
+ declare const defineModel: (config: ChatCompletions.Model) => ChatCompletions.Model;
188
+ //#endregion
189
+ //#region src/dom/log.d.ts
190
+ /**
191
+ * log 配置选项
192
+ */
193
+ interface LogOptions {
194
+ /**
195
+ * 是否显示时间
196
+ * @default true
197
+ */
198
+ time?: boolean;
199
+ /**
200
+ * 是否显示调用者文件名
201
+ * @default true
202
+ */
203
+ fileName?: boolean;
204
+ }
205
+ /**
206
+ * 带额外信息的 console.log
207
+ * @param message - 日志消息,支持单条消息或消息数组
208
+ * @param options - 配置选项
209
+ *
210
+ * @example
211
+ * log("调试信息"); // "[14:30:00] [index.ts:15] 调试信息"
212
+ * log("调试信息", { time: false }); // "[index.ts:15] 调试信息"
213
+ * log("调试信息", { fileName: false }); // "[14:30:00] 调试信息"
214
+ * log("调试信息", { time: false, fileName: false }); // "调试信息"
215
+ * log(["消息1", "消息2"]); // "[14:30:00] [index.ts:15] 消息1 消息2"
216
+ */
217
+ declare const log: (message: any | any[], options?: LogOptions) => void;
218
+ //#endregion
219
+ //#region src/function/loop-until.d.ts
220
+ /**
221
+ * 循环执行函数,直到符合停止条件
222
+ *
223
+ * @example
224
+ * // 循环请求大语言模型,直到其不再调用工具
225
+ * loopUntil(
226
+ * async () => {
227
+ * const completion = await chatCompletions();
228
+ * completion.tool_calls?.forEach(chooseAndHandleTool)
229
+ * return completion;
230
+ * },
231
+ * {
232
+ * shouldStop: (completion) => !completion.tool_calls,
233
+ * },
234
+ * ),
235
+ *
236
+ * @example
237
+ * // 不传递 shouldStop,执行 3 次后正常返回最后结果
238
+ * loopUntil(
239
+ * () => {
240
+ * return doSomething();
241
+ * },
242
+ * {
243
+ * maxRetries: 3,
244
+ * },
245
+ * ),
246
+ */
247
+ declare const loopUntil: <T>(fn: (count: number) => T | Promise<T>, options?: {
248
+ /**
249
+ * 最大循环次数
250
+ * @default 5
251
+ */
252
+ maxRetries?: number; /** 停止循环条件。如果未传递,则执行 maxRetries 次后退出并返回最后结果 */
253
+ shouldStop?: (result: T) => boolean;
254
+ }) => Promise<T>;
255
+ //#endregion
256
+ //#region src/hoc/with-cache.d.ts
257
+ type SetTtl = (seconds: number) => void;
258
+ /**
259
+ * 创建一个带缓存的高阶函数
260
+ *
261
+ * @template Args 被包装函数的参数类型数组
262
+ * @template Result 被包装函数的返回类型
263
+ *
264
+ * @param fn 需要被缓存的函数,参数里附带的 setTtl 方法用于根据具体情况改写过期时间
265
+ * @param ttlSeconds 以秒为单位的过期时间,-1 表示永不过期,默认 -1,会被回调函数里的 setTtl() 覆盖
266
+ *
267
+ * @returns 返回包装后的函数,以及缓存相关的额外方法
268
+ *
269
+ * @example
270
+ * // 异步函数示例
271
+ * const fetchData = withCache(async function (url: string) {
272
+ * const data = await fetch(url).then((res) => res.json());
273
+ * this.setTtl(data.expiresIn); // 根据实际情况调整过期时间
274
+ * return data;
275
+ * });
276
+ *
277
+ * await fetchData(urlA);
278
+ * await fetchData(urlA); // 使用缓存结果
279
+ * await fetchData(urlB);
280
+ * await fetchData(urlB); // 使用缓存结果
281
+ *
282
+ * fetchData.clear(); // 清除缓存
283
+ * await fetchData(urlA); // 重新请求
284
+ * await fetchData(urlB); // 重新请求
285
+ *
286
+ * // 缓存过期前
287
+ * await sleep();
288
+ * fetchData.updateTtl(180); // 更新 ttl 并为所有未过期的缓存续期
289
+ * await fetchData(urlA); // 使用缓存结果
290
+ * await fetchData(urlB); // 使用缓存结果
291
+ */
292
+ declare const withCache: <Args extends any[], Result>(fn: (this: {
293
+ setTtl: SetTtl;
294
+ }, ...args: Args) => Result, ttlSeconds?: number) => {
295
+ (...args: Args): Result;
296
+ clear(): void;
297
+ updateTtl(seconds: number): void;
298
+ };
299
+ //#endregion
300
+ //#region src/is/is-nil.d.ts
301
+ /**
302
+ * 检测传入的值是否为**空值**(null、undefined
303
+ *
304
+ * @example
305
+ * isNil(null); // true
306
+ * isNil(undefined); // true
307
+ * isNil(1); // false
308
+ */
309
+ declare const isNil: (value: any) => value is null | undefined;
310
+ //#endregion
311
+ //#region src/is/is-object.d.ts
312
+ /**
313
+ * 检测传入的值是否为**普通对象**
314
+ *
315
+ * @example
316
+ * const obj = { a: 1 };
317
+ * isObject(obj); // true
318
+ */
319
+ declare const isObject: (value: any) => value is Record<string, any>;
320
+ //#endregion
321
+ //#region src/is/is-primitive.d.ts
322
+ type Primitive = number | string | boolean | symbol | bigint | undefined | null;
323
+ /**
324
+ * 检测传入的值是否为**原始值**(number、string、boolean、symbol、bigint、undefined、null)
325
+ *
326
+ * @example
327
+ * isPrimitive(1); // true
328
+ * isPrimitive([]); // false
329
+ */
330
+ declare const isPrimitive: (value: any) => value is Primitive;
331
+ //#endregion
332
+ //#region src/network/fetcher.d.ts
333
+ type RequestInit = globalThis.RequestInit & {
334
+ /**
335
+ * searchParams 查询参数对象
336
+ */
337
+ params?: Record<string, any>;
338
+ /**
339
+ * 响应解析器,默认的解析方法为 response.json()
340
+ */
341
+ parser?: (response: Response) => Promise<any>;
342
+ };
343
+ /**
344
+ * 基于 Fetch API 的请求实例
345
+ * @param baseUrl 接口前缀
346
+ * @param baseOptions 应用于整个实例的请求体,后续请求都会带上
347
+ *
348
+ * @remarks
349
+ * 特性:
350
+ * - 支持在创建实例、发出请求时合并相同的请求体(后者覆盖前者)
351
+ * - 支持在 GET 的 params 请求体中传递对象
352
+ * - 支持在 POST、PUT 的 body 请求体中传递对象
353
+ * - 可选 to() 函数转换请求结果为 [Error, Response]
354
+ * - 可选 withCache() 函数缓存请求结果
355
+ *
356
+ * @example
357
+ * // 直接发请求
358
+ * const res = await fetcher().get<Blog>("https://nickyzj.run:3030/blogs/hello-world", {
359
+ * params: {
360
+ * page: 2,
361
+ * pageSize: 10,
362
+ * }
363
+ * });
364
+ *
365
+ * // 创建实例,发请求
366
+ * const api = fetcher("https://nickyzj.run:3030", {
367
+ * headers: {
368
+ * Authorization: "Bearer token"
369
+ * }
370
+ * });
371
+ * const res = await api.get<Blog>("/blogs/hello-world");
372
+ *
373
+ * // 安全返回请求结果,不抛异常
374
+ * const [error, data] = await to(api.get<Blog>("/blogs/hello-world"));
375
+ * if (error) {
376
+ * // ...
377
+ * }
378
+ * // ...
379
+ *
380
+ * // 缓存请求结果
381
+ * const getBlogs = withCache(api.get);
382
+ * await getBlogs("/blogs");
383
+ * await getBlogs("/blogs"); // 不发请求,使用缓存
384
+ */
385
+ declare const fetcher: (baseUrl?: string, baseOptions?: RequestInit) => {
386
+ get: <T>(url: string, options?: Omit<RequestInit, "method">) => Promise<T>;
387
+ post: <T>(url: string, body: any, options?: Omit<RequestInit, "method" | "body">) => Promise<T>;
388
+ put: <T>(url: string, body: any, options?: Omit<RequestInit, "method" | "body">) => Promise<T>;
389
+ delete: <T>(url: string, options?: Omit<RequestInit, "method" | "body">) => Promise<T>;
390
+ };
391
+ //#endregion
392
+ //#region src/network/get-real-url.d.ts
393
+ /** 从 url 响应头获取真实链接 */
394
+ declare const getRealURL: (originURL: string) => Promise<string>;
395
+ //#endregion
396
+ //#region src/network/image.d.ts
397
+ /**
398
+ * 图片压缩选项
399
+ */
400
+ type ImageCompressionOptions = {
401
+ /** 压缩比率,默认 0.92 */quality?: number;
402
+ /**
403
+ * 自定义压缩函数,用于覆盖默认压缩行为
404
+ * @param arrayBuffer 图片的 ArrayBuffer 数据
405
+ * @param mime 图片的 MIME 类型
406
+ * @param quality 压缩质量
407
+ * @returns 压缩后的 base64 字符串
408
+ */
409
+ compressor?: (arrayBuffer: ArrayBuffer, mime: string, quality: number) => Promise<string> | string;
410
+ /**
411
+ * 自定义 fetch 函数,用于使用自己封装的请求库读取图片
412
+ * 必须返回符合 Web 标准的 Response 对象
413
+ * @param url 图片地址
414
+ * @returns Promise<Response>
415
+ */
416
+ fetcher?: (url: string) => Promise<Response>;
417
+ };
418
+ /**
419
+ * 图片地址转 base64 数据
420
+ *
421
+ * @param imageUrl 图片地址
422
+ * @param options 可选配置
423
+ * @param options.quality 压缩比率,默认 0.92
424
+ * @param options.compressor 自定义压缩函数,用于覆盖默认压缩行为
425
+ *
426
+ * @example
427
+ * // 基本用法(浏览器自动使用 Canvas 压缩,Node.js 自动检测并使用 sharp)
428
+ * imageUrlToBase64("https://example.com/image.jpg");
429
+ *
430
+ * @example
431
+ * // 使用自定义 fetch 函数(如 axios 封装)
432
+ * imageUrlToBase64("https://example.com/image.jpg", {
433
+ * fetcher: async (url) => {
434
+ * // 使用 axios 或其他请求库,但必须返回 Response 对象
435
+ * const response = await axios.get(url, { responseType: 'arraybuffer' });
436
+ * return new Response(response.data, {
437
+ * status: response.status,
438
+ * statusText: response.statusText,
439
+ * headers: response.headers
440
+ * });
441
+ * }
442
+ * });
443
+ *
444
+ * @example
445
+ * // 使用自定义压缩函数覆盖默认行为
446
+ * imageUrlToBase64("https://example.com/image.jpg", {
447
+ * quality: 0.8,
448
+ * compressor: async (buffer, mime, quality) => {
449
+ * // 自定义压缩逻辑
450
+ * return `data:${mime};base64,...`;
451
+ * }
452
+ * });
453
+ */
454
+ declare const imageUrlToBase64: (imageUrl: string, options?: ImageCompressionOptions) => Promise<string>;
455
+ //#endregion
456
+ //#region src/network/to.d.ts
457
+ /**
458
+ * Go 语言风格的异步处理方式
459
+ * @param promise 一个能被 await 的异步函数
460
+ * @returns 如果成功,返回 [null, 异步函数结果],否则返回 [Error, undefined]
461
+ *
462
+ * @example
463
+ * const [error, response] = await to(fetcher().get<Blog>("/blogs/hello-world"));
464
+ */
465
+ declare const to: <T, E = Error>(promise: Promise<T>) => Promise<[null, T] | [E, undefined]>;
466
+ //#endregion
467
+ //#region src/number/random-int.d.ts
468
+ /**
469
+ * 在指定闭区间内生成随机整数
470
+ *
471
+ * @example
472
+ * randomInt(1, 10); // 1 <= x <= 10
473
+ */
474
+ declare const randomInt: (min: number, max: number) => number;
475
+ //#endregion
476
+ //#region src/object/map.d.ts
477
+ type DeepMapKeys<T> = T extends Array<infer U> ? Array<DeepMapKeys<U>> : T extends object ? {
478
+ [key: string]: DeepMapKeys<T[keyof T]>;
479
+ } : T;
480
+ /**
481
+ * 递归处理对象里的 key
482
+ *
483
+ * @remarks
484
+ * 无法完整推导出类型,只能做到有递归,key 全为 string,value 为同层级的所有类型的联合
485
+ *
486
+ * @template T 要转换的对象
487
+ *
488
+ * @example
489
+ * const obj = { a: { b: 1 } };
490
+ * const result = mapKeys(obj, (key) => key.toUpperCase());
491
+ * console.log(result); // { A: { B: 1 } }
492
+ */
493
+ declare const mapKeys: <T>(obj: T, getNewKey: (key: string) => string) => DeepMapKeys<T>;
494
+ type DeepMapValues<T, R> = T extends Array<infer U> ? Array<DeepMapValues<U, R>> : T extends object ? { [K in keyof T]: T[K] extends object ? DeepMapValues<T[K], R> : R } : R;
495
+ /**
496
+ * 递归处理对象里的 value
497
+ *
498
+ * @remarks
499
+ * 无法完整推导出类型,所有 value 最终都会变为 any
500
+ *
501
+ * @template T 要转换的对象
502
+ * @template R 转换后的值类型,为 any,无法进一步推导
503
+ *
504
+ * @example
505
+ * const obj = { a: 1, b: { c: 2 } };
506
+ * const result = mapValues(obj, (value, key) => isPrimitive(value) ? value + 1 : value);
507
+ * console.log(result); // { a: 2, b: { c: 3 } }
508
+ */
509
+ declare const mapValues: <T, R = any>(obj: T, getNewValue: (value: any, key: string | number) => R, options?: {
510
+ /** 过滤函数,返回 true 表示保留该字段 */filter?: (value: any, key: string | number) => boolean;
511
+ }) => DeepMapValues<T, R>;
512
+ //#endregion
513
+ //#region src/object/merge.d.ts
514
+ /**
515
+ * 深度合并两个对象,规则如下:
516
+ * 1. 原始值覆盖:如果两个值都是原始类型,则用后者覆盖;
517
+ * 2. 数组拼接:如果两个值都是数组,则拼接为大数组;
518
+ * 3. 对象递归合并:如果两个值都是对象,则进行递归深度合并;
519
+ *
520
+ * @template T 第一个对象
521
+ * @template U 第二个对象
522
+ * @param {T} obj1 要合并的第一个对象,相同字段会被 obj2 覆盖
523
+ * @param {U} obj2 要合并的第二个对象
524
+ */
525
+ declare const mergeObjects: <T extends Record<string, any>, U extends Record<string, any>>(obj1: T, obj2: U) => T & U;
526
+ //#endregion
527
+ //#region src/object/omit.d.ts
528
+ /**
529
+ * 从对象中排除指定的键,返回不包含这些键的新对象
530
+ *
531
+ * @typeParam T - 源对象的类型
532
+ * @typeParam K - 要排除的键,必须是源对象的键之一
533
+ *
534
+ * @param obj - 源对象
535
+ * @param keys - 要排除的键名数组
536
+ * @returns 不包含指定键的新对象
537
+ *
538
+ * @example
539
+ * const user = {
540
+ * id: 1,
541
+ * name: "Alice",
542
+ * age: 25,
543
+ * password: "secret"
544
+ * };
545
+ * // { id: 1, name: "Alice", age: 25 }
546
+ * const safeUser = omit(user, ["password"]);
547
+ */
548
+ declare const omit: <T extends Record<string, any>, K extends keyof T>(obj: T, keys: readonly K[]) => Omit<T, K>;
549
+ /**
550
+ * 从对象中排除满足条件的键值对,返回不包含这些键的新对象
551
+ *
552
+ * @typeParam T - 源对象的类型
553
+ *
554
+ * @param obj - 源对象
555
+ * @param shouldOmit - 判断函数,接收键和值,返回 `true` 则排除该键值对
556
+ * @returns 不包含满足条件的键值对的新对象
557
+ *
558
+ * @example
559
+ * const user = {
560
+ * id: 1,
561
+ * name: "Alice",
562
+ * age: 25,
563
+ * password: "secret"
564
+ * };
565
+ * // { name: "Alice", password: "secret" }
566
+ * const stringFields = omitBy(user, (key, value) => typeof value === "number");
567
+ */
568
+ declare const omitBy: <T extends Record<string, any>>(obj: T, shouldOmit: (key: keyof T, value: T[keyof T]) => boolean) => Partial<T>;
569
+ //#endregion
570
+ //#region src/object/pick.d.ts
571
+ /**
572
+ * 从对象中选取指定的键,返回仅包含这些键的新对象
573
+ *
574
+ * @typeParam T - 源对象的类型
575
+ * @typeParam K - 要选取的键,必须是源对象的键之一
576
+ *
577
+ * @param obj - 源对象
578
+ * @param keys - 要选取的键名数组
579
+ * @returns 仅包含指定键的新对象
580
+ *
581
+ * @example
582
+ * const user = {
583
+ * id: 1,
584
+ * name: "Alice",
585
+ * age: 25,
586
+ * password: "secret"
587
+ * };
588
+ * // { id: 1, name: "Alice", age: 25 }
589
+ * const safeUser = pick(user, ["id", "name", "age"]);
590
+ */
591
+ declare const pick: <T extends Record<string, any>, K extends keyof T>(obj: T, keys: readonly K[]) => Pick<T, K>;
592
+ /**
593
+ * 从对象中选取满足条件的键值对,返回仅包含这些键的新对象
594
+ *
595
+ * @typeParam T - 源对象的类型
596
+ *
597
+ * @param obj - 源对象
598
+ * @param shouldPick - 判断函数,返回 `true` 时保留该字段
599
+ * @returns 仅包含满足条件的键值对的新对象
600
+ *
601
+ * @example
602
+ * const user = {
603
+ * id: 1,
604
+ * name: "Alice",
605
+ * age: 25,
606
+ * password: "secret"
607
+ * };
608
+ * // { id: 1, age: 25 }
609
+ * const numericFields = pickBy(user, (key, value) => typeof value === "number");
610
+ */
611
+ declare const pickBy: <T extends Record<string, any>>(obj: T, shouldPick: (key: keyof T, value: T[keyof T]) => boolean) => Partial<T>;
612
+ //#endregion
613
+ //#region src/string/case.d.ts
614
+ type SnakeToCamel<S extends string> = S extends `${infer Before}_${infer After}` ? After extends `${infer First}${infer Rest}` ? `${Before}${Uppercase<First>}${SnakeToCamel<Rest>}` : Before : S;
615
+ /**
616
+ * 下划线命名法转为驼峰命名法
617
+ *
618
+ * @example
619
+ * snakeToCamel("user_name") // "userName"
620
+ */
621
+ declare const snakeToCamel: <S extends string>(str: S) => SnakeToCamel<S>;
622
+ type CamelToSnake<S extends string> = S extends `${infer First}${infer Rest}` ? Rest extends Uncapitalize<Rest> ? `${Lowercase<First>}${CamelToSnake<Rest>}` : `${Lowercase<First>}_${CamelToSnake<Rest>}` : Lowercase<S>;
623
+ /**
624
+ * 驼峰命名法转为下划线命名法
625
+ *
626
+ * @example
627
+ * camelToSnake("shouldComponentUpdate") // "should_component_update"
628
+ */
629
+ declare const camelToSnake: <S extends string>(str: S) => CamelToSnake<S>;
630
+ type Capitalize<S extends string> = S extends `${infer P1}${infer Rest}` ? P1 extends Capitalize<P1> ? S : `${Uppercase<P1>}${Rest}` : S;
631
+ /**
632
+ * 字符串首字母大写
633
+ *
634
+ * @example
635
+ * capitalize("hello") // "Hello"
636
+ */
637
+ declare const capitalize: <S extends string>(s: S) => Capitalize<S>;
638
+ type Decapitalize<S extends string> = S extends `${infer P1}${infer Rest}` ? P1 extends Lowercase<P1> ? P1 : `${Lowercase<P1>}${Rest}` : S;
639
+ /**
640
+ * 字符串首字母小写
641
+ *
642
+ * @example
643
+ * decapitalize("Hello") // "hello"
644
+ */
645
+ declare const decapitalize: <S extends string>(s: S) => Decapitalize<S>;
646
+ //#endregion
647
+ //#region src/string/compact.d.ts
648
+ /**
649
+ * 将字符串压缩为单行精简格式
650
+ *
651
+ * @example
652
+ * // "Hello\nworld"
653
+ * compactStr(`Hello,
654
+ *
655
+ * world
656
+ *
657
+ * !`);
658
+ *
659
+ * @example
660
+ * // "Hello...world"
661
+ * compactStr("Hello, beautiful world!", { maxLength: 15 });
662
+ */
663
+ declare const compactStr: (text?: string, options?: {
664
+ /**
665
+ * 最大保留长度,超过该长度使用 "..." 替代
666
+ @default Infinity
667
+ */
668
+ maxLength?: number;
669
+ /**
670
+ * 是否将换行符替换为字面量"\n"
671
+ * @default false
672
+ */
673
+ disableNewLineReplace?: boolean;
674
+ /**
675
+ * 是否合并连续的换行符/制表符为单个
676
+ * @default false
677
+ */
678
+ disableCollapse?: boolean;
679
+ }) => string;
680
+ //#endregion
681
+ //#region src/string/extract-error-message.d.ts
682
+ /** 从任意异常中提取类似 error.message 的可读文字 */
683
+ declare const extractErrorMessage: (error: unknown) => string;
684
+ //#endregion
685
+ //#region src/string/qs.d.ts
686
+ /**
687
+ * 针对 URL 查询字符串的解析和序列化
688
+ * @example
689
+ * qs.parse("?a=1&b=2") // { a: 1, b: 2 }
690
+ * qs.stringify({ a: 1, b: 2 }, { addQueryPrefix: true }) // "?a=1&b=2"
691
+ */
692
+ declare const qs: {
693
+ /** queryString -> queryParams */parse: (queryString: string) => Record<string, any>;
694
+ stringify: (params: Record<string, any>, options?: {
695
+ /**
696
+ * 是否在结果前添加“?”
697
+ * @default false
698
+ */
699
+ addQueryPrefix: boolean;
700
+ }) => string;
701
+ };
702
+ //#endregion
703
+ //#region src/time/debounce.d.ts
704
+ /**
705
+ * 防抖:在指定时间内只执行最后一次调用
706
+ * @param fn 要防抖的函数
707
+ * @param delay 延迟时间,默认 300ms
708
+ *
709
+ * @remarks
710
+ * 连续触发时,只有最后一次会执行。适合用于搜索框输入、窗口大小调整等场景。
711
+ * 例如:用户输入"hello"过程中,不会触发搜索,只有停下来时才执行。
712
+ *
713
+ * 防抖 vs 节流:
714
+ * - 防抖:等待触发停止后才执行(最后一次)
715
+ * - 节流:按固定节奏执行(每隔多久执行一次)
716
+ *
717
+ * @example
718
+ * const search = debounce((keyword: string) => {
719
+ * console.log('搜索:', keyword);
720
+ * });
721
+ * search('hello'); // 300ms 后执行
722
+ */
723
+ declare const debounce: <T extends (...args: any[]) => any>(fn: T, delay?: number) => (...args: Parameters<T>) => void;
724
+ //#endregion
725
+ //#region src/time/lock-queue.d.ts
726
+ /**
727
+ * 排队锁
728
+ *
729
+ * @remarks
730
+ * 使用场景如:同时给大模型发送多条消息,使其依次回复
731
+ *
732
+ * @example
733
+ * const queue = new LockQueue();
734
+ * const messages = [];
735
+ *
736
+ * const chatCompletions = async () => {
737
+ * // 等待前一个队列释放
738
+ * const release = await queue.waitInQueue();
739
+ *
740
+ * const message = await requestLLM();
741
+ * messages.push(message);
742
+ * sendMessage(message);
743
+ *
744
+ * // 释放队列
745
+ * release();
746
+ * };
747
+ *
748
+ * chatCompletions();
749
+ * chatCompletions();
750
+ * chatCompletions();
751
+ */
752
+ declare class LockQueue {
753
+ queue: Promise<any>;
754
+ constructor();
755
+ waitInQueue(): Promise<(value?: any) => void>;
756
+ }
757
+ //#endregion
758
+ //#region src/time/sleep.d.ts
759
+ /**
760
+ * 延迟一段时间再执行后续代码
761
+ * @param time 延迟时间,默认 150ms
762
+ * @example
763
+ * await sleep(1000); // 等待 1 秒执行后续代码
764
+ */
765
+ declare const sleep: (time?: number) => Promise<unknown>;
766
+ //#endregion
767
+ //#region src/time/throttle.d.ts
768
+ /**
769
+ * 节流函数 - 在指定时间间隔内最多执行一次调用
770
+ * @param fn 要节流的函数
771
+ * @param delay 间隔时间,默认 300ms
772
+ *
773
+ * @remarks
774
+ * 节流:连续触发时,按照固定间隔执行。适合用于滚动、拖拽等高频触发场景。
775
+ * 例如:滚动页面时,每300ms最多执行一次回调,而不是每次滚动都执行。
776
+ *
777
+ * 防抖 vs 节流:
778
+ * - 防抖:等待触发停止后才执行(最后一次)
779
+ * - 节流:按固定节奏执行(每隔多久执行一次)
780
+ *
781
+ * @example
782
+ * const handleScroll = throttle(() => {
783
+ * console.log('滚动位置:', window.scrollY);
784
+ * }, 200);
785
+ * window.addEventListener('scroll', handleScroll);
786
+ */
787
+ declare const throttle: <T extends (...args: any[]) => any>(fn: T, delay?: number) => (this: any, ...args: Parameters<T>) => void;
788
+ //#endregion
785
789
  export { CamelToSnake, Capitalize, type ChatCompletions, Decapitalize, DeepMapKeys, DeepMapValues, ImageCompressionOptions, LockQueue, LogOptions, Primitive, RequestInit, SetTtl, SnakeToCamel, camelToSnake, capitalize, chatCompletions, compactStr, debounce, decapitalize, defineModel, extractErrorMessage, fetcher, getRealURL, imageUrlToBase64, isNil, isObject, isPrimitive, log, loopUntil, mapKeys, mapValues, mergeObjects, omit, omitBy, pick, pickBy, qs, randomInt, sleep, snakeToCamel, throttle, to, withCache };