@seasonkoh/webaz 0.1.24 → 0.1.26

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 (195) hide show
  1. package/README.md +5 -1
  2. package/dist/layer0-foundation/L0-1-database/db-backends/pg-backend.js +51 -0
  3. package/dist/layer0-foundation/L0-1-database/db-backends/sql-dialect-datetime.js +437 -0
  4. package/dist/layer0-foundation/L0-1-database/db-backends/sql-placeholders.js +98 -0
  5. package/dist/layer0-foundation/L0-1-database/db.js +65 -0
  6. package/dist/layer0-foundation/L0-2-state-machine/order-chain.js +13 -11
  7. package/dist/layer0-foundation/L0-2-state-machine/transitions.js +1 -1
  8. package/dist/layer0-foundation/L0-5-manifest/manifest.js +13 -11
  9. package/dist/layer1-agent/L1-1-mcp-server/server.js +288 -208
  10. package/dist/layer1-agent/L1-2-external-anchor/anchor-engine.js +14 -12
  11. package/dist/layer2-business/L2-6-notifications/notification-engine.js +8 -5
  12. package/dist/layer2-business/L2-7-snf/snf-engine.js +16 -14
  13. package/dist/layer2-business/L2-8-feedback/build-feedback-engine.js +18 -10
  14. package/dist/layer2-business/L2-9-contribution/build-reputation-engine.js +37 -23
  15. package/dist/layer2-business/L2-9-contribution/build-task-agent-metadata-store.js +182 -0
  16. package/dist/layer2-business/L2-9-contribution/build-task-participation.js +47 -0
  17. package/dist/layer2-business/L2-9-contribution/build-task-read.js +222 -0
  18. package/dist/layer2-business/L2-9-contribution/build-tasks-engine.js +11 -3
  19. package/dist/layer2-business/L2-9-contribution/canonical-contribution-target.js +16 -0
  20. package/dist/layer2-business/L2-9-contribution/contribution-display-envelope.js +40 -0
  21. package/dist/layer2-business/L2-9-contribution/contribution-score-contract.js +36 -0
  22. package/dist/layer2-business/L2-9-contribution/contribution-score-evidence.js +61 -0
  23. package/dist/layer2-business/L2-9-contribution/github-credential/canonical.js +60 -0
  24. package/dist/layer2-business/L2-9-contribution/github-credential/github-credential.schema.js +140 -0
  25. package/dist/layer2-business/L2-9-contribution/github-credential/github-fetch-adapter.js +437 -0
  26. package/dist/layer2-business/L2-9-contribution/github-credential/self-consistency.js +38 -0
  27. package/dist/layer2-business/L2-9-contribution/github-credential/verifier.js +231 -0
  28. package/dist/layer2-business/L2-9-contribution/github-credential-ingestion-engine.js +145 -0
  29. package/dist/layer2-business/L2-9-contribution/github-credential-store.js +115 -0
  30. package/dist/layer2-business/L2-9-contribution/identity-binding-engine.js +134 -0
  31. package/dist/layer2-business/L2-9-contribution/identity-binding-store.js +101 -0
  32. package/dist/layer2-business/L2-9-contribution/identity-claim-challenge-engine.js +126 -0
  33. package/dist/layer2-business/L2-9-contribution/identity-claim-challenge-store.js +30 -0
  34. package/dist/layer2-business/L2-9-contribution/identity-claim-discovery.js +55 -0
  35. package/dist/layer2-business/L2-9-contribution/identity-claim-engine.js +109 -0
  36. package/dist/layer2-business/L2-9-contribution/identity-claim-fact-precondition.js +22 -0
  37. package/dist/layer2-business/L2-9-contribution/identity-claim-proof-verifier.js +97 -0
  38. package/dist/layer2-business/L2-9-contribution/identity-claim-read.js +59 -0
  39. package/dist/layer2-business/L2-9-contribution/task-proposal-ai-store.js +99 -0
  40. package/dist/layer2-business/L2-9-contribution/task-proposal-draft.js +191 -0
  41. package/dist/layer2-business/L2-9-contribution/task-proposal-store.js +129 -0
  42. package/dist/layer2-business/L2-notes/note-photo-storage.js +4 -2
  43. package/dist/layer3-trust/L3-1-dispute-engine/dispute-engine.js +17 -15
  44. package/dist/layer3-trust/L3-1-dispute-engine/evidence-storage.js +11 -8
  45. package/dist/layer4-economics/L4-3-reputation/reputation-engine.js +9 -8
  46. package/dist/layer4-economics/L4-4-skill-market/skill-engine.js +11 -8
  47. package/dist/layer4-economics/L4-4-skill-market/skill-listing-engine.js +22 -16
  48. package/dist/pwa/acp-feed.js +13 -1
  49. package/dist/pwa/admin-bearer-auth.js +21 -0
  50. package/dist/pwa/contract-fingerprint.js +2 -0
  51. package/dist/pwa/email-delivery.js +127 -0
  52. package/dist/pwa/endpoint-actions.js +5 -1
  53. package/dist/pwa/goal-index.js +8 -8
  54. package/dist/pwa/human-presence.js +62 -0
  55. package/dist/pwa/public/app.js +1485 -283
  56. package/dist/pwa/public/i18n.js +297 -59
  57. package/dist/pwa/public/index.html +1 -0
  58. package/dist/pwa/public/openapi.json +5 -5
  59. package/dist/pwa/public/whitepaper/en/index.html +153 -0
  60. package/dist/pwa/public/whitepaper/zh-CN/index.html +153 -0
  61. package/dist/pwa/rate-limit.js +22 -0
  62. package/dist/pwa/routes/account-deletion.js +15 -13
  63. package/dist/pwa/routes/addresses.js +10 -9
  64. package/dist/pwa/routes/admin-admins.js +13 -14
  65. package/dist/pwa/routes/admin-analytics.js +109 -69
  66. package/dist/pwa/routes/admin-atomic.js +10 -4
  67. package/dist/pwa/routes/admin-catalog.js +13 -11
  68. package/dist/pwa/routes/admin-editor-picks.js +15 -10
  69. package/dist/pwa/routes/admin-events.js +5 -3
  70. package/dist/pwa/routes/admin-health.js +2 -1
  71. package/dist/pwa/routes/admin-moderation.js +50 -29
  72. package/dist/pwa/routes/admin-ops.js +35 -23
  73. package/dist/pwa/routes/admin-protocol-params.js +16 -19
  74. package/dist/pwa/routes/admin-reports.js +23 -21
  75. package/dist/pwa/routes/admin-tokenomics.js +26 -25
  76. package/dist/pwa/routes/admin-users-lifecycle.js +37 -40
  77. package/dist/pwa/routes/admin-users-query.js +65 -53
  78. package/dist/pwa/routes/admin-verifier-flow.js +82 -41
  79. package/dist/pwa/routes/admin-verifier-whitelist.js +55 -27
  80. package/dist/pwa/routes/admin-wallet-ops.js +32 -7
  81. package/dist/pwa/routes/agent-buy.js +46 -22
  82. package/dist/pwa/routes/agent-governance.js +52 -56
  83. package/dist/pwa/routes/ai.js +7 -5
  84. package/dist/pwa/routes/analytics.js +43 -41
  85. package/dist/pwa/routes/anchors.js +19 -20
  86. package/dist/pwa/routes/announcements.js +13 -13
  87. package/dist/pwa/routes/arbitrator.js +97 -31
  88. package/dist/pwa/routes/auction.js +157 -116
  89. package/dist/pwa/routes/auth-login.js +6 -4
  90. package/dist/pwa/routes/auth-read.js +21 -10
  91. package/dist/pwa/routes/auth-register.js +111 -26
  92. package/dist/pwa/routes/auth-sessions.js +12 -11
  93. package/dist/pwa/routes/blocklist.js +16 -15
  94. package/dist/pwa/routes/build-feedback.js +10 -9
  95. package/dist/pwa/routes/build-reputation.js +6 -2
  96. package/dist/pwa/routes/build-tasks.js +45 -13
  97. package/dist/pwa/routes/buyer-feeds.js +27 -25
  98. package/dist/pwa/routes/cart.js +16 -15
  99. package/dist/pwa/routes/charity.js +212 -150
  100. package/dist/pwa/routes/chat.js +42 -43
  101. package/dist/pwa/routes/checkin-tasks.js +10 -9
  102. package/dist/pwa/routes/checkout-helpers.js +12 -10
  103. package/dist/pwa/routes/claim-initiators.js +34 -14
  104. package/dist/pwa/routes/claim-verify.js +86 -53
  105. package/dist/pwa/routes/claim-voting.js +43 -18
  106. package/dist/pwa/routes/contribution-identity.js +164 -0
  107. package/dist/pwa/routes/contribution-score.js +19 -0
  108. package/dist/pwa/routes/coupons.js +19 -16
  109. package/dist/pwa/routes/dashboards.js +18 -16
  110. package/dist/pwa/routes/dispute-cases.js +25 -24
  111. package/dist/pwa/routes/disputes-read.js +45 -51
  112. package/dist/pwa/routes/disputes-write.js +124 -61
  113. package/dist/pwa/routes/evidence.js +9 -9
  114. package/dist/pwa/routes/external-anchors.js +13 -12
  115. package/dist/pwa/routes/feedback.js +29 -33
  116. package/dist/pwa/routes/flash-sales.js +18 -16
  117. package/dist/pwa/routes/follows.js +25 -24
  118. package/dist/pwa/routes/governance-auto-deactivate.js +21 -9
  119. package/dist/pwa/routes/governance-onboarding.js +70 -59
  120. package/dist/pwa/routes/group-buys.js +22 -22
  121. package/dist/pwa/routes/growth.js +34 -31
  122. package/dist/pwa/routes/import-product.js +12 -10
  123. package/dist/pwa/routes/kyc.js +9 -8
  124. package/dist/pwa/routes/leaderboard.js +20 -18
  125. package/dist/pwa/routes/listings.js +23 -22
  126. package/dist/pwa/routes/logistics.js +10 -8
  127. package/dist/pwa/routes/manifests.js +27 -27
  128. package/dist/pwa/routes/me-data.js +23 -21
  129. package/dist/pwa/routes/notifications.js +7 -6
  130. package/dist/pwa/routes/offers.js +30 -12
  131. package/dist/pwa/routes/orders-action.js +51 -29
  132. package/dist/pwa/routes/orders-create.js +75 -20
  133. package/dist/pwa/routes/orders-read.js +21 -20
  134. package/dist/pwa/routes/p2p-products.js +30 -18
  135. package/dist/pwa/routes/payments-governance.js +61 -56
  136. package/dist/pwa/routes/peers.js +9 -8
  137. package/dist/pwa/routes/pin-receipts.js +13 -13
  138. package/dist/pwa/routes/products-aliases.js +12 -10
  139. package/dist/pwa/routes/products-claims.js +36 -17
  140. package/dist/pwa/routes/products-create.js +53 -38
  141. package/dist/pwa/routes/products-crud.js +17 -16
  142. package/dist/pwa/routes/products-links.js +49 -26
  143. package/dist/pwa/routes/products-list.js +6 -4
  144. package/dist/pwa/routes/products-meta.js +40 -39
  145. package/dist/pwa/routes/products-update.js +19 -5
  146. package/dist/pwa/routes/profile-credentials.js +20 -19
  147. package/dist/pwa/routes/profile-identity.js +14 -13
  148. package/dist/pwa/routes/profile-location.js +7 -6
  149. package/dist/pwa/routes/profile-placement.js +20 -19
  150. package/dist/pwa/routes/profile-prefs.js +11 -11
  151. package/dist/pwa/routes/promoter.js +58 -66
  152. package/dist/pwa/routes/public-build-tasks.js +19 -0
  153. package/dist/pwa/routes/public-utils.js +108 -46
  154. package/dist/pwa/routes/push.js +16 -15
  155. package/dist/pwa/routes/ratings.js +92 -32
  156. package/dist/pwa/routes/recover-key.js +66 -26
  157. package/dist/pwa/routes/referral.js +37 -52
  158. package/dist/pwa/routes/reputation.js +3 -2
  159. package/dist/pwa/routes/returns.js +76 -73
  160. package/dist/pwa/routes/reviews.js +41 -18
  161. package/dist/pwa/routes/rewards-apply.js +16 -15
  162. package/dist/pwa/routes/rewards-auto-downgrade.js +9 -7
  163. package/dist/pwa/routes/rewards-escrow-expire.js +7 -5
  164. package/dist/pwa/routes/rfqs.js +163 -85
  165. package/dist/pwa/routes/search.js +16 -14
  166. package/dist/pwa/routes/secondhand.js +25 -22
  167. package/dist/pwa/routes/seller-quota.js +24 -26
  168. package/dist/pwa/routes/share-redirects.js +60 -55
  169. package/dist/pwa/routes/shareables-interactions.js +34 -35
  170. package/dist/pwa/routes/shareables.js +55 -51
  171. package/dist/pwa/routes/shop-referral.js +58 -0
  172. package/dist/pwa/routes/shops.js +25 -20
  173. package/dist/pwa/routes/signaling.js +10 -9
  174. package/dist/pwa/routes/skill-market.js +16 -16
  175. package/dist/pwa/routes/skills.js +15 -14
  176. package/dist/pwa/routes/snf.js +14 -13
  177. package/dist/pwa/routes/tags.js +10 -9
  178. package/dist/pwa/routes/task-proposals.js +121 -0
  179. package/dist/pwa/routes/trial.js +72 -52
  180. package/dist/pwa/routes/trusted-kpi.js +20 -18
  181. package/dist/pwa/routes/url-claim.js +67 -28
  182. package/dist/pwa/routes/users-public.js +62 -70
  183. package/dist/pwa/routes/variants.js +12 -13
  184. package/dist/pwa/routes/verifier-user.js +61 -21
  185. package/dist/pwa/routes/verify-tasks.js +49 -25
  186. package/dist/pwa/routes/waitlist.js +16 -15
  187. package/dist/pwa/routes/wallet-read.js +75 -37
  188. package/dist/pwa/routes/wallet-write.js +12 -9
  189. package/dist/pwa/routes/webauthn.js +25 -26
  190. package/dist/pwa/routes/webhooks.js +26 -26
  191. package/dist/pwa/routes/welcome.js +45 -50
  192. package/dist/pwa/routes/wishlist-qa.js +29 -32
  193. package/dist/pwa/server.js +304 -90
  194. package/dist/version.js +1 -1
  195. package/package.json +76 -3
@@ -1,33 +1,35 @@
1
+ import { dbOne, dbAll, dbRun } from '../../layer0-foundation/L0-1-database/db.js'; // RFC-016 异步 DB seam
1
2
  export function registerAdminTokenomicsRoutes(app, deps) {
2
- const { db, requireProtocolAdmin, logAdminAction } = deps;
3
+ // db 已走 RFC-016 异步 seam(dbOne/dbAll/dbRun),不再直接用 deps.db
4
+ const { requireProtocolAdmin, logAdminAction } = deps;
3
5
  // Tokenomics 详细数据 + Tier 配置 + 高额榜
4
- app.get('/api/admin/tokenomics', (req, res) => {
6
+ app.get('/api/admin/tokenomics', async (req, res) => {
5
7
  const admin = requireProtocolAdmin(req, res);
6
8
  if (!admin)
7
9
  return;
8
- const tiers = db.prepare("SELECT * FROM binary_tier_config ORDER BY tier ASC").all();
9
- const topComm = db.prepare(`
10
+ const tiers = await dbAll("SELECT * FROM binary_tier_config ORDER BY tier ASC");
11
+ const topComm = await dbAll(`
10
12
  SELECT cr.beneficiary_id, u.name, COUNT(*) as records, COALESCE(SUM(cr.amount),0) as earned
11
13
  FROM commission_records cr LEFT JOIN users u ON u.id = cr.beneficiary_id
12
14
  WHERE cr.beneficiary_id != 'sys_protocol'
13
15
  GROUP BY cr.beneficiary_id ORDER BY earned DESC LIMIT 10
14
- `).all();
15
- const topBinary = db.prepare(`
16
+ `);
17
+ const topBinary = await dbAll(`
16
18
  SELECT bsr.user_id, u.name,
17
19
  COUNT(*) as hits,
18
20
  COALESCE(SUM(CASE WHEN settled_at IS NOT NULL THEN waz_amount ELSE 0 END),0) as waz_total,
19
21
  COALESCE(SUM(score),0) as score_total
20
22
  FROM binary_score_records bsr LEFT JOIN users u ON u.id = bsr.user_id
21
23
  GROUP BY bsr.user_id ORDER BY waz_total DESC LIMIT 10
22
- `).all();
23
- const gf = db.prepare("SELECT * FROM global_fund WHERE id=1").get();
24
- const mb = db.prepare("SELECT balance FROM management_bonus_pool WHERE id=1").get();
25
- const pvLedger = db.prepare(`
24
+ `);
25
+ const gf = await dbOne("SELECT * FROM global_fund WHERE id=1");
26
+ const mb = await dbOne("SELECT balance FROM management_bonus_pool WHERE id=1");
27
+ const pvLedger = await dbOne(`
26
28
  SELECT COUNT(*) as total,
27
29
  SUM(CASE WHEN processed=0 THEN 1 ELSE 0 END) as pending,
28
30
  COALESCE(SUM(CASE WHEN processed=0 THEN pv ELSE 0 END),0) as pending_pv
29
31
  FROM pv_ledger
30
- `).get();
32
+ `);
31
33
  res.json({
32
34
  global_fund: gf,
33
35
  management_bonus_pool: mb,
@@ -38,7 +40,7 @@ export function registerAdminTokenomicsRoutes(app, deps) {
38
40
  });
39
41
  });
40
42
  // 调整 Tier 配置
41
- app.post('/api/admin/tokenomics/tier', (req, res) => {
43
+ app.post('/api/admin/tokenomics/tier', async (req, res) => {
42
44
  const admin = requireProtocolAdmin(req, res);
43
45
  if (!admin)
44
46
  return;
@@ -47,50 +49,49 @@ export function registerAdminTokenomicsRoutes(app, deps) {
47
49
  return void res.json({ error: 'tier 无效' });
48
50
  if (Number(pv_threshold) <= 0 || Number(score_per_hit) <= 0)
49
51
  return void res.json({ error: '阈值/分数必须 > 0' });
50
- db.prepare(`INSERT OR REPLACE INTO binary_tier_config (tier, pv_threshold, score_per_hit, active) VALUES (?,?,?,?)`)
51
- .run(tier, Number(pv_threshold), Number(score_per_hit), active ? 1 : 0);
52
+ await dbRun(`INSERT OR REPLACE INTO binary_tier_config (tier, pv_threshold, score_per_hit, active) VALUES (?,?,?,?)`, [tier, Number(pv_threshold), Number(score_per_hit), active ? 1 : 0]);
52
53
  logAdminAction(admin.id, 'tokenomics_tier_update', 'tier', String(tier), { pv_threshold, score_per_hit, active });
53
54
  res.json({ success: true });
54
55
  });
55
56
  // 管理津贴资格列表 + 开关
56
- app.get('/api/admin/tokenomics/mgmt-bonus', (req, res) => {
57
+ app.get('/api/admin/tokenomics/mgmt-bonus', async (req, res) => {
57
58
  const admin = requireProtocolAdmin(req, res);
58
59
  if (!admin)
59
60
  return;
60
- const enabled = db.prepare("SELECT value FROM system_state WHERE key='mgmt_bonus_enabled'").get()?.value === '1';
61
- const eligible = db.prepare(`
61
+ const enabled = (await dbOne("SELECT value FROM system_state WHERE key='mgmt_bonus_enabled'"))?.value === '1';
62
+ const eligible = await dbAll(`
62
63
  SELECT u.id, u.name, u.created_at,
63
64
  (SELECT COUNT(*) FROM users WHERE sponsor_id = u.id) as l1_count,
64
65
  COALESCE((SELECT SUM(amount) FROM commission_records WHERE beneficiary_id = u.id),0) as total_commission
65
66
  FROM users u WHERE u.mgmt_bonus_eligible = 1
66
67
  ORDER BY u.created_at DESC LIMIT 100
67
- `).all();
68
+ `);
68
69
  res.json({ enabled, eligible_users: eligible, eligible_count: eligible.length });
69
70
  });
70
71
  // 注册必须 ref 开关
71
- app.post('/api/admin/tokenomics/require-ref/toggle', (req, res) => {
72
+ app.post('/api/admin/tokenomics/require-ref/toggle', async (req, res) => {
72
73
  const admin = requireProtocolAdmin(req, res);
73
74
  if (!admin)
74
75
  return;
75
76
  const { enabled } = req.body;
76
77
  const v = enabled ? '1' : '0';
77
- db.prepare("INSERT OR REPLACE INTO system_state (key, value) VALUES ('require_ref_to_register', ?)").run(v);
78
+ await dbRun("INSERT OR REPLACE INTO system_state (key, value) VALUES ('require_ref_to_register', ?)", [v]);
78
79
  logAdminAction(admin.id, 'require_ref_toggle', 'system', 'require_ref_to_register', { value: v });
79
80
  res.json({ success: true, enabled: !!enabled });
80
81
  });
81
82
  // 管理津贴池开关
82
- app.post('/api/admin/tokenomics/mgmt-bonus/toggle', (req, res) => {
83
+ app.post('/api/admin/tokenomics/mgmt-bonus/toggle', async (req, res) => {
83
84
  const admin = requireProtocolAdmin(req, res);
84
85
  if (!admin)
85
86
  return;
86
87
  const { enabled } = req.body;
87
88
  const v = enabled ? '1' : '0';
88
- db.prepare("INSERT OR REPLACE INTO system_state (key, value) VALUES ('mgmt_bonus_enabled', ?)").run(v);
89
+ await dbRun("INSERT OR REPLACE INTO system_state (key, value) VALUES ('mgmt_bonus_enabled', ?)", [v]);
89
90
  logAdminAction(admin.id, 'mgmt_bonus_toggle', 'system', 'mgmt_bonus_enabled', { value: v });
90
91
  res.json({ success: true, enabled: !!enabled });
91
92
  });
92
93
  // 池注资
93
- app.post('/api/admin/tokenomics/inject', (req, res) => {
94
+ app.post('/api/admin/tokenomics/inject', async (req, res) => {
94
95
  const admin = requireProtocolAdmin(req, res);
95
96
  if (!admin)
96
97
  return;
@@ -99,10 +100,10 @@ export function registerAdminTokenomicsRoutes(app, deps) {
99
100
  if (!(n > 0))
100
101
  return void res.json({ error: '金额必须 > 0' });
101
102
  if (pool === 'global_fund') {
102
- db.prepare("UPDATE global_fund SET pool_balance = pool_balance + ? WHERE id=1").run(n);
103
+ await dbRun("UPDATE global_fund SET pool_balance = pool_balance + ? WHERE id=1", [n]);
103
104
  }
104
105
  else if (pool === 'management_bonus') {
105
- db.prepare("UPDATE management_bonus_pool SET balance = balance + ? WHERE id=1").run(n);
106
+ await dbRun("UPDATE management_bonus_pool SET balance = balance + ? WHERE id=1", [n]);
106
107
  }
107
108
  else {
108
109
  return void res.json({ error: 'pool 名称无效(global_fund / management_bonus)' });
@@ -1,7 +1,9 @@
1
+ import { dbOne, dbRun } from '../../layer0-foundation/L0-1-database/db.js'; // RFC-016 异步 DB seam
1
2
  export function registerAdminUsersLifecycleRoutes(app, deps) {
2
- const { db, requireUsersAdmin, requireProtocolAdmin, requireContentAdmin, requireRootAdmin, adminCanOperateOn, isRootAdmin, safeRoles, logAdminAction, QUOTA_TIERS } = deps;
3
+ // db 已走 RFC-016 异步 seam(dbOne/dbRun),不再直接用 deps.db
4
+ const { requireUsersAdmin, requireProtocolAdmin, requireContentAdmin, requireRootAdmin, adminCanOperateOn, isRootAdmin, safeRoles, logAdminAction, QUOTA_TIERS } = deps;
3
5
  // L1 分享权限 override:0 auto / 1 强允 / -1 强禁
4
- app.post('/api/admin/users/:id/l1-share-override', (req, res) => {
6
+ app.post('/api/admin/users/:id/l1-share-override', async (req, res) => {
5
7
  const admin = requireProtocolAdmin(req, res);
6
8
  if (!admin)
7
9
  return;
@@ -11,38 +13,38 @@ export function registerAdminUsersLifecycleRoutes(app, deps) {
11
13
  const v = Number(value);
12
14
  if (![0, 1, -1].includes(v))
13
15
  return void res.json({ error: 'value 必须是 0 / 1 / -1' });
14
- const target = db.prepare("SELECT id FROM users WHERE id = ?").get(req.params.id);
16
+ const target = await dbOne("SELECT id FROM users WHERE id = ?", [req.params.id]);
15
17
  if (!target)
16
18
  return void res.json({ error: '用户不存在' });
17
- db.prepare("UPDATE users SET l1_share_override = ?, updated_at = datetime('now') WHERE id = ?").run(v, req.params.id);
19
+ await dbRun("UPDATE users SET l1_share_override = ?, updated_at = datetime('now') WHERE id = ?", [v, req.params.id]);
18
20
  logAdminAction(admin.id, 'l1_share_override', 'user', req.params.id, { value: v, note: note || null });
19
21
  res.json({ success: true, value: v });
20
22
  });
21
- app.post('/api/admin/users/:id/mgmt-bonus-eligible', (req, res) => {
23
+ app.post('/api/admin/users/:id/mgmt-bonus-eligible', async (req, res) => {
22
24
  const admin = requireProtocolAdmin(req, res);
23
25
  if (!admin)
24
26
  return;
25
27
  if (!adminCanOperateOn(admin, req.params.id, res))
26
28
  return;
27
29
  const { eligible, note } = req.body;
28
- const target = db.prepare("SELECT id, name FROM users WHERE id = ?").get(req.params.id);
30
+ const target = await dbOne("SELECT id, name FROM users WHERE id = ?", [req.params.id]);
29
31
  if (!target)
30
32
  return void res.json({ error: '用户不存在' });
31
- db.prepare("UPDATE users SET mgmt_bonus_eligible = ?, updated_at = datetime('now') WHERE id = ?").run(eligible ? 1 : 0, req.params.id);
33
+ await dbRun("UPDATE users SET mgmt_bonus_eligible = ?, updated_at = datetime('now') WHERE id = ?", [eligible ? 1 : 0, req.params.id]);
32
34
  logAdminAction(admin.id, eligible ? 'mgmt_bonus_grant' : 'mgmt_bonus_revoke', 'user', req.params.id, { note: note || null });
33
35
  res.json({ success: true });
34
36
  });
35
- app.post('/api/admin/users/:id/reset-failed-attempts', (req, res) => {
37
+ app.post('/api/admin/users/:id/reset-failed-attempts', async (req, res) => {
36
38
  const admin = requireUsersAdmin(req, res);
37
39
  if (!admin)
38
40
  return;
39
41
  if (!adminCanOperateOn(admin, req.params.id, res))
40
42
  return;
41
- db.prepare("UPDATE users SET failed_attempts = 0, locked_until = NULL WHERE id = ?").run(req.params.id);
43
+ await dbRun("UPDATE users SET failed_attempts = 0, locked_until = NULL WHERE id = ?", [req.params.id]);
42
44
  logAdminAction(admin.id, 'reset_failed_attempts', 'user', req.params.id, {});
43
45
  res.json({ success: true });
44
46
  });
45
- app.post('/api/admin/users/:id/force-delist-all', (req, res) => {
47
+ app.post('/api/admin/users/:id/force-delist-all', async (req, res) => {
46
48
  // P0.5: content 权限 + scope
47
49
  const admin = requireContentAdmin(req, res);
48
50
  if (!admin)
@@ -50,15 +52,15 @@ export function registerAdminUsersLifecycleRoutes(app, deps) {
50
52
  if (!adminCanOperateOn(admin, req.params.id, res))
51
53
  return;
52
54
  const { reason } = req.body;
53
- const seller = db.prepare("SELECT id, name FROM users WHERE id = ?").get(req.params.id);
55
+ const seller = await dbOne("SELECT id, name FROM users WHERE id = ?", [req.params.id]);
54
56
  if (!seller)
55
57
  return void res.json({ error: '用户不存在' });
56
- const result = db.prepare("UPDATE products SET status = 'paused', updated_at = datetime('now') WHERE seller_id = ? AND status = 'active'").run(req.params.id);
58
+ const result = await dbRun("UPDATE products SET status = 'paused', updated_at = datetime('now') WHERE seller_id = ? AND status = 'active'", [req.params.id]);
57
59
  logAdminAction(admin.id, 'force_delist_all', 'user', req.params.id, { reason: reason || null, count: result.changes });
58
60
  res.json({ success: true, count: result.changes });
59
61
  });
60
62
  // P0.4: users + scope;suspend admin → root only
61
- app.post('/api/admin/users/:id/suspend', (req, res) => {
63
+ app.post('/api/admin/users/:id/suspend', async (req, res) => {
62
64
  const admin = requireUsersAdmin(req, res);
63
65
  if (!admin)
64
66
  return;
@@ -66,7 +68,7 @@ export function registerAdminUsersLifecycleRoutes(app, deps) {
66
68
  const { reason } = req.body;
67
69
  if (targetId === admin.id)
68
70
  return void res.json({ error: '不能暂停自己' });
69
- const target = db.prepare("SELECT id, role, region FROM users WHERE id = ?").get(targetId);
71
+ const target = await dbOne("SELECT id, role, region FROM users WHERE id = ?", [targetId]);
70
72
  if (!target)
71
73
  return void res.json({ error: '用户不存在' });
72
74
  if (target.role === 'admin') {
@@ -75,35 +77,34 @@ export function registerAdminUsersLifecycleRoutes(app, deps) {
75
77
  }
76
78
  if (target.role !== 'admin' && !adminCanOperateOn(admin, targetId, res))
77
79
  return;
78
- db.prepare(`INSERT INTO user_moderation (user_id, suspended, reason, suspended_by, suspended_at)
80
+ await dbRun(`INSERT INTO user_moderation (user_id, suspended, reason, suspended_by, suspended_at)
79
81
  VALUES (?, 1, ?, ?, datetime('now'))
80
82
  ON CONFLICT(user_id) DO UPDATE SET
81
83
  suspended = 1,
82
84
  reason = excluded.reason,
83
85
  suspended_by = excluded.suspended_by,
84
- suspended_at = datetime('now')`)
85
- .run(targetId, reason || null, admin.id);
86
+ suspended_at = datetime('now')`, [targetId, reason || null, admin.id]);
86
87
  logAdminAction(admin.id, 'suspend_user', 'user', targetId, { reason: reason || null });
87
88
  res.json({ success: true });
88
89
  });
89
- app.post('/api/admin/users/:id/unsuspend', (req, res) => {
90
+ app.post('/api/admin/users/:id/unsuspend', async (req, res) => {
90
91
  const admin = requireUsersAdmin(req, res);
91
92
  if (!admin)
92
93
  return;
93
94
  const targetId = req.params.id;
94
- const target = db.prepare("SELECT id, role FROM users WHERE id = ?").get(targetId);
95
+ const target = await dbOne("SELECT id, role FROM users WHERE id = ?", [targetId]);
95
96
  if (!target)
96
97
  return void res.json({ error: '用户不存在' });
97
98
  if (target.role === 'admin' && !isRootAdmin(admin))
98
99
  return void res.status(403).json({ error: '仅 root 可恢复其他 admin' });
99
100
  if (target.role !== 'admin' && !adminCanOperateOn(admin, targetId, res))
100
101
  return;
101
- db.prepare("UPDATE user_moderation SET suspended = 0, suspended_at = NULL WHERE user_id = ?").run(targetId);
102
+ await dbRun("UPDATE user_moderation SET suspended = 0, suspended_at = NULL WHERE user_id = ?", [targetId]);
102
103
  logAdminAction(admin.id, 'unsuspend_user', 'user', targetId, {});
103
104
  res.json({ success: true });
104
105
  });
105
106
  // P0.1: admin 角色提权必须 root;其他角色需 users + scope
106
- app.post('/api/admin/users/:id/grant-role', (req, res) => {
107
+ app.post('/api/admin/users/:id/grant-role', async (req, res) => {
107
108
  const { role } = req.body;
108
109
  const allowed = ['admin', 'verifier', 'arbitrator', 'logistics', 'seller', 'buyer'];
109
110
  if (!allowed.includes(role))
@@ -114,20 +115,19 @@ export function registerAdminUsersLifecycleRoutes(app, deps) {
114
115
  const targetId = req.params.id;
115
116
  if (!adminCanOperateOn(admin, targetId, res))
116
117
  return;
117
- const target = db.prepare("SELECT id, roles FROM users WHERE id = ?").get(targetId);
118
+ const target = await dbOne("SELECT id, roles FROM users WHERE id = ?", [targetId]);
118
119
  if (!target)
119
120
  return void res.json({ error: '用户不存在' });
120
121
  const roles = safeRoles(target);
121
122
  if (roles.includes(role))
122
123
  return void res.json({ error: '该用户已拥有此角色' });
123
124
  roles.push(role);
124
- db.prepare("UPDATE users SET roles = ?, updated_at = datetime('now') WHERE id = ?")
125
- .run(JSON.stringify(roles), targetId);
125
+ await dbRun("UPDATE users SET roles = ?, updated_at = datetime('now') WHERE id = ?", [JSON.stringify(roles), targetId]);
126
126
  logAdminAction(admin.id, 'grant_role', 'user', targetId, { role });
127
127
  res.json({ success: true, roles });
128
128
  });
129
129
  // P0.2: preview diff,含 admin 变更 → root only
130
- app.post('/api/admin/users/:id/set-roles', (req, res) => {
130
+ app.post('/api/admin/users/:id/set-roles', async (req, res) => {
131
131
  const { roles } = req.body;
132
132
  const allowed = ['buyer', 'seller', 'logistics', 'arbitrator', 'verifier', 'admin'];
133
133
  if (!Array.isArray(roles) || roles.length === 0)
@@ -138,7 +138,7 @@ export function registerAdminUsersLifecycleRoutes(app, deps) {
138
138
  }
139
139
  const dedup = Array.from(new Set(roles));
140
140
  const targetId = req.params.id;
141
- const target = db.prepare("SELECT id, role, roles FROM users WHERE id = ?").get(targetId);
141
+ const target = await dbOne("SELECT id, role, roles FROM users WHERE id = ?", [targetId]);
142
142
  if (!target)
143
143
  return void res.json({ error: '用户不存在' });
144
144
  const oldRoles = (() => { try {
@@ -162,8 +162,7 @@ export function registerAdminUsersLifecycleRoutes(app, deps) {
162
162
  return void res.json({ error: '角色无变更' });
163
163
  }
164
164
  const newActiveRole = dedup.includes(target.role) ? target.role : dedup[0];
165
- db.prepare("UPDATE users SET role = ?, roles = ?, updated_at = datetime('now') WHERE id = ?")
166
- .run(newActiveRole, JSON.stringify(dedup), targetId);
165
+ await dbRun("UPDATE users SET role = ?, roles = ?, updated_at = datetime('now') WHERE id = ?", [newActiveRole, JSON.stringify(dedup), targetId]);
167
166
  if (added.length)
168
167
  logAdminAction(admin.id, 'grant_role_batch', 'user', targetId, { roles: added });
169
168
  if (removed.length)
@@ -171,7 +170,7 @@ export function registerAdminUsersLifecycleRoutes(app, deps) {
171
170
  res.json({ success: true, roles: dedup, added, removed });
172
171
  });
173
172
  // P0.3: revoke admin → root only
174
- app.post('/api/admin/users/:id/revoke-role', (req, res) => {
173
+ app.post('/api/admin/users/:id/revoke-role', async (req, res) => {
175
174
  const { role } = req.body;
176
175
  const admin = role === 'admin' ? requireRootAdmin(req, res) : requireUsersAdmin(req, res);
177
176
  if (!admin)
@@ -181,19 +180,18 @@ export function registerAdminUsersLifecycleRoutes(app, deps) {
181
180
  return;
182
181
  if (targetId === admin.id && role === 'admin')
183
182
  return void res.json({ error: '不能撤销自己的管理员角色(防自杀)' });
184
- const target = db.prepare("SELECT id, role, roles FROM users WHERE id = ?").get(targetId);
183
+ const target = await dbOne("SELECT id, role, roles FROM users WHERE id = ?", [targetId]);
185
184
  if (!target)
186
185
  return void res.json({ error: '用户不存在' });
187
186
  const roles = safeRoles(target).filter(r => r !== role);
188
187
  if (roles.length === 0)
189
188
  return void res.json({ error: '用户至少保留一个角色' });
190
189
  const newActiveRole = target.role === role ? roles[0] : target.role;
191
- db.prepare("UPDATE users SET role = ?, roles = ?, updated_at = datetime('now') WHERE id = ?")
192
- .run(newActiveRole, JSON.stringify(roles), targetId);
190
+ await dbRun("UPDATE users SET role = ?, roles = ?, updated_at = datetime('now') WHERE id = ?", [newActiveRole, JSON.stringify(roles), targetId]);
193
191
  logAdminAction(admin.id, 'revoke_role', 'user', targetId, { role });
194
192
  res.json({ success: true, roles });
195
193
  });
196
- app.post('/api/admin/users/:id/set-product-quota', (req, res) => {
194
+ app.post('/api/admin/users/:id/set-product-quota', async (req, res) => {
197
195
  const admin = requireUsersAdmin(req, res);
198
196
  if (!admin)
199
197
  return;
@@ -203,14 +201,14 @@ export function registerAdminUsersLifecycleRoutes(app, deps) {
203
201
  const n = Number(max_products);
204
202
  if (!QUOTA_TIERS.includes(n))
205
203
  return void res.json({ error: `配额应为 ${QUOTA_TIERS.join(' / ')} 之一` });
206
- const target = db.prepare("SELECT id FROM users WHERE id = ?").get(req.params.id);
204
+ const target = await dbOne("SELECT id FROM users WHERE id = ?", [req.params.id]);
207
205
  if (!target)
208
206
  return void res.json({ error: '用户不存在' });
209
- db.prepare("UPDATE users SET max_products = ?, updated_at = datetime('now') WHERE id = ?").run(n, req.params.id);
207
+ await dbRun("UPDATE users SET max_products = ?, updated_at = datetime('now') WHERE id = ?", [n, req.params.id]);
210
208
  logAdminAction(admin.id, 'set_product_quota', 'user', req.params.id, { quota: n });
211
209
  res.json({ success: true, max_products: n });
212
210
  });
213
- app.post('/api/admin/users/:id/pause-listing', (req, res) => {
211
+ app.post('/api/admin/users/:id/pause-listing', async (req, res) => {
214
212
  const admin = requireUsersAdmin(req, res);
215
213
  if (!admin)
216
214
  return;
@@ -219,18 +217,17 @@ export function registerAdminUsersLifecycleRoutes(app, deps) {
219
217
  const { reason } = req.body;
220
218
  if (!reason?.trim())
221
219
  return void res.json({ error: '请填写暂停原因' });
222
- db.prepare(`UPDATE users SET listing_paused = 1, listing_paused_reason = ?, listing_paused_by = ?, listing_paused_at = datetime('now'), updated_at = datetime('now') WHERE id = ?`)
223
- .run(reason.trim(), admin.id, req.params.id);
220
+ await dbRun(`UPDATE users SET listing_paused = 1, listing_paused_reason = ?, listing_paused_by = ?, listing_paused_at = datetime('now'), updated_at = datetime('now') WHERE id = ?`, [reason.trim(), admin.id, req.params.id]);
224
221
  logAdminAction(admin.id, 'pause_listing', 'user', req.params.id, { reason: reason.trim() });
225
222
  res.json({ success: true });
226
223
  });
227
- app.post('/api/admin/users/:id/resume-listing', (req, res) => {
224
+ app.post('/api/admin/users/:id/resume-listing', async (req, res) => {
228
225
  const admin = requireUsersAdmin(req, res);
229
226
  if (!admin)
230
227
  return;
231
228
  if (!adminCanOperateOn(admin, req.params.id, res))
232
229
  return;
233
- db.prepare(`UPDATE users SET listing_paused = 0, listing_paused_reason = NULL, updated_at = datetime('now') WHERE id = ?`).run(req.params.id);
230
+ await dbRun(`UPDATE users SET listing_paused = 0, listing_paused_reason = NULL, updated_at = datetime('now') WHERE id = ?`, [req.params.id]);
234
231
  logAdminAction(admin.id, 'resume_listing', 'user', req.params.id, {});
235
232
  res.json({ success: true });
236
233
  });