@downcity/city 0.2.205 → 0.2.213
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/README.md +71 -5
- package/bin/client/bureau.d.ts +56 -0
- package/bin/client/bureau.d.ts.map +1 -0
- package/bin/client/bureau.js +253 -0
- package/bin/client/bureau.js.map +1 -0
- package/bin/client/city.d.ts +22 -79
- package/bin/client/city.d.ts.map +1 -1
- package/bin/client/city.js +51 -95
- package/bin/client/city.js.map +1 -1
- package/bin/client/types.d.ts +10 -70
- package/bin/client/types.d.ts.map +1 -1
- package/bin/client/types.js +3 -3
- package/bin/federation/auth/authenticator.d.ts +14 -13
- package/bin/federation/auth/authenticator.d.ts.map +1 -1
- package/bin/federation/auth/authenticator.js +33 -27
- package/bin/federation/auth/authenticator.js.map +1 -1
- package/bin/federation/auth/bureau-token-schema.d.ts +202 -0
- package/bin/federation/auth/bureau-token-schema.d.ts.map +1 -0
- package/bin/federation/auth/bureau-token-schema.js +35 -0
- package/bin/federation/auth/bureau-token-schema.js.map +1 -0
- package/bin/federation/auth/bureau-token-store.d.ts +22 -0
- package/bin/federation/auth/bureau-token-store.d.ts.map +1 -0
- package/bin/federation/auth/bureau-token-store.js +95 -0
- package/bin/federation/auth/bureau-token-store.js.map +1 -0
- package/bin/federation/auth/federation-key-store.d.ts +26 -0
- package/bin/federation/auth/federation-key-store.d.ts.map +1 -0
- package/bin/federation/auth/federation-key-store.js +96 -0
- package/bin/federation/auth/federation-key-store.js.map +1 -0
- package/bin/federation/auth/key-schema.d.ts +275 -0
- package/bin/federation/auth/key-schema.d.ts.map +1 -0
- package/bin/federation/auth/key-schema.js +44 -0
- package/bin/federation/auth/key-schema.js.map +1 -0
- package/bin/federation/auth/types.d.ts +62 -4
- package/bin/federation/auth/types.d.ts.map +1 -1
- package/bin/federation/auth/user-token-authority.d.ts +26 -0
- package/bin/federation/auth/user-token-authority.d.ts.map +1 -0
- package/bin/federation/auth/user-token-authority.js +179 -0
- package/bin/federation/auth/user-token-authority.js.map +1 -0
- package/bin/federation/federation-init.d.ts.map +1 -1
- package/bin/federation/federation-init.js +23 -4
- package/bin/federation/federation-init.js.map +1 -1
- package/bin/federation/federation-router.d.ts.map +1 -1
- package/bin/federation/federation-router.js +16 -0
- package/bin/federation/federation-router.js.map +1 -1
- package/bin/federation/federation-runtime.d.ts.map +1 -1
- package/bin/federation/federation-runtime.js +14 -2
- package/bin/federation/federation-runtime.js.map +1 -1
- package/bin/federation/federation.d.ts.map +1 -1
- package/bin/federation/federation.js +2 -0
- package/bin/federation/federation.js.map +1 -1
- package/bin/federation/runtime.d.ts +4 -0
- package/bin/federation/runtime.d.ts.map +1 -1
- package/bin/index.d.ts +6 -3
- package/bin/index.d.ts.map +1 -1
- package/bin/index.js +2 -1
- package/bin/index.js.map +1 -1
- package/bin/pact/admin/index.d.ts +7 -19
- package/bin/pact/admin/index.d.ts.map +1 -1
- package/bin/pact/admin/index.js +10 -18
- package/bin/pact/admin/index.js.map +1 -1
- package/bin/pact/admin/types.d.ts +4 -10
- package/bin/pact/admin/types.d.ts.map +1 -1
- package/bin/pact/invoker/bureaus/index.d.ts +25 -0
- package/bin/pact/invoker/bureaus/index.d.ts.map +1 -0
- package/bin/pact/invoker/bureaus/index.js +36 -0
- package/bin/pact/invoker/bureaus/index.js.map +1 -0
- package/bin/pact/invoker/cities/types.d.ts +2 -2
- package/bin/pact/invoker/cities/types.d.ts.map +1 -1
- package/bin/pact/invoker/user/index.d.ts +19 -0
- package/bin/pact/invoker/user/index.d.ts.map +1 -0
- package/bin/pact/invoker/user/index.js +24 -0
- package/bin/pact/invoker/user/index.js.map +1 -0
- package/bin/pact/user/index.d.ts +2 -1
- package/bin/pact/user/index.d.ts.map +1 -1
- package/bin/pact/user/index.js +7 -3
- package/bin/pact/user/index.js.map +1 -1
- package/bin/pact/user/types.d.ts +0 -2
- package/bin/pact/user/types.d.ts.map +1 -1
- package/bin/service/bureaus/bureaus-service.d.ts +13 -0
- package/bin/service/bureaus/bureaus-service.d.ts.map +1 -0
- package/bin/service/bureaus/bureaus-service.js +36 -0
- package/bin/service/bureaus/bureaus-service.js.map +1 -0
- package/bin/service/instruction.js +1 -1
- package/bin/service/instruction.js.map +1 -1
- package/bin/service/service.d.ts +3 -0
- package/bin/service/service.d.ts.map +1 -1
- package/bin/service/service.js +2 -0
- package/bin/service/service.js.map +1 -1
- package/bin/types/Bureau.d.ts +64 -0
- package/bin/types/Bureau.d.ts.map +1 -0
- package/bin/types/Bureau.js +8 -0
- package/bin/types/Bureau.js.map +1 -0
- package/bin/types/User.d.ts +24 -0
- package/bin/types/User.d.ts.map +1 -0
- package/bin/types/User.js +8 -0
- package/bin/types/User.js.map +1 -0
- package/package.json +4 -3
- package/bin/federation/auth/token-signer.d.ts +0 -27
- package/bin/federation/auth/token-signer.d.ts.map +0 -1
- package/bin/federation/auth/token-signer.js +0 -116
- package/bin/federation/auth/token-signer.js.map +0 -1
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
- 挂载 `Service` / `AIService`
|
|
8
8
|
- 初始化内置 `cities` / `env` 表
|
|
9
|
-
- 校验 `user_token`
|
|
9
|
+
- 校验 `user_token`、`bureau_token` 和控制面凭证
|
|
10
10
|
- 暴露统一的 `/v1/*` HTTP 路由
|
|
11
11
|
- 提供 env、数据库、hook 和鉴权上下文
|
|
12
12
|
|
|
@@ -114,7 +114,7 @@ console.log(text);
|
|
|
114
114
|
GET /v1/federation/instruction
|
|
115
115
|
```
|
|
116
116
|
|
|
117
|
-
|
|
117
|
+
这个接口只允许携带 Federation `admin_secret_key` 的控制面请求访问,返回 `text/plain`。
|
|
118
118
|
|
|
119
119
|
## Service
|
|
120
120
|
|
|
@@ -208,10 +208,76 @@ base.use(usageService());
|
|
|
208
208
|
## 鉴权语义
|
|
209
209
|
|
|
210
210
|
- 默认 action 需要 `user_token`
|
|
211
|
-
- `auth: ["admin"]`
|
|
211
|
+
- `auth: ["admin"]` 只允许携带 Federation `admin_secret_key` 的控制面请求
|
|
212
212
|
- `auth: []` 表示免登录
|
|
213
213
|
|
|
214
|
-
|
|
214
|
+
Federation 首次启动会自动生成并持久化 Ed25519 Key Ring。私钥只用于 Federation
|
|
215
|
+
签发 `user_token`,公开公钥通过以下接口发布:
|
|
216
|
+
|
|
217
|
+
```text
|
|
218
|
+
GET /.well-known/downcity.json
|
|
219
|
+
GET /.well-known/jwks.json
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
用户侧 `City` 只需要 Federation 地址和登录后获得的 token:
|
|
223
|
+
|
|
224
|
+
```ts
|
|
225
|
+
const city = new City({
|
|
226
|
+
federation_url: "https://fed.example.com",
|
|
227
|
+
user_token,
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
const profile = await city.user().profile();
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
`city_id` 由 Federation 验签后从 token 中读取,客户端不再重复传入。
|
|
234
|
+
|
|
235
|
+
City 直接访问 Federation,不依赖 Bureau。只有产品需要自己的后端能力时,才通过
|
|
236
|
+
`fed bureau token` 登记并部署 Bureau:
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
fed bureau token
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
命令生成的高熵 `bureau_token` 只显示一次,Federation 数据库只保存 hash。将明文
|
|
243
|
+
配置到 Bureau 所在服务器:
|
|
244
|
+
|
|
245
|
+
```env
|
|
246
|
+
DOWNCITY_FEDERATION_URL=https://fed.example.com
|
|
247
|
+
DOWNCITY_BUREAU_TOKEN=fb_br_xxx.secret
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
Bureau 使用 Federation JWKS 在本地识别请求身份,并通过 `bureau_token` 调用 Federation
|
|
251
|
+
管理 API:
|
|
252
|
+
|
|
253
|
+
```ts
|
|
254
|
+
const bureau = new Bureau({
|
|
255
|
+
federation_url: "https://fed.example.com",
|
|
256
|
+
bureau_token,
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
const identity = await bureau.identify(request);
|
|
260
|
+
const profile = await (await bureau.user(request)).profile();
|
|
261
|
+
|
|
262
|
+
await bureau.cities.list();
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
City 访问 Bureau 的独立服务时,使用 JSON `get()` / `post()` 自动注入当前 `user_token`:
|
|
266
|
+
|
|
267
|
+
```ts
|
|
268
|
+
const city = new City({
|
|
269
|
+
federation_url: "https://fed.example.com",
|
|
270
|
+
user_token,
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
const result = await city.post(
|
|
274
|
+
"https://bureau.example.com/reports/summary",
|
|
275
|
+
{ range: "today" },
|
|
276
|
+
);
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
`Bureau` 不绑定 `city_id`。`identify()` 返回 `user_token` 中的 `city_id`,由 Bureau 自己
|
|
280
|
+
决定是否允许该产品访问某个独立服务。
|
|
215
281
|
|
|
216
282
|
## 主要导出
|
|
217
283
|
|
|
@@ -223,7 +289,7 @@ base.use(usageService());
|
|
|
223
289
|
- `AIChannel`
|
|
224
290
|
- `CityModel`
|
|
225
291
|
- `CityModelDescriptor`
|
|
226
|
-
- `
|
|
292
|
+
- `Bureau`
|
|
227
293
|
- `EnvService`
|
|
228
294
|
- `CitiesService`
|
|
229
295
|
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bureau 管理与独立服务节点客户端。
|
|
3
|
+
*
|
|
4
|
+
* Bureau 使用 Bureau Token 管理 Federation,并使用 Federation JWKS 在本地
|
|
5
|
+
* 验证独立服务收到的 user_token。Bureau 不绑定 City,一个实例可以服务同一
|
|
6
|
+
* Federation 下的多个 City。
|
|
7
|
+
*/
|
|
8
|
+
import type { BureauFetch, BureauIdentity, BureauOptions } from "../types/Bureau.js";
|
|
9
|
+
import { AdminPactAccess } from "../pact/admin/index.js";
|
|
10
|
+
import type { ServiceClient } from "../pact/invoker/invoker.js";
|
|
11
|
+
import type { AdminModelRecord, AdminServiceSummary } from "../pact/admin/types.js";
|
|
12
|
+
import type { UserProfile } from "../types/User.js";
|
|
13
|
+
/** 已通过本地验签的用户后端会话。 */
|
|
14
|
+
export declare class BureauUser {
|
|
15
|
+
private readonly federation_url;
|
|
16
|
+
private readonly user_token;
|
|
17
|
+
private readonly fetcher;
|
|
18
|
+
/** 当前用户身份。 */
|
|
19
|
+
readonly identity: BureauIdentity;
|
|
20
|
+
constructor(identity: BureauIdentity, federation_url: string, user_token: string, fetcher: BureauFetch);
|
|
21
|
+
/** 在线读取 Federation 当前用户 Profile。 */
|
|
22
|
+
profile(): Promise<UserProfile | null>;
|
|
23
|
+
}
|
|
24
|
+
/** Bureau 管理与独立服务节点客户端。 */
|
|
25
|
+
export declare class Bureau {
|
|
26
|
+
private readonly federation_url;
|
|
27
|
+
private readonly fetcher;
|
|
28
|
+
private readonly cache_ttl;
|
|
29
|
+
private readonly admin_access;
|
|
30
|
+
private cache?;
|
|
31
|
+
private refresh_promise?;
|
|
32
|
+
constructor(options: BureauOptions);
|
|
33
|
+
/** Federation 余额管理入口。 */
|
|
34
|
+
get balance(): AdminPactAccess["balance"];
|
|
35
|
+
/** Federation City 管理入口。 */
|
|
36
|
+
get cities(): AdminPactAccess["cities"];
|
|
37
|
+
/** Federation Bureau Token 注册表管理入口。 */
|
|
38
|
+
get bureaus(): AdminPactAccess["bureaus"];
|
|
39
|
+
/** Federation 环境变量管理入口。 */
|
|
40
|
+
get env(): AdminPactAccess["env"];
|
|
41
|
+
/** 获取 Federation 管理身份下的 Service 调用器。 */
|
|
42
|
+
service(name: string): ServiceClient;
|
|
43
|
+
/** 列出 Federation 暴露的 Service。 */
|
|
44
|
+
listServices(): Promise<AdminServiceSummary[]>;
|
|
45
|
+
/** 列出 Federation 模型目录及管理状态。 */
|
|
46
|
+
listModels(): Promise<AdminModelRecord[]>;
|
|
47
|
+
/** 读取 Federation 聚合说明文档。 */
|
|
48
|
+
instruction(): Promise<string>;
|
|
49
|
+
/** 从 HTTP Request 或 user_token 中本地识别 Federation 用户。 */
|
|
50
|
+
identify(input: Request | string): Promise<BureauIdentity>;
|
|
51
|
+
/** 验证请求并创建一个可读取 Federation 用户数据的会话。 */
|
|
52
|
+
user(input: Request | string): Promise<BureauUser>;
|
|
53
|
+
private get_cache;
|
|
54
|
+
private refresh_cache;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=bureau.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bureau.d.ts","sourceRoot":"","sources":["../../src/client/bureau.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EACV,WAAW,EACX,cAAc,EACd,aAAa,EACd,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,KAAK,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AACpF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAoBpD,sBAAsB;AACtB,qBAAa,UAAU;IAMnB,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAP1B,cAAc;IACd,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;gBAGhC,QAAQ,EAAE,cAAc,EACP,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,WAAW;IAKvC,oCAAoC;IAC9B,OAAO,IAAI,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;CAW7C;AAED,2BAA2B;AAC3B,qBAAa,MAAM;IACjB,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAc;IACtC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAkB;IAC/C,OAAO,CAAC,KAAK,CAAC,CAAc;IAC5B,OAAO,CAAC,eAAe,CAAC,CAAuB;gBAEnC,OAAO,EAAE,aAAa;IAelC,yBAAyB;IACzB,IAAI,OAAO,IAAI,eAAe,CAAC,SAAS,CAAC,CAExC;IAED,4BAA4B;IAC5B,IAAI,MAAM,IAAI,eAAe,CAAC,QAAQ,CAAC,CAEtC;IAED,uCAAuC;IACvC,IAAI,OAAO,IAAI,eAAe,CAAC,SAAS,CAAC,CAExC;IAED,2BAA2B;IAC3B,IAAI,GAAG,IAAI,eAAe,CAAC,KAAK,CAAC,CAEhC;IAED,wCAAwC;IACxC,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa;IAIpC,iCAAiC;IACjC,YAAY,IAAI,OAAO,CAAC,mBAAmB,EAAE,CAAC;IAI9C,+BAA+B;IAC/B,UAAU,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAIzC,4BAA4B;IAC5B,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC;IAI9B,uDAAuD;IACjD,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAgChE,uCAAuC;IACjC,IAAI,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;YAM1C,SAAS;YAUT,aAAa;CAsB5B"}
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bureau 管理与独立服务节点客户端。
|
|
3
|
+
*
|
|
4
|
+
* Bureau 使用 Bureau Token 管理 Federation,并使用 Federation JWKS 在本地
|
|
5
|
+
* 验证独立服务收到的 user_token。Bureau 不绑定 City,一个实例可以服务同一
|
|
6
|
+
* Federation 下的多个 City。
|
|
7
|
+
*/
|
|
8
|
+
import { decodeProtectedHeader, importJWK, jwtVerify } from "jose";
|
|
9
|
+
import { httpError } from "../utils/helpers.js";
|
|
10
|
+
import { AdminPactAccess } from "../pact/admin/index.js";
|
|
11
|
+
import { USER_TOKEN_ALGORITHM } from "../federation/auth/federation-key-store.js";
|
|
12
|
+
import { normalize_user_token, read_user_token_payload } from "../federation/auth/user-token-authority.js";
|
|
13
|
+
const DEFAULT_CACHE_TTL = 5 * 60 * 1000;
|
|
14
|
+
/** 已通过本地验签的用户后端会话。 */
|
|
15
|
+
export class BureauUser {
|
|
16
|
+
federation_url;
|
|
17
|
+
user_token;
|
|
18
|
+
fetcher;
|
|
19
|
+
/** 当前用户身份。 */
|
|
20
|
+
identity;
|
|
21
|
+
constructor(identity, federation_url, user_token, fetcher) {
|
|
22
|
+
this.federation_url = federation_url;
|
|
23
|
+
this.user_token = user_token;
|
|
24
|
+
this.fetcher = fetcher;
|
|
25
|
+
this.identity = identity;
|
|
26
|
+
}
|
|
27
|
+
/** 在线读取 Federation 当前用户 Profile。 */
|
|
28
|
+
async profile() {
|
|
29
|
+
const response = await this.fetcher(`${this.federation_url}/v1/accounts/me`, {
|
|
30
|
+
method: "GET",
|
|
31
|
+
headers: { authorization: `Bearer ${this.user_token}` },
|
|
32
|
+
});
|
|
33
|
+
if (!response.ok) {
|
|
34
|
+
throw httpError(response.status, "Federation user profile unavailable");
|
|
35
|
+
}
|
|
36
|
+
const body = await response.json();
|
|
37
|
+
return body.profile ?? null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/** Bureau 管理与独立服务节点客户端。 */
|
|
41
|
+
export class Bureau {
|
|
42
|
+
federation_url;
|
|
43
|
+
fetcher;
|
|
44
|
+
cache_ttl;
|
|
45
|
+
admin_access;
|
|
46
|
+
cache;
|
|
47
|
+
refresh_promise;
|
|
48
|
+
constructor(options) {
|
|
49
|
+
if (!options || typeof options !== "object") {
|
|
50
|
+
throw new TypeError("Bureau options are required");
|
|
51
|
+
}
|
|
52
|
+
this.federation_url = normalize_federation_url(options.federation_url);
|
|
53
|
+
const bureau_token = read_required_string(options.bureau_token, "bureau_token");
|
|
54
|
+
this.fetcher = options.fetch ?? globalThis.fetch.bind(globalThis);
|
|
55
|
+
this.cache_ttl = read_cache_ttl(options.jwks_cache_ttl);
|
|
56
|
+
this.admin_access = new AdminPactAccess({
|
|
57
|
+
base_url: this.federation_url,
|
|
58
|
+
credential: bureau_token,
|
|
59
|
+
fetch: options.fetch,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
/** Federation 余额管理入口。 */
|
|
63
|
+
get balance() {
|
|
64
|
+
return this.admin_access.balance;
|
|
65
|
+
}
|
|
66
|
+
/** Federation City 管理入口。 */
|
|
67
|
+
get cities() {
|
|
68
|
+
return this.admin_access.cities;
|
|
69
|
+
}
|
|
70
|
+
/** Federation Bureau Token 注册表管理入口。 */
|
|
71
|
+
get bureaus() {
|
|
72
|
+
return this.admin_access.bureaus;
|
|
73
|
+
}
|
|
74
|
+
/** Federation 环境变量管理入口。 */
|
|
75
|
+
get env() {
|
|
76
|
+
return this.admin_access.env;
|
|
77
|
+
}
|
|
78
|
+
/** 获取 Federation 管理身份下的 Service 调用器。 */
|
|
79
|
+
service(name) {
|
|
80
|
+
return this.admin_access.service(name);
|
|
81
|
+
}
|
|
82
|
+
/** 列出 Federation 暴露的 Service。 */
|
|
83
|
+
listServices() {
|
|
84
|
+
return this.admin_access.listServices();
|
|
85
|
+
}
|
|
86
|
+
/** 列出 Federation 模型目录及管理状态。 */
|
|
87
|
+
listModels() {
|
|
88
|
+
return this.admin_access.listModels();
|
|
89
|
+
}
|
|
90
|
+
/** 读取 Federation 聚合说明文档。 */
|
|
91
|
+
instruction() {
|
|
92
|
+
return this.admin_access.instruction();
|
|
93
|
+
}
|
|
94
|
+
/** 从 HTTP Request 或 user_token 中本地识别 Federation 用户。 */
|
|
95
|
+
async identify(input) {
|
|
96
|
+
const user_token = typeof input === "string" ? read_token_string(input) : read_request_token(input);
|
|
97
|
+
const normalized_token = normalize_user_token(user_token);
|
|
98
|
+
let cache = await this.get_cache(false);
|
|
99
|
+
let key = find_jwk(cache.jwks, normalized_token);
|
|
100
|
+
if (!key) {
|
|
101
|
+
cache = await this.get_cache(true);
|
|
102
|
+
key = find_jwk(cache.jwks, normalized_token);
|
|
103
|
+
}
|
|
104
|
+
if (!key)
|
|
105
|
+
throw httpError(401, "Unknown token signing key");
|
|
106
|
+
try {
|
|
107
|
+
const public_key = await importJWK(key, USER_TOKEN_ALGORITHM);
|
|
108
|
+
const result = await jwtVerify(normalized_token, public_key, {
|
|
109
|
+
algorithms: [USER_TOKEN_ALGORITHM],
|
|
110
|
+
audience: cache.discovery.user_token_audience,
|
|
111
|
+
issuer: cache.discovery.issuer,
|
|
112
|
+
});
|
|
113
|
+
const payload = read_user_token_payload(result.payload);
|
|
114
|
+
return {
|
|
115
|
+
user_id: payload.user_id,
|
|
116
|
+
city_id: payload.city_id,
|
|
117
|
+
metadata: payload.metadata ?? {},
|
|
118
|
+
token_id: payload.jti,
|
|
119
|
+
expires_at: payload.exp,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
if (is_http_error(error))
|
|
124
|
+
throw error;
|
|
125
|
+
throw map_identify_error(error);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/** 验证请求并创建一个可读取 Federation 用户数据的会话。 */
|
|
129
|
+
async user(input) {
|
|
130
|
+
const user_token = typeof input === "string" ? read_token_string(input) : read_request_token(input);
|
|
131
|
+
const identity = await this.identify(user_token);
|
|
132
|
+
return new BureauUser(identity, this.federation_url, user_token, this.fetcher);
|
|
133
|
+
}
|
|
134
|
+
async get_cache(force_refresh) {
|
|
135
|
+
if (!force_refresh && this.cache && this.cache.expires_at > Date.now())
|
|
136
|
+
return this.cache;
|
|
137
|
+
if (!this.refresh_promise) {
|
|
138
|
+
this.refresh_promise = this.refresh_cache().finally(() => {
|
|
139
|
+
this.refresh_promise = undefined;
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
return this.refresh_promise;
|
|
143
|
+
}
|
|
144
|
+
async refresh_cache() {
|
|
145
|
+
const discovery = await read_json(this.fetcher, `${this.federation_url}/.well-known/downcity.json`, "Federation discovery unavailable");
|
|
146
|
+
validate_discovery(discovery, this.federation_url);
|
|
147
|
+
const jwks = await read_json(this.fetcher, discovery.jwks_uri, "Federation signing keys unavailable");
|
|
148
|
+
validate_jwks(jwks);
|
|
149
|
+
const cache = {
|
|
150
|
+
discovery,
|
|
151
|
+
jwks,
|
|
152
|
+
expires_at: Date.now() + this.cache_ttl,
|
|
153
|
+
};
|
|
154
|
+
this.cache = cache;
|
|
155
|
+
return cache;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
function find_jwk(jwks, jwt) {
|
|
159
|
+
const header = decodeProtectedHeader(jwt);
|
|
160
|
+
if (header.alg !== USER_TOKEN_ALGORITHM)
|
|
161
|
+
throw httpError(401, "Invalid user token algorithm");
|
|
162
|
+
const key_id = typeof header.kid === "string" ? header.kid : "";
|
|
163
|
+
if (!key_id)
|
|
164
|
+
throw httpError(401, "Unknown token signing key");
|
|
165
|
+
return jwks.keys.find((key) => key.kid === key_id);
|
|
166
|
+
}
|
|
167
|
+
function read_request_token(request) {
|
|
168
|
+
const authorization = request.headers.get("authorization") ?? "";
|
|
169
|
+
if (!authorization.startsWith("Bearer "))
|
|
170
|
+
throw httpError(401, "Authentication required");
|
|
171
|
+
return read_required_string(authorization.slice("Bearer ".length), "user_token");
|
|
172
|
+
}
|
|
173
|
+
function read_token_string(value) {
|
|
174
|
+
const token = value.trim();
|
|
175
|
+
return read_required_string(token.startsWith("Bearer ") ? token.slice("Bearer ".length) : token, "user_token");
|
|
176
|
+
}
|
|
177
|
+
function normalize_federation_url(value) {
|
|
178
|
+
const input = read_required_string(value, "federation_url").replace(/\/+$/, "");
|
|
179
|
+
const url = new URL(input);
|
|
180
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
181
|
+
throw new TypeError("federation_url must use http or https");
|
|
182
|
+
}
|
|
183
|
+
if (url.username || url.password)
|
|
184
|
+
throw new TypeError("federation_url must not contain credentials");
|
|
185
|
+
return input;
|
|
186
|
+
}
|
|
187
|
+
function validate_discovery(discovery, federation_url) {
|
|
188
|
+
if (!discovery || typeof discovery !== "object")
|
|
189
|
+
throw httpError(503, "Federation discovery unavailable");
|
|
190
|
+
read_required_string(discovery.issuer, "Federation issuer");
|
|
191
|
+
if (discovery.user_token_audience !== "downcity:user")
|
|
192
|
+
throw httpError(503, "Invalid Federation user token audience");
|
|
193
|
+
const expected = new URL(`${federation_url}/.well-known/jwks.json`);
|
|
194
|
+
const actual = new URL(discovery.jwks_uri);
|
|
195
|
+
if (actual.origin !== expected.origin || actual.pathname !== expected.pathname) {
|
|
196
|
+
throw httpError(503, "Invalid Federation JWKS location");
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
function validate_jwks(jwks) {
|
|
200
|
+
if (!jwks || !Array.isArray(jwks.keys))
|
|
201
|
+
throw httpError(503, "Federation signing keys unavailable");
|
|
202
|
+
for (const key of jwks.keys) {
|
|
203
|
+
if (key.kty !== "OKP" || key.crv !== "Ed25519" || key.alg !== USER_TOKEN_ALGORITHM
|
|
204
|
+
|| key.use !== "sig" || typeof key.kid !== "string" || typeof key.x !== "string") {
|
|
205
|
+
throw httpError(503, "Invalid Federation signing key");
|
|
206
|
+
}
|
|
207
|
+
if ("d" in key)
|
|
208
|
+
throw httpError(503, "Federation JWKS exposed a private key");
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
async function read_json(fetcher, url, error_message) {
|
|
212
|
+
let response;
|
|
213
|
+
try {
|
|
214
|
+
response = await fetcher(url, { headers: { accept: "application/json" } });
|
|
215
|
+
}
|
|
216
|
+
catch {
|
|
217
|
+
throw httpError(503, error_message);
|
|
218
|
+
}
|
|
219
|
+
if (!response.ok)
|
|
220
|
+
throw httpError(response.status === 401 ? 401 : 503, error_message);
|
|
221
|
+
try {
|
|
222
|
+
return await response.json();
|
|
223
|
+
}
|
|
224
|
+
catch {
|
|
225
|
+
throw httpError(503, error_message);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
function read_required_string(value, name) {
|
|
229
|
+
if (typeof value !== "string" || !value.trim())
|
|
230
|
+
throw new TypeError(`${name} must be a non-empty string`);
|
|
231
|
+
return value.trim();
|
|
232
|
+
}
|
|
233
|
+
function read_cache_ttl(value) {
|
|
234
|
+
if (value === undefined)
|
|
235
|
+
return DEFAULT_CACHE_TTL;
|
|
236
|
+
if (!Number.isFinite(value) || value <= 0)
|
|
237
|
+
throw new TypeError("jwks_cache_ttl must be a positive number");
|
|
238
|
+
return value;
|
|
239
|
+
}
|
|
240
|
+
function is_http_error(error) {
|
|
241
|
+
return error instanceof Error && typeof error.statusCode === "number";
|
|
242
|
+
}
|
|
243
|
+
function map_identify_error(error) {
|
|
244
|
+
const code = error && typeof error === "object" ? String(error.code ?? "") : "";
|
|
245
|
+
if (code === "ERR_JWT_EXPIRED")
|
|
246
|
+
return httpError(401, "User token expired");
|
|
247
|
+
if (code === "ERR_JWS_SIGNATURE_VERIFICATION_FAILED")
|
|
248
|
+
return httpError(401, "Invalid user token signature");
|
|
249
|
+
if (code === "ERR_JWT_CLAIM_VALIDATION_FAILED")
|
|
250
|
+
return httpError(401, "Invalid user token claims");
|
|
251
|
+
return httpError(401, "Invalid user token");
|
|
252
|
+
}
|
|
253
|
+
//# sourceMappingURL=bureau.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bureau.js","sourceRoot":"","sources":["../../src/client/bureau.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,qBAAqB,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AACnE,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAMhD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AASzD,OAAO,EAAE,oBAAoB,EAAE,MAAM,4CAA4C,CAAC;AAClF,OAAO,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,MAAM,4CAA4C,CAAC;AAE3G,MAAM,iBAAiB,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;AAWxC,sBAAsB;AACtB,MAAM,OAAO,UAAU;IAMF;IACA;IACA;IAPnB,cAAc;IACL,QAAQ,CAAiB;IAElC,YACE,QAAwB,EACP,cAAsB,EACtB,UAAkB,EAClB,OAAoB;QAFpB,mBAAc,GAAd,cAAc,CAAQ;QACtB,eAAU,GAAV,UAAU,CAAQ;QAClB,YAAO,GAAP,OAAO,CAAa;QAErC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;IAED,oCAAoC;IACpC,KAAK,CAAC,OAAO;QACX,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,cAAc,iBAAiB,EAAE;YAC3E,MAAM,EAAE,KAAK;YACb,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,IAAI,CAAC,UAAU,EAAE,EAAE;SACxD,CAAC,CAAC;QACH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,qCAAqC,CAAC,CAAC;QAC1E,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAsC,CAAC;QACvE,OAAO,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC;IAC9B,CAAC;CACF;AAED,2BAA2B;AAC3B,MAAM,OAAO,MAAM;IACA,cAAc,CAAS;IACvB,OAAO,CAAc;IACrB,SAAS,CAAS;IAClB,YAAY,CAAkB;IACvC,KAAK,CAAe;IACpB,eAAe,CAAwB;IAE/C,YAAY,OAAsB;QAChC,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;YAC5C,MAAM,IAAI,SAAS,CAAC,6BAA6B,CAAC,CAAC;QACrD,CAAC;QACD,IAAI,CAAC,cAAc,GAAG,wBAAwB,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;QACvE,MAAM,YAAY,GAAG,oBAAoB,CAAC,OAAO,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC;QAChF,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,KAAK,IAAI,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAClE,IAAI,CAAC,SAAS,GAAG,cAAc,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;QACxD,IAAI,CAAC,YAAY,GAAG,IAAI,eAAe,CAAC;YACtC,QAAQ,EAAE,IAAI,CAAC,cAAc;YAC7B,UAAU,EAAE,YAAY;YACxB,KAAK,EAAE,OAAO,CAAC,KAAK;SACrB,CAAC,CAAC;IACL,CAAC;IAED,yBAAyB;IACzB,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC;IACnC,CAAC;IAED,4BAA4B;IAC5B,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC;IAClC,CAAC;IAED,uCAAuC;IACvC,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC;IACnC,CAAC;IAED,2BAA2B;IAC3B,IAAI,GAAG;QACL,OAAO,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC;IAC/B,CAAC;IAED,wCAAwC;IACxC,OAAO,CAAC,IAAY;QAClB,OAAO,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,CAAC;IAED,iCAAiC;IACjC,YAAY;QACV,OAAO,IAAI,CAAC,YAAY,CAAC,YAAY,EAAE,CAAC;IAC1C,CAAC;IAED,+BAA+B;IAC/B,UAAU;QACR,OAAO,IAAI,CAAC,YAAY,CAAC,UAAU,EAAE,CAAC;IACxC,CAAC;IAED,4BAA4B;IAC5B,WAAW;QACT,OAAO,IAAI,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC;IACzC,CAAC;IAED,uDAAuD;IACvD,KAAK,CAAC,QAAQ,CAAC,KAAuB;QACpC,MAAM,UAAU,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC;QACpG,MAAM,gBAAgB,GAAG,oBAAoB,CAAC,UAAU,CAAC,CAAC;QAC1D,IAAI,KAAK,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QACxC,IAAI,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC;QACjD,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,KAAK,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YACnC,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC;QAC/C,CAAC;QACD,IAAI,CAAC,GAAG;YAAE,MAAM,SAAS,CAAC,GAAG,EAAE,2BAA2B,CAAC,CAAC;QAE5D,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE,oBAAoB,CAAC,CAAC;YAC9D,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,gBAAgB,EAAE,UAAU,EAAE;gBAC3D,UAAU,EAAE,CAAC,oBAAoB,CAAC;gBAClC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC,mBAAmB;gBAC7C,MAAM,EAAE,KAAK,CAAC,SAAS,CAAC,MAAM;aAC/B,CAAC,CAAC;YACH,MAAM,OAAO,GAAG,uBAAuB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YACxD,OAAO;gBACL,OAAO,EAAE,OAAO,CAAC,OAAO;gBACxB,OAAO,EAAE,OAAO,CAAC,OAAO;gBACxB,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,EAAE;gBAChC,QAAQ,EAAE,OAAO,CAAC,GAAG;gBACrB,UAAU,EAAE,OAAO,CAAC,GAAG;aACxB,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,aAAa,CAAC,KAAK,CAAC;gBAAE,MAAM,KAAK,CAAC;YACtC,MAAM,kBAAkB,CAAC,KAAK,CAAC,CAAC;QAClC,CAAC;IACH,CAAC;IAED,uCAAuC;IACvC,KAAK,CAAC,IAAI,CAAC,KAAuB;QAChC,MAAM,UAAU,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC;QACpG,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QACjD,OAAO,IAAI,UAAU,CAAC,QAAQ,EAAE,IAAI,CAAC,cAAc,EAAE,UAAU,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IACjF,CAAC;IAEO,KAAK,CAAC,SAAS,CAAC,aAAsB;QAC5C,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE;YAAE,OAAO,IAAI,CAAC,KAAK,CAAC;QAC1F,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC;YAC1B,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE;gBACvD,IAAI,CAAC,eAAe,GAAG,SAAS,CAAC;YACnC,CAAC,CAAC,CAAC;QACL,CAAC;QACD,OAAO,IAAI,CAAC,eAAe,CAAC;IAC9B,CAAC;IAEO,KAAK,CAAC,aAAa;QACzB,MAAM,SAAS,GAAG,MAAM,SAAS,CAC/B,IAAI,CAAC,OAAO,EACZ,GAAG,IAAI,CAAC,cAAc,4BAA4B,EAClD,kCAAkC,CACnC,CAAC;QACF,kBAAkB,CAAC,SAAS,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC;QAEnD,MAAM,IAAI,GAAG,MAAM,SAAS,CAC1B,IAAI,CAAC,OAAO,EACZ,SAAS,CAAC,QAAQ,EAClB,qCAAqC,CACtC,CAAC;QACF,aAAa,CAAC,IAAI,CAAC,CAAC;QACpB,MAAM,KAAK,GAAgB;YACzB,SAAS;YACT,IAAI;YACJ,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,SAAS;SACxC,CAAC;QACF,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,OAAO,KAAK,CAAC;IACf,CAAC;CACF;AAED,SAAS,QAAQ,CAAC,IAAoB,EAAE,GAAW;IACjD,MAAM,MAAM,GAAG,qBAAqB,CAAC,GAAG,CAAC,CAAC;IAC1C,IAAI,MAAM,CAAC,GAAG,KAAK,oBAAoB;QAAE,MAAM,SAAS,CAAC,GAAG,EAAE,8BAA8B,CAAC,CAAC;IAC9F,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IAChE,IAAI,CAAC,MAAM;QAAE,MAAM,SAAS,CAAC,GAAG,EAAE,2BAA2B,CAAC,CAAC;IAC/D,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,KAAK,MAAM,CAAC,CAAC;AACrD,CAAC;AAED,SAAS,kBAAkB,CAAC,OAAgB;IAC1C,MAAM,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC;IACjE,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,SAAS,CAAC;QAAE,MAAM,SAAS,CAAC,GAAG,EAAE,yBAAyB,CAAC,CAAC;IAC1F,OAAO,oBAAoB,CAAC,aAAa,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,YAAY,CAAC,CAAC;AACnF,CAAC;AAED,SAAS,iBAAiB,CAAC,KAAa;IACtC,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC3B,OAAO,oBAAoB,CAAC,KAAK,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;AACjH,CAAC;AAED,SAAS,wBAAwB,CAAC,KAAc;IAC9C,MAAM,KAAK,GAAG,oBAAoB,CAAC,KAAK,EAAE,gBAAgB,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAChF,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;IAC3B,IAAI,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC1D,MAAM,IAAI,SAAS,CAAC,uCAAuC,CAAC,CAAC;IAC/D,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,QAAQ;QAAE,MAAM,IAAI,SAAS,CAAC,6CAA6C,CAAC,CAAC;IACrG,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,kBAAkB,CAAC,SAA8B,EAAE,cAAsB;IAChF,IAAI,CAAC,SAAS,IAAI,OAAO,SAAS,KAAK,QAAQ;QAAE,MAAM,SAAS,CAAC,GAAG,EAAE,kCAAkC,CAAC,CAAC;IAC1G,oBAAoB,CAAC,SAAS,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;IAC5D,IAAI,SAAS,CAAC,mBAAmB,KAAK,eAAe;QAAE,MAAM,SAAS,CAAC,GAAG,EAAE,wCAAwC,CAAC,CAAC;IACtH,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,GAAG,cAAc,wBAAwB,CAAC,CAAC;IACpE,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IAC3C,IAAI,MAAM,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,CAAC,QAAQ,EAAE,CAAC;QAC/E,MAAM,SAAS,CAAC,GAAG,EAAE,kCAAkC,CAAC,CAAC;IAC3D,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,IAAoB;IACzC,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,MAAM,SAAS,CAAC,GAAG,EAAE,qCAAqC,CAAC,CAAC;IACpG,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,GAAG,CAAC,GAAG,KAAK,KAAK,IAAI,GAAG,CAAC,GAAG,KAAK,SAAS,IAAI,GAAG,CAAC,GAAG,KAAK,oBAAoB;eAC7E,GAAG,CAAC,GAAG,KAAK,KAAK,IAAI,OAAO,GAAG,CAAC,GAAG,KAAK,QAAQ,IAAI,OAAO,GAAG,CAAC,CAAC,KAAK,QAAQ,EAAE,CAAC;YACnF,MAAM,SAAS,CAAC,GAAG,EAAE,gCAAgC,CAAC,CAAC;QACzD,CAAC;QACD,IAAI,GAAG,IAAI,GAAG;YAAE,MAAM,SAAS,CAAC,GAAG,EAAE,uCAAuC,CAAC,CAAC;IAChF,CAAC;AACH,CAAC;AAED,KAAK,UAAU,SAAS,CACtB,OAAoB,EACpB,GAAW,EACX,aAAqB;IAErB,IAAI,QAAkB,CAAC;IACvB,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE,EAAE,CAAC,CAAC;IAC7E,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,SAAS,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;IACtC,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,EAAE;QAAE,MAAM,SAAS,CAAC,QAAQ,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;IACtF,IAAI,CAAC;QACH,OAAO,MAAM,QAAQ,CAAC,IAAI,EAAO,CAAC;IACpC,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,SAAS,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;IACtC,CAAC;AACH,CAAC;AAED,SAAS,oBAAoB,CAAC,KAAc,EAAE,IAAY;IACxD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE;QAAE,MAAM,IAAI,SAAS,CAAC,GAAG,IAAI,6BAA6B,CAAC,CAAC;IAC1G,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC;AACtB,CAAC;AAED,SAAS,cAAc,CAAC,KAAyB;IAC/C,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,iBAAiB,CAAC;IAClD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC;QAAE,MAAM,IAAI,SAAS,CAAC,0CAA0C,CAAC,CAAC;IAC3G,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,aAAa,CAAC,KAAc;IACnC,OAAO,KAAK,YAAY,KAAK,IAAI,OAAQ,KAAkC,CAAC,UAAU,KAAK,QAAQ,CAAC;AACtG,CAAC;AAED,SAAS,kBAAkB,CAAC,KAAc;IACxC,MAAM,IAAI,GAAG,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAE,KAA4B,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACxG,IAAI,IAAI,KAAK,iBAAiB;QAAE,OAAO,SAAS,CAAC,GAAG,EAAE,oBAAoB,CAAC,CAAC;IAC5E,IAAI,IAAI,KAAK,uCAAuC;QAAE,OAAO,SAAS,CAAC,GAAG,EAAE,8BAA8B,CAAC,CAAC;IAC5G,IAAI,IAAI,KAAK,iCAAiC;QAAE,OAAO,SAAS,CAAC,GAAG,EAAE,2BAA2B,CAAC,CAAC;IACnG,OAAO,SAAS,CAAC,GAAG,EAAE,oBAAoB,CAAC,CAAC;AAC9C,CAAC"}
|
package/bin/client/city.d.ts
CHANGED
|
@@ -1,90 +1,33 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* City
|
|
2
|
+
* City 终端用户客户端。
|
|
3
3
|
*
|
|
4
|
-
* City
|
|
5
|
-
*
|
|
4
|
+
* City 只持有 Federation 地址与可选 user_token。city_id 由 Federation 在服务端
|
|
5
|
+
* 验签后从 token 中读取,客户端不能重复声明或覆盖。
|
|
6
6
|
*/
|
|
7
|
-
import { AdminPactAccess } from "../pact/admin/index.js";
|
|
8
7
|
import { UserPactAccess } from "../pact/user/index.js";
|
|
9
8
|
import type { ServiceClient } from "../pact/invoker/invoker.js";
|
|
10
|
-
import type {
|
|
11
|
-
import type { AdminModelRecord, AdminServiceSummary } from "../pact/admin/types.js";
|
|
9
|
+
import type { CityOptions } from "./types.js";
|
|
12
10
|
import type { UserServiceSummary } from "../pact/user/types.js";
|
|
13
|
-
/**
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
readonly role: TRole;
|
|
21
|
-
/**
|
|
22
|
-
* Admin 能力面。
|
|
23
|
-
*
|
|
24
|
-
* 仅 `role: "admin"` 时可用。
|
|
25
|
-
*/
|
|
26
|
-
private readonly admin_access?;
|
|
27
|
-
/**
|
|
28
|
-
* User 能力面。
|
|
29
|
-
*
|
|
30
|
-
* 仅 `role: "user"` 时可用。
|
|
31
|
-
*/
|
|
32
|
-
private readonly user_access?;
|
|
33
|
-
constructor(options: CityOptionsForRole<TRole>);
|
|
34
|
-
/**
|
|
35
|
-
* User 角色的 AI 调用入口。
|
|
36
|
-
*/
|
|
11
|
+
/** Downcity City 用户客户端。 */
|
|
12
|
+
export declare class City {
|
|
13
|
+
private readonly user_access;
|
|
14
|
+
private readonly user_token?;
|
|
15
|
+
private readonly fetcher;
|
|
16
|
+
constructor(options: CityOptions);
|
|
17
|
+
/** 用户侧 AI 调用入口。 */
|
|
37
18
|
get ai(): UserPactAccess["ai"];
|
|
38
|
-
/**
|
|
39
|
-
* User 角色的支付入口。
|
|
40
|
-
*/
|
|
19
|
+
/** 用户侧支付入口。 */
|
|
41
20
|
get payment(): UserPactAccess["payment"];
|
|
42
|
-
/**
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
get balance(): AdminPactAccess["balance"];
|
|
46
|
-
/**
|
|
47
|
-
* Admin 角色的 City 管理入口。
|
|
48
|
-
*/
|
|
49
|
-
get cities(): AdminPactAccess["cities"];
|
|
50
|
-
/**
|
|
51
|
-
* Admin 角色的环境变量服务入口。
|
|
52
|
-
*/
|
|
53
|
-
get env(): AdminPactAccess["env"];
|
|
54
|
-
/**
|
|
55
|
-
* Token 管理入口。
|
|
56
|
-
*
|
|
57
|
-
* 不需要传 city_id,构造时传入的 city_id 会自动注入。
|
|
58
|
-
*/
|
|
59
|
-
get tokens(): {
|
|
60
|
-
apply: (input: {
|
|
61
|
-
user_id: string;
|
|
62
|
-
metadata?: Record<string, unknown>;
|
|
63
|
-
ttl?: string | number;
|
|
64
|
-
}) => Promise<{
|
|
65
|
-
user_token: string;
|
|
66
|
-
city_id: string;
|
|
67
|
-
user_id: string;
|
|
68
|
-
expires_at?: string;
|
|
69
|
-
}>;
|
|
70
|
-
};
|
|
71
|
-
/**
|
|
72
|
-
* 获取普通 service 调用器。
|
|
73
|
-
*/
|
|
21
|
+
/** Federation 当前用户数据入口。 */
|
|
22
|
+
user(): UserPactAccess["user"];
|
|
23
|
+
/** 获取普通 Service 调用器。 */
|
|
74
24
|
service(name: string): ServiceClient;
|
|
75
|
-
/**
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
listModels(): Promise<AdminModelRecord[]>;
|
|
83
|
-
/**
|
|
84
|
-
* 读取 Federation 聚合说明文档。
|
|
85
|
-
*/
|
|
86
|
-
instruction(): Promise<string>;
|
|
87
|
-
private require_admin;
|
|
88
|
-
private require_user;
|
|
25
|
+
/** 列出 Federation 暴露的 Service。 */
|
|
26
|
+
listServices(): Promise<UserServiceSummary[]>;
|
|
27
|
+
/** 发送 JSON GET 请求,并返回解析后的 JSON。 */
|
|
28
|
+
get<T = unknown>(url: string): Promise<T>;
|
|
29
|
+
/** 发送 JSON POST 请求,第二个参数会直接序列化为请求体。 */
|
|
30
|
+
post<T = unknown>(url: string, body?: unknown): Promise<T>;
|
|
31
|
+
private request_json;
|
|
89
32
|
}
|
|
90
33
|
//# sourceMappingURL=city.d.ts.map
|
package/bin/client/city.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"city.d.ts","sourceRoot":"","sources":["../../src/client/city.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"city.d.ts","sourceRoot":"","sources":["../../src/client/city.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAGhE,2BAA2B;AAC3B,qBAAa,IAAI;IACf,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAiB;IAC7C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAY;gBAExB,OAAO,EAAE,WAAW;IAahC,mBAAmB;IACnB,IAAI,EAAE,IAAI,cAAc,CAAC,IAAI,CAAC,CAE7B;IAED,eAAe;IACf,IAAI,OAAO,IAAI,cAAc,CAAC,SAAS,CAAC,CAEvC;IAED,2BAA2B;IAC3B,IAAI,IAAI,cAAc,CAAC,MAAM,CAAC;IAI9B,wBAAwB;IACxB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa;IAIpC,iCAAiC;IACjC,YAAY,IAAI,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAI7C,mCAAmC;IACnC,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;IAIzC,uCAAuC;IACvC,IAAI,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE,OAAY,GAAG,OAAO,CAAC,CAAC,CAAC;IAO9D,OAAO,CAAC,YAAY;CAYrB"}
|