@downcity/city 0.2.205 → 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 (118) hide show
  1. package/README.md +63 -5
  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 +8 -3
  59. package/bin/index.d.ts.map +1 -1
  60. package/bin/index.js +3 -1
  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/bureaus/index.d.ts +25 -0
  69. package/bin/pact/invoker/bureaus/index.d.ts.map +1 -0
  70. package/bin/pact/invoker/bureaus/index.js +36 -0
  71. package/bin/pact/invoker/bureaus/index.js.map +1 -0
  72. package/bin/pact/invoker/cities/types.d.ts +2 -2
  73. package/bin/pact/invoker/cities/types.d.ts.map +1 -1
  74. package/bin/pact/invoker/user/index.d.ts +19 -0
  75. package/bin/pact/invoker/user/index.d.ts.map +1 -0
  76. package/bin/pact/invoker/user/index.js +24 -0
  77. package/bin/pact/invoker/user/index.js.map +1 -0
  78. package/bin/pact/user/index.d.ts +2 -1
  79. package/bin/pact/user/index.d.ts.map +1 -1
  80. package/bin/pact/user/index.js +7 -3
  81. package/bin/pact/user/index.js.map +1 -1
  82. package/bin/pact/user/types.d.ts +0 -2
  83. package/bin/pact/user/types.d.ts.map +1 -1
  84. package/bin/service/ai/ai-service.d.ts +1 -1
  85. package/bin/service/ai/ai-service.d.ts.map +1 -1
  86. package/bin/service/ai/model-registry.d.ts +1 -1
  87. package/bin/service/ai/model-registry.d.ts.map +1 -1
  88. package/bin/service/bureaus/bureaus-service.d.ts +15 -0
  89. package/bin/service/bureaus/bureaus-service.d.ts.map +1 -0
  90. package/bin/service/bureaus/bureaus-service.js +55 -0
  91. package/bin/service/bureaus/bureaus-service.js.map +1 -0
  92. package/bin/service/installable-service.d.ts +5 -2
  93. package/bin/service/installable-service.d.ts.map +1 -1
  94. package/bin/service/installable-service.js +1 -0
  95. package/bin/service/installable-service.js.map +1 -1
  96. package/bin/service/instruction.js +1 -1
  97. package/bin/service/instruction.js.map +1 -1
  98. package/bin/service/service.d.ts +7 -1
  99. package/bin/service/service.d.ts.map +1 -1
  100. package/bin/service/service.js +2 -0
  101. package/bin/service/service.js.map +1 -1
  102. package/bin/types/Bureau.d.ts +96 -0
  103. package/bin/types/Bureau.d.ts.map +1 -0
  104. package/bin/types/Bureau.js +8 -0
  105. package/bin/types/Bureau.js.map +1 -0
  106. package/bin/types/FederationAdmin.d.ts +16 -0
  107. package/bin/types/FederationAdmin.d.ts.map +1 -0
  108. package/bin/types/FederationAdmin.js +7 -0
  109. package/bin/types/FederationAdmin.js.map +1 -0
  110. package/bin/types/User.d.ts +24 -0
  111. package/bin/types/User.d.ts.map +1 -0
  112. package/bin/types/User.js +8 -0
  113. package/bin/types/User.js.map +1 -0
  114. package/package.json +4 -3
  115. package/bin/federation/auth/token-signer.d.ts +0 -27
  116. package/bin/federation/auth/token-signer.d.ts.map +0 -1
  117. package/bin/federation/auth/token-signer.js +0 -116
  118. package/bin/federation/auth/token-signer.js.map +0 -1
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Bureau 公共类型模块。
3
+ *
4
+ * Bureau 是某个 City 部署在独立服务器上的可选后端。它使用 Bureau Token
5
+ * 获取自身 City 上下文,并使用 Federation 公钥在本地验证 user_token。
6
+ */
7
+ /** Bureau 使用的标准 fetch 能力。 */
8
+ export type BureauFetch = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
9
+ /** Bureau Token 可访问的 Federation 服务端能力。 */
10
+ export type BureauCapability = "accounts:read";
11
+ /** Federation 数据库中的 Bureau Token 记录。 */
12
+ export interface BureauTokenRecord extends Record<string, unknown> {
13
+ /** Bureau Token 的公开查找 ID。 */
14
+ token_id: string;
15
+ /** Bureau 所属的唯一 City ID。 */
16
+ city_id: string;
17
+ /** Bureau Token 完整明文的 SHA-256 Base64URL hash。 */
18
+ token_hash: string;
19
+ /** JSON 编码的 Bureau capability 列表。 */
20
+ capabilities: string;
21
+ /** Token 当前状态。 */
22
+ status: "active" | "revoked";
23
+ /** Token 创建时间。 */
24
+ created_at: string;
25
+ /** Token 最后更新时间。 */
26
+ updated_at: string;
27
+ }
28
+ /** 已通过 Federation 验证的 Bureau 服务端身份。 */
29
+ export interface RuntimeBureau {
30
+ /** Bureau Token ID。 */
31
+ token_id: string;
32
+ /** Bureau 所属的唯一 City ID。 */
33
+ city_id: string;
34
+ /** Bureau 被授予的 Federation 能力。 */
35
+ capabilities: BureauCapability[];
36
+ }
37
+ /** Federation 管理端登记 Bureau Token 的输入。 */
38
+ export interface RegisterBureauTokenInput {
39
+ /** CLI 生成的 Bureau Token 查找 ID。 */
40
+ token_id: string;
41
+ /** CLI 对完整 Bureau Token 计算的 SHA-256 Base64URL hash。 */
42
+ token_hash: string;
43
+ /** Bureau 所属的唯一 City ID。 */
44
+ city_id: string;
45
+ /** Bureau capability;默认允许读取用户账户数据。 */
46
+ capabilities?: BureauCapability[];
47
+ }
48
+ /** Federation 服务端列出的 Bureau Token 元数据。 */
49
+ export interface BureauTokenSummary {
50
+ /** Bureau Token 的公开查找 ID。 */
51
+ token_id: string;
52
+ /** Bureau 所属的唯一 City ID。 */
53
+ city_id: string;
54
+ /** Bureau capability。 */
55
+ capabilities: BureauCapability[];
56
+ /** Token 当前状态。 */
57
+ status: "active" | "revoked";
58
+ /** Token 创建时间。 */
59
+ created_at: string;
60
+ /** Token 最后更新时间。 */
61
+ updated_at: string;
62
+ }
63
+ /** Bureau 从 Federation 获取的可信运行上下文。 */
64
+ export interface BureauContext {
65
+ /** Bureau Token ID。 */
66
+ token_id: string;
67
+ /** Bureau 所属的唯一 City ID。 */
68
+ city_id: string;
69
+ /** Bureau 被授予的 Federation 能力。 */
70
+ capabilities: BureauCapability[];
71
+ }
72
+ /** Bureau 构造参数。 */
73
+ export interface BureauOptions {
74
+ /** 预先信任的 Federation HTTP 入口地址。 */
75
+ federation_url: string;
76
+ /** Federation 注册表中属于该 City 后端的 Bureau Token。 */
77
+ bureau_token: string;
78
+ /** 自定义 fetch 实现。 */
79
+ fetch?: BureauFetch;
80
+ /** Federation 上下文与 JWKS 的本地缓存时间,单位毫秒。 */
81
+ jwks_cache_ttl?: number;
82
+ }
83
+ /** Bureau 本地验签后得到的 Federation 用户身份。 */
84
+ export interface BureauIdentity {
85
+ /** Federation 用户 ID,来源于已验证 JWT。 */
86
+ user_id: string;
87
+ /** 与当前 Bureau 注册记录一致的 City ID。 */
88
+ city_id: string;
89
+ /** user_token 中携带的可信业务元数据。 */
90
+ metadata: Record<string, unknown>;
91
+ /** user_token 唯一 ID,来源于 JWT jti。 */
92
+ token_id: string;
93
+ /** user_token 过期时间,Unix 秒。 */
94
+ expires_at: number;
95
+ }
96
+ //# sourceMappingURL=Bureau.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Bureau.d.ts","sourceRoot":"","sources":["../../src/types/Bureau.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,6BAA6B;AAC7B,MAAM,MAAM,WAAW,GAAG,CACxB,KAAK,EAAE,WAAW,GAAG,GAAG,EACxB,IAAI,CAAC,EAAE,WAAW,KACf,OAAO,CAAC,QAAQ,CAAC,CAAC;AAEvB,0CAA0C;AAC1C,MAAM,MAAM,gBAAgB,GAAG,eAAe,CAAC;AAE/C,wCAAwC;AACxC,MAAM,WAAW,iBAAkB,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAChE,6BAA6B;IAC7B,QAAQ,EAAE,MAAM,CAAC;IAEjB,4BAA4B;IAC5B,OAAO,EAAE,MAAM,CAAC;IAEhB,iDAAiD;IACjD,UAAU,EAAE,MAAM,CAAC;IAEnB,qCAAqC;IACrC,YAAY,EAAE,MAAM,CAAC;IAErB,kBAAkB;IAClB,MAAM,EAAE,QAAQ,GAAG,SAAS,CAAC;IAE7B,kBAAkB;IAClB,UAAU,EAAE,MAAM,CAAC;IAEnB,oBAAoB;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,uCAAuC;AACvC,MAAM,WAAW,aAAa;IAC5B,uBAAuB;IACvB,QAAQ,EAAE,MAAM,CAAC;IAEjB,4BAA4B;IAC5B,OAAO,EAAE,MAAM,CAAC;IAEhB,iCAAiC;IACjC,YAAY,EAAE,gBAAgB,EAAE,CAAC;CAClC;AAED,yCAAyC;AACzC,MAAM,WAAW,wBAAwB;IACvC,kCAAkC;IAClC,QAAQ,EAAE,MAAM,CAAC;IAEjB,uDAAuD;IACvD,UAAU,EAAE,MAAM,CAAC;IAEnB,4BAA4B;IAC5B,OAAO,EAAE,MAAM,CAAC;IAEhB,sCAAsC;IACtC,YAAY,CAAC,EAAE,gBAAgB,EAAE,CAAC;CACnC;AAED,0CAA0C;AAC1C,MAAM,WAAW,kBAAkB;IACjC,6BAA6B;IAC7B,QAAQ,EAAE,MAAM,CAAC;IAEjB,4BAA4B;IAC5B,OAAO,EAAE,MAAM,CAAC;IAEhB,yBAAyB;IACzB,YAAY,EAAE,gBAAgB,EAAE,CAAC;IAEjC,kBAAkB;IAClB,MAAM,EAAE,QAAQ,GAAG,SAAS,CAAC;IAE7B,kBAAkB;IAClB,UAAU,EAAE,MAAM,CAAC;IAEnB,oBAAoB;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,sCAAsC;AACtC,MAAM,WAAW,aAAa;IAC5B,uBAAuB;IACvB,QAAQ,EAAE,MAAM,CAAC;IAEjB,4BAA4B;IAC5B,OAAO,EAAE,MAAM,CAAC;IAEhB,iCAAiC;IACjC,YAAY,EAAE,gBAAgB,EAAE,CAAC;CAClC;AAED,mBAAmB;AACnB,MAAM,WAAW,aAAa;IAC5B,kCAAkC;IAClC,cAAc,EAAE,MAAM,CAAC;IAEvB,gDAAgD;IAChD,YAAY,EAAE,MAAM,CAAC;IAErB,oBAAoB;IACpB,KAAK,CAAC,EAAE,WAAW,CAAC;IAEpB,yCAAyC;IACzC,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,uCAAuC;AACvC,MAAM,WAAW,cAAc;IAC7B,mCAAmC;IACnC,OAAO,EAAE,MAAM,CAAC;IAEhB,kCAAkC;IAClC,OAAO,EAAE,MAAM,CAAC;IAEhB,8BAA8B;IAC9B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAElC,oCAAoC;IACpC,QAAQ,EAAE,MAAM,CAAC;IAEjB,8BAA8B;IAC9B,UAAU,EAAE,MAAM,CAAC;CACpB"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Bureau 公共类型模块。
3
+ *
4
+ * Bureau 是某个 City 部署在独立服务器上的可选后端。它使用 Bureau Token
5
+ * 获取自身 City 上下文,并使用 Federation 公钥在本地验证 user_token。
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=Bureau.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Bureau.js","sourceRoot":"","sources":["../../src/types/Bureau.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * FederationAdmin 公共类型模块。
3
+ *
4
+ * FederationAdmin 只属于 Federation 控制面,不参与 City 或 Bureau 用户请求。
5
+ */
6
+ import type { FetchLike } from "../pact/http.js";
7
+ /** FederationAdmin 构造参数。 */
8
+ export interface FederationAdminOptions {
9
+ /** Federation 的 HTTP 入口地址。 */
10
+ federation_url: string;
11
+ /** Federation 全局管理 Bearer Secret。 */
12
+ admin_secret_key: string;
13
+ /** 自定义 fetch 实现。 */
14
+ fetch?: FetchLike;
15
+ }
16
+ //# sourceMappingURL=FederationAdmin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FederationAdmin.d.ts","sourceRoot":"","sources":["../../src/types/FederationAdmin.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,4BAA4B;AAC5B,MAAM,WAAW,sBAAsB;IACrC,8BAA8B;IAC9B,cAAc,EAAE,MAAM,CAAC;IAEvB,qCAAqC;IACrC,gBAAgB,EAAE,MAAM,CAAC;IAEzB,oBAAoB;IACpB,KAAK,CAAC,EAAE,SAAS,CAAC;CACnB"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * FederationAdmin 公共类型模块。
3
+ *
4
+ * FederationAdmin 只属于 Federation 控制面,不参与 City 或 Bureau 用户请求。
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=FederationAdmin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FederationAdmin.js","sourceRoot":"","sources":["../../src/types/FederationAdmin.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Federation 用户公共类型模块。
3
+ *
4
+ * City 直接访问 Federation,Bureau 也可以在完成本地验签后按需读取同一份
5
+ * 用户数据,因此两端共用这些类型。
6
+ */
7
+ /** Federation Accounts 当前用户 Profile。 */
8
+ export interface UserProfile {
9
+ /** Federation 用户 ID。 */
10
+ user_id: string;
11
+ /** 用户资料邮箱。 */
12
+ email: string;
13
+ /** 用户展示名称。 */
14
+ display_name: string;
15
+ /** 用户头像 URL。 */
16
+ avatar_url: string;
17
+ /** 用户个人简介。 */
18
+ bio: string;
19
+ /** 资料创建时间。 */
20
+ created_at: string;
21
+ /** 资料更新时间。 */
22
+ updated_at: string;
23
+ }
24
+ //# sourceMappingURL=User.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"User.d.ts","sourceRoot":"","sources":["../../src/types/User.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,wCAAwC;AACxC,MAAM,WAAW,WAAW;IAC1B,wBAAwB;IACxB,OAAO,EAAE,MAAM,CAAC;IAEhB,cAAc;IACd,KAAK,EAAE,MAAM,CAAC;IAEd,cAAc;IACd,YAAY,EAAE,MAAM,CAAC;IAErB,gBAAgB;IAChB,UAAU,EAAE,MAAM,CAAC;IAEnB,cAAc;IACd,GAAG,EAAE,MAAM,CAAC;IAEZ,cAAc;IACd,UAAU,EAAE,MAAM,CAAC;IAEnB,cAAc;IACd,UAAU,EAAE,MAAM,CAAC;CACpB"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Federation 用户公共类型模块。
3
+ *
4
+ * City 直接访问 Federation,Bureau 也可以在完成本地验签后按需读取同一份
5
+ * 用户数据,因此两端共用这些类型。
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=User.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"User.js","sourceRoot":"","sources":["../../src/types/User.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@downcity/city",
3
- "version": "0.2.205",
3
+ "version": "0.2.211",
4
4
  "description": "Downcity City runtime and City access SDK for services, actions, auth, env, and cities.",
5
5
  "type": "module",
6
6
  "main": "./bin/index.js",
@@ -41,10 +41,11 @@
41
41
  "typescript": "^6.0.3"
42
42
  },
43
43
  "dependencies": {
44
- "@downcity/type": "0.1.155",
44
+ "@downcity/type": "0.1.158",
45
45
  "ai": "^6.0.193",
46
46
  "drizzle-orm": "^0.45.2",
47
- "hono": "^4.12.23"
47
+ "hono": "^4.12.23",
48
+ "jose": "^6.2.3"
48
49
  },
49
50
  "scripts": {
50
51
  "build": "rm -rf bin tsconfig.tsbuildinfo && tsc",
@@ -1,27 +0,0 @@
1
- /**
2
- * user_token 签发与校验模块。
3
- *
4
- * Downcity 使用 Web Crypto API 的 HMAC-SHA256 生成最小可用的 user_token。
5
- * 零 Node.js 依赖,兼容所有现代运行时(Node、Workers、Deno、Bun、浏览器)。
6
- */
7
- import type { CreateUserTokenInput, UserTokenPayload } from "./types.js";
8
- export declare class TokenSigner {
9
- readonly signingKey: string;
10
- /** 缓存的 CryptoKey,避免每次签名都重新 import */
11
- private cryptoKey?;
12
- constructor(signingKey: string);
13
- /**
14
- * 获取(或缓存)HMAC CryptoKey。
15
- *
16
- * 使用 Web Crypto API 的 crypto.subtle.importKey,
17
- * 首次调用时创建并缓存 Promise,后续复用。
18
- */
19
- private getCryptoKey;
20
- /** 签发 user_token */
21
- sign(input: CreateUserTokenInput): Promise<string>;
22
- /** 校验并解析 user_token,失败抛 httpError(401) */
23
- verify(token: string): Promise<UserTokenPayload>;
24
- /** 把 ttl 解析成秒数 */
25
- static parseTTL(ttl: string | number): number;
26
- }
27
- //# sourceMappingURL=token-signer.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"token-signer.d.ts","sourceRoot":"","sources":["../../../src/federation/auth/token-signer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEzE,qBAAa,WAAW;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAE5B,qCAAqC;IACrC,OAAO,CAAC,SAAS,CAAC,CAAqB;gBAE3B,UAAU,EAAE,MAAM;IAO9B;;;;;OAKG;IACH,OAAO,CAAC,YAAY;IAcpB,oBAAoB;IACd,IAAI,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,MAAM,CAAC;IA4BxD,0CAA0C;IACpC,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA6BtD,kBAAkB;IAClB,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM;CAyB9C"}
@@ -1,116 +0,0 @@
1
- /**
2
- * user_token 签发与校验模块。
3
- *
4
- * Downcity 使用 Web Crypto API 的 HMAC-SHA256 生成最小可用的 user_token。
5
- * 零 Node.js 依赖,兼容所有现代运行时(Node、Workers、Deno、Bun、浏览器)。
6
- */
7
- import { httpError, base64UrlEncode, base64UrlDecode, base64UrlEncodeBytes, base64UrlDecodeBytes, timingSafeEqualBytes } from "../../utils/helpers.js";
8
- export class TokenSigner {
9
- signingKey;
10
- /** 缓存的 CryptoKey,避免每次签名都重新 import */
11
- cryptoKey;
12
- constructor(signingKey) {
13
- if (!signingKey) {
14
- throw new Error("TokenSigner requires a signing key");
15
- }
16
- this.signingKey = signingKey;
17
- }
18
- /**
19
- * 获取(或缓存)HMAC CryptoKey。
20
- *
21
- * 使用 Web Crypto API 的 crypto.subtle.importKey,
22
- * 首次调用时创建并缓存 Promise,后续复用。
23
- */
24
- getCryptoKey() {
25
- if (!this.cryptoKey) {
26
- const encoder = new TextEncoder();
27
- this.cryptoKey = crypto.subtle.importKey("raw", encoder.encode(this.signingKey), { name: "HMAC", hash: "SHA-256" }, false, ["sign", "verify"]);
28
- }
29
- return this.cryptoKey;
30
- }
31
- /** 签发 user_token */
32
- async sign(input) {
33
- if (!input || typeof input.city_id !== "string" || input.city_id.length === 0) {
34
- throw new TypeError("city_id is required");
35
- }
36
- if (typeof input.user_id !== "string" || input.user_id.length === 0) {
37
- throw new TypeError("user_id is required");
38
- }
39
- const ttl = input.ttl;
40
- const now = Math.floor(Date.now() / 1000);
41
- const payload = {
42
- aud: "downcity:user",
43
- city_id: input.city_id,
44
- user_id: input.user_id,
45
- metadata: input.metadata ?? {},
46
- iat: now,
47
- };
48
- if (ttl) {
49
- payload.exp = now + TokenSigner.parseTTL(ttl);
50
- }
51
- const encodedPayload = base64UrlEncode(JSON.stringify(payload));
52
- const signature = await signPayload(await this.getCryptoKey(), encodedPayload);
53
- return `ub_${encodedPayload}.${signature}`;
54
- }
55
- /** 校验并解析 user_token,失败抛 httpError(401) */
56
- async verify(token) {
57
- const rawToken = token.startsWith("ub_") ? token.slice(3) : token;
58
- const [encodedPayload, signature] = rawToken.split(".");
59
- if (!encodedPayload || !signature) {
60
- throw httpError(401, "Invalid user token");
61
- }
62
- if (!await verifyPayload(await this.getCryptoKey(), encodedPayload, signature)) {
63
- throw httpError(401, "Invalid user token signature");
64
- }
65
- const payload = JSON.parse(base64UrlDecode(encodedPayload));
66
- const now = Math.floor(Date.now() / 1000);
67
- if (payload.exp && payload.exp <= now) {
68
- throw httpError(401, "User token expired");
69
- }
70
- if (payload.aud !== "downcity:user") {
71
- throw httpError(401, "Invalid user token audience");
72
- }
73
- if (!payload.city_id || !payload.user_id) {
74
- throw httpError(401, "Invalid user token payload");
75
- }
76
- return payload;
77
- }
78
- /** 把 ttl 解析成秒数 */
79
- static parseTTL(ttl) {
80
- if (typeof ttl === "number" && Number.isFinite(ttl) && ttl > 0) {
81
- return ttl;
82
- }
83
- if (typeof ttl !== "string") {
84
- throw new TypeError("ttl must be a positive number of seconds or a string like 1h");
85
- }
86
- const match = ttl.match(/^(\d+)(s|m|h|d)$/);
87
- if (!match) {
88
- throw new Error(`Invalid ttl: ${ttl}`);
89
- }
90
- const value = Number(match[1]);
91
- const unit = match[2];
92
- const multipliers = {
93
- s: 1,
94
- m: 60,
95
- h: 60 * 60,
96
- d: 24 * 60 * 60,
97
- };
98
- return value * multipliers[unit];
99
- }
100
- }
101
- /**
102
- * 使用 HMAC-SHA256 对 payload 签名,返回 base64url 编码的签名。
103
- */
104
- async function signPayload(cryptoKey, encodedPayload) {
105
- const signature = await crypto.subtle.sign("HMAC", cryptoKey, new TextEncoder().encode(encodedPayload));
106
- return base64UrlEncodeBytes(new Uint8Array(signature));
107
- }
108
- /**
109
- * 验证 HMAC-SHA256 签名是否匹配。
110
- */
111
- async function verifyPayload(cryptoKey, encodedPayload, signature) {
112
- const expected = base64UrlDecodeBytes(signature);
113
- const actual = await crypto.subtle.sign("HMAC", cryptoKey, new TextEncoder().encode(encodedPayload));
114
- return timingSafeEqualBytes(new Uint8Array(actual), expected);
115
- }
116
- //# sourceMappingURL=token-signer.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"token-signer.js","sourceRoot":"","sources":["../../../src/federation/auth/token-signer.ts"],"names":[],"mappings":"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"}