@zhin.js/plugin-60s 3.0.4 → 3.0.5
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/lib/api.js +17 -3
- package/lib/api.js.map +1 -1
- package/lib/runtime-deps.js +22 -0
- package/lib/runtime-deps.js.map +1 -0
- package/package.json +6 -6
- package/plugin.ts +5 -4
- package/src/api.ts +19 -3
- package/src/runtime-deps.ts +26 -0
package/lib/api.js
CHANGED
|
@@ -1,13 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 60s API 共享模块 — 供 *.tool.md handler 使用
|
|
3
3
|
*/
|
|
4
|
-
|
|
4
|
+
import { resolveApiBase } from './runtime-deps.js';
|
|
5
5
|
export async function fetchApi(endpoint, params) {
|
|
6
|
-
const url = new URL(`${
|
|
6
|
+
const url = new URL(`${resolveApiBase()}/v2${endpoint}`);
|
|
7
7
|
if (params) {
|
|
8
8
|
Object.entries(params).forEach(([k, v]) => url.searchParams.set(k, v));
|
|
9
9
|
}
|
|
10
|
-
|
|
10
|
+
let res;
|
|
11
|
+
try {
|
|
12
|
+
res = await fetch(url.toString(), { signal: AbortSignal.timeout(30_000) });
|
|
13
|
+
}
|
|
14
|
+
catch (e) {
|
|
15
|
+
const err = e;
|
|
16
|
+
throw new Error(err.name === 'TimeoutError' ? '请求超时(30s)' : `请求失败: ${err.message}`, { cause: e });
|
|
17
|
+
}
|
|
18
|
+
if (!res.ok) {
|
|
19
|
+
throw new Error(`API 请求失败: ${res.status} ${res.statusText}`);
|
|
20
|
+
}
|
|
21
|
+
const contentType = res.headers.get('content-type') ?? '';
|
|
22
|
+
if (!contentType.includes('application/json')) {
|
|
23
|
+
throw new Error(`API 返回非 JSON 响应 (content-type: ${contentType || 'unknown'})`);
|
|
24
|
+
}
|
|
11
25
|
const data = (await res.json());
|
|
12
26
|
if (data.error)
|
|
13
27
|
throw new Error(data.error);
|
package/lib/api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 60s apiBase 运行时注入 — plugin setup 注册 getter,fetchApi 每次调用时求值。
|
|
3
|
+
* 参考 lottery 的 registerLotteryAgentDeps:registration 模式,卸载时反注册,无 process.env 残留。
|
|
4
|
+
*/
|
|
5
|
+
export const DEFAULT_API_BASE = 'https://60s.viki.moe';
|
|
6
|
+
const registrations = [];
|
|
7
|
+
/** Generation-owned apiBase binding used by Plugin Runtime setup(). Returns unregister. */
|
|
8
|
+
export function registerSixtySApiBase(getter) {
|
|
9
|
+
const registration = Object.freeze({ value: getter });
|
|
10
|
+
registrations.push(registration);
|
|
11
|
+
return () => {
|
|
12
|
+
const index = registrations.lastIndexOf(registration);
|
|
13
|
+
if (index >= 0)
|
|
14
|
+
registrations.splice(index, 1);
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/** Resolve the apiBase at call time so config patches take effect without reload. */
|
|
18
|
+
export function resolveApiBase() {
|
|
19
|
+
const getter = registrations[registrations.length - 1]?.value;
|
|
20
|
+
return getter?.() || DEFAULT_API_BASE;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=runtime-deps.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime-deps.js","sourceRoot":"","sources":["../src/runtime-deps.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,CAAC,MAAM,gBAAgB,GAAG,sBAAsB,CAAC;AAIvD,MAAM,aAAa,GAAmD,EAAE,CAAC;AAEzE,2FAA2F;AAC3F,MAAM,UAAU,qBAAqB,CAAC,MAA2B;IAC/D,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IACtD,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACjC,OAAO,GAAG,EAAE;QACV,MAAM,KAAK,GAAG,aAAa,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC;QACtD,IAAI,KAAK,IAAI,CAAC;YAAE,aAAa,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACjD,CAAC,CAAC;AACJ,CAAC;AAED,qFAAqF;AACrF,MAAM,UAAU,cAAc;IAC5B,MAAM,MAAM,GAAG,aAAa,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC;IAC9D,OAAO,MAAM,EAAE,EAAE,IAAI,gBAAgB,CAAC;AACxC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/plugin-60s",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.5",
|
|
4
4
|
"description": "60s API aggregation plugin for Zhin.js — news, weather, hot searches, utilities (Plugin Runtime)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -45,19 +45,19 @@
|
|
|
45
45
|
},
|
|
46
46
|
"license": "MIT",
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@zhin.js/command": "1.0.
|
|
49
|
-
"@zhin.js/plugin-runtime": "1.1.
|
|
50
|
-
"@zhin.js/tool": "1.0.
|
|
48
|
+
"@zhin.js/command": "1.0.3",
|
|
49
|
+
"@zhin.js/plugin-runtime": "1.1.1",
|
|
50
|
+
"@zhin.js/tool": "1.0.3"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"typescript": "^6.0.3",
|
|
54
54
|
"vitest": "^4.1.10",
|
|
55
55
|
"zod": "^4.4.3",
|
|
56
|
-
"@zhin.js/agent": "1.0.
|
|
56
|
+
"@zhin.js/agent": "1.0.6"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
59
|
"zod": "^4.0.0",
|
|
60
|
-
"@zhin.js/agent": "1.0.
|
|
60
|
+
"@zhin.js/agent": "1.0.6"
|
|
61
61
|
},
|
|
62
62
|
"peerDependenciesMeta": {
|
|
63
63
|
"@zhin.js/agent": {
|
package/plugin.ts
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
import { definePlugin } from '@zhin.js/plugin-runtime';
|
|
2
|
+
import { DEFAULT_API_BASE, registerSixtySApiBase } from './src/runtime-deps.js';
|
|
2
3
|
|
|
3
4
|
export interface SixtySConfig {
|
|
4
5
|
readonly apiBase?: string;
|
|
5
6
|
}
|
|
6
7
|
|
|
7
|
-
const DEFAULT_API_BASE = 'https://60s.viki.moe';
|
|
8
|
-
|
|
9
8
|
export default definePlugin<SixtySConfig>({
|
|
10
9
|
name: 'sixty-s',
|
|
11
10
|
metadata: {
|
|
12
11
|
displayName: '60s API',
|
|
13
12
|
},
|
|
14
13
|
setup(context) {
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
// 运行时读取配置:config patch 即时生效;卸载时 lifecycle 反注册,无 process.env 残留
|
|
15
|
+
context.lifecycle.add(
|
|
16
|
+
registerSixtySApiBase(() => context.config.get().apiBase?.trim() || DEFAULT_API_BASE),
|
|
17
|
+
);
|
|
17
18
|
},
|
|
18
19
|
});
|
package/src/api.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* 60s API 共享模块 — 供 *.tool.md handler 使用
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
import { resolveApiBase } from './runtime-deps.js';
|
|
6
6
|
|
|
7
7
|
export type ListItem = string | Record<string, unknown>;
|
|
8
8
|
|
|
@@ -13,11 +13,27 @@ export async function fetchApi<T = ApiPayload>(
|
|
|
13
13
|
endpoint: string,
|
|
14
14
|
params?: Record<string, string>,
|
|
15
15
|
): Promise<T> {
|
|
16
|
-
const url = new URL(`${
|
|
16
|
+
const url = new URL(`${resolveApiBase()}/v2${endpoint}`);
|
|
17
17
|
if (params) {
|
|
18
18
|
Object.entries(params).forEach(([k, v]) => url.searchParams.set(k, v));
|
|
19
19
|
}
|
|
20
|
-
|
|
20
|
+
let res: Response;
|
|
21
|
+
try {
|
|
22
|
+
res = await fetch(url.toString(), { signal: AbortSignal.timeout(30_000) });
|
|
23
|
+
} catch (e) {
|
|
24
|
+
const err = e as Error;
|
|
25
|
+
throw new Error(
|
|
26
|
+
err.name === 'TimeoutError' ? '请求超时(30s)' : `请求失败: ${err.message}`,
|
|
27
|
+
{ cause: e },
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
if (!res.ok) {
|
|
31
|
+
throw new Error(`API 请求失败: ${res.status} ${res.statusText}`);
|
|
32
|
+
}
|
|
33
|
+
const contentType = res.headers.get('content-type') ?? '';
|
|
34
|
+
if (!contentType.includes('application/json')) {
|
|
35
|
+
throw new Error(`API 返回非 JSON 响应 (content-type: ${contentType || 'unknown'})`);
|
|
36
|
+
}
|
|
21
37
|
const data = (await res.json()) as {
|
|
22
38
|
error?: string;
|
|
23
39
|
code?: number;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 60s apiBase 运行时注入 — plugin setup 注册 getter,fetchApi 每次调用时求值。
|
|
3
|
+
* 参考 lottery 的 registerLotteryAgentDeps:registration 模式,卸载时反注册,无 process.env 残留。
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export const DEFAULT_API_BASE = 'https://60s.viki.moe';
|
|
7
|
+
|
|
8
|
+
export type SixtySApiBaseGetter = () => string;
|
|
9
|
+
|
|
10
|
+
const registrations: Array<{ readonly value: SixtySApiBaseGetter }> = [];
|
|
11
|
+
|
|
12
|
+
/** Generation-owned apiBase binding used by Plugin Runtime setup(). Returns unregister. */
|
|
13
|
+
export function registerSixtySApiBase(getter: SixtySApiBaseGetter): () => void {
|
|
14
|
+
const registration = Object.freeze({ value: getter });
|
|
15
|
+
registrations.push(registration);
|
|
16
|
+
return () => {
|
|
17
|
+
const index = registrations.lastIndexOf(registration);
|
|
18
|
+
if (index >= 0) registrations.splice(index, 1);
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Resolve the apiBase at call time so config patches take effect without reload. */
|
|
23
|
+
export function resolveApiBase(): string {
|
|
24
|
+
const getter = registrations[registrations.length - 1]?.value;
|
|
25
|
+
return getter?.() || DEFAULT_API_BASE;
|
|
26
|
+
}
|