feat: 完成分类、worksheet 接口开发,资源迁移到七牛

This commit is contained in:
R524809
2026-10-16 17:32:23 +08:00
parent e6ded00a4c
commit 8827110f2f
107 changed files with 12775 additions and 125 deletions
+108
View File
@@ -0,0 +1,108 @@
import assert from 'node:assert/strict';
import { test } from 'node:test';
import { WechatClient, type WechatFetch } from '../src/auth/wechat-client';
import { ApiException } from '../src/common/api-exception';
import { testConfig } from './test-config';
const responding =
(payload: unknown, status = 200): WechatFetch =>
async () =>
new Response(JSON.stringify(payload), {
status,
headers: { 'Content-Type': 'application/json' },
});
test('微信兑换只向固定地址发送服务端凭据,忽略 session_key,不重试一次性 code', async () => {
let calls = 0;
const http: WechatFetch = async (input, init) => {
calls += 1;
const url = new URL(String(input));
assert.equal(url.origin, 'https://api.weixin.qq.com');
assert.equal(url.pathname, '/sns/jscode2session');
assert.equal(url.searchParams.get('appid'), testConfig.wechatMiniAppId);
assert.equal(
url.searchParams.get('secret'),
testConfig.wechatMiniAppSecret,
);
assert.equal(url.searchParams.get('js_code'), 'once-code');
assert.equal(init?.redirect, 'error');
assert.ok(init?.signal);
return responding({
openid: 'OpenIdA',
unionid: 'UnionA',
session_key: 'private-session-key',
})(input, init);
};
assert.deepEqual(
await new WechatClient(testConfig, http).exchangeCode('once-code'),
{ openid: 'OpenIdA', unionid: 'UnionA' },
);
assert.equal(calls, 1);
for (const unionid of [undefined, null, '']) {
const result = await new WechatClient(
testConfig,
responding({ openid: 'A', unionid, errcode: 0 }),
).exchangeCode('code');
assert.equal(result.unionid, null);
}
});
test('微信错误、畸形响应和网络失败映射为有限安全错误,不传播原始消息', async () => {
for (const [payload, status, reason] of [
[{ errcode: 40029 }, 400, 'WECHAT_CODE_INVALID'],
[{ errcode: 40163 }, 400, 'WECHAT_CODE_INVALID'],
[{ errcode: 40226 }, 403, 'WECHAT_LOGIN_BLOCKED'],
[{ errcode: 45011 }, 429, 'RATE_LIMITED'],
[{ errcode: -1 }, 503, 'AUTH_UPSTREAM_UNAVAILABLE'],
[
{ errcode: 40013, errmsg: 'private-secret' },
503,
'AUTH_UPSTREAM_UNAVAILABLE',
],
[{ openid: '' }, 503, 'AUTH_UPSTREAM_UNAVAILABLE'],
[{ openid: 'A', unionid: 123 }, 503, 'AUTH_UPSTREAM_UNAVAILABLE'],
[{ openid: 'x'.repeat(129) }, 503, 'AUTH_UPSTREAM_UNAVAILABLE'],
[{ openid: ' A' }, 503, 'AUTH_UPSTREAM_UNAVAILABLE'],
[null, 503, 'AUTH_UPSTREAM_UNAVAILABLE'],
[[], 503, 'AUTH_UPSTREAM_UNAVAILABLE'],
] as const) {
await assert.rejects(
new WechatClient(testConfig, responding(payload)).exchangeCode(
'code',
),
(error: unknown) => {
assert.ok(error instanceof ApiException);
assert.equal(error.getStatus(), status);
assert.equal(error.reason, reason);
assert.ok(
!JSON.stringify(error.getResponse()).includes(
'private-secret',
),
);
return true;
},
);
}
let calls = 0;
const failed: WechatFetch = async () => {
calls += 1;
throw new Error('https://api.weixin.qq.com?secret=private-secret');
};
await assert.rejects(
new WechatClient(testConfig, failed).exchangeCode('code'),
(error: unknown) =>
error instanceof ApiException &&
error.reason === 'AUTH_UPSTREAM_UNAVAILABLE',
);
assert.equal(calls, 1);
for (const http of [
responding({}, 502),
(async () => new Response('not-json')) as WechatFetch,
])
await assert.rejects(
new WechatClient(testConfig, http).exchangeCode('code'),
(error: unknown) =>
error instanceof ApiException &&
error.reason === 'AUTH_UPSTREAM_UNAVAILABLE',
);
});