@downcity/city 0.2.200 → 0.2.211

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.
Files changed (221) hide show
  1. package/README.md +89 -13
  2. package/bin/client/bureau.d.ts +41 -0
  3. package/bin/client/bureau.d.ts.map +1 -0
  4. package/bin/client/bureau.js +240 -0
  5. package/bin/client/bureau.js.map +1 -0
  6. package/bin/client/city.d.ts +15 -79
  7. package/bin/client/city.d.ts.map +1 -1
  8. package/bin/client/city.js +15 -99
  9. package/bin/client/city.js.map +1 -1
  10. package/bin/client/federation-admin.d.ts +32 -0
  11. package/bin/client/federation-admin.d.ts.map +1 -0
  12. package/bin/client/federation-admin.js +54 -0
  13. package/bin/client/federation-admin.js.map +1 -0
  14. package/bin/client/types.d.ts +10 -70
  15. package/bin/client/types.d.ts.map +1 -1
  16. package/bin/client/types.js +3 -3
  17. package/bin/federation/auth/authenticator.d.ts +17 -13
  18. package/bin/federation/auth/authenticator.d.ts.map +1 -1
  19. package/bin/federation/auth/authenticator.js +38 -27
  20. package/bin/federation/auth/authenticator.js.map +1 -1
  21. package/bin/federation/auth/bureau-token-schema.d.ts +274 -0
  22. package/bin/federation/auth/bureau-token-schema.d.ts.map +1 -0
  23. package/bin/federation/auth/bureau-token-schema.js +43 -0
  24. package/bin/federation/auth/bureau-token-schema.js.map +1 -0
  25. package/bin/federation/auth/bureau-token-store.d.ts +22 -0
  26. package/bin/federation/auth/bureau-token-store.d.ts.map +1 -0
  27. package/bin/federation/auth/bureau-token-store.js +122 -0
  28. package/bin/federation/auth/bureau-token-store.js.map +1 -0
  29. package/bin/federation/auth/federation-key-store.d.ts +26 -0
  30. package/bin/federation/auth/federation-key-store.d.ts.map +1 -0
  31. package/bin/federation/auth/federation-key-store.js +96 -0
  32. package/bin/federation/auth/federation-key-store.js.map +1 -0
  33. package/bin/federation/auth/key-schema.d.ts +275 -0
  34. package/bin/federation/auth/key-schema.d.ts.map +1 -0
  35. package/bin/federation/auth/key-schema.js +44 -0
  36. package/bin/federation/auth/key-schema.js.map +1 -0
  37. package/bin/federation/auth/types.d.ts +62 -4
  38. package/bin/federation/auth/types.d.ts.map +1 -1
  39. package/bin/federation/auth/user-token-authority.d.ts +26 -0
  40. package/bin/federation/auth/user-token-authority.d.ts.map +1 -0
  41. package/bin/federation/auth/user-token-authority.js +179 -0
  42. package/bin/federation/auth/user-token-authority.js.map +1 -0
  43. package/bin/federation/federation-init.d.ts.map +1 -1
  44. package/bin/federation/federation-init.js +23 -4
  45. package/bin/federation/federation-init.js.map +1 -1
  46. package/bin/federation/federation-router.d.ts +3 -1
  47. package/bin/federation/federation-router.d.ts.map +1 -1
  48. package/bin/federation/federation-router.js +17 -0
  49. package/bin/federation/federation-router.js.map +1 -1
  50. package/bin/federation/federation-runtime.d.ts.map +1 -1
  51. package/bin/federation/federation-runtime.js +14 -2
  52. package/bin/federation/federation-runtime.js.map +1 -1
  53. package/bin/federation/federation.d.ts.map +1 -1
  54. package/bin/federation/federation.js +2 -0
  55. package/bin/federation/federation.js.map +1 -1
  56. package/bin/federation/runtime.d.ts +4 -0
  57. package/bin/federation/runtime.d.ts.map +1 -1
  58. package/bin/index.d.ts +11 -10
  59. package/bin/index.d.ts.map +1 -1
  60. package/bin/index.js +5 -3
  61. package/bin/index.js.map +1 -1
  62. package/bin/pact/admin/index.d.ts +7 -19
  63. package/bin/pact/admin/index.d.ts.map +1 -1
  64. package/bin/pact/admin/index.js +10 -18
  65. package/bin/pact/admin/index.js.map +1 -1
  66. package/bin/pact/admin/types.d.ts +4 -10
  67. package/bin/pact/admin/types.d.ts.map +1 -1
  68. package/bin/pact/invoker/ai/CityModel.d.ts +1 -1
  69. package/bin/pact/invoker/ai/CityModel.d.ts.map +1 -1
  70. package/bin/pact/invoker/ai/CityModel.js +3 -65
  71. package/bin/pact/invoker/ai/CityModel.js.map +1 -1
  72. package/bin/pact/invoker/ai/types.d.ts +1 -1
  73. package/bin/pact/invoker/ai/types.js +1 -1
  74. package/bin/pact/invoker/bureaus/index.d.ts +25 -0
  75. package/bin/pact/invoker/bureaus/index.d.ts.map +1 -0
  76. package/bin/pact/invoker/bureaus/index.js +36 -0
  77. package/bin/pact/invoker/bureaus/index.js.map +1 -0
  78. package/bin/pact/invoker/cities/types.d.ts +2 -2
  79. package/bin/pact/invoker/cities/types.d.ts.map +1 -1
  80. package/bin/pact/invoker/user/index.d.ts +19 -0
  81. package/bin/pact/invoker/user/index.d.ts.map +1 -0
  82. package/bin/pact/invoker/user/index.js +24 -0
  83. package/bin/pact/invoker/user/index.js.map +1 -0
  84. package/bin/pact/user/index.d.ts +2 -1
  85. package/bin/pact/user/index.d.ts.map +1 -1
  86. package/bin/pact/user/index.js +7 -3
  87. package/bin/pact/user/index.js.map +1 -1
  88. package/bin/pact/user/types.d.ts +11 -6
  89. package/bin/pact/user/types.d.ts.map +1 -1
  90. package/bin/service/ai/AIChannel.d.ts +57 -0
  91. package/bin/service/ai/AIChannel.d.ts.map +1 -0
  92. package/bin/service/ai/AIChannel.js +151 -0
  93. package/bin/service/ai/AIChannel.js.map +1 -0
  94. package/bin/service/ai/OpenAIChatCompletionsAdapter.d.ts +23 -0
  95. package/bin/service/ai/OpenAIChatCompletionsAdapter.d.ts.map +1 -0
  96. package/bin/service/ai/OpenAIChatCompletionsAdapter.js +503 -0
  97. package/bin/service/ai/OpenAIChatCompletionsAdapter.js.map +1 -0
  98. package/bin/service/ai/ai-service-values.d.ts +16 -19
  99. package/bin/service/ai/ai-service-values.d.ts.map +1 -1
  100. package/bin/service/ai/ai-service-values.js +9 -13
  101. package/bin/service/ai/ai-service-values.js.map +1 -1
  102. package/bin/service/ai/ai-service.d.ts +16 -15
  103. package/bin/service/ai/ai-service.d.ts.map +1 -1
  104. package/bin/service/ai/ai-service.js +97 -106
  105. package/bin/service/ai/ai-service.js.map +1 -1
  106. package/bin/service/ai/helpers.d.ts +8 -35
  107. package/bin/service/ai/helpers.d.ts.map +1 -1
  108. package/bin/service/ai/helpers.js +8 -140
  109. package/bin/service/ai/helpers.js.map +1 -1
  110. package/bin/service/ai/image-job-store.d.ts +2 -3
  111. package/bin/service/ai/image-job-store.d.ts.map +1 -1
  112. package/bin/service/ai/image-job-store.js.map +1 -1
  113. package/bin/service/ai/language-model-stream.d.ts +9 -4
  114. package/bin/service/ai/language-model-stream.d.ts.map +1 -1
  115. package/bin/service/ai/language-model-stream.js +8 -4
  116. package/bin/service/ai/language-model-stream.js.map +1 -1
  117. package/bin/service/ai/language-model-text.d.ts +15 -0
  118. package/bin/service/ai/language-model-text.d.ts.map +1 -0
  119. package/bin/service/ai/language-model-text.js +67 -0
  120. package/bin/service/ai/language-model-text.js.map +1 -0
  121. package/bin/service/ai/model-context-window.d.ts +2 -2
  122. package/bin/service/ai/model-context-window.d.ts.map +1 -1
  123. package/bin/service/ai/model-context-window.js.map +1 -1
  124. package/bin/service/ai/model-registry.d.ts +9 -8
  125. package/bin/service/ai/model-registry.d.ts.map +1 -1
  126. package/bin/service/ai/model-registry.js +1 -5
  127. package/bin/service/ai/model-registry.js.map +1 -1
  128. package/bin/service/ai/model-routing.d.ts +1 -1
  129. package/bin/service/ai/model-routing.d.ts.map +1 -1
  130. package/bin/service/ai/model-routing.js +1 -1
  131. package/bin/service/ai/model-routing.js.map +1 -1
  132. package/bin/service/ai/reasoning.d.ts +4 -4
  133. package/bin/service/ai/reasoning.d.ts.map +1 -1
  134. package/bin/service/ai/reasoning.js.map +1 -1
  135. package/bin/service/bureaus/bureaus-service.d.ts +15 -0
  136. package/bin/service/bureaus/bureaus-service.d.ts.map +1 -0
  137. package/bin/service/bureaus/bureaus-service.js +55 -0
  138. package/bin/service/bureaus/bureaus-service.js.map +1 -0
  139. package/bin/service/installable-service.d.ts +5 -2
  140. package/bin/service/installable-service.d.ts.map +1 -1
  141. package/bin/service/installable-service.js +1 -0
  142. package/bin/service/installable-service.js.map +1 -1
  143. package/bin/service/instruction.js +1 -1
  144. package/bin/service/instruction.js.map +1 -1
  145. package/bin/service/service.d.ts +15 -2
  146. package/bin/service/service.d.ts.map +1 -1
  147. package/bin/service/service.js +2 -0
  148. package/bin/service/service.js.map +1 -1
  149. package/bin/types/AI.d.ts +289 -0
  150. package/bin/types/AI.d.ts.map +1 -0
  151. package/bin/types/AI.js +8 -0
  152. package/bin/types/AI.js.map +1 -0
  153. package/bin/types/AITransport.d.ts +251 -0
  154. package/bin/types/AITransport.d.ts.map +1 -0
  155. package/bin/types/AITransport.js +12 -0
  156. package/bin/types/AITransport.js.map +1 -0
  157. package/bin/types/Bureau.d.ts +96 -0
  158. package/bin/types/Bureau.d.ts.map +1 -0
  159. package/bin/types/Bureau.js +8 -0
  160. package/bin/types/Bureau.js.map +1 -0
  161. package/bin/types/FederationAdmin.d.ts +16 -0
  162. package/bin/types/FederationAdmin.d.ts.map +1 -0
  163. package/bin/types/FederationAdmin.js +7 -0
  164. package/bin/types/FederationAdmin.js.map +1 -0
  165. package/bin/types/Metering.d.ts +2 -2
  166. package/bin/types/Metering.d.ts.map +1 -1
  167. package/bin/types/User.d.ts +24 -0
  168. package/bin/types/User.d.ts.map +1 -0
  169. package/bin/types/User.js +8 -0
  170. package/bin/types/User.js.map +1 -0
  171. package/bin/utils/CityLanguageModelCodec.d.ts +1 -1
  172. package/bin/utils/CityLanguageModelCodec.d.ts.map +1 -1
  173. package/bin/utils/CityLanguageModelResult.d.ts +11 -0
  174. package/bin/utils/CityLanguageModelResult.d.ts.map +1 -0
  175. package/bin/utils/CityLanguageModelResult.js +76 -0
  176. package/bin/utils/CityLanguageModelResult.js.map +1 -0
  177. package/package.json +4 -3
  178. package/bin/federation/auth/token-signer.d.ts +0 -27
  179. package/bin/federation/auth/token-signer.d.ts.map +0 -1
  180. package/bin/federation/auth/token-signer.js +0 -116
  181. package/bin/federation/auth/token-signer.js.map +0 -1
  182. package/bin/service/ai/charge.d.ts +0 -76
  183. package/bin/service/ai/charge.d.ts.map +0 -1
  184. package/bin/service/ai/charge.js +0 -10
  185. package/bin/service/ai/charge.js.map +0 -1
  186. package/bin/service/ai/job-types.d.ts +0 -69
  187. package/bin/service/ai/job-types.d.ts.map +0 -1
  188. package/bin/service/ai/job-types.js +0 -9
  189. package/bin/service/ai/job-types.js.map +0 -1
  190. package/bin/service/ai/provider.d.ts +0 -143
  191. package/bin/service/ai/provider.d.ts.map +0 -1
  192. package/bin/service/ai/provider.js +0 -221
  193. package/bin/service/ai/provider.js.map +0 -1
  194. package/bin/service/ai/types.d.ts +0 -174
  195. package/bin/service/ai/types.d.ts.map +0 -1
  196. package/bin/service/ai/types.js +0 -7
  197. package/bin/service/ai/types.js.map +0 -1
  198. package/bin/types/AIImageJobClaim.d.ts +0 -14
  199. package/bin/types/AIImageJobClaim.d.ts.map +0 -1
  200. package/bin/types/AIImageJobClaim.js +0 -7
  201. package/bin/types/AIImageJobClaim.js.map +0 -1
  202. package/bin/types/AIReasoning.d.ts +0 -25
  203. package/bin/types/AIReasoning.d.ts.map +0 -1
  204. package/bin/types/AIReasoning.js +0 -7
  205. package/bin/types/AIReasoning.js.map +0 -1
  206. package/bin/types/AIRouting.d.ts +0 -37
  207. package/bin/types/AIRouting.d.ts.map +0 -1
  208. package/bin/types/AIRouting.js +0 -7
  209. package/bin/types/AIRouting.js.map +0 -1
  210. package/bin/types/CityLanguageModelRuntime.d.ts +0 -46
  211. package/bin/types/CityLanguageModelRuntime.d.ts.map +0 -1
  212. package/bin/types/CityLanguageModelRuntime.js +0 -8
  213. package/bin/types/CityLanguageModelRuntime.js.map +0 -1
  214. package/bin/types/CityLanguageModelTransport.d.ts +0 -49
  215. package/bin/types/CityLanguageModelTransport.d.ts.map +0 -1
  216. package/bin/types/CityLanguageModelTransport.js +0 -9
  217. package/bin/types/CityLanguageModelTransport.js.map +0 -1
  218. package/bin/types/CityModelRuntime.d.ts +0 -17
  219. package/bin/types/CityModelRuntime.d.ts.map +0 -1
  220. package/bin/types/CityModelRuntime.js +0 -8
  221. package/bin/types/CityModelRuntime.js.map +0 -1
@@ -1,126 +1,42 @@
1
1
  /**
2
- * City 客户端统一访问入口。
2
+ * City 终端用户客户端。
3
3
  *
4
- * City 面向开发者表达“我以某种角色进入 Federation”,内部再委托给
5
- * admin / user 协议访问层(`pact/`),让用户在第一层概念上无需关心 client 拆分。
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
- /**
10
- * Downcity City 客户端。
11
- */
8
+ /** Downcity City 用户客户端。 */
12
9
  export class City {
13
- /**
14
- * 当前 City 客户端的访问角色。
15
- */
16
- role;
17
- /**
18
- * Admin 能力面。
19
- *
20
- * 仅 `role: "admin"` 时可用。
21
- */
22
- admin_access;
23
- /**
24
- * User 能力面。
25
- *
26
- * 仅 `role: "user"` 时可用。
27
- */
28
10
  user_access;
29
11
  constructor(options) {
30
12
  if (!options || typeof options !== "object") {
31
13
  throw new TypeError("City options are required");
32
14
  }
33
- this.role = options.role;
34
- if (options.role === "admin") {
35
- this.admin_access = new AdminPactAccess({
36
- base_url: options.federation_url,
37
- city_id: options.city_id,
38
- admin_secret_key: options.admin_secret_key,
39
- fetch: options.fetch,
40
- });
41
- return;
42
- }
43
15
  this.user_access = new UserPactAccess({
44
16
  base_url: options.federation_url,
45
- city_id: options.city_id,
46
17
  user_token: options.user_token,
47
18
  fetch: options.fetch,
48
19
  });
49
20
  }
50
- /**
51
- * User 角色的 AI 调用入口。
52
- */
21
+ /** 用户侧 AI 调用入口。 */
53
22
  get ai() {
54
- return this.require_user().ai;
23
+ return this.user_access.ai;
55
24
  }
56
- /**
57
- * User 角色的支付入口。
58
- */
25
+ /** 用户侧支付入口。 */
59
26
  get payment() {
60
- return this.require_user().payment;
61
- }
62
- /**
63
- * Admin 角色的余额服务入口。
64
- */
65
- get balance() {
66
- return this.require_admin().balance;
67
- }
68
- /**
69
- * Admin 角色的 City 管理入口。
70
- */
71
- get cities() {
72
- return this.require_admin().cities;
73
- }
74
- /**
75
- * Admin 角色的环境变量服务入口。
76
- */
77
- get env() {
78
- return this.require_admin().env;
27
+ return this.user_access.payment;
79
28
  }
80
- /**
81
- * Token 管理入口。
82
- *
83
- * 不需要传 city_id,构造时传入的 city_id 会自动注入。
84
- */
85
- get tokens() {
86
- const admin = this.require_admin();
87
- return { apply: (input) => admin.applyToken(input) };
29
+ /** Federation 当前用户数据入口。 */
30
+ user() {
31
+ return this.user_access.user;
88
32
  }
89
- /**
90
- * 获取普通 service 调用器。
91
- */
33
+ /** 获取普通 Service 调用器。 */
92
34
  service(name) {
93
- return this.admin_access?.service(name) ?? this.require_user().service(name);
35
+ return this.user_access.service(name);
94
36
  }
95
- /**
96
- * 列出当前 Federation 暴露的 service。
97
- */
37
+ /** 列出 Federation 暴露的 Service。 */
98
38
  listServices() {
99
- return this.admin_access?.listServices() ?? this.require_user().listServices();
100
- }
101
- /**
102
- * 列出 Federation 模型目录。
103
- */
104
- listModels() {
105
- return this.require_admin().listModels();
106
- }
107
- /**
108
- * 读取 Federation 聚合说明文档。
109
- */
110
- instruction() {
111
- return this.require_admin().instruction();
112
- }
113
- require_admin() {
114
- if (!this.admin_access) {
115
- throw new TypeError("City role admin is required for this operation");
116
- }
117
- return this.admin_access;
118
- }
119
- require_user() {
120
- if (!this.user_access) {
121
- throw new TypeError("City role user is required for this operation");
122
- }
123
- return this.user_access;
39
+ return this.user_access.listServices();
124
40
  }
125
41
  }
126
42
  //# sourceMappingURL=city.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"city.js","sourceRoot":"","sources":["../../src/client/city.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"city.js","sourceRoot":"","sources":["../../src/client/city.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAKvD,2BAA2B;AAC3B,MAAM,OAAO,IAAI;IACE,WAAW,CAAiB;IAE7C,YAAY,OAAoB;QAC9B,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;YAC5C,MAAM,IAAI,SAAS,CAAC,2BAA2B,CAAC,CAAC;QACnD,CAAC;QACD,IAAI,CAAC,WAAW,GAAG,IAAI,cAAc,CAAC;YACpC,QAAQ,EAAE,OAAO,CAAC,cAAc;YAChC,UAAU,EAAE,OAAO,CAAC,UAAU;YAC9B,KAAK,EAAE,OAAO,CAAC,KAAK;SACrB,CAAC,CAAC;IACL,CAAC;IAED,mBAAmB;IACnB,IAAI,EAAE;QACJ,OAAO,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;IAC7B,CAAC;IAED,eAAe;IACf,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC;IAClC,CAAC;IAED,2BAA2B;IAC3B,IAAI;QACF,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;IAC/B,CAAC;IAED,wBAAwB;IACxB,OAAO,CAAC,IAAY;QAClB,OAAO,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IAED,iCAAiC;IACjC,YAAY;QACV,OAAO,IAAI,CAAC,WAAW,CAAC,YAAY,EAAE,CAAC;IACzC,CAAC;CACF"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Federation 全局控制面客户端。
3
+ *
4
+ * 该客户端承载 env、City、余额、模型和 Service 管理能力,不参与终端用户
5
+ * 或 Bureau 产品后端的请求链路。
6
+ */
7
+ import { AdminPactAccess } from "../pact/admin/index.js";
8
+ import type { ServiceClient } from "../pact/invoker/invoker.js";
9
+ import type { AdminModelRecord, AdminServiceSummary } from "../pact/admin/types.js";
10
+ import type { FederationAdminOptions } from "../types/FederationAdmin.js";
11
+ /** Federation 全局控制面客户端。 */
12
+ export declare class FederationAdmin {
13
+ private readonly admin_access;
14
+ constructor(options: FederationAdminOptions);
15
+ /** Federation 余额管理入口。 */
16
+ get balance(): AdminPactAccess["balance"];
17
+ /** Federation City 管理入口。 */
18
+ get cities(): AdminPactAccess["cities"];
19
+ /** Federation Bureau 注册表管理入口。 */
20
+ get bureaus(): AdminPactAccess["bureaus"];
21
+ /** Federation 环境变量管理入口。 */
22
+ get env(): AdminPactAccess["env"];
23
+ /** 获取管理身份下的 Service 调用器。 */
24
+ service(name: string): ServiceClient;
25
+ /** 列出 Federation 暴露的 Service。 */
26
+ listServices(): Promise<AdminServiceSummary[]>;
27
+ /** 列出 Federation 模型目录及管理状态。 */
28
+ listModels(): Promise<AdminModelRecord[]>;
29
+ /** 读取 Federation 聚合说明文档。 */
30
+ instruction(): Promise<string>;
31
+ }
32
+ //# sourceMappingURL=federation-admin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"federation-admin.d.ts","sourceRoot":"","sources":["../../src/client/federation-admin.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,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,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAE1E,2BAA2B;AAC3B,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAkB;gBAEnC,OAAO,EAAE,sBAAsB;IAW3C,yBAAyB;IACzB,IAAI,OAAO,IAAI,eAAe,CAAC,SAAS,CAAC,CAExC;IAED,4BAA4B;IAC5B,IAAI,MAAM,IAAI,eAAe,CAAC,QAAQ,CAAC,CAEtC;IAED,iCAAiC;IACjC,IAAI,OAAO,IAAI,eAAe,CAAC,SAAS,CAAC,CAExC;IAED,2BAA2B;IAC3B,IAAI,GAAG,IAAI,eAAe,CAAC,KAAK,CAAC,CAEhC;IAED,4BAA4B;IAC5B,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;CAG/B"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Federation 全局控制面客户端。
3
+ *
4
+ * 该客户端承载 env、City、余额、模型和 Service 管理能力,不参与终端用户
5
+ * 或 Bureau 产品后端的请求链路。
6
+ */
7
+ import { AdminPactAccess } from "../pact/admin/index.js";
8
+ /** Federation 全局控制面客户端。 */
9
+ export class FederationAdmin {
10
+ admin_access;
11
+ constructor(options) {
12
+ if (!options || typeof options !== "object") {
13
+ throw new TypeError("FederationAdmin options are required");
14
+ }
15
+ this.admin_access = new AdminPactAccess({
16
+ base_url: options.federation_url,
17
+ admin_secret_key: options.admin_secret_key,
18
+ fetch: options.fetch,
19
+ });
20
+ }
21
+ /** Federation 余额管理入口。 */
22
+ get balance() {
23
+ return this.admin_access.balance;
24
+ }
25
+ /** Federation City 管理入口。 */
26
+ get cities() {
27
+ return this.admin_access.cities;
28
+ }
29
+ /** Federation Bureau 注册表管理入口。 */
30
+ get bureaus() {
31
+ return this.admin_access.bureaus;
32
+ }
33
+ /** Federation 环境变量管理入口。 */
34
+ get env() {
35
+ return this.admin_access.env;
36
+ }
37
+ /** 获取管理身份下的 Service 调用器。 */
38
+ service(name) {
39
+ return this.admin_access.service(name);
40
+ }
41
+ /** 列出 Federation 暴露的 Service。 */
42
+ listServices() {
43
+ return this.admin_access.listServices();
44
+ }
45
+ /** 列出 Federation 模型目录及管理状态。 */
46
+ listModels() {
47
+ return this.admin_access.listModels();
48
+ }
49
+ /** 读取 Federation 聚合说明文档。 */
50
+ instruction() {
51
+ return this.admin_access.instruction();
52
+ }
53
+ }
54
+ //# sourceMappingURL=federation-admin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"federation-admin.js","sourceRoot":"","sources":["../../src/client/federation-admin.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAKzD,2BAA2B;AAC3B,MAAM,OAAO,eAAe;IACT,YAAY,CAAkB;IAE/C,YAAY,OAA+B;QACzC,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;YAC5C,MAAM,IAAI,SAAS,CAAC,sCAAsC,CAAC,CAAC;QAC9D,CAAC;QACD,IAAI,CAAC,YAAY,GAAG,IAAI,eAAe,CAAC;YACtC,QAAQ,EAAE,OAAO,CAAC,cAAc;YAChC,gBAAgB,EAAE,OAAO,CAAC,gBAAgB;YAC1C,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,iCAAiC;IACjC,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,4BAA4B;IAC5B,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;CACF"}
@@ -1,81 +1,21 @@
1
1
  /**
2
- * City 客户端构造类型模块。
2
+ * City 用户客户端构造类型模块。
3
3
  *
4
- * City 是访问 Federation 的统一客户端入口:开发者只需要声明访问角色,
5
- * SDK 会在内部选择 admin user 能力面。底层 HTTP 协议实现位于 `pact/`。
4
+ * City 只表达终端用户访问 Federation。已登录身份和 city_id 均来自 user_token,
5
+ * Bureau 是可选产品后端,Federation 控制面由 FederationAdmin 独立提供。
6
6
  */
7
7
  import type { FetchLike } from "../pact/http.js";
8
- /**
9
- * City 访问角色。
10
- */
11
- export type CityRole = "admin" | "user";
12
- /**
13
- * City 客户端共享构造参数。
14
- */
15
- export interface CityBaseOptions {
16
- /**
17
- * Federation 的 HTTP 入口地址。
18
- *
19
- * 示例:`https://city.example.com`、`http://localhost:43127`
20
- * 或本机 loopback HTTP:`http://127.0.0.1:15315`。
21
- */
8
+ /** City 用户客户端构造参数。 */
9
+ export interface CityOptions {
10
+ /** Federation 的 HTTP 入口地址。 */
22
11
  federation_url: string;
23
12
  /**
24
- * 自定义 fetch 实现。
25
- *
26
- * 主要用于测试、Worker 运行时适配,或在请求层注入日志与追踪。
27
- */
28
- fetch?: FetchLike;
29
- }
30
- /**
31
- * Admin 角色的 City 构造参数。
32
- */
33
- export interface AdminCityOptions extends CityBaseOptions {
34
- /**
35
- * 使用 admin 身份访问 Federation。
36
- */
37
- role: "admin";
38
- /**
39
- * 当前管理的 City ID。
13
+ * Federation 签发的终端用户 token。
40
14
  *
41
- * token 签发等服务会自动使用该 ID,调用方无需再传 city_id。
42
- */
43
- city_id: string;
44
- /**
45
- * Federation 管理密钥。
46
- *
47
- * 未传入时会由 SDK 回退读取 `DOWNCITY_FEDERATION_ADMIN_SECRET_KEY`。
48
- */
49
- admin_secret_key?: string;
50
- }
51
- /**
52
- * User 角色的 City 构造参数。
53
- */
54
- export interface UserCityOptions extends CityBaseOptions {
55
- /**
56
- * 使用 user 身份访问 Federation。
57
- */
58
- role: "user";
59
- /**
60
- * 当前 user_token 绑定的 City ID。
61
- *
62
- * 普通 service action 调用会自动把该值注入为 `city_id`。
63
- * AI 调用会优先使用 `user_token` 解析出的 City 身份。
64
- */
65
- city_id?: string;
66
- /**
67
- * 终端用户访问 token。
68
- *
69
- * 仅访问 public action(例如 accounts 本地登录)时可以暂不传。
15
+ * 访问 accounts 登录等公开 Action 时可以省略;受保护操作必须提供。
70
16
  */
71
17
  user_token?: string;
18
+ /** 自定义 fetch 实现。 */
19
+ fetch?: FetchLike;
72
20
  }
73
- /**
74
- * City 构造参数。
75
- */
76
- export type CityOptions = AdminCityOptions | UserCityOptions;
77
- /**
78
- * 按角色收窄后的 City 构造参数。
79
- */
80
- export type CityOptionsForRole<TRole extends CityRole> = TRole extends "admin" ? AdminCityOptions : UserCityOptions;
81
21
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/client/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,CAAC;AAExC;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;OAKG;IACH,cAAc,EAAE,MAAM,CAAC;IAEvB;;;;OAIG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAiB,SAAQ,eAAe;IACvD;;OAEG;IACH,IAAI,EAAE,OAAO,CAAC;IAEd;;;;OAIG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,eAAgB,SAAQ,eAAe;IACtD;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,gBAAgB,GAAG,eAAe,CAAC;AAE7D;;GAEG;AACH,MAAM,MAAM,kBAAkB,CAAC,KAAK,SAAS,QAAQ,IAAI,KAAK,SAAS,OAAO,GAC1E,gBAAgB,GAChB,eAAe,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/client/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,sBAAsB;AACtB,MAAM,WAAW,WAAW;IAC1B,8BAA8B;IAC9B,cAAc,EAAE,MAAM,CAAC;IAEvB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,oBAAoB;IACpB,KAAK,CAAC,EAAE,SAAS,CAAC;CACnB"}
@@ -1,8 +1,8 @@
1
1
  /**
2
- * City 客户端构造类型模块。
2
+ * City 用户客户端构造类型模块。
3
3
  *
4
- * City 是访问 Federation 的统一客户端入口:开发者只需要声明访问角色,
5
- * SDK 会在内部选择 admin user 能力面。底层 HTTP 协议实现位于 `pact/`。
4
+ * City 只表达终端用户访问 Federation。已登录身份和 city_id 均来自 user_token,
5
+ * Bureau 是可选产品后端,Federation 控制面由 FederationAdmin 独立提供。
6
6
  */
7
7
  export {};
8
8
  //# sourceMappingURL=types.js.map
@@ -1,14 +1,17 @@
1
1
  /**
2
2
  * 统一鉴权模块。
3
3
  *
4
- * Authenticator 统一处理 admin(secret key)和 user(JWT token)两种鉴权方式。
4
+ * Authenticator 统一处理 admin(secret key)、bureau(不透明部署凭证)和
5
+ * user(Ed25519 JWT)三种鉴权方式。
5
6
  * 所有鉴权失败统一抛出 httpError(ErrorWithStatus)。
6
- *
7
- * TokenSigner 实例通过 getSigner() 缓存,避免重复 new TokenSigner(key)。
8
7
  */
9
8
  import { type RouteAuth, type RouteIdentity } from "../../service/service.js";
10
9
  import type { EnvProvider } from "../runtime.js";
11
- import type { CreateUserTokenInput, UserTokenPayload, UserTokenIssueResult, RuntimeUser } from "./types.js";
10
+ import { type UserTokenAuthority } from "./user-token-authority.js";
11
+ import type { FederationKeyStore } from "./federation-key-store.js";
12
+ import type { BureauTokenStore } from "./bureau-token-store.js";
13
+ import type { CreateUserTokenInput, FederationDiscovery, FederationJwks, UserTokenPayload, UserTokenIssueResult, RuntimeUser } from "./types.js";
14
+ import type { RuntimeBureau } from "../../types/Bureau.js";
12
15
  import type { FederationTrustedIdentity } from "../types.js";
13
16
  /** 鉴权级别 */
14
17
  /** 鉴权结果 */
@@ -22,13 +25,16 @@ export interface AuthResult {
22
25
  city_id: string;
23
26
  status: string;
24
27
  };
28
+ /** 解析出的 Bureau 信息(bureau token 时可用)。 */
29
+ bureau?: RuntimeBureau;
25
30
  }
26
31
  /** 统一鉴权器 */
27
32
  export declare class Authenticator {
28
33
  private env;
29
34
  private store;
30
- /** 缓存的 TokenSigner 实例 */
31
- private tokenSigner?;
35
+ private readonly token_authority;
36
+ private readonly key_store;
37
+ private readonly bureau_token_store;
32
38
  constructor(env: EnvProvider, store: () => Promise<{
33
39
  city: {
34
40
  get(id: string): Promise<{
@@ -36,13 +42,7 @@ export declare class Authenticator {
36
42
  status: string;
37
43
  } | undefined>;
38
44
  };
39
- }>);
40
- /**
41
- * 获取(或创建)TokenSigner 单例。
42
- *
43
- * 首次调用时从 env 读取 DOWNCITY_FEDERATION_TOKEN_SIGNING_KEY 创建实例并缓存。
44
- */
45
- private getSigner;
45
+ }>, token_authority: UserTokenAuthority, key_store: FederationKeyStore, bureau_token_store: BureauTokenStore);
46
46
  /**
47
47
  * 解析请求身份。
48
48
  *
@@ -84,5 +84,9 @@ export declare class Authenticator {
84
84
  * @returns 解析出的 token 载荷
85
85
  */
86
86
  verifyToken(token: string): Promise<UserTokenPayload>;
87
+ /** 返回 Federation 当前可公开使用的 JWKS。 */
88
+ get_public_jwks(): Promise<FederationJwks>;
89
+ /** 根据当前请求 origin 生成 Federation 发现信息。 */
90
+ get_discovery(origin: string): FederationDiscovery;
87
91
  }
88
92
  //# sourceMappingURL=authenticator.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"authenticator.d.ts","sourceRoot":"","sources":["../../../src/federation/auth/authenticator.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,EAAsB,KAAK,SAAS,EAAE,KAAK,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAClG,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD,OAAO,KAAK,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC5G,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAE7D,WAAW;AACX,WAAW;AACX,MAAM,WAAW,UAAU;IACzB,eAAe;IACf,KAAK,EAAE,aAAa,CAAC;IACrB,2BAA2B;IAC3B,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,+BAA+B;IAC/B,IAAI,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAC5C;AAED,YAAY;AACZ,qBAAa,aAAa;IAKtB,OAAO,CAAC,GAAG;IACX,OAAO,CAAC,KAAK;IALf,yBAAyB;IACzB,OAAO,CAAC,WAAW,CAAC,CAAc;gBAGxB,GAAG,EAAE,WAAW,EAChB,KAAK,EAAE,MAAM,OAAO,CAAC;QAAE,IAAI,EAAE;YAAE,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC;gBAAE,OAAO,EAAE,MAAM,CAAC;gBAAC,MAAM,EAAE,MAAM,CAAA;aAAE,GAAG,SAAS,CAAC,CAAA;SAAE,CAAA;KAAE,CAAC;IAGvH;;;;OAIG;IACH,OAAO,CAAC,SAAS;IASjB;;;;;OAKG;IACG,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC;IA0BpD;;;;;;OAMG;IACH,cAAc,CAAC,QAAQ,EAAE,yBAAyB,GAAG,UAAU;IAW/D;;;;;;OAMG;IACH,SAAS,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,SAAS,GAAG,UAAU;IAY/D;;OAEG;IACG,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC;IAI/E;;;;;OAKG;IACG,WAAW,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAiB7E;;;;;OAKG;IACG,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;CAG5D"}
1
+ {"version":3,"file":"authenticator.d.ts","sourceRoot":"","sources":["../../../src/federation/auth/authenticator.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAsB,KAAK,SAAS,EAAE,KAAK,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAClG,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAwB,KAAK,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC1F,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,OAAO,KAAK,EACV,oBAAoB,EACpB,mBAAmB,EACnB,cAAc,EACd,gBAAgB,EAChB,oBAAoB,EACpB,WAAW,EACZ,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAE7D,WAAW;AACX,WAAW;AACX,MAAM,WAAW,UAAU;IACzB,eAAe;IACf,KAAK,EAAE,aAAa,CAAC;IACrB,2BAA2B;IAC3B,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,+BAA+B;IAC/B,IAAI,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3C,wCAAwC;IACxC,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB;AAED,YAAY;AACZ,qBAAa,aAAa;IAEtB,OAAO,CAAC,GAAG;IACX,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,kBAAkB;gBAJ3B,GAAG,EAAE,WAAW,EAChB,KAAK,EAAE,MAAM,OAAO,CAAC;QAAE,IAAI,EAAE;YAAE,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC;gBAAE,OAAO,EAAE,MAAM,CAAC;gBAAC,MAAM,EAAE,MAAM,CAAA;aAAE,GAAG,SAAS,CAAC,CAAA;SAAE,CAAA;KAAE,CAAC,EACpG,eAAe,EAAE,kBAAkB,EACnC,SAAS,EAAE,kBAAkB,EAC7B,kBAAkB,EAAE,gBAAgB;IAGvD;;;;;OAKG;IACG,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC;IAkCpD;;;;;;OAMG;IACH,cAAc,CAAC,QAAQ,EAAE,yBAAyB,GAAG,UAAU;IAW/D;;;;;;OAMG;IACH,SAAS,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,SAAS,GAAG,UAAU;IAY/D;;OAEG;IACG,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC;IAI/E;;;;;OAKG;IACG,WAAW,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAgB7E;;;;;OAKG;IACG,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAI3D,mCAAmC;IACnC,eAAe,IAAI,OAAO,CAAC,cAAc,CAAC;IAI1C,wCAAwC;IACxC,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,mBAAmB;CASnD"}
@@ -1,37 +1,26 @@
1
1
  /**
2
2
  * 统一鉴权模块。
3
3
  *
4
- * Authenticator 统一处理 admin(secret key)和 user(JWT token)两种鉴权方式。
4
+ * Authenticator 统一处理 admin(secret key)、bureau(不透明部署凭证)和
5
+ * user(Ed25519 JWT)三种鉴权方式。
5
6
  * 所有鉴权失败统一抛出 httpError(ErrorWithStatus)。
6
- *
7
- * TokenSigner 实例通过 getSigner() 缓存,避免重复 new TokenSigner(key)。
8
7
  */
9
8
  import { bearerToken, httpError } from "../../utils/helpers.js";
10
- import { TokenSigner } from "./token-signer.js";
11
9
  import { normalizeRouteAuth } from "../../service/service.js";
10
+ import { parse_user_token_ttl } from "./user-token-authority.js";
12
11
  /** 统一鉴权器 */
13
12
  export class Authenticator {
14
13
  env;
15
14
  store;
16
- /** 缓存的 TokenSigner 实例 */
17
- tokenSigner;
18
- constructor(env, store) {
15
+ token_authority;
16
+ key_store;
17
+ bureau_token_store;
18
+ constructor(env, store, token_authority, key_store, bureau_token_store) {
19
19
  this.env = env;
20
20
  this.store = store;
21
- }
22
- /**
23
- * 获取(或创建)TokenSigner 单例。
24
- *
25
- * 首次调用时从 env 读取 DOWNCITY_FEDERATION_TOKEN_SIGNING_KEY 创建实例并缓存。
26
- */
27
- getSigner() {
28
- if (!this.tokenSigner) {
29
- const signingKey = this.env.get("DOWNCITY_FEDERATION_TOKEN_SIGNING_KEY");
30
- if (!signingKey)
31
- throw new Error("DOWNCITY_FEDERATION_TOKEN_SIGNING_KEY is required");
32
- this.tokenSigner = new TokenSigner(signingKey);
33
- }
34
- return this.tokenSigner;
21
+ this.token_authority = token_authority;
22
+ this.key_store = key_store;
23
+ this.bureau_token_store = bureau_token_store;
35
24
  }
36
25
  /**
37
26
  * 解析请求身份。
@@ -47,8 +36,16 @@ export class Authenticator {
47
36
  if (adminKey && token === adminKey) {
48
37
  return { level: "admin" };
49
38
  }
39
+ const bureau = await this.bureau_token_store.resolve(token);
40
+ if (bureau) {
41
+ const store = await this.store();
42
+ const city = await store.city.get(bureau.city_id);
43
+ if (!city || city.status !== "active")
44
+ return { level: "guest" };
45
+ return { level: "bureau", bureau, city };
46
+ }
50
47
  try {
51
- const payload = await this.getSigner().verify(token);
48
+ const payload = await this.token_authority.verify(token);
52
49
  const store = await this.store();
53
50
  const city = await store.city.get(payload.city_id);
54
51
  if (!city)
@@ -119,14 +116,13 @@ export class Authenticator {
119
116
  throw httpError(404, `Unknown city: ${input.city_id}`);
120
117
  if (city.status !== "active")
121
118
  throw httpError(403, `City is not active: ${input.city_id}`);
122
- const user_token = await this.getSigner().sign(input);
119
+ const ttl_seconds = parse_user_token_ttl(input.ttl);
120
+ const user_token = await this.token_authority.sign(input);
123
121
  return {
124
122
  user_token,
125
123
  city_id: input.city_id,
126
124
  user_id: input.user_id,
127
- ...(input.ttl
128
- ? { expires_at: new Date(Date.now() + TokenSigner.parseTTL(input.ttl) * 1000).toISOString() }
129
- : {}),
125
+ expires_at: new Date(Date.now() + ttl_seconds * 1000).toISOString(),
130
126
  };
131
127
  }
132
128
  /**
@@ -136,7 +132,22 @@ export class Authenticator {
136
132
  * @returns 解析出的 token 载荷
137
133
  */
138
134
  async verifyToken(token) {
139
- return this.getSigner().verify(token);
135
+ return this.token_authority.verify(token);
136
+ }
137
+ /** 返回 Federation 当前可公开使用的 JWKS。 */
138
+ get_public_jwks() {
139
+ return this.key_store.get_public_jwks();
140
+ }
141
+ /** 根据当前请求 origin 生成 Federation 发现信息。 */
142
+ get_discovery(origin) {
143
+ const federation_id = this.env.get("DOWNCITY_FEDERATION_ID");
144
+ if (!federation_id)
145
+ throw new Error("DOWNCITY_FEDERATION_ID is required");
146
+ return {
147
+ issuer: `urn:downcity:federation:${federation_id}`,
148
+ jwks_uri: `${origin.replace(/\/+$/, "")}/.well-known/jwks.json`,
149
+ user_token_audience: "downcity:user",
150
+ };
140
151
  }
141
152
  }
142
153
  //# sourceMappingURL=authenticator.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"authenticator.js","sourceRoot":"","sources":["../../../src/federation/auth/authenticator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"authenticator.js","sourceRoot":"","sources":["../../../src/federation/auth/authenticator.ts"],"names":[],"mappings":"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"}