@usethink/cf-core 0.3.0

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 (169) hide show
  1. package/README.md +88 -0
  2. package/dist/features/anti-abuse/index.d.ts +62 -0
  3. package/dist/features/anti-abuse/index.d.ts.map +1 -0
  4. package/dist/features/anti-abuse/index.js +139 -0
  5. package/dist/features/anti-abuse/index.js.map +1 -0
  6. package/dist/features/email/index.d.ts +68 -0
  7. package/dist/features/email/index.d.ts.map +1 -0
  8. package/dist/features/email/index.js +120 -0
  9. package/dist/features/email/index.js.map +1 -0
  10. package/dist/features/payment/fetch-utils.d.ts +17 -0
  11. package/dist/features/payment/fetch-utils.d.ts.map +1 -0
  12. package/dist/features/payment/fetch-utils.js +56 -0
  13. package/dist/features/payment/fetch-utils.js.map +1 -0
  14. package/dist/features/payment/index.d.ts +20 -0
  15. package/dist/features/payment/index.d.ts.map +1 -0
  16. package/dist/features/payment/index.js +21 -0
  17. package/dist/features/payment/index.js.map +1 -0
  18. package/dist/features/payment/providers/alipay.d.ts +30 -0
  19. package/dist/features/payment/providers/alipay.d.ts.map +1 -0
  20. package/dist/features/payment/providers/alipay.js +149 -0
  21. package/dist/features/payment/providers/alipay.js.map +1 -0
  22. package/dist/features/payment/providers/stripe.d.ts +34 -0
  23. package/dist/features/payment/providers/stripe.d.ts.map +1 -0
  24. package/dist/features/payment/providers/stripe.js +168 -0
  25. package/dist/features/payment/providers/stripe.js.map +1 -0
  26. package/dist/features/payment/providers/trc20.d.ts +24 -0
  27. package/dist/features/payment/providers/trc20.d.ts.map +1 -0
  28. package/dist/features/payment/providers/trc20.js +96 -0
  29. package/dist/features/payment/providers/trc20.js.map +1 -0
  30. package/dist/features/payment/registry.d.ts +43 -0
  31. package/dist/features/payment/registry.d.ts.map +1 -0
  32. package/dist/features/payment/registry.js +65 -0
  33. package/dist/features/payment/registry.js.map +1 -0
  34. package/dist/features/payment/types.d.ts +72 -0
  35. package/dist/features/payment/types.d.ts.map +1 -0
  36. package/dist/features/payment/types.js +8 -0
  37. package/dist/features/payment/types.js.map +1 -0
  38. package/dist/features/thompson-router/index.d.ts +101 -0
  39. package/dist/features/thompson-router/index.d.ts.map +1 -0
  40. package/dist/features/thompson-router/index.js +186 -0
  41. package/dist/features/thompson-router/index.js.map +1 -0
  42. package/dist/features/webhook/index.d.ts +76 -0
  43. package/dist/features/webhook/index.d.ts.map +1 -0
  44. package/dist/features/webhook/index.js +127 -0
  45. package/dist/features/webhook/index.js.map +1 -0
  46. package/dist/src/audit.d.ts +45 -0
  47. package/dist/src/audit.d.ts.map +1 -0
  48. package/dist/src/audit.js +40 -0
  49. package/dist/src/audit.js.map +1 -0
  50. package/dist/src/auth/jwt.d.ts +33 -0
  51. package/dist/src/auth/jwt.d.ts.map +1 -0
  52. package/dist/src/auth/jwt.js +87 -0
  53. package/dist/src/auth/jwt.js.map +1 -0
  54. package/dist/src/auth/password.d.ts +26 -0
  55. package/dist/src/auth/password.d.ts.map +1 -0
  56. package/dist/src/auth/password.js +52 -0
  57. package/dist/src/auth/password.js.map +1 -0
  58. package/dist/src/bootstrap.d.ts +74 -0
  59. package/dist/src/bootstrap.d.ts.map +1 -0
  60. package/dist/src/bootstrap.js +231 -0
  61. package/dist/src/bootstrap.js.map +1 -0
  62. package/dist/src/cache.d.ts +52 -0
  63. package/dist/src/cache.d.ts.map +1 -0
  64. package/dist/src/cache.js +76 -0
  65. package/dist/src/cache.js.map +1 -0
  66. package/dist/src/config.d.ts +83 -0
  67. package/dist/src/config.d.ts.map +1 -0
  68. package/dist/src/config.js +96 -0
  69. package/dist/src/config.js.map +1 -0
  70. package/dist/src/crypto.d.ts +33 -0
  71. package/dist/src/crypto.d.ts.map +1 -0
  72. package/dist/src/crypto.js +87 -0
  73. package/dist/src/crypto.js.map +1 -0
  74. package/dist/src/db/connection.d.ts +53 -0
  75. package/dist/src/db/connection.d.ts.map +1 -0
  76. package/dist/src/db/connection.js +104 -0
  77. package/dist/src/db/connection.js.map +1 -0
  78. package/dist/src/db/index.d.ts +6 -0
  79. package/dist/src/db/index.d.ts.map +1 -0
  80. package/dist/src/db/index.js +6 -0
  81. package/dist/src/db/index.js.map +1 -0
  82. package/dist/src/db/schema.d.ts +649 -0
  83. package/dist/src/db/schema.d.ts.map +1 -0
  84. package/dist/src/db/schema.js +76 -0
  85. package/dist/src/db/schema.js.map +1 -0
  86. package/dist/src/error.d.ts +47 -0
  87. package/dist/src/error.d.ts.map +1 -0
  88. package/dist/src/error.js +94 -0
  89. package/dist/src/error.js.map +1 -0
  90. package/dist/src/http.d.ts +83 -0
  91. package/dist/src/http.d.ts.map +1 -0
  92. package/dist/src/http.js +116 -0
  93. package/dist/src/http.js.map +1 -0
  94. package/dist/src/idempotency.d.ts +78 -0
  95. package/dist/src/idempotency.d.ts.map +1 -0
  96. package/dist/src/idempotency.js +84 -0
  97. package/dist/src/idempotency.js.map +1 -0
  98. package/dist/src/index.d.ts +31 -0
  99. package/dist/src/index.d.ts.map +1 -0
  100. package/dist/src/index.js +45 -0
  101. package/dist/src/index.js.map +1 -0
  102. package/dist/src/logger.d.ts +31 -0
  103. package/dist/src/logger.d.ts.map +1 -0
  104. package/dist/src/logger.js +45 -0
  105. package/dist/src/logger.js.map +1 -0
  106. package/dist/src/middleware/admin-auth.d.ts +38 -0
  107. package/dist/src/middleware/admin-auth.d.ts.map +1 -0
  108. package/dist/src/middleware/admin-auth.js +55 -0
  109. package/dist/src/middleware/admin-auth.js.map +1 -0
  110. package/dist/src/middleware/api-key-auth.d.ts +42 -0
  111. package/dist/src/middleware/api-key-auth.d.ts.map +1 -0
  112. package/dist/src/middleware/api-key-auth.js +104 -0
  113. package/dist/src/middleware/api-key-auth.js.map +1 -0
  114. package/dist/src/middleware/index.d.ts +3 -0
  115. package/dist/src/middleware/index.d.ts.map +1 -0
  116. package/dist/src/middleware/index.js +3 -0
  117. package/dist/src/middleware/index.js.map +1 -0
  118. package/dist/src/rate-limit.d.ts +54 -0
  119. package/dist/src/rate-limit.d.ts.map +1 -0
  120. package/dist/src/rate-limit.js +134 -0
  121. package/dist/src/rate-limit.js.map +1 -0
  122. package/dist/src/security.d.ts +78 -0
  123. package/dist/src/security.d.ts.map +1 -0
  124. package/dist/src/security.js +175 -0
  125. package/dist/src/security.js.map +1 -0
  126. package/dist/src/types.d.ts +64 -0
  127. package/dist/src/types.d.ts.map +1 -0
  128. package/dist/src/types.js +8 -0
  129. package/dist/src/types.js.map +1 -0
  130. package/features/anti-abuse/index.ts +180 -0
  131. package/features/anti-abuse/tests/index.test.ts +50 -0
  132. package/features/email/index.ts +172 -0
  133. package/features/email/tests/index.test.ts +44 -0
  134. package/features/payment/fetch-utils.ts +65 -0
  135. package/features/payment/index.ts +39 -0
  136. package/features/payment/providers/alipay.ts +171 -0
  137. package/features/payment/providers/stripe.ts +192 -0
  138. package/features/payment/providers/trc20.ts +115 -0
  139. package/features/payment/registry.ts +87 -0
  140. package/features/payment/tests/index.test.ts +506 -0
  141. package/features/payment/types.ts +93 -0
  142. package/features/telegram-miniapp/index.ts +109 -0
  143. package/features/telegram-miniapp/tests/index.test.ts +11 -0
  144. package/features/thompson-router/index.ts +243 -0
  145. package/features/thompson-router/tests/index.test.ts +93 -0
  146. package/features/webhook/index.ts +183 -0
  147. package/features/webhook/tests/index.test.ts +21 -0
  148. package/package.json +202 -0
  149. package/src/audit.ts +70 -0
  150. package/src/auth/jwt.ts +114 -0
  151. package/src/auth/password.ts +75 -0
  152. package/src/bootstrap.ts +322 -0
  153. package/src/cache.ts +78 -0
  154. package/src/config.ts +134 -0
  155. package/src/crypto.ts +106 -0
  156. package/src/db/connection.ts +127 -0
  157. package/src/db/index.ts +6 -0
  158. package/src/db/schema.ts +90 -0
  159. package/src/error.ts +125 -0
  160. package/src/http.ts +150 -0
  161. package/src/idempotency.ts +127 -0
  162. package/src/index.ts +85 -0
  163. package/src/logger.ts +63 -0
  164. package/src/middleware/admin-auth.ts +71 -0
  165. package/src/middleware/api-key-auth.ts +164 -0
  166. package/src/middleware/index.ts +2 -0
  167. package/src/rate-limit.ts +167 -0
  168. package/src/security.ts +219 -0
  169. package/src/types.ts +70 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../features/webhook/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * 审计日志模块
3
+ *
4
+ * 提供管理员操作审计和通用事件日志。
5
+ * 设计为 fire-and-forget:写入失败不阻塞主流程。
6
+ * 内置 5% 概率自动清理旧日志,避免数据无限增长。
7
+ *
8
+ * 来源:eshop/vcode audit-service.ts 合并
9
+ */
10
+ import { adminAuditLogs } from "./db/schema";
11
+ /**
12
+ * 通用 Drizzle 数据库接口(仅约束审计模块需要的方法)
13
+ */
14
+ interface AuditDbLike {
15
+ insert: (table: typeof adminAuditLogs) => {
16
+ values: (data: {
17
+ id: string;
18
+ action: string;
19
+ targetType: string;
20
+ targetId: string;
21
+ metadataJson: string;
22
+ ipHash: string;
23
+ createdAt: string;
24
+ }) => Promise<unknown>;
25
+ };
26
+ $client?: {
27
+ execute: (sql: string) => Promise<unknown>;
28
+ };
29
+ }
30
+ export interface AuditInput {
31
+ action: string;
32
+ targetType?: string;
33
+ targetId?: string;
34
+ metadata?: unknown;
35
+ ipHash?: string;
36
+ }
37
+ /**
38
+ * 写入管理员审计日志
39
+ *
40
+ * fire-and-forget 模式:调用方应使用 ctx.waitUntil() 或直接 await。
41
+ * 写入失败仅打印 warn,不抛异常。
42
+ */
43
+ export declare function writeAdminAudit(db: AuditDbLike, input: AuditInput): Promise<void>;
44
+ export {};
45
+ //# sourceMappingURL=audit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../src/audit.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C;;GAEG;AACH,UAAU,WAAW;IACnB,MAAM,EAAE,CAAC,KAAK,EAAE,OAAO,cAAc,KAAK;QACxC,MAAM,EAAE,CAAC,IAAI,EAAE;YACb,EAAE,EAAE,MAAM,CAAC;YACX,MAAM,EAAE,MAAM,CAAC;YACf,UAAU,EAAE,MAAM,CAAC;YACnB,QAAQ,EAAE,MAAM,CAAC;YACjB,YAAY,EAAE,MAAM,CAAC;YACrB,MAAM,EAAE,MAAM,CAAC;YACf,SAAS,EAAE,MAAM,CAAC;SACnB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;KACxB,CAAC;IACF,OAAO,CAAC,EAAE;QACR,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;KAC5C,CAAC;CACH;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAuBvF"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * 审计日志模块
3
+ *
4
+ * 提供管理员操作审计和通用事件日志。
5
+ * 设计为 fire-and-forget:写入失败不阻塞主流程。
6
+ * 内置 5% 概率自动清理旧日志,避免数据无限增长。
7
+ *
8
+ * 来源:eshop/vcode audit-service.ts 合并
9
+ */
10
+ import { adminAuditLogs } from "./db/schema";
11
+ /**
12
+ * 写入管理员审计日志
13
+ *
14
+ * fire-and-forget 模式:调用方应使用 ctx.waitUntil() 或直接 await。
15
+ * 写入失败仅打印 warn,不抛异常。
16
+ */
17
+ export async function writeAdminAudit(db, input) {
18
+ try {
19
+ await db.insert(adminAuditLogs).values({
20
+ id: crypto.randomUUID(),
21
+ action: input.action,
22
+ targetType: input.targetType || "",
23
+ targetId: input.targetId || "",
24
+ metadataJson: JSON.stringify(input.metadata || {}),
25
+ ipHash: input.ipHash || "",
26
+ createdAt: new Date().toISOString(),
27
+ });
28
+ // 5% 概率清理超过 90 天的旧日志
29
+ if (Math.random() < 0.05) {
30
+ try {
31
+ db.$client?.execute(`DELETE FROM admin_audit_logs WHERE created_at < datetime('now', '-90 days')`).catch(() => { });
32
+ }
33
+ catch { /* mock DB may not have execute */ }
34
+ }
35
+ }
36
+ catch (err) {
37
+ console.warn("[audit] writeAdminAudit failed:", err instanceof Error ? err.message : String(err));
38
+ }
39
+ }
40
+ //# sourceMappingURL=audit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.js","sourceRoot":"","sources":["../../src/audit.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AA8B7C;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,EAAe,EAAE,KAAiB;IACtE,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,MAAM,CAAC;YACrC,EAAE,EAAE,MAAM,CAAC,UAAU,EAAE;YACvB,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,UAAU,EAAE,KAAK,CAAC,UAAU,IAAI,EAAE;YAClC,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,EAAE;YAC9B,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,QAAQ,IAAI,EAAE,CAAC;YAClD,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,EAAE;YAC1B,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,CAAC,CAAC;QAEH,qBAAqB;QACrB,IAAI,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI,EAAE,CAAC;YACzB,IAAI,CAAC;gBACH,EAAE,CAAC,OAAO,EAAE,OAAO,CACjB,6EAA6E,CAC9E,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YACpB,CAAC;YAAC,MAAM,CAAC,CAAC,kCAAkC,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,IAAI,CAAC,iCAAiC,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IACpG,CAAC;AACH,CAAC"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * JWT 签发与验证(HMAC-SHA256)
3
+ *
4
+ * 纯 Web Crypto API 实现,零外部依赖。
5
+ * Workers 原生支持,性能优异。
6
+ *
7
+ * 来源:xtools src/lib/auth.ts
8
+ */
9
+ export interface JwtPayload {
10
+ sub: string;
11
+ email: string;
12
+ iat: number;
13
+ exp: number;
14
+ }
15
+ /**
16
+ * 签发 JWT
17
+ */
18
+ export declare function signJwt(userId: string, email: string, secret: string, expirySeconds?: number): Promise<string>;
19
+ /**
20
+ * 验证并解析 JWT — 验证失败返回 null
21
+ */
22
+ export declare function verifyJwt(token: string, secret: string): Promise<JwtPayload | null>;
23
+ /**
24
+ * 从请求中提取 JWT Token
25
+ *
26
+ * 优先级:Authorization: Bearer > Cookie: token=
27
+ */
28
+ export declare function extractJwt(c: {
29
+ req: {
30
+ header: (name: string) => string | undefined;
31
+ };
32
+ }): string | null;
33
+ //# sourceMappingURL=jwt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwt.d.ts","sourceRoot":"","sources":["../../../src/auth/jwt.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb;AA+BD;;GAEG;AACH,wBAAsB,OAAO,CAC3B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,aAAa,SAAiB,GAC7B,OAAO,CAAC,MAAM,CAAC,CAYjB;AAED;;GAEG;AACH,wBAAsB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAwBzF;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE;IAAE,GAAG,EAAE;QAAE,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAA;KAAE,CAAA;CAAE,GAAG,MAAM,GAAG,IAAI,CAYtG"}
@@ -0,0 +1,87 @@
1
+ /**
2
+ * JWT 签发与验证(HMAC-SHA256)
3
+ *
4
+ * 纯 Web Crypto API 实现,零外部依赖。
5
+ * Workers 原生支持,性能优异。
6
+ *
7
+ * 来源:xtools src/lib/auth.ts
8
+ */
9
+ const DEFAULT_EXPIRY = 24 * 60 * 60; // 24 小时
10
+ function base64UrlEncode(data) {
11
+ const bytes = typeof data === "string" ? new TextEncoder().encode(data) : data;
12
+ let binary = "";
13
+ for (const b of bytes)
14
+ binary += String.fromCharCode(b);
15
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
16
+ }
17
+ function base64UrlDecode(str) {
18
+ let base64 = str.replace(/-/g, "+").replace(/_/g, "/");
19
+ const padding = 4 - (base64.length % 4);
20
+ if (padding !== 4)
21
+ base64 += "=".repeat(padding);
22
+ const binary = atob(base64);
23
+ const bytes = new Uint8Array(binary.length);
24
+ for (let i = 0; i < binary.length; i++)
25
+ bytes[i] = binary.charCodeAt(i);
26
+ return bytes;
27
+ }
28
+ async function importHmacKey(secret) {
29
+ return crypto.subtle.importKey("raw", new TextEncoder().encode(secret), { name: "HMAC", hash: "SHA-256" }, false, ["sign", "verify"]);
30
+ }
31
+ /**
32
+ * 签发 JWT
33
+ */
34
+ export async function signJwt(userId, email, secret, expirySeconds = DEFAULT_EXPIRY) {
35
+ const now = Math.floor(Date.now() / 1000);
36
+ const payload = { sub: userId, email, iat: now, exp: now + expirySeconds };
37
+ const header = base64UrlEncode(JSON.stringify({ alg: "HS256", typ: "JWT" }));
38
+ const body = base64UrlEncode(JSON.stringify(payload));
39
+ const signingInput = `${header}.${body}`;
40
+ const key = await importHmacKey(secret);
41
+ const signature = await crypto.subtle.sign("HMAC", key, new TextEncoder().encode(signingInput));
42
+ return `${signingInput}.${base64UrlEncode(new Uint8Array(signature))}`;
43
+ }
44
+ /**
45
+ * 验证并解析 JWT — 验证失败返回 null
46
+ */
47
+ export async function verifyJwt(token, secret) {
48
+ try {
49
+ const parts = token.split(".");
50
+ if (parts.length !== 3)
51
+ return null;
52
+ const [header, body, signature] = parts;
53
+ const signingInput = `${header}.${body}`;
54
+ const key = await importHmacKey(secret);
55
+ const valid = await crypto.subtle.verify("HMAC", key, base64UrlDecode(signature), new TextEncoder().encode(signingInput));
56
+ if (!valid)
57
+ return null;
58
+ const payload = JSON.parse(new TextDecoder().decode(base64UrlDecode(body)));
59
+ if (payload.exp < Math.floor(Date.now() / 1000))
60
+ return null;
61
+ return payload;
62
+ }
63
+ catch {
64
+ return null;
65
+ }
66
+ }
67
+ /**
68
+ * 从请求中提取 JWT Token
69
+ *
70
+ * 优先级:Authorization: Bearer > Cookie: token=
71
+ */
72
+ export function extractJwt(c) {
73
+ const auth = c.req.header("Authorization");
74
+ if (auth?.startsWith("Bearer ")) {
75
+ const token = auth.slice(7).trim();
76
+ if (token.split(".").length === 3)
77
+ return token;
78
+ }
79
+ const cookie = c.req.header("Cookie");
80
+ if (cookie) {
81
+ const match = cookie.match(/(?:^|;\s*)token=([^;]+)/);
82
+ if (match)
83
+ return decodeURIComponent(match[1]);
84
+ }
85
+ return null;
86
+ }
87
+ //# sourceMappingURL=jwt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwt.js","sourceRoot":"","sources":["../../../src/auth/jwt.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AASH,MAAM,cAAc,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,QAAQ;AAE7C,SAAS,eAAe,CAAC,IAAyB;IAChD,MAAM,KAAK,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC/E,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,KAAK,MAAM,CAAC,IAAI,KAAK;QAAE,MAAM,IAAI,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IACxD,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AACjF,CAAC;AAED,SAAS,eAAe,CAAC,GAAW;IAClC,IAAI,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACvD,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACxC,IAAI,OAAO,KAAK,CAAC;QAAE,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACjD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;IAC5B,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC5C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE;QAAE,KAAK,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IACxE,OAAO,KAAK,CAAC;AACf,CAAC;AAED,KAAK,UAAU,aAAa,CAAC,MAAc;IACzC,OAAO,MAAM,CAAC,MAAM,CAAC,SAAS,CAC5B,KAAK,EACL,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EAChC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,EACjC,KAAK,EACL,CAAC,MAAM,EAAE,QAAQ,CAAC,CACnB,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,MAAc,EACd,KAAa,EACb,MAAc,EACd,aAAa,GAAG,cAAc;IAE9B,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;IAC1C,MAAM,OAAO,GAAe,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,GAAG,aAAa,EAAE,CAAC;IAEvF,MAAM,MAAM,GAAG,eAAe,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;IAC7E,MAAM,IAAI,GAAG,eAAe,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;IACtD,MAAM,YAAY,GAAG,GAAG,MAAM,IAAI,IAAI,EAAE,CAAC;IAEzC,MAAM,GAAG,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,CAAC;IACxC,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC;IAEhG,OAAO,GAAG,YAAY,IAAI,eAAe,CAAC,IAAI,UAAU,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC;AACzE,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,KAAa,EAAE,MAAc;IAC3D,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC/B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QAEpC,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,SAAS,CAAC,GAAG,KAAK,CAAC;QACxC,MAAM,YAAY,GAAG,GAAG,MAAM,IAAI,IAAI,EAAE,CAAC;QAEzC,MAAM,GAAG,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,CAAC;QACxC,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CACtC,MAAM,EACN,GAAG,EACH,eAAe,CAAC,SAAS,CAAC,EAC1B,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,CACvC,CAAC;QACF,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QAExB,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAe,CAAC;QAC1F,IAAI,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QAE7D,OAAO,OAAO,CAAC;IACjB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,CAA4D;IACrF,MAAM,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;IAC3C,IAAI,IAAI,EAAE,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAChC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACnC,IAAI,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC;IAClD,CAAC;IACD,MAAM,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACtC,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC;QACtD,IAAI,KAAK;YAAE,OAAO,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACjD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * 密码哈希模块(PBKDF2-HMAC-SHA256)
3
+ *
4
+ * 纯 Web Crypto API 实现,零外部依赖。
5
+ * - 100,000 次迭代(OWASP 推荐最低值)
6
+ * - 16 字节随机 salt
7
+ * - 32 字节(256 bit)哈希输出
8
+ *
9
+ * 来源:xtools src/lib/auth.ts
10
+ */
11
+ /**
12
+ * 哈希密码
13
+ *
14
+ * @param password - 明文密码
15
+ * @param saltHex - 盐值 hex(可选,不提供则自动生成)
16
+ * @returns { hash, salt } — 均为 hex 字符串
17
+ */
18
+ export declare function hashPassword(password: string, saltHex?: string): Promise<{
19
+ hash: string;
20
+ salt: string;
21
+ }>;
22
+ /**
23
+ * 验证密码 — 恒定时间比较(防 timing attack)
24
+ */
25
+ export declare function verifyPassword(password: string, hashHex: string, saltHex: string): Promise<boolean>;
26
+ //# sourceMappingURL=password.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"password.d.ts","sourceRoot":"","sources":["../../../src/auth/password.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAkBH;;;;;;GAMG;AACH,wBAAsB,YAAY,CAChC,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAoBzC;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,OAAO,CAAC,CAQlB"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * 密码哈希模块(PBKDF2-HMAC-SHA256)
3
+ *
4
+ * 纯 Web Crypto API 实现,零外部依赖。
5
+ * - 100,000 次迭代(OWASP 推荐最低值)
6
+ * - 16 字节随机 salt
7
+ * - 32 字节(256 bit)哈希输出
8
+ *
9
+ * 来源:xtools src/lib/auth.ts
10
+ */
11
+ const ITERATIONS = 100_000;
12
+ const SALT_LENGTH = 16;
13
+ const HASH_LENGTH = 32;
14
+ function toHex(bytes) {
15
+ return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
16
+ }
17
+ function fromHex(hex) {
18
+ const bytes = new Uint8Array(hex.length / 2);
19
+ for (let i = 0; i < hex.length; i += 2) {
20
+ bytes[i / 2] = parseInt(hex.substring(i, i + 2), 16);
21
+ }
22
+ return bytes;
23
+ }
24
+ /**
25
+ * 哈希密码
26
+ *
27
+ * @param password - 明文密码
28
+ * @param saltHex - 盐值 hex(可选,不提供则自动生成)
29
+ * @returns { hash, salt } — 均为 hex 字符串
30
+ */
31
+ export async function hashPassword(password, saltHex) {
32
+ const salt = saltHex
33
+ ? fromHex(saltHex)
34
+ : crypto.getRandomValues(new Uint8Array(SALT_LENGTH));
35
+ const keyMaterial = await crypto.subtle.importKey("raw", new TextEncoder().encode(password), "PBKDF2", false, ["deriveBits"]);
36
+ const hashBuffer = await crypto.subtle.deriveBits({ name: "PBKDF2", salt, iterations: ITERATIONS, hash: "SHA-256" }, keyMaterial, HASH_LENGTH * 8);
37
+ return { hash: toHex(new Uint8Array(hashBuffer)), salt: toHex(salt) };
38
+ }
39
+ /**
40
+ * 验证密码 — 恒定时间比较(防 timing attack)
41
+ */
42
+ export async function verifyPassword(password, hashHex, saltHex) {
43
+ const result = await hashPassword(password, saltHex);
44
+ if (result.hash.length !== hashHex.length)
45
+ return false;
46
+ let diff = 0;
47
+ for (let i = 0; i < result.hash.length; i++) {
48
+ diff |= result.hash.charCodeAt(i) ^ hashHex.charCodeAt(i);
49
+ }
50
+ return diff === 0;
51
+ }
52
+ //# sourceMappingURL=password.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"password.js","sourceRoot":"","sources":["../../../src/auth/password.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,UAAU,GAAG,OAAO,CAAC;AAC3B,MAAM,WAAW,GAAG,EAAE,CAAC;AACvB,MAAM,WAAW,GAAG,EAAE,CAAC;AAEvB,SAAS,KAAK,CAAC,KAAiB;IAC9B,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAChF,CAAC;AAED,SAAS,OAAO,CAAC,GAAW;IAC1B,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC7C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACvC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACvD,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,QAAgB,EAChB,OAAgB;IAEhB,MAAM,IAAI,GAAG,OAAO;QAClB,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;QAClB,CAAC,CAAC,MAAM,CAAC,eAAe,CAAC,IAAI,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC;IAExD,MAAM,WAAW,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,SAAS,CAC/C,KAAK,EACL,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,EAClC,QAAQ,EACR,KAAK,EACL,CAAC,YAAY,CAAC,CACf,CAAC;IAEF,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,UAAU,CAC/C,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,EACjE,WAAW,EACX,WAAW,GAAG,CAAC,CAChB,CAAC;IAEF,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,UAAU,CAAC,UAAU,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;AACxE,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,QAAgB,EAChB,OAAe,EACf,OAAe;IAEf,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACrD,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,KAAK,OAAO,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IACxD,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5C,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IAC5D,CAAC;IACD,OAAO,IAAI,KAAK,CAAC,CAAC;AACpB,CAAC"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Worker 入口工厂
3
+ *
4
+ * 将三项目 index.ts 中高度重复的 Worker 启动逻辑抽象为统一工厂函数:
5
+ * - 数据库初始化中间件
6
+ * - 请求体大小限制
7
+ * - 安全响应头注入
8
+ * - API 路由 / 静态资源分流
9
+ * - 全局错误处理
10
+ *
11
+ * 来源:eshop/xtools/vcode 三项目 index.ts 入口合并
12
+ */
13
+ import { Hono } from "hono";
14
+ import { type SecurityHeadersOptions } from "./security";
15
+ export interface BootstrapOptions<TSchema extends Record<string, unknown> = Record<string, never>> {
16
+ /** Drizzle schema(传入后支持关系查询) */
17
+ schema?: TSchema;
18
+ /** API 路由前缀,默认 "/api" */
19
+ apiPrefix?: string;
20
+ /** 请求体大小限制(字节),默认 100KB */
21
+ maxBodySize?: number;
22
+ /**
23
+ * 请求级超时(毫秒),默认 25000(25 秒)。
24
+ * Cloudflare Workers 硬限制 30 秒,留 5 秒余量给 CF 运行时。
25
+ * 超时后请求会被中止并返回 504 Gateway Timeout。
26
+ */
27
+ requestTimeoutMs?: number;
28
+ /** 安全响应头配置 */
29
+ securityHeaders?: SecurityHeadersOptions;
30
+ /**
31
+ * 错误告警回调 — 生产环境错误通知。
32
+ * 当请求处理过程中发生未捕获错误时调用,可用于发送到外部告警系统
33
+ * (如 Slack webhook、邮件、PagerDuty 等)。
34
+ *
35
+ * @example
36
+ * ```ts
37
+ * onErrorAlert: async (error, context) => {
38
+ * await fetch("https://hooks.slack.com/...", {
39
+ * method: "POST",
40
+ * body: JSON.stringify({ text: `[ERROR] ${error.message}` }),
41
+ * });
42
+ * }
43
+ * ```
44
+ */
45
+ onErrorAlert?: (error: Error, context: {
46
+ path: string;
47
+ method: string;
48
+ ip?: string;
49
+ }) => void | Promise<void>;
50
+ /** 注册 API 路由的回调 */
51
+ registerRoutes: (api: Hono<any>) => void;
52
+ /**
53
+ * 静态资源路由表 — 页面路径到 HTML 文件的映射
54
+ * @example { "/admin": "/admin.html", "/shop": "/index.html" }
55
+ */
56
+ pageRoutes?: Record<string, string>;
57
+ /**
58
+ * SPA 路由 — 这些路径都返回同一个 HTML 文件
59
+ * @example { fallback: "/_app/index.html", paths: ["/shop", "/order"] }
60
+ */
61
+ spaRoutes?: {
62
+ fallback: string;
63
+ paths: string[];
64
+ };
65
+ /**
66
+ * 长缓存路径前缀(如 /_app/assets/)
67
+ * 匹配的路径会设置 Cache-Control: immutable, max-age=31536000
68
+ */
69
+ immutablePrefixes?: string[];
70
+ }
71
+ export declare function bootstrap<TSchema extends Record<string, unknown>>(options: BootstrapOptions<TSchema>): {
72
+ fetch(request: Request, env: Record<string, unknown>, ctx: ExecutionContext): Promise<Response>;
73
+ };
74
+ //# sourceMappingURL=bootstrap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../../src/bootstrap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAG5B,OAAO,EAAwB,KAAK,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAE/E,MAAM,WAAW,gBAAgB,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC;IAC/F,gCAAgC;IAChC,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB,yBAAyB;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,2BAA2B;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B,cAAc;IACd,eAAe,CAAC,EAAE,sBAAsB,CAAC;IAEzC;;;;;;;;;;;;;;OAcG;IACH,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE9G,mBAAmB;IAEnB,cAAc,EAAE,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC;IAEzC;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEpC;;;OAGG;IACH,SAAS,CAAC,EAAE;QACV,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,EAAE,MAAM,EAAE,CAAC;KACjB,CAAC;IAEF;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC9B;AAoDD,wBAAgB,SAAS,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/D,OAAO,EAAE,gBAAgB,CAAC,OAAO,CAAC;mBAyHX,OAAO,OAAO,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,OAAO,gBAAgB;EAoEpF"}
@@ -0,0 +1,231 @@
1
+ /**
2
+ * Worker 入口工厂
3
+ *
4
+ * 将三项目 index.ts 中高度重复的 Worker 启动逻辑抽象为统一工厂函数:
5
+ * - 数据库初始化中间件
6
+ * - 请求体大小限制
7
+ * - 安全响应头注入
8
+ * - API 路由 / 静态资源分流
9
+ * - 全局错误处理
10
+ *
11
+ * 来源:eshop/xtools/vcode 三项目 index.ts 入口合并
12
+ */
13
+ import { Hono } from "hono";
14
+ import { initDatabaseWithHealthCheck } from "./db/connection";
15
+ import { fail } from "./http";
16
+ import { buildSecurityHeaders } from "./security";
17
+ /**
18
+ * 创建 Cloudflare Workers 应用
19
+ *
20
+ * 返回标准的 Workers fetch handler 导出对象。
21
+ *
22
+ * @example
23
+ * ```ts
24
+ * import * as schema from "./db/schema";
25
+ * import { bootstrap } from "@usethink/cf-core/bootstrap";
26
+ *
27
+ * export default bootstrap({
28
+ * schema,
29
+ * registerRoutes: (api) => {
30
+ * api.route("/products", productRoutes);
31
+ * api.route("/orders", orderRoutes);
32
+ * },
33
+ * pageRoutes: { "/admin": "/admin.html" },
34
+ * spaRoutes: { fallback: "/_app/index.html", paths: ["/shop", "/order"] },
35
+ * immutablePrefixes: ["/_app/assets/"],
36
+ * });
37
+ * ```
38
+ */
39
+ /** 生成友好的 HTML 错误页面(内联 CSS,无外部依赖) */
40
+ function errorPageHtml(status, message) {
41
+ return `<!DOCTYPE html>
42
+ <html lang="zh-CN">
43
+ <head>
44
+ <meta charset="UTF-8">
45
+ <meta name="viewport" content="width=device-width,initial-scale=1">
46
+ <title>${status} - ${message}</title>
47
+ <style>
48
+ *{margin:0;padding:0;box-sizing:border-box}
49
+ body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;background:#0f0f0f;color:#e0e0e0;display:flex;align-items:center;justify-content:center;min-height:100vh;padding:20px}
50
+ .container{text-align:center;max-width:480px}
51
+ .code{font-size:6rem;font-weight:800;background:linear-gradient(135deg,#6c63ff,#a78bfa);-webkit-background-clip:text;-webkit-text-fill-color:transparent;line-height:1}
52
+ .msg{font-size:1.25rem;color:#888;margin:1rem 0 2rem}
53
+ a{color:#6c63ff;text-decoration:none;font-weight:500}
54
+ a:hover{text-decoration:underline}
55
+ </style>
56
+ </head>
57
+ <body>
58
+ <div class="container">
59
+ <p class="code">${status}</p>
60
+ <p class="msg">${message}</p>
61
+ <a href="/">← 返回首页</a>
62
+ </div>
63
+ </body>
64
+ </html>`;
65
+ }
66
+ export function bootstrap(options) {
67
+ const { schema, apiPrefix = "/api", maxBodySize = 1024 * 100, requestTimeoutMs = 25_000, securityHeaders: secOpts = {}, onErrorAlert, registerRoutes, pageRoutes = {}, spaRoutes, immutablePrefixes = [], } = options;
68
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
69
+ const api = new Hono();
70
+ // ── 请求级超时中间件(防止慢请求耗尽 Workers CPU) ──
71
+ api.use("*", async (c, next) => {
72
+ // /health 不受超时限制(用于监控探活)
73
+ if (c.req.path === "/health") {
74
+ await next();
75
+ return;
76
+ }
77
+ const controller = new AbortController();
78
+ const timeoutId = setTimeout(() => controller.abort(), requestTimeoutMs);
79
+ try {
80
+ // 将 signal 传递给下游(路由可选择性使用)
81
+ c.set("abortSignal", controller.signal);
82
+ await next();
83
+ }
84
+ catch (err) {
85
+ if (err instanceof DOMException && err.name === "AbortError") {
86
+ console.error(`[bootstrap:timeout] 请求超时 ${requestTimeoutMs}ms: ${c.req.method} ${c.req.path}`);
87
+ return fail(c, "请求处理超时", 504);
88
+ }
89
+ throw err;
90
+ }
91
+ finally {
92
+ clearTimeout(timeoutId);
93
+ }
94
+ });
95
+ // ── DB 初始化中间件(带连接验证 + 重试) ──
96
+ api.use("*", async (c, next) => {
97
+ const isHealth = c.req.path === "/health";
98
+ try {
99
+ const db = await initDatabaseWithHealthCheck(c.env.TURSO_URL, c.env.TURSO_TOKEN, schema);
100
+ c.set("db", db);
101
+ if ("executionCtx" in c) {
102
+ c.set("executionCtx", c.env.executionCtx);
103
+ }
104
+ await next();
105
+ }
106
+ catch (err) {
107
+ console.error("[bootstrap:db-init]", err);
108
+ if (isHealth) {
109
+ c.set("db", undefined);
110
+ await next();
111
+ return;
112
+ }
113
+ return fail(c, "服务暂时不可用", 503);
114
+ }
115
+ });
116
+ // ── 请求体大小限制 ──
117
+ api.use("*", async (c, next) => {
118
+ const len = parseInt(c.req.header("content-length") || "0");
119
+ if (len > maxBodySize)
120
+ return fail(c, `请求体过大(最大 ${Math.floor(maxBodySize / 1024)}KB)`, 413);
121
+ await next();
122
+ });
123
+ // ── 注册业务路由 ──
124
+ registerRoutes(api);
125
+ // ── 404 + 全局错误(浏览器返回 HTML,API 返回 JSON) ──
126
+ api.notFound((c) => {
127
+ const accept = c.req.header("accept") || "";
128
+ if (accept.includes("text/html")) {
129
+ return c.html(errorPageHtml(404, "页面未找到"), 404);
130
+ }
131
+ return fail(c, "API not found", 404);
132
+ });
133
+ api.onError((error, c) => {
134
+ console.error("[bootstrap:onError]", error?.constructor?.name, error?.message, error?.stack);
135
+ // 触发告警回调(如果配置了)
136
+ if (onErrorAlert) {
137
+ const ip = c.req.header("cf-connecting-ip") || c.req.header("x-forwarded-for") || "unknown";
138
+ // 异步发送告警,不阻塞响应
139
+ Promise.resolve(onErrorAlert(error, {
140
+ path: c.req.path,
141
+ method: c.req.method,
142
+ ip,
143
+ })).catch((alertErr) => {
144
+ console.error("[bootstrap:onErrorAlert] 告警发送失败:", alertErr);
145
+ });
146
+ }
147
+ const accept = c.req.header("accept") || "";
148
+ if (accept.includes("text/html")) {
149
+ return c.html(errorPageHtml(500, "服务暂时不可用"), 500);
150
+ }
151
+ return fail(c, "服务暂时不可用", 500, { error: error?.message });
152
+ });
153
+ // ── 预计算安全响应头 ──
154
+ const defaultHeaders = buildSecurityHeaders(secOpts);
155
+ const adminHeaders = buildSecurityHeaders({ ...secOpts, allowUnsafeEval: true });
156
+ function applyHeaders(response, isImmutable = false, isAdmin = false) {
157
+ const headers = new Headers(response.headers);
158
+ const base = isAdmin ? adminHeaders : defaultHeaders;
159
+ for (const [k, v] of base)
160
+ headers.set(k, v);
161
+ if (isImmutable) {
162
+ headers.set("Cache-Control", "public, max-age=31536000, immutable");
163
+ }
164
+ return new Response(response.body, { status: response.status, statusText: response.statusText, headers });
165
+ }
166
+ return {
167
+ async fetch(request, env, ctx) {
168
+ try {
169
+ const url = new URL(request.url);
170
+ const path = url.pathname;
171
+ // API 路由 → Hono
172
+ const prefix = apiPrefix.replace(/\/$/, "");
173
+ if (path === prefix || path.startsWith(`${prefix}/`)) {
174
+ url.pathname = path.replace(new RegExp(`^${prefix}`), "") || "/";
175
+ return api.fetch(new Request(url, request), env, ctx);
176
+ }
177
+ // 静态资源处理需要 ASSETS binding
178
+ const assets = env.ASSETS;
179
+ if (!assets) {
180
+ return new Response(JSON.stringify({ ok: false, error: "ASSETS binding not configured" }), {
181
+ status: 500,
182
+ headers: { "content-type": "application/json" },
183
+ });
184
+ }
185
+ // 长缓存静态资源
186
+ if (immutablePrefixes.some((p) => path.startsWith(p))) {
187
+ return applyHeaders(await assets.fetch(request), true);
188
+ }
189
+ // 页面路由(pageRoutes 精确匹配)
190
+ for (const [route, file] of Object.entries(pageRoutes)) {
191
+ if (path === route || path.startsWith(`${route}/`)) {
192
+ url.pathname = file;
193
+ const isAdmin = route === "/admin" || route.startsWith("/admin");
194
+ return applyHeaders(await assets.fetch(new Request(url, request)), false, isAdmin);
195
+ }
196
+ }
197
+ // SPA 路由
198
+ if (spaRoutes && spaRoutes.paths.some((p) => path === p || path.startsWith(`${p}/`))) {
199
+ url.pathname = spaRoutes.fallback;
200
+ const res = await assets.fetch(new Request(url, request));
201
+ if (res.ok)
202
+ return applyHeaders(res);
203
+ url.pathname = "/index.html";
204
+ return applyHeaders(await assets.fetch(new Request(url, request)));
205
+ }
206
+ // 根路径
207
+ if (path === "/") {
208
+ url.pathname = "/index.html";
209
+ return applyHeaders(await assets.fetch(new Request(url, request)));
210
+ }
211
+ // 其他静态资源
212
+ return applyHeaders(await assets.fetch(request));
213
+ }
214
+ catch (err) {
215
+ console.error("[bootstrap:fetch]", err);
216
+ const accept = request.headers.get("accept") || "";
217
+ if (accept.includes("text/html")) {
218
+ return new Response(errorPageHtml(500, "服务暂时不可用"), {
219
+ status: 500,
220
+ headers: { "content-type": "text/html; charset=utf-8" },
221
+ });
222
+ }
223
+ return new Response(JSON.stringify({ ok: false, error: "服务暂时不可用" }), {
224
+ status: 500,
225
+ headers: { "content-type": "application/json" },
226
+ });
227
+ }
228
+ },
229
+ };
230
+ }
231
+ //# sourceMappingURL=bootstrap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../../src/bootstrap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,2BAA2B,EAAwB,MAAM,iBAAiB,CAAC;AACpF,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,oBAAoB,EAA+B,MAAM,YAAY,CAAC;AAiE/E;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,oCAAoC;AACpC,SAAS,aAAa,CAAC,MAAc,EAAE,OAAe;IACpD,OAAO;;;;;SAKA,MAAM,MAAM,OAAO;;;;;;;;;;;;;kBAaV,MAAM;iBACP,OAAO;;;;QAIhB,CAAC;AACT,CAAC;AAED,MAAM,UAAU,SAAS,CACvB,OAAkC;IAElC,MAAM,EACJ,MAAM,EACN,SAAS,GAAG,MAAM,EAClB,WAAW,GAAG,IAAI,GAAG,GAAG,EACxB,gBAAgB,GAAG,MAAM,EACzB,eAAe,EAAE,OAAO,GAAG,EAAE,EAC7B,YAAY,EACZ,cAAc,EACd,UAAU,GAAG,EAAE,EACf,SAAS,EACT,iBAAiB,GAAG,EAAE,GACvB,GAAG,OAAO,CAAC;IAEZ,8DAA8D;IAC9D,MAAM,GAAG,GAAG,IAAI,IAAI,EAAO,CAAC;IAE5B,sCAAsC;IACtC,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE;QAC7B,yBAAyB;QACzB,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC7B,MAAM,IAAI,EAAE,CAAC;YACb,OAAO;QACT,CAAC;QAED,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QACzC,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,gBAAgB,CAAC,CAAC;QAEzE,IAAI,CAAC;YACH,2BAA2B;YAC3B,CAAC,CAAC,GAAG,CAAC,aAAa,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;YACxC,MAAM,IAAI,EAAE,CAAC;QACf,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,YAAY,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;gBAC7D,OAAO,CAAC,KAAK,CAAC,4BAA4B,gBAAgB,OAAO,CAAC,CAAC,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;gBAC/F,OAAO,IAAI,CAAC,CAAC,EAAE,QAAQ,EAAE,GAAG,CAAC,CAAC;YAChC,CAAC;YACD,MAAM,GAAG,CAAC;QACZ,CAAC;gBAAS,CAAC;YACT,YAAY,CAAC,SAAS,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,8BAA8B;IAC9B,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE;QAC7B,MAAM,QAAQ,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC;QAC1C,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,MAAM,2BAA2B,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC,GAAG,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;YACzF,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAChB,IAAI,cAAc,IAAI,CAAC,EAAE,CAAC;gBACxB,CAAC,CAAC,GAAG,CAAC,cAAc,EAAE,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;YAC5C,CAAC;YACD,MAAM,IAAI,EAAE,CAAC;QACf,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,qBAAqB,EAAE,GAAG,CAAC,CAAC;YAC1C,IAAI,QAAQ,EAAE,CAAC;gBACb,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;gBACvB,MAAM,IAAI,EAAE,CAAC;gBACb,OAAO;YACT,CAAC;YACD,OAAO,IAAI,CAAC,CAAC,EAAE,SAAS,EAAE,GAAG,CAAC,CAAC;QACjC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,gBAAgB;IAChB,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE;QAC7B,MAAM,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,gBAAgB,CAAC,IAAI,GAAG,CAAC,CAAC;QAC5D,IAAI,GAAG,GAAG,WAAW;YAAE,OAAO,IAAI,CAAC,CAAC,EAAE,YAAY,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAC5F,MAAM,IAAI,EAAE,CAAC;IACf,CAAC,CAAC,CAAC;IAEH,eAAe;IACf,cAAc,CAAC,GAAG,CAAC,CAAC;IAEpB,2CAA2C;IAC3C,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE;QACjB,MAAM,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;QAC5C,IAAI,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;YACjC,OAAO,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,GAAG,CAAC,CAAC;QAClD,CAAC;QACD,OAAO,IAAI,CAAC,CAAC,EAAE,eAAe,EAAE,GAAG,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;IACH,GAAG,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE;QACvB,OAAO,CAAC,KAAK,CAAC,qBAAqB,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;QAE7F,gBAAgB;QAChB,IAAI,YAAY,EAAE,CAAC;YACjB,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,iBAAiB,CAAC,IAAI,SAAS,CAAC;YAC5F,eAAe;YACf,OAAO,CAAC,OAAO,CAAC,YAAY,CAAC,KAAc,EAAE;gBAC3C,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI;gBAChB,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM;gBACpB,EAAE;aACH,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE,EAAE;gBACrB,OAAO,CAAC,KAAK,CAAC,kCAAkC,EAAE,QAAQ,CAAC,CAAC;YAC9D,CAAC,CAAC,CAAC;QACL,CAAC;QAED,MAAM,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;QAC5C,IAAI,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;YACjC,OAAO,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,EAAE,SAAS,CAAC,EAAE,GAAG,CAAC,CAAC;QACpD,CAAC;QACD,OAAO,IAAI,CAAC,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;IAEH,iBAAiB;IACjB,MAAM,cAAc,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAC;IACrD,MAAM,YAAY,GAAG,oBAAoB,CAAC,EAAE,GAAG,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC,CAAC;IAEjF,SAAS,YAAY,CAAC,QAAkB,EAAE,WAAW,GAAG,KAAK,EAAE,OAAO,GAAG,KAAK;QAC5E,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAC9C,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,cAAc,CAAC;QACrD,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,IAAI;YAAE,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAC7C,IAAI,WAAW,EAAE,CAAC;YAChB,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,qCAAqC,CAAC,CAAC;QACtE,CAAC;QACD,OAAO,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,CAAC,UAAU,EAAE,OAAO,EAAE,CAAC,CAAC;IAC5G,CAAC;IAED,OAAO;QACL,KAAK,CAAC,KAAK,CAAC,OAAgB,EAAE,GAA4B,EAAE,GAAqB;YAC/E,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;gBACjC,MAAM,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAC;gBAE1B,gBAAgB;gBAChB,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;gBAC5C,IAAI,IAAI,KAAK,MAAM,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,MAAM,GAAG,CAAC,EAAE,CAAC;oBACrD,GAAG,CAAC,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC;oBACjE,OAAO,GAAG,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;gBACxD,CAAC;gBAED,0BAA0B;gBAC1B,MAAM,MAAM,GAAG,GAAG,CAAC,MAA6B,CAAC;gBACjD,IAAI,CAAC,MAAM,EAAE,CAAC;oBACZ,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,+BAA+B,EAAE,CAAC,EAAE;wBACzF,MAAM,EAAE,GAAG;wBACX,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;qBAChD,CAAC,CAAC;gBACL,CAAC;gBAED,UAAU;gBACV,IAAI,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;oBACtD,OAAO,YAAY,CAAC,MAAM,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,CAAC;gBACzD,CAAC;gBAED,wBAAwB;gBACxB,KAAK,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;oBACvD,IAAI,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,KAAK,GAAG,CAAC,EAAE,CAAC;wBACnD,GAAG,CAAC,QAAQ,GAAG,IAAI,CAAC;wBACpB,MAAM,OAAO,GAAG,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;wBACjE,OAAO,YAAY,CAAC,MAAM,MAAM,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;oBACrF,CAAC;gBACH,CAAC;gBAED,SAAS;gBACT,IAAI,SAAS,IAAI,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,KAAK,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;oBACrF,GAAG,CAAC,QAAQ,GAAG,SAAS,CAAC,QAAQ,CAAC;oBAClC,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC;oBAC1D,IAAI,GAAG,CAAC,EAAE;wBAAE,OAAO,YAAY,CAAC,GAAG,CAAC,CAAC;oBACrC,GAAG,CAAC,QAAQ,GAAG,aAAa,CAAC;oBAC7B,OAAO,YAAY,CAAC,MAAM,MAAM,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;gBACrE,CAAC;gBAED,MAAM;gBACN,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;oBACjB,GAAG,CAAC,QAAQ,GAAG,aAAa,CAAC;oBAC7B,OAAO,YAAY,CAAC,MAAM,MAAM,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;gBACrE,CAAC;gBAED,SAAS;gBACT,OAAO,YAAY,CAAC,MAAM,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;YACnD,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,KAAK,CAAC,mBAAmB,EAAE,GAAG,CAAC,CAAC;gBACxC,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;gBACnD,IAAI,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;oBACjC,OAAO,IAAI,QAAQ,CAAC,aAAa,CAAC,GAAG,EAAE,SAAS,CAAC,EAAE;wBACjD,MAAM,EAAE,GAAG;wBACX,OAAO,EAAE,EAAE,cAAc,EAAE,0BAA0B,EAAE;qBACxD,CAAC,CAAC;gBACL,CAAC;gBACD,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,EAAE;oBACnE,MAAM,EAAE,GAAG;oBACX,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;iBAChD,CAAC,CAAC;YACL,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}