@maiyunnet/kebab 8.0.6 → 8.2.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/index.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  * --- 本文件用来定义每个目录实体地址的常量 ---
6
6
  */
7
7
  /** --- 当前系统版本号 --- */
8
- export declare const VER = "8.0.6";
8
+ export declare const VER = "8.2.0";
9
9
  /** --- 框架根目录,以 / 结尾 --- */
10
10
  export declare const ROOT_PATH: string;
11
11
  export declare const LIB_PATH: string;
package/index.js CHANGED
@@ -6,7 +6,7 @@
6
6
  * --- 本文件用来定义每个目录实体地址的常量 ---
7
7
  */
8
8
  /** --- 当前系统版本号 --- */
9
- export const VER = '8.0.6';
9
+ export const VER = '8.2.0';
10
10
  // --- 服务端用的路径 ---
11
11
  const imu = decodeURIComponent(import.meta.url).replace('file://', '').replace(/^\/(\w:)/, '$1');
12
12
  /** --- /xxx/xxx --- */
package/lib/ai.d.ts CHANGED
@@ -22,7 +22,15 @@ export declare enum ESERVICE {
22
22
  /** --- 微软 Azure 2 --- */
23
23
  'AZURE2' = 3,
24
24
  /** --- 微软 Azure 3 --- */
25
- 'AZURE3' = 4
25
+ 'AZURE3' = 4,
26
+ /** --- Gemini --- */
27
+ 'GEMINI' = 5,
28
+ /** --- Grok --- */
29
+ 'GROK' = 6,
30
+ /** --- 火山引擎中国大陆区 --- */
31
+ 'VOLCN' = 7,
32
+ /** --- 火山引擎国际区 --- */
33
+ 'VOLAS' = 8
26
34
  }
27
35
  /** --- 选项 --- */
28
36
  export interface IOptions {
@@ -36,16 +44,97 @@ export interface IOptions {
36
44
  'fetch'?: (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
37
45
  }
38
46
  export declare class Ai {
39
- /** --- openai 原生对象,建议只读 --- */
47
+ /** --- openai 原生对象 --- */
40
48
  readonly link: openai.OpenAI;
49
+ private readonly _fetch;
50
+ private readonly _service;
51
+ private readonly _endpoint;
41
52
  private readonly _ctr?;
42
53
  constructor(ctrEtc: sCtr.Ctr | kebab.IConfigAi, opt: IOptions);
54
+ /** --- 获取当前服务商 --- */
55
+ get service(): ESERVICE;
43
56
  /** --- 创建非流式对话 --- */
44
57
  chat(body: openai.default.Chat.Completions.ChatCompletionCreateParamsNonStreaming): Promise<openai.APIPromise<openai.default.Chat.ChatCompletion> | false>;
45
58
  /** --- 创建流式对话 --- */
46
59
  chat(body: openai.default.Chat.Completions.ChatCompletionCreateParamsStreaming): Promise<openai.APIPromise<streaming.Stream<openai.default.Chat.ChatCompletionChunk>> | false>;
47
60
  /** --- 创建向量 --- */
48
61
  embedding(body: openai.default.EmbeddingCreateParams): Promise<openai.APIPromise<openai.default.CreateEmbeddingResponse> | false>;
62
+ /** --- 生成图像,不支持 GEMINI、GROK 服务商 --- */
63
+ image(opt: {
64
+ 'model': string;
65
+ /** --- 提示词 --- */
66
+ 'prompt': string;
67
+ /** --- 参考图,请注意模型是否支持,以及是否支持多张,仅支持 ALICN、ALIAS、VOLCN、VOLAS 服务商 --- */
68
+ 'imgs'?: string[];
69
+ /** --- 模型是否自动优化提示词,默认为 false,但有些服务商可能无效 --- */
70
+ 'extend'?: boolean;
71
+ /** --- 负面提示词,用于引导模型避免生成某些内容 --- */
72
+ 'negative'?: string;
73
+ /** --- 长 x 宽,不同模型要求不同,如 [1664, 928] --- */
74
+ 'size': number[];
75
+ 'n'?: number;
76
+ /** --- 随机种子,默认为随机 --- */
77
+ 'seed'?: number;
78
+ }): Promise<{
79
+ /** --- 图像列表 --- */
80
+ 'list': Array<{
81
+ 'url': string;
82
+ /** --- 优化后的提示词 --- */
83
+ 'text': string;
84
+ }>;
85
+ /** --- 随机种子 --- */
86
+ 'seed': number;
87
+ /** --- 请求编号 --- */
88
+ 'request': string;
89
+ } | false>;
90
+ /** --- 异步生成视频,仅支持 ALICN、ALIAS --- */
91
+ video(opt: {
92
+ 'model': string;
93
+ /** --- 提示词,参考类可用 [I1] 指代图片,如 `[I1] 看向 [I2]` --- */
94
+ 'prompt': string;
95
+ /** --- 文本(默认)、首尾帧、参考图 --- */
96
+ 'mode'?: 'text' | 'frame' | 'ref';
97
+ 'imgs'?: string[];
98
+ /** --- 负面提示词,用于引导模型避免生成某些内容 --- */
99
+ 'negative'?: string;
100
+ /** --- 模型是否自动优化提示词,默认为 false,但有些服务商可能无效 --- */
101
+ 'extend'?: boolean;
102
+ /** --- 分辨率,默认 720p --- */
103
+ 'resolution'?: '480p' | '720p' | '1080p';
104
+ /** --- 比例,默认 16:9 --- */
105
+ 'ratio'?: '16:9' | '9:16' | '4:3' | '3:4' | '1:1' | '21:9';
106
+ /** --- 视频时长,默认 2 秒 --- */
107
+ 'duration'?: number;
108
+ /** --- 镜头,默认单镜头 single --- */
109
+ 'shot'?: 'single' | 'multi';
110
+ /** --- 视频声音,默认 false,true 代表自动配音,字符串代表自定义音频网址 --- */
111
+ 'audio'?: boolean | string;
112
+ /** --- 随机种子,默认为随机,范围 0 - 2147483647 --- */
113
+ 'seed'?: number;
114
+ }): Promise<{
115
+ 'task': string;
116
+ 'status': 'PENDING' | 'RUNNING' | 'SUCCEEDED' | 'FAILED' | 'CANCELED' | 'UNKNOWN';
117
+ 'seed': number;
118
+ 'request': string;
119
+ } | false>;
120
+ /** --- 轮询任务 --- */
121
+ poll(opt: {
122
+ 'type': 'video';
123
+ 'task': string;
124
+ }): Promise<{
125
+ 'task': string;
126
+ 'status': 'PENDING' | 'RUNNING' | 'SUCCEEDED' | 'FAILED' | 'CANCELED' | 'UNKNOWN';
127
+ /** --- 任务提交时间 --- */
128
+ 'add'?: number;
129
+ /** --- 任务开始时间 --- */
130
+ 'start'?: number;
131
+ /** --- 任务结束时间 --- */
132
+ 'end'?: number;
133
+ /** --- 文件地址 --- */
134
+ 'url'?: string;
135
+ /** --- 错误信息,成功时不返回 --- */
136
+ 'error'?: string;
137
+ } | false>;
49
138
  }
50
139
  /**
51
140
  * --- 创建一个 AI 对象 ---
package/lib/ai.js CHANGED
@@ -5,6 +5,7 @@
5
5
  */
6
6
  import * as openai from 'openai';
7
7
  import * as lCore from '#kebab/lib/core.js';
8
+ import * as lText from '#kebab/lib/text.js';
8
9
  import * as sCtr from '#kebab/sys/ctr.js';
9
10
  /**
10
11
  * --- 参考:https://help.aliyun.com/zh/model-studio/what-is-model-studio ---
@@ -23,12 +24,23 @@ export var ESERVICE;
23
24
  ESERVICE[ESERVICE["AZURE2"] = 3] = "AZURE2";
24
25
  /** --- 微软 Azure 3 --- */
25
26
  ESERVICE[ESERVICE["AZURE3"] = 4] = "AZURE3";
27
+ /** --- Gemini --- */
28
+ ESERVICE[ESERVICE["GEMINI"] = 5] = "GEMINI";
29
+ /** --- Grok --- */
30
+ ESERVICE[ESERVICE["GROK"] = 6] = "GROK";
31
+ /** --- 火山引擎中国大陆区 --- */
32
+ ESERVICE[ESERVICE["VOLCN"] = 7] = "VOLCN";
33
+ /** --- 火山引擎国际区 --- */
34
+ ESERVICE[ESERVICE["VOLAS"] = 8] = "VOLAS";
26
35
  })(ESERVICE || (ESERVICE = {}));
27
36
  /** --- openai 的连接对象 --- */
28
37
  const links = [];
29
38
  export class Ai {
30
- /** --- openai 原生对象,建议只读 --- */
39
+ /** --- openai 原生对象 --- */
31
40
  link;
41
+ _fetch;
42
+ _service;
43
+ _endpoint;
32
44
  _ctr;
33
45
  constructor(ctrEtc, opt) {
34
46
  let configAi = null;
@@ -41,6 +53,7 @@ export class Ai {
41
53
  configAi = ctrEtc;
42
54
  }
43
55
  const secretKey = opt.secretKey ?? configAi.skey ?? '';
56
+ const token = `${opt.service}-${secretKey}`;
44
57
  let endpoint;
45
58
  switch (opt.service) {
46
59
  case ESERVICE.ALICN: {
@@ -59,16 +72,32 @@ export class Ai {
59
72
  endpoint = opt.endpoint ?? configAi.endpoint ?? '';
60
73
  break;
61
74
  }
62
- case ESERVICE.AZURE3: {
63
- endpoint = opt.endpoint ?? configAi.endpoint ?? '';
75
+ case ESERVICE.GEMINI: {
76
+ endpoint = opt.endpoint ?? `https://generativelanguage.googleapis.com/v1beta/openai/`;
77
+ break;
78
+ }
79
+ case ESERVICE.GROK: {
80
+ endpoint = opt.endpoint ?? `https://api.x.ai/v1`;
81
+ break;
82
+ }
83
+ case ESERVICE.VOLCN: {
84
+ endpoint = opt.endpoint ?? `https://ark.cn-beijing.volces.com/api/v3`;
85
+ break;
86
+ }
87
+ case ESERVICE.VOLAS: {
88
+ endpoint = opt.endpoint ?? `https://ark.ap-southeast.bytepluses.com/api/v3`;
64
89
  break;
65
90
  }
66
91
  default: {
67
- endpoint = undefined;
92
+ // --- ESERVICE.AZURE3 ---
93
+ endpoint = opt.endpoint ?? configAi.endpoint ?? '';
68
94
  }
69
95
  }
70
- const token = `${opt.service}-${secretKey}`;
71
- const link = links.find((item) => item.token === token);
96
+ this._fetch = opt.fetch ?? fetch;
97
+ this._service = opt.service;
98
+ this._endpoint = endpoint;
99
+ // --- 处理连接 ---
100
+ const link = links.find(item => item.token === token);
72
101
  if (link) {
73
102
  this.link = link.link;
74
103
  return;
@@ -83,6 +112,10 @@ export class Ai {
83
112
  'link': this.link,
84
113
  });
85
114
  }
115
+ /** --- 获取当前服务商 --- */
116
+ get service() {
117
+ return this._service;
118
+ }
86
119
  /** --- 创建对话 --- */
87
120
  async chat(body) {
88
121
  try {
@@ -105,6 +138,327 @@ export class Ai {
105
138
  return false;
106
139
  }
107
140
  }
141
+ /** --- 生成图像,不支持 GEMINI、GROK 服务商 --- */
142
+ async image(opt) {
143
+ const seed = opt.seed ?? lCore.rand(0, 2147483647);
144
+ switch (this._service) {
145
+ case ESERVICE.ALICN:
146
+ case ESERVICE.ALIAS: {
147
+ try {
148
+ const res = await this._fetch(`https://dashscope${this._service === ESERVICE.ALIAS ? '-intl' : ''}.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation`, {
149
+ 'method': 'POST',
150
+ 'headers': {
151
+ 'authorization': `Bearer ${this.link.apiKey}`,
152
+ 'content-type': 'application/json',
153
+ },
154
+ 'body': lText.stringifyJson({
155
+ 'model': opt.model,
156
+ 'input': {
157
+ 'messages': [
158
+ {
159
+ 'role': 'user',
160
+ 'content': [
161
+ ...(opt.imgs?.map(url => ({
162
+ 'image': url,
163
+ })) ?? []),
164
+ {
165
+ 'text': opt.prompt,
166
+ }
167
+ ]
168
+ }
169
+ ]
170
+ },
171
+ 'parameters': {
172
+ 'negative_prompt': opt.negative ?? ' ',
173
+ 'prompt_extend': opt.extend ?? false,
174
+ 'watermark': false,
175
+ 'size': `${opt.size[0]}*${opt.size[1]}`,
176
+ 'n': opt.n ?? 1,
177
+ 'seed': seed,
178
+ },
179
+ }),
180
+ });
181
+ const json = await res.json();
182
+ if (!json.output?.choices?.[0]) {
183
+ lCore.debug('[AI][IMAGE]', json);
184
+ lCore.log(this._ctr ?? {}, `[AI][IMAGE] ${lText.stringifyJson(json)}`, '-error');
185
+ return false;
186
+ }
187
+ return {
188
+ 'list': json.output.choices[0].message.content.filter((item) => item.image).map((item) => {
189
+ const content = json.output.choices[0].message.content;
190
+ const itemIndex = content.indexOf(item);
191
+ return {
192
+ 'url': item.image,
193
+ 'text': content[itemIndex + 1]?.text ?? '',
194
+ };
195
+ }),
196
+ 'seed': seed,
197
+ 'request': json.request_id,
198
+ };
199
+ }
200
+ catch (e) {
201
+ lCore.debug('[AI][IMAGE]', e);
202
+ lCore.log(this._ctr ?? {}, `[AI][IMAGE] ${e.message}`, '-error');
203
+ return false;
204
+ }
205
+ }
206
+ case ESERVICE.AZURE:
207
+ case ESERVICE.AZURE2:
208
+ case ESERVICE.AZURE3: {
209
+ try {
210
+ const json = await this.link.images.generate({
211
+ 'model': opt.model,
212
+ 'prompt': opt.prompt,
213
+ 'size': `${opt.size[0]}x${opt.size[1]}`,
214
+ 'n': opt.n ?? 1,
215
+ });
216
+ if (!json.data?.[0]) {
217
+ lCore.debug('[AI][IMAGE]', json);
218
+ lCore.log(this._ctr ?? {}, `[AI][IMAGE] ${lText.stringifyJson(json)}`, '-error');
219
+ return false;
220
+ }
221
+ return {
222
+ 'list': json.data.map((item) => ({
223
+ 'url': item.url ?? item.b64_json,
224
+ 'text': item.revised_prompt ?? opt.prompt,
225
+ })),
226
+ 'seed': seed,
227
+ 'request': json.created.toString(),
228
+ };
229
+ }
230
+ catch (e) {
231
+ lCore.debug('[AI][IMAGE]', e);
232
+ lCore.log(this._ctr ?? {}, `[AI][IMAGE] ${e.message}`, '-error');
233
+ return false;
234
+ }
235
+ }
236
+ case ESERVICE.GEMINI: {
237
+ return false;
238
+ }
239
+ case ESERVICE.GROK: {
240
+ return false;
241
+ }
242
+ case ESERVICE.VOLCN:
243
+ case ESERVICE.VOLAS: {
244
+ try {
245
+ const res = await this._fetch(`${this._endpoint}/images/generations`, {
246
+ 'method': 'POST',
247
+ 'headers': {
248
+ 'authorization': `Bearer ${this.link.apiKey}`,
249
+ 'content-type': 'application/json',
250
+ },
251
+ 'body': lText.stringifyJson({
252
+ 'model': opt.model,
253
+ 'prompt': opt.prompt,
254
+ 'watermark': false,
255
+ 'size': `${opt.size[0]}x${opt.size[1]}`,
256
+ 'seed': seed,
257
+ ...(opt.n && opt.n > 1 ? {
258
+ 'sequential_image_generation': 'auto',
259
+ 'sequential_image_generation_options': {
260
+ 'max_images': 4,
261
+ },
262
+ } : {
263
+ 'sequential_image_generation': 'disabled',
264
+ }),
265
+ ...(opt.imgs?.length ? {
266
+ 'image': opt.imgs.length === 1 ? opt.imgs[0] : opt.imgs,
267
+ } : {}),
268
+ }),
269
+ });
270
+ const json = await res.json();
271
+ if (!json.data?.[0]) {
272
+ lCore.debug('[AI][IMAGE]', json);
273
+ lCore.log(this._ctr ?? {}, `[AI][IMAGE] ${lText.stringifyJson(json)}`, '-error');
274
+ return false;
275
+ }
276
+ return {
277
+ 'list': json.data.map((item) => ({
278
+ 'url': item.url,
279
+ 'text': opt.prompt,
280
+ })),
281
+ 'seed': seed,
282
+ 'request': json.created.toString(),
283
+ };
284
+ }
285
+ catch (e) {
286
+ lCore.debug('[AI][IMAGE]', e);
287
+ lCore.log(this._ctr ?? {}, `[AI][IMAGE] ${e.message}`, '-error');
288
+ return false;
289
+ }
290
+ }
291
+ }
292
+ }
293
+ /** --- 异步生成视频,仅支持 ALICN、ALIAS --- */
294
+ async video(opt) {
295
+ if (this._service !== ESERVICE.ALICN && this._service !== ESERVICE.ALIAS) {
296
+ return false;
297
+ }
298
+ const mode = opt.mode ?? 'text';
299
+ const imgs = opt.imgs ?? [];
300
+ const resolution = opt.resolution ?? '720p';
301
+ const ratio = opt.ratio ?? '16:9';
302
+ const duration = opt.duration ?? 2;
303
+ const shot = opt.shot ?? 'single';
304
+ const audio = opt.audio ?? false;
305
+ const seed = opt.seed ?? lCore.rand(0, 2147483647);
306
+ const extend = opt.extend ?? false;
307
+ /** --- x*x --- */
308
+ let size = '';
309
+ if (resolution === '480p') {
310
+ // --- 不支持 ---
311
+ return false;
312
+ }
313
+ else if (resolution === '720p') {
314
+ switch (ratio) {
315
+ case '21:9': {
316
+ // --- 不支持 ---
317
+ return false;
318
+ }
319
+ case '16:9': {
320
+ size = '1280*720';
321
+ break;
322
+ }
323
+ case '9:16': {
324
+ size = '720*1280';
325
+ break;
326
+ }
327
+ case '4:3': {
328
+ size = '1088*832';
329
+ break;
330
+ }
331
+ case '3:4': {
332
+ size = '832*1088';
333
+ break;
334
+ }
335
+ default: {
336
+ // --- 1:1 ---
337
+ size = '960*960';
338
+ }
339
+ }
340
+ }
341
+ else {
342
+ // --- 1080p ---
343
+ switch (ratio) {
344
+ case '21:9': {
345
+ // --- 不支持 ---
346
+ return false;
347
+ }
348
+ case '16:9': {
349
+ size = '1920*1080';
350
+ break;
351
+ }
352
+ case '9:16': {
353
+ size = '1080*1920';
354
+ break;
355
+ }
356
+ case '4:3': {
357
+ size = '1632*1248';
358
+ break;
359
+ }
360
+ case '3:4': {
361
+ size = '1248*1632';
362
+ break;
363
+ }
364
+ default: {
365
+ // --- 1:1 ---
366
+ size = '1440*1440';
367
+ }
368
+ }
369
+ }
370
+ try {
371
+ const res = await this._fetch(`https://dashscope${this._service === ESERVICE.ALIAS ? '-intl' : ''}.aliyuncs.com/api/v1/services/aigc/video-generation/video-synthesis`, {
372
+ 'method': 'POST',
373
+ 'headers': {
374
+ 'authorization': `Bearer ${this.link.apiKey}`,
375
+ 'content-type': 'application/json',
376
+ 'X-DashScope-Async': 'enable',
377
+ },
378
+ 'body': lText.stringifyJson({
379
+ 'model': opt.model,
380
+ 'input': {
381
+ 'prompt': opt.prompt.replace(/\[I(\d+)\]/g, 'Character$1'),
382
+ ...(typeof audio === 'string' ? {
383
+ 'audio_url': audio,
384
+ } : {})
385
+ },
386
+ 'parameters': {
387
+ 'negative_prompt': opt.negative ?? ' ',
388
+ 'watermark': false,
389
+ 'size': size,
390
+ 'seed': seed,
391
+ 'audio': audio ? true : false,
392
+ 'duration': duration,
393
+ 'shot_type': shot,
394
+ 'prompt_extend': extend,
395
+ ...((mode !== 'text') && (mode === 'frame' ? (imgs.length > 1 ? {
396
+ // --- 首尾帧 ---
397
+ 'first_frame_url': imgs[0],
398
+ 'last_frame_url': imgs[1],
399
+ } : {
400
+ // --- 首帧 ---
401
+ 'img_url': imgs[0],
402
+ }) : {
403
+ 'reference_urls': imgs,
404
+ })),
405
+ },
406
+ }),
407
+ });
408
+ const json = await res.json();
409
+ if (!json.output?.task_id) {
410
+ lCore.debug('[AI][VIDEO]', json);
411
+ lCore.log(this._ctr ?? {}, `[AI][VIDEO] ${lText.stringifyJson(json)}`, '-error');
412
+ return false;
413
+ }
414
+ const task = json.output.task_id;
415
+ return {
416
+ 'task': task,
417
+ 'status': json.output.task_status,
418
+ 'seed': seed,
419
+ 'request': json.request_id,
420
+ };
421
+ }
422
+ catch (e) {
423
+ lCore.debug('[AI][VIDEO]', e);
424
+ lCore.log(this._ctr ?? {}, `[AI][VIDEO] ${e.message}`, '-error');
425
+ return false;
426
+ }
427
+ }
428
+ /** --- 轮询任务 --- */
429
+ async poll(opt) {
430
+ if (this._service !== ESERVICE.ALICN && this._service !== ESERVICE.ALIAS) {
431
+ return false;
432
+ }
433
+ try {
434
+ const res = await this._fetch(`https://dashscope${this._service === ESERVICE.ALIAS ? '-intl' : ''}.aliyuncs.com/api/v1/tasks/${opt.task}`, {
435
+ 'method': 'GET',
436
+ 'headers': {
437
+ 'authorization': `Bearer ${this.link.apiKey}`,
438
+ },
439
+ });
440
+ const json = await res.json();
441
+ if (!json.output?.task_status) {
442
+ lCore.debug('[AI][POLL]', json);
443
+ lCore.log(this._ctr ?? {}, `[AI][POLL] ${lText.stringifyJson(json)}`, '-error');
444
+ return false;
445
+ }
446
+ return {
447
+ 'task': json.output.task_id,
448
+ 'status': json.output.task_status,
449
+ 'add': json.output.submit_time,
450
+ 'start': json.output.scheduled_time,
451
+ 'end': json.output.end_time,
452
+ 'url': json.output.video_url,
453
+ 'error': json.output.message ? `(${json.output.code})${json.output.message}` : undefined,
454
+ };
455
+ }
456
+ catch (e) {
457
+ lCore.debug('[AI][POLL]', e);
458
+ lCore.log(this._ctr ?? {}, `[AI][POLL] ${e.message}`, '-error');
459
+ return false;
460
+ }
461
+ }
108
462
  }
109
463
  /**
110
464
  * --- 创建一个 AI 对象 ---
package/lib/net.js CHANGED
@@ -452,12 +452,25 @@ async function buildCookieObject(cookie, setCookies, uri) {
452
452
  for (let index = 0; index < list.length; ++index) {
453
453
  const item = list[index];
454
454
  const arr = item.split('=');
455
+ /** --- 提取 key 并修整 --- */
455
456
  const key = arr[0].trim();
456
- const val = arr[1] ?? '';
457
+ if (key === '') {
458
+ continue;
459
+ }
460
+ /** --- 提取 value --- */
461
+ let val = '';
462
+ if (arr.length > 1) {
463
+ val = item.slice(item.indexOf('=') + 1).trim();
464
+ }
457
465
  if (index === 0) {
458
466
  // --- 用户定义的信息 ---
459
467
  cookieTmp['name'] = key;
460
- cookieTmp['value'] = decodeURIComponent(val);
468
+ try {
469
+ cookieTmp['value'] = decodeURIComponent(val);
470
+ }
471
+ catch {
472
+ cookieTmp['value'] = val;
473
+ }
461
474
  }
462
475
  else {
463
476
  // --- cookie 配置信息,可转小写方便读取 ---
@@ -507,15 +520,26 @@ async function buildCookieObject(cookie, setCookies, uri) {
507
520
  }
508
521
  }
509
522
  const cookieKey = cookieTmp['name'] + '-' + domainN;
510
- if (cookieTmp['max-age'] && (Number(cookieTmp['max-age']) <= 0)) {
511
- if (cookie[cookieKey]) {
512
- delete cookie[cookieKey];
513
- continue;
523
+ let exp = -1992199400;
524
+ if (cookieTmp['max-age'] !== undefined) {
525
+ const maxAge = Number(cookieTmp['max-age']);
526
+ if (!(isNaN(maxAge))) {
527
+ if (maxAge <= 0) {
528
+ delete cookie[cookieKey];
529
+ continue;
530
+ }
531
+ exp = tim + maxAge;
514
532
  }
515
533
  }
516
- let exp = -1992199400;
517
- if (cookieTmp['max-age']) {
518
- exp = tim + Number(cookieTmp['max-age']);
534
+ if ((exp === -1992199400) && cookieTmp['expires']) {
535
+ const expires = lTime.stamp(cookieTmp['expires']);
536
+ if (!(isNaN(expires))) {
537
+ if (expires <= tim) {
538
+ delete cookie[cookieKey];
539
+ continue;
540
+ }
541
+ exp = expires;
542
+ }
519
543
  }
520
544
  // --- path ---
521
545
  let path = cookieTmp['path'] ?? '';
package/lib/session.d.ts CHANGED
@@ -10,6 +10,7 @@ export interface IOptions {
10
10
  'name'?: string;
11
11
  'ttl'?: number;
12
12
  'ssl'?: boolean;
13
+ 'domain'?: string;
13
14
  'sqlPre'?: string;
14
15
  }
15
16
  export declare class Session {
package/lib/session.js CHANGED
@@ -155,7 +155,8 @@ export class Session {
155
155
  }
156
156
  lCore.setCookie(ctr, this._name, this._token, {
157
157
  'ttl': this._ttl,
158
- 'ssl': ssl
158
+ 'domain': opt.domain,
159
+ 'ssl': ssl,
159
160
  });
160
161
  return true;
161
162
  }
package/lib/time.js CHANGED
@@ -105,6 +105,12 @@ export function stamp(date, zone) {
105
105
  return Math.floor(date.getTime() / 1000);
106
106
  }
107
107
  if (zone === null || zone === undefined) {
108
+ /** --- 如果不传 zone,则尝试由 Date 自行解析(能自动识别字符串内的时区) --- */
109
+ const t = (new Date(date)).getTime();
110
+ if (!isNaN(t)) {
111
+ return Math.floor(t / 1000);
112
+ }
113
+ /** --- 解析不到的情况下走系统默认时区 --- */
108
114
  zone = -(new Date()).getTimezoneOffset();
109
115
  }
110
116
  else if (zone instanceof sCtr.Ctr) {