nolo-cli 0.1.30 → 0.1.31

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 (308) hide show
  1. package/agent-runtime/agentRecordConfig.ts +0 -2
  2. package/agent-runtime/hostAdapter.ts +0 -1
  3. package/agent-runtime/hostRuntimeCapabilities.ts +7 -0
  4. package/agent-runtime/hostRuntimeConfig.ts +86 -0
  5. package/agent-runtime/index.ts +13 -0
  6. package/agent-runtime/localToolPolicy.ts +13 -6
  7. package/agent-runtime/localWorkspaceTools.ts +333 -30
  8. package/agent-runtime/platformChatProvider.ts +4 -1
  9. package/agent-runtime/runtimeToolPolicy.ts +32 -47
  10. package/agent-runtime/shellCommandPolicy.ts +117 -0
  11. package/agent-runtime/toolGate.ts +38 -0
  12. package/agentRecordCommands.ts +1 -1
  13. package/agentRecordHelpers.ts +35 -20
  14. package/agentRunParsing.ts +18 -5
  15. package/agentRuntimeLocal.ts +10 -0
  16. package/ai/agent/agentRunDialogLineage.ts +56 -0
  17. package/ai/agent/agentSlice.ts +45 -10
  18. package/ai/agent/avatarUtils.ts +1 -1
  19. package/ai/agent/buildSystemPrompt.ts +1 -2
  20. package/ai/agent/cliExecutor.ts +330 -19
  21. package/ai/agent/createAgentSchema.ts +22 -0
  22. package/ai/agent/hooks/fetchPublicAgents.ts +14 -39
  23. package/ai/agent/hooks/usePublicAgents.ts +90 -192
  24. package/ai/agent/publicAgentCatalog.ts +359 -0
  25. package/ai/agent/publicAgentIdentity.ts +76 -0
  26. package/ai/agent/server/fetchPublicAgents.ts +21 -46
  27. package/ai/agent/serverOrigin.ts +7 -0
  28. package/ai/agent/streamAgentChatTurn.ts +23 -21
  29. package/ai/agent/streamAgentChatTurnUtils.ts +292 -6
  30. package/ai/agent/types.ts +2 -0
  31. package/ai/agent/web/agentDisplayUtils.ts +171 -0
  32. package/ai/agent/web/useAgentModelAvatarComponent.ts +32 -0
  33. package/ai/ai.locale.ts +8 -0
  34. package/ai/chat/sendOpenAICompletionsRequest.native.ts +15 -0
  35. package/ai/chat/sendOpenAICompletionsRequest.ts +93 -1
  36. package/ai/chat/sendOpenAIResponseRequest.ts +86 -9
  37. package/ai/chat/updateTotalUsage.ts +7 -0
  38. package/ai/llm/deepinfra.ts +30 -15
  39. package/ai/llm/mistral.ts +3 -4
  40. package/ai/llm/providers.ts +2 -0
  41. package/ai/llm/types.ts +15 -0
  42. package/ai/memory/capture.ts +3 -3
  43. package/ai/memory/consolidate.ts +2 -2
  44. package/ai/memory/delete.ts +4 -3
  45. package/ai/memory/query.ts +3 -3
  46. package/ai/memory/remember.ts +2 -2
  47. package/ai/memory/store.ts +3 -3
  48. package/ai/memory/storeShared.ts +3 -2
  49. package/ai/policy/commercialMultiplier.ts +16 -0
  50. package/ai/token/billingAdminAuditEvent.ts +68 -0
  51. package/ai/token/billingAdminAuditEventWriter.ts +41 -0
  52. package/ai/token/billingAnomaly.ts +90 -0
  53. package/ai/token/billingAnomalyLifecycle.ts +54 -0
  54. package/ai/token/billingAnomalyLifecycleWriter.ts +44 -0
  55. package/ai/token/billingAnomalyWriter.ts +41 -0
  56. package/ai/token/calculatePrice.ts +3 -2
  57. package/ai/token/deepinfraReconciliation.ts +153 -0
  58. package/ai/token/deepinfraRequestIdQuery.ts +92 -0
  59. package/ai/token/externalToolCost.ts +54 -41
  60. package/ai/token/missingUsageEstimate.ts +12 -3
  61. package/ai/token/normalizeUsage.ts +45 -5
  62. package/ai/token/openaiReconciliation.ts +188 -0
  63. package/ai/token/providerBillableEvent.ts +84 -0
  64. package/ai/token/providerBillableEventWriter.ts +36 -0
  65. package/ai/token/providerBillingAnomalyDrilldown.ts +308 -0
  66. package/ai/token/providerBillingDrilldown.ts +361 -0
  67. package/ai/token/providerBillingHealthReport.ts +366 -0
  68. package/ai/token/providerCall.ts +144 -0
  69. package/ai/token/providerCallSweeper.ts +168 -0
  70. package/ai/token/providerCallWriter.ts +33 -0
  71. package/ai/token/providerCredential.ts +89 -0
  72. package/ai/token/providerCredentialAnomaly.ts +154 -0
  73. package/ai/token/providerCredentialLifecycle.ts +59 -0
  74. package/ai/token/providerCredentialLifecycleWriter.ts +44 -0
  75. package/ai/token/providerCredentialRegistry.ts +83 -0
  76. package/ai/token/providerCredentialRegistryCommand.ts +97 -0
  77. package/ai/token/providerCredentialRegistryList.ts +124 -0
  78. package/ai/token/providerCredentialRegistryResolver.ts +150 -0
  79. package/ai/token/providerCredentialRegistryWriter.ts +41 -0
  80. package/ai/token/providerCredentialRotationCommand.ts +102 -0
  81. package/ai/token/providerCredentialRuntime.ts +56 -0
  82. package/ai/token/providerDispatchIntent.ts +67 -0
  83. package/ai/token/providerDispatchIntentWriter.ts +36 -0
  84. package/ai/token/providerGateway.ts +260 -0
  85. package/ai/token/providerReconciliation.ts +148 -0
  86. package/ai/token/providerReconciliationLocal.ts +97 -0
  87. package/ai/token/providerReconciliationRunner.ts +165 -0
  88. package/ai/token/providerReconciliationWriter.ts +41 -0
  89. package/ai/token/ratingResult.ts +202 -0
  90. package/ai/token/ratingResultWriter.ts +33 -0
  91. package/ai/token/serverDialogProjection.ts +5 -3
  92. package/ai/token/serverTokenWriter.ts +11 -3
  93. package/ai/token/types.ts +10 -0
  94. package/ai/tools/agent/callAgentTool.ts +3 -4
  95. package/ai/tools/agent/presets/appBuilderPreset.ts +5 -7
  96. package/ai/tools/agent/runStreamingAgentTool.ts +1 -2
  97. package/ai/tools/agent/streamParallelAgentsTool.ts +2 -3
  98. package/ai/tools/readXPostTool.ts +1 -5
  99. package/app/admin/adminPages.ts +9 -0
  100. package/app/i18n/i18n.config.ts +5 -0
  101. package/app/i18n/translations/pricing.locale.ts +397 -0
  102. package/app/utils/desktopAgentRuntimeStatusClient.ts +5 -4
  103. package/app/utils/desktopAgentRuntimeTurnClient.ts +4 -1
  104. package/app/utils/imageUtils.ts +64 -34
  105. package/auth/adminPermissions.ts +18 -0
  106. package/auth/authSlice.ts +26 -12
  107. package/auth/hooks/useFetchUsers.ts +3 -0
  108. package/auth/routes.ts +46 -0
  109. package/auth/server/accessActivity.ts +4 -3
  110. package/auth/server/adminPermissions.ts +43 -0
  111. package/auth/server/adminUsageReport.ts +375 -0
  112. package/auth/server/billingAnomalies.ts +235 -0
  113. package/auth/server/billingUsageReport.ts +41 -2
  114. package/auth/server/creatorEarningCreditConversion.ts +10 -2
  115. package/auth/server/deduct.ts +14 -7
  116. package/auth/server/delete.ts +10 -2
  117. package/auth/server/disable.ts +4 -3
  118. package/auth/server/emailAutomation.ts +7 -5
  119. package/auth/server/emailDbConfig.ts +4 -2
  120. package/auth/server/emailDelivery.ts +24 -20
  121. package/auth/server/emailDeliveryGuards.ts +10 -7
  122. package/auth/server/emailPreferences.ts +6 -4
  123. package/auth/server/emailReport.ts +6 -4
  124. package/auth/server/emailRuntimeConfig.ts +3 -3
  125. package/auth/server/emailScenarioNotifications.ts +9 -8
  126. package/auth/server/enable.ts +4 -3
  127. package/auth/server/getRechargeHistory.ts +3 -2
  128. package/auth/server/getUser.ts +3 -2
  129. package/auth/server/gptProAccess.ts +44 -0
  130. package/auth/server/inviteReward.ts +10 -7
  131. package/auth/server/listusers.ts +6 -4
  132. package/auth/server/login.ts +2 -2
  133. package/auth/server/productEntitlements.ts +7 -4
  134. package/auth/server/productPurchase.ts +10 -2
  135. package/auth/server/providerBillingDrilldown.ts +47 -0
  136. package/auth/server/providerBillingHealth.ts +71 -0
  137. package/auth/server/providerCredentials.ts +136 -0
  138. package/auth/server/recharge.ts +14 -8
  139. package/auth/server/revokeSessions.ts +4 -3
  140. package/auth/server/route.ts +77 -0
  141. package/auth/server/sendEmail.ts +5 -4
  142. package/auth/server/signup.ts +10 -3
  143. package/auth/server/token.ts +53 -55
  144. package/auth/server/tokenUsageBilling.ts +18 -7
  145. package/auth/server/usageManagementAccess.ts +43 -0
  146. package/auth/server/usageReport.ts +59 -0
  147. package/auth/types.ts +12 -0
  148. package/auth/utils.ts +24 -22
  149. package/authCommands.ts +36 -2
  150. package/buildPublish.ts +3 -1
  151. package/buildPublishArtifactAssembly.ts +62 -1
  152. package/buildPublishImportAnalysis.ts +21 -16
  153. package/chat/dialog/dialogLaunchScope.ts +32 -0
  154. package/chat/dialog/objectAssistantRegistry.ts +2 -2
  155. package/chat/dialog/useCreateDialog.ts +1 -1
  156. package/chat/hooks/useChatInput.ts +41 -10
  157. package/chat/messages/messageSlice.ts +5 -1
  158. package/chat/messages/pendingAttachmentParts.ts +28 -2
  159. package/chat/messages/sendFirstMessage.ts +76 -79
  160. package/chat/messages/types.ts +9 -0
  161. package/chat/messages/web/streamingMarkdownModel.ts +41 -0
  162. package/chat/messages/web/useStreamingReveal.ts +91 -0
  163. package/chat/web/messageInputAgentUi.ts +94 -6
  164. package/cliEnvHelpers.ts +8 -0
  165. package/cliRuntimeDoctorReport.ts +193 -0
  166. package/client/agentConfigResolver.test.ts +0 -2
  167. package/client/agentRun.test.ts +171 -10
  168. package/client/agentRun.ts +44 -637
  169. package/client/agentRunInput.ts +10 -0
  170. package/client/agentRunLocalExecutor.ts +179 -0
  171. package/client/agentRunServerTransport.ts +394 -0
  172. package/client/agentRunTaskRunRecorder.ts +176 -0
  173. package/client/localRuntimeAdapter.test.ts +236 -9
  174. package/client/localRuntimeAdapter.ts +221 -23
  175. package/client/localToolPolicy.test.ts +28 -4
  176. package/connector-experimental/daemonLauncher.ts +38 -4
  177. package/connectorRunArtifact.ts +34 -10
  178. package/connectorWebSocketTarget.ts +9 -5
  179. package/core/builtinAgents.ts +155 -11
  180. package/create/space/contentLabels.ts +1 -1
  181. package/create/space/contentTypeMeta.ts +3 -2
  182. package/create/space/sidebarVisibleTypes.ts +27 -0
  183. package/create/space/space.locale.ts +76 -4
  184. package/database/actions/agentReadResolution.ts +2 -8
  185. package/database/actions/read.ts +11 -9
  186. package/database/actions/readAndWait.ts +10 -5
  187. package/database/server/agentDelegation.ts +3 -2
  188. package/database/server/authorityStoreConformance.ts +209 -0
  189. package/database/server/authorityStoreTypes.ts +31 -0
  190. package/database/server/coreDataProxy.ts +1 -1
  191. package/database/server/dataHandlers.ts +13 -5
  192. package/database/server/db.ts +15 -34
  193. package/database/server/delete.ts +88 -71
  194. package/database/server/emailRepository.ts +11 -9
  195. package/database/server/fileService.ts +2 -1
  196. package/database/server/legacyServerDb.ts +58 -0
  197. package/database/server/levelAuthorityStore.ts +75 -0
  198. package/database/server/memoryAuthorityStore.ts +133 -0
  199. package/database/server/patch.ts +13 -12
  200. package/database/server/query.ts +3 -2
  201. package/database/server/read.ts +33 -30
  202. package/database/server/resourceAccess.ts +7 -5
  203. package/database/server/serverStoreFactory.ts +124 -0
  204. package/database/server/spaceMemberAuthority.ts +3 -2
  205. package/database/server/storeBatchCompat.ts +37 -0
  206. package/database/server/testAuthorityStore.ts +76 -0
  207. package/database/server/write.ts +29 -27
  208. package/integrations/anthropic/anthropicModels.ts +12 -12
  209. package/integrations/deepseek/models.ts +67 -67
  210. package/integrations/google/models.ts +111 -53
  211. package/integrations/openai/models.ts +22 -22
  212. package/integrations/xai/models.ts +1 -1
  213. package/localRuntimeDb.ts +39 -2
  214. package/machineCommandPrompts.ts +2 -0
  215. package/machineCommands.ts +193 -63
  216. package/machineWsRunDispatch.ts +80 -15
  217. package/machineWsSession.ts +39 -2
  218. package/noloReadBridgePrompt.ts +16 -0
  219. package/package.json +99 -6
  220. package/render/layout/mainLayoutViewMode.ts +25 -0
  221. package/render/page/server/createPage.ts +3 -1
  222. package/render/page/server/handleCreatePage.ts +2 -11
  223. package/runtimeDoctorCommands.ts +15 -66
  224. package/server/api/methods.ts +34 -12
  225. package/server/api/tableHandlers.ts +6 -3
  226. package/server/authenticateToken.ts +47 -2
  227. package/server/billingLedgerRoutes.ts +15 -0
  228. package/server/buildManifest.ts +54 -0
  229. package/server/coreReadiness.ts +34 -25
  230. package/server/coreRuntime.ts +15 -10
  231. package/server/handlers/activityStatsHandler.ts +5 -2
  232. package/server/handlers/agentEmailRegistrationE2EHandler.ts +25 -23
  233. package/server/handlers/agentRun/agentLookup.ts +1 -7
  234. package/server/handlers/agentRun/autonomousRuntime.ts +11 -10
  235. package/server/handlers/agentRun/builtinAgents.ts +12 -88
  236. package/server/handlers/agentRun/continueDialogContext.ts +15 -3
  237. package/server/handlers/agentRun/{inheritedDialogPrompt.ts → conversationReference.ts} +3 -3
  238. package/server/handlers/agentRun/dialogLookup.ts +4 -3
  239. package/server/handlers/agentRun/index.ts +864 -404
  240. package/server/handlers/agentRun/localRuntimeBootstrap.ts +17 -1
  241. package/server/handlers/agentRun/loop.ts +920 -508
  242. package/server/handlers/agentRun/machineConnector.ts +56 -8
  243. package/server/handlers/agentRun/machineRunAudit.ts +3 -2
  244. package/server/handlers/agentRun/modelUsageToolHandlers.ts +13 -10
  245. package/server/handlers/agentRun/requestContext.ts +12 -8
  246. package/server/handlers/agentRun/runtimeExecutionContext.ts +15 -3
  247. package/server/handlers/agentRun/runtimePreparation.ts +26 -24
  248. package/server/handlers/agentRun/runtimeRouting.ts +25 -40
  249. package/server/handlers/agentRun/runtimeSystemMessages.ts +65 -0
  250. package/server/handlers/agentRun/saveDialog.ts +97 -87
  251. package/server/handlers/agentRun/taskRunToolHandler.ts +9 -7
  252. package/server/handlers/agentRun/toolExecutor.ts +42 -78
  253. package/server/handlers/agentRun/types.ts +2 -1
  254. package/server/handlers/appDeployStatusStore.ts +17 -10
  255. package/server/handlers/appDomainHandler.ts +21 -15
  256. package/server/handlers/appLegacyInfraCleanup.ts +5 -2
  257. package/server/handlers/appSandboxHandler.ts +29 -8
  258. package/server/handlers/appSpaceAccess.ts +15 -8
  259. package/server/handlers/chatHandler.ts +22 -2
  260. package/server/handlers/chatUpstreamRetry.ts +225 -2
  261. package/server/handlers/connector/connectorConnectionRegistry.ts +55 -7
  262. package/server/handlers/connector/connectorWebSocket.ts +14 -10
  263. package/server/handlers/desktopAgentRuntimeAdapter.ts +4 -4
  264. package/server/handlers/desktopAgentRuntimeHostCapabilities.ts +25 -0
  265. package/server/handlers/desktopAgentRuntimeReadiness.ts +62 -0
  266. package/server/handlers/desktopAgentRuntimeStatusHandler.ts +38 -30
  267. package/server/handlers/desktopAgentRuntimeTurnHandler.ts +7 -3
  268. package/server/handlers/desktopAgentRuntimeTurnService.ts +39 -45
  269. package/server/handlers/desktopLlamaRuntimeHandler.ts +85 -51
  270. package/server/handlers/desktopUpdaterHandler.ts +132 -24
  271. package/server/handlers/favoriteHandlers.ts +8 -2
  272. package/server/handlers/getDialogBillingHandler.ts +4 -3
  273. package/server/handlers/getTransactionsHandler.ts +5 -2
  274. package/server/handlers/machines/machineBinding.ts +1 -0
  275. package/server/handlers/machines/machineHandlers.ts +0 -14
  276. package/server/handlers/machines/machineInstallAssets.ts +4 -2
  277. package/server/handlers/notificationEmitter.ts +5 -3
  278. package/server/handlers/notificationsHandler.ts +5 -2
  279. package/server/handlers/providerCallsRecentHandler.ts +234 -0
  280. package/server/handlers/providerReconciliationRunHandler.ts +180 -0
  281. package/server/handlers/providerRequestIdsHandler.ts +105 -0
  282. package/server/handlers/tableAccess.ts +6 -2
  283. package/server/handlers/tableToolHandlers.ts +28 -14
  284. package/server/handlers/userSecretsHandler.ts +17 -6
  285. package/server/handlers/versionHandler.ts +9 -4
  286. package/server/handlers/versionStore.ts +18 -10
  287. package/server/html/ssrPreload.ts +5 -3
  288. package/server/payments/crypto/cryptoUsdcBasePaymentProvider.ts +11 -8
  289. package/server/payments/crypto/cryptoUsdcBaseScanner.ts +12 -7
  290. package/server/payments/crypto/cryptoUsdtTronPaymentProvider.ts +11 -8
  291. package/server/payments/crypto/cryptoUsdtTronScanner.ts +9 -7
  292. package/server/payments/waffo/waffoPaymentProvider.ts +12 -9
  293. package/server/runtimeRole.ts +15 -0
  294. package/server/scheduler/scheduledTaskRuntime.ts +4 -2
  295. package/server/scheduler/schedulerService.ts +2 -2
  296. package/server/taskRunBridgeRoutes.ts +8 -5
  297. package/share/server/fetchCommunityShares.ts +1 -1
  298. package/share/server/helpers.ts +19 -17
  299. package/share/server/importShare.ts +9 -13
  300. package/share/server/listCommunityShares.ts +4 -4
  301. package/share/server/purchaseDoc.ts +8 -16
  302. package/share/server/readCommunityShareCover.ts +3 -2
  303. package/share/server/readSharedTable.ts +14 -13
  304. package/share/server/tableReplication.ts +42 -39
  305. package/spaceAttachCommands.ts +135 -0
  306. package/spaceInternalCommandEntries.ts +2 -0
  307. package/ai/agent/runtimeServerBase.ts +0 -37
  308. package/server/handlers/desktopAgentRuntimeHostFacts.ts +0 -40
@@ -1,4 +1,4 @@
1
- import serverDb from "../../database/server/db";
1
+ import { getServerAuthorityStore } from "../../database/server/db";
2
2
 
3
3
  export type ProductKind = "doc" | "agent" | "tool" | "license";
4
4
  export type ProductStatus = "active" | "disabled";
@@ -66,6 +66,9 @@ export type ProductEntitlementStore = {
66
66
  get: (key: string) => Promise<unknown>;
67
67
  };
68
68
 
69
+ const getDefaultProductEntitlementStore = (): ProductEntitlementStore =>
70
+ getServerAuthorityStore();
71
+
69
72
  export const productKey = (productId: string) => `product-${productId}`;
70
73
 
71
74
  export const productPurchaseKey = (buyerId: string, productId: string) =>
@@ -87,7 +90,7 @@ const getMaybe = async <T>(
87
90
  };
88
91
 
89
92
  export const getProductRecord = async ({
90
- store = serverDb,
93
+ store = getDefaultProductEntitlementStore(),
91
94
  productId,
92
95
  }: {
93
96
  store?: ProductEntitlementStore;
@@ -96,7 +99,7 @@ export const getProductRecord = async ({
96
99
  getMaybe<ProductRecord>(store, productKey(productId));
97
100
 
98
101
  export const getProductPriceCredits = async ({
99
- store = serverDb,
102
+ store = getDefaultProductEntitlementStore(),
100
103
  productId,
101
104
  }: {
102
105
  store?: ProductEntitlementStore;
@@ -112,7 +115,7 @@ export const getProductPriceCredits = async ({
112
115
  };
113
116
 
114
117
  export const getActiveEntitlement = async ({
115
- store = serverDb,
118
+ store = getDefaultProductEntitlementStore(),
116
119
  userId,
117
120
  productId,
118
121
  nowMs = Date.now(),
@@ -1,5 +1,6 @@
1
1
  import { DB_PREFIX, createTransactionKey } from "../../database/keys";
2
- import serverDb from "../../database/server/db";
2
+ import { getServerAuthorityStore } from "../../database/server/db";
3
+ import { writeStoreOps } from "../../database/server/storeBatchCompat";
3
4
 
4
5
  import { balanceLockManager } from "./locks";
5
6
  import {
@@ -26,6 +27,13 @@ type ProductPurchaseStore = {
26
27
  ) => Promise<void>;
27
28
  };
28
29
 
30
+ const createProductPurchaseStore = (
31
+ authorityStore = getServerAuthorityStore()
32
+ ): ProductPurchaseStore => ({
33
+ get: (key) => authorityStore.get(key),
34
+ batch: (ops) => writeStoreOps(authorityStore, ops),
35
+ });
36
+
29
37
  export type PurchaseProductResult =
30
38
  | {
31
39
  success: true;
@@ -73,7 +81,7 @@ const isPositiveFinite = (value: unknown): value is number =>
73
81
  typeof value === "number" && Number.isFinite(value) && value > 0;
74
82
 
75
83
  export async function purchaseProduct({
76
- store = serverDb,
84
+ store = createProductPurchaseStore(getServerAuthorityStore()),
77
85
  runtime,
78
86
  buyerId,
79
87
  productId,
@@ -0,0 +1,47 @@
1
+ import { buildProviderBillingDrilldown } from "../../ai/token/providerBillingDrilldown";
2
+ import { getServerAuthorityStore } from "../../database/server/db";
3
+ import {
4
+ createErrorResponse,
5
+ createSuccessResponse,
6
+ handleOptionsRequest,
7
+ } from "./shared";
8
+ import { canManageUsageReportAccess } from "./usageManagementAccess";
9
+
10
+ const parseLimit = (value: string | null) => {
11
+ const parsed = Number(value);
12
+ if (!Number.isFinite(parsed)) return 50;
13
+ return Math.min(Math.max(Math.floor(parsed), 1), 200);
14
+ };
15
+
16
+ export async function handleGetProviderBillingDrilldown(req: Request) {
17
+ if (req.method === "OPTIONS") {
18
+ return handleOptionsRequest();
19
+ }
20
+
21
+ const { userId: actionUserId } = req.user;
22
+ if (!(await canManageUsageReportAccess(actionUserId))) {
23
+ return createErrorResponse("Unauthorized: Usage management access required", 403);
24
+ }
25
+
26
+ try {
27
+ const url = new URL(req.url);
28
+ const bucketId = url.searchParams.get("bucketId")?.trim();
29
+ if (!bucketId) {
30
+ return createErrorResponse("Missing bucketId", 400);
31
+ }
32
+ const drilldown = await buildProviderBillingDrilldown({
33
+ store: getServerAuthorityStore(),
34
+ bucketId,
35
+ limit: parseLimit(url.searchParams.get("limit")),
36
+ });
37
+ return createSuccessResponse({ success: true, drilldown });
38
+ } catch (error) {
39
+ if (
40
+ error instanceof Error &&
41
+ error.message.startsWith("provider reconciliation bucket not found:")
42
+ ) {
43
+ return createErrorResponse("Provider reconciliation bucket not found", 404);
44
+ }
45
+ return createErrorResponse("Internal server error");
46
+ }
47
+ }
@@ -0,0 +1,71 @@
1
+ import { buildProviderBillingHealthReport } from "../../ai/token/providerBillingHealthReport";
2
+ import { getServerAuthorityStore } from "../../database/server/db";
3
+ import {
4
+ createErrorResponse,
5
+ createSuccessResponse,
6
+ handleOptionsRequest,
7
+ } from "./shared";
8
+ import { canManageUsageReportAccess } from "./usageManagementAccess";
9
+
10
+ const parseTimestamp = (value: string | null) => {
11
+ if (!value) return null;
12
+ const trimmed = value.trim();
13
+ if (!trimmed) return null;
14
+ if (/^\d+$/.test(trimmed)) {
15
+ const numberValue = Number(trimmed);
16
+ return Number.isFinite(numberValue) ? new Date(numberValue).toISOString() : null;
17
+ }
18
+ const parsed = Date.parse(trimmed);
19
+ return Number.isFinite(parsed) ? new Date(parsed).toISOString() : null;
20
+ };
21
+
22
+ const parseSinceDays = (value: string | null) => {
23
+ if (!value) return 7;
24
+ const parsed = Number(value);
25
+ if (!Number.isFinite(parsed) || parsed <= 0) return 7;
26
+ return Math.min(parsed, 3660);
27
+ };
28
+
29
+ const parseLimit = (value: string | null) => {
30
+ const parsed = Number(value);
31
+ if (!Number.isFinite(parsed)) return 20;
32
+ return Math.min(Math.max(Math.floor(parsed), 1), 200);
33
+ };
34
+
35
+ export async function handleGetProviderBillingHealth(req: Request) {
36
+ if (req.method === "OPTIONS") {
37
+ return handleOptionsRequest();
38
+ }
39
+
40
+ const { userId: actionUserId } = req.user;
41
+ if (!(await canManageUsageReportAccess(actionUserId))) {
42
+ return createErrorResponse("Unauthorized: Usage management access required", 403);
43
+ }
44
+
45
+ try {
46
+ const url = new URL(req.url);
47
+ const now = Date.now();
48
+ const until =
49
+ parseTimestamp(url.searchParams.get("until")) ?? new Date(now).toISOString();
50
+ const since =
51
+ parseTimestamp(url.searchParams.get("since")) ??
52
+ new Date(
53
+ Date.parse(until) -
54
+ parseSinceDays(url.searchParams.get("sinceDays")) * 24 * 3600_000
55
+ ).toISOString();
56
+ if (Date.parse(since) > Date.parse(until)) {
57
+ return createErrorResponse("Invalid provider billing health time range", 400);
58
+ }
59
+
60
+ const report = await buildProviderBillingHealthReport({
61
+ store: getServerAuthorityStore(),
62
+ since,
63
+ until,
64
+ limit: parseLimit(url.searchParams.get("limit")),
65
+ });
66
+
67
+ return createSuccessResponse({ success: true, report });
68
+ } catch {
69
+ return createErrorResponse("Internal server error");
70
+ }
71
+ }
@@ -0,0 +1,136 @@
1
+ import { listProviderCredentialRegistryRecords } from "../../ai/token/providerCredentialRegistryList";
2
+ import type { ProviderCredentialStatus } from "../../ai/token/providerCredentialRegistry";
3
+ import { createProviderCredentialLifecycleEvent } from "../../ai/token/providerCredentialLifecycle";
4
+ import { writeProviderCredentialLifecycleEvent } from "../../ai/token/providerCredentialLifecycleWriter";
5
+ import { getServerAuthorityStore } from "../../database/server/db";
6
+ import { ulid } from "ulid";
7
+ import {
8
+ createErrorResponse,
9
+ createSuccessResponse,
10
+ handleOptionsRequest,
11
+ } from "./shared";
12
+ import { canManageUsageReportAccess } from "./usageManagementAccess";
13
+
14
+ const serverDb = getServerAuthorityStore();
15
+
16
+ const parseStatus = (value: string | null): ProviderCredentialStatus | undefined => {
17
+ if (value === "active" || value === "rotating" || value === "revoked") {
18
+ return value;
19
+ }
20
+ return undefined;
21
+ };
22
+
23
+ const parseTimestamp = (value: string | null) => {
24
+ if (!value?.trim()) return undefined;
25
+ const parsed = Date.parse(value);
26
+ return Number.isFinite(parsed) ? new Date(parsed).toISOString() : undefined;
27
+ };
28
+
29
+ const parseBodyTimestamp = (value: unknown) => {
30
+ if (typeof value !== "string" || !value.trim()) return undefined;
31
+ const parsed = Date.parse(value);
32
+ return Number.isFinite(parsed) ? new Date(parsed).toISOString() : undefined;
33
+ };
34
+
35
+ type ProviderCredentialLifecycleDeps = {
36
+ store?: Parameters<typeof writeProviderCredentialLifecycleEvent>[0]["store"];
37
+ canManage?: (userId?: string | null) => Promise<boolean>;
38
+ now?: () => string;
39
+ createEventId?: () => string;
40
+ };
41
+
42
+ export async function handleListProviderCredentials(req: Request) {
43
+ if (req.method === "OPTIONS") {
44
+ return handleOptionsRequest();
45
+ }
46
+
47
+ const { userId: actionUserId } = req.user;
48
+ if (!(await canManageUsageReportAccess(actionUserId))) {
49
+ return createErrorResponse("Unauthorized: Usage management access required", 403);
50
+ }
51
+
52
+ try {
53
+ const url = new URL(req.url);
54
+ const result = await listProviderCredentialRegistryRecords({
55
+ store: serverDb,
56
+ provider: url.searchParams.get("provider") ?? undefined,
57
+ status: parseStatus(url.searchParams.get("status")),
58
+ at: parseTimestamp(url.searchParams.get("at")),
59
+ });
60
+
61
+ return createSuccessResponse({ success: true, ...result });
62
+ } catch {
63
+ return createErrorResponse("Internal server error");
64
+ }
65
+ }
66
+
67
+ export async function handleUpdateProviderCredentialLifecycle(
68
+ req: Request,
69
+ deps: ProviderCredentialLifecycleDeps = {}
70
+ ) {
71
+ if (req.method === "OPTIONS") {
72
+ return handleOptionsRequest();
73
+ }
74
+
75
+ const { userId: actionUserId } = req.user;
76
+ const canManage = deps.canManage ?? canManageUsageReportAccess;
77
+ if (!(await canManage(actionUserId))) {
78
+ return createErrorResponse("Unauthorized: Usage management access required", 403);
79
+ }
80
+
81
+ let body: Record<string, unknown>;
82
+ try {
83
+ body = (await req.json()) as Record<string, unknown>;
84
+ } catch {
85
+ return createErrorResponse("Invalid JSON body", 400);
86
+ }
87
+
88
+ const credentialId =
89
+ typeof body.credentialId === "string" ? body.credentialId.trim() : "";
90
+ if (!credentialId) {
91
+ return createErrorResponse("credentialId is required", 400);
92
+ }
93
+
94
+ const status = parseStatus(
95
+ typeof body.status === "string" ? body.status : null
96
+ );
97
+ if (!status) {
98
+ return createErrorResponse("status must be active, rotating, or revoked", 400);
99
+ }
100
+
101
+ const now = deps.now?.() ?? new Date().toISOString();
102
+ const effectiveAt = parseBodyTimestamp(body.effectiveAt) ?? now;
103
+ const event = createProviderCredentialLifecycleEvent({
104
+ credentialId,
105
+ eventId:
106
+ typeof body.eventId === "string" && body.eventId.trim()
107
+ ? body.eventId.trim()
108
+ : deps.createEventId?.() ?? `evt_${ulid()}`,
109
+ status,
110
+ effectiveAt,
111
+ createdAt: now,
112
+ reason: typeof body.reason === "string" ? body.reason : undefined,
113
+ actorId: actionUserId,
114
+ });
115
+
116
+ try {
117
+ const result = await writeProviderCredentialLifecycleEvent({
118
+ store: deps.store ?? serverDb,
119
+ event,
120
+ });
121
+ return createSuccessResponse({
122
+ success: true,
123
+ key: result.key,
124
+ event: {
125
+ credentialId: event.credentialId,
126
+ eventId: event.eventId,
127
+ status: event.status,
128
+ effectiveAt: event.effectiveAt,
129
+ createdAt: event.createdAt,
130
+ actorId: event.actorId,
131
+ },
132
+ });
133
+ } catch {
134
+ return createErrorResponse("Internal server error");
135
+ }
136
+ }
@@ -1,6 +1,7 @@
1
1
  // auth/server/recharge.ts
2
2
  import { ulid } from "ulid";
3
- import serverDb from "../../database/server/db";
3
+ import { getServerAuthorityStore } from "../../database/server/db";
4
+ import { writeStoreOps } from "../../database/server/storeBatchCompat";
4
5
  import { createTransactionKey } from "../../database/keys";
5
6
  import { balanceLockManager } from "./locks";
6
7
  import { withRetry } from "./utils";
@@ -12,7 +13,6 @@ import {
12
13
  prepareLedgerTransactionAppend,
13
14
  userAvailableCreditsAccountId,
14
15
  } from "./ledger";
15
-
16
16
  const logger = pino({ name: "recharge" });
17
17
 
18
18
  interface RechargeResult {
@@ -59,6 +59,12 @@ export async function rechargeUserBalance(
59
59
  txId: string = ulid()
60
60
  ): Promise<RechargeResult> {
61
61
  const lock = balanceLockManager.getLock(toUserId);
62
+ const store = getServerAuthorityStore();
63
+ const ledgerStore = {
64
+ get: (key: string) => store.get(key),
65
+ batch: (ops: Array<{ type: "put"; key: string; value: unknown }>) =>
66
+ writeStoreOps(store, ops),
67
+ };
62
68
 
63
69
  return await lock.runExclusive(async () => {
64
70
  try {
@@ -73,7 +79,7 @@ export async function rechargeUserBalance(
73
79
  let existingTx = null;
74
80
 
75
81
  try {
76
- existingTx = await serverDb.get(txIndexKey);
82
+ existingTx = await store.get(txIndexKey);
77
83
  } catch (err) {
78
84
  if (!(err instanceof Error && "notFound" in err)) {
79
85
  throw err;
@@ -93,7 +99,7 @@ export async function rechargeUserBalance(
93
99
  let userData: UserData | null = null;
94
100
 
95
101
  try {
96
- userData = await serverDb.get(userKey);
102
+ userData = await store.get(userKey);
97
103
  logger.debug({ toUserId, userData, userKey }, "Retrieved user data");
98
104
  } catch (err) {
99
105
  if (err instanceof Error && "notFound" in err) {
@@ -121,7 +127,7 @@ export async function rechargeUserBalance(
121
127
  const currentBalance = userData.balance;
122
128
  const now = Date.now();
123
129
  const ledgerAppend = await prepareLedgerTransactionAppend({
124
- store: serverDb,
130
+ store: ledgerStore,
125
131
  type: "recharge",
126
132
  reason,
127
133
  idempotencyKey: txId,
@@ -181,7 +187,7 @@ export async function rechargeUserBalance(
181
187
 
182
188
  await withRetry(
183
189
  async () => {
184
- await serverDb.batch([
190
+ await writeStoreOps(store, [
185
191
  ...ledgerAppend.operations,
186
192
  {
187
193
  type: "put",
@@ -239,7 +245,7 @@ export async function rechargeUserBalance(
239
245
  let txRecord: TransactionRecord | null = null;
240
246
 
241
247
  try {
242
- txRecord = await serverDb.get(txKey);
248
+ txRecord = await store.get(txKey);
243
249
  } catch (err) {
244
250
  if (!(err instanceof Error && "notFound" in err)) {
245
251
  throw err;
@@ -247,7 +253,7 @@ export async function rechargeUserBalance(
247
253
  }
248
254
 
249
255
  if (txRecord) {
250
- await serverDb.put(txKey, {
256
+ await store.put(txKey, {
251
257
  ...txRecord,
252
258
  status: "failed",
253
259
  });
@@ -1,6 +1,6 @@
1
1
  import { verifyToken } from "../token";
2
2
  import { getNextSessionTokenVersion } from "../sessionTokenVersion";
3
- import serverDb from "../../database/server/db";
3
+ import { getServerAuthorityStore } from "../../database/server/db";
4
4
  import { DB_PREFIX } from "../../database/keys";
5
5
 
6
6
  import {
@@ -10,6 +10,7 @@ import {
10
10
  } from "./shared";
11
11
 
12
12
  export async function handleRevokeSessions(req: any) {
13
+ const store = getServerAuthorityStore();
13
14
  if (req.method === "OPTIONS") {
14
15
  return handleOptionsRequest();
15
16
  }
@@ -29,7 +30,7 @@ export async function handleRevokeSessions(req: any) {
29
30
  }
30
31
 
31
32
  const userKey = `${DB_PREFIX.USER}${authedUserId}`;
32
- const user = await serverDb.get(userKey);
33
+ const user = await store.get(userKey);
33
34
  if (!user?.publicKey) {
34
35
  return createErrorResponse("User not found", 404);
35
36
  }
@@ -46,7 +47,7 @@ export async function handleRevokeSessions(req: any) {
46
47
  }
47
48
 
48
49
  const nextTokenVersion = getNextSessionTokenVersion(user);
49
- await serverDb.put(userKey, {
50
+ await store.put(userKey, {
50
51
  ...user,
51
52
  tokenVersion: nextTokenVersion,
52
53
  tokenVersionUpdatedAt: Date.now(),
@@ -14,6 +14,7 @@ import { handleRevokeSessions } from "./revokeSessions";
14
14
  import { handleTransferUser } from "./transfer";
15
15
  import { handleDisableUser } from "./disable";
16
16
  import { handleEnableUser } from "./enable";
17
+ import { handleUpdateUserAdminPermissions } from "./adminPermissions";
17
18
  import { handleSendEmail } from "./sendEmail";
18
19
  import {
19
20
  handleGetEmailPreferences,
@@ -29,6 +30,19 @@ import {
29
30
  handleUpdateEmailRuntimeConfig,
30
31
  } from "./emailRuntimeConfig";
31
32
  import { handleGetRechargeHistory } from "./getRechargeHistory";
33
+ import { handleAdminUsageReport } from "./adminUsageReport";
34
+ import { handleGetUsageReport } from "./usageReport";
35
+ import { handleGetProviderBillingHealth } from "./providerBillingHealth";
36
+ import { handleGetProviderBillingDrilldown } from "./providerBillingDrilldown";
37
+ import {
38
+ handleListProviderCredentials,
39
+ handleUpdateProviderCredentialLifecycle,
40
+ } from "./providerCredentials";
41
+ import {
42
+ handleCreateBillingAdminAuditEvent,
43
+ handleGetBillingAnomalyDrilldown,
44
+ handleUpdateBillingAnomalyLifecycle,
45
+ } from "./billingAnomalies";
32
46
 
33
47
  const routeHandlers = [
34
48
  {
@@ -86,6 +100,14 @@ const routeHandlers = [
86
100
  "send-email",
87
101
  "email-preferences",
88
102
  "email-report",
103
+ "usage-report",
104
+ "provider-billing-health",
105
+ "provider-billing-drilldown",
106
+ "provider-credentials",
107
+ "provider-credentials/lifecycle",
108
+ "billing-anomalies/lifecycle",
109
+ "billing-anomalies/drilldown",
110
+ "billing-anomalies/audit",
89
111
  "email-retry",
90
112
  "email-replay-failures",
91
113
  "email-config",
@@ -125,6 +147,16 @@ const routeHandlers = [
125
147
  handler: (req, params: RouteParams) =>
126
148
  handleEnableUser(req, params.userId!),
127
149
  },
150
+ {
151
+ ...authRoutes.users.adminPermissions,
152
+ match: (path: string) => {
153
+ const matcher = createPathMatcher(authRoutes.users.adminPermissions.path);
154
+ const match = path.match(matcher);
155
+ return match ? { userId: match[1] } : false;
156
+ },
157
+ handler: (req, params: RouteParams) =>
158
+ handleUpdateUserAdminPermissions(req, params.userId!),
159
+ },
128
160
  {
129
161
  ...authRoutes.users.sendEmail,
130
162
  match: (path: string) => path === authRoutes.users.sendEmail.path,
@@ -145,6 +177,51 @@ const routeHandlers = [
145
177
  match: (path: string) => path === authRoutes.users.emailReport.path,
146
178
  handler: (req) => handleGetEmailReport(req),
147
179
  },
180
+ {
181
+ ...authRoutes.users.usageReport,
182
+ match: (path: string) => path === authRoutes.users.usageReport.path,
183
+ handler: (req) => {
184
+ const url = new URL(req.url);
185
+ return url.searchParams.has("sinceMs") || url.searchParams.has("untilMs")
186
+ ? handleAdminUsageReport(req)
187
+ : handleGetUsageReport(req);
188
+ },
189
+ },
190
+ {
191
+ ...authRoutes.users.providerBillingHealth,
192
+ match: (path: string) => path === authRoutes.users.providerBillingHealth.path,
193
+ handler: (req) => handleGetProviderBillingHealth(req),
194
+ },
195
+ {
196
+ ...authRoutes.users.providerBillingDrilldown,
197
+ match: (path: string) => path === authRoutes.users.providerBillingDrilldown.path,
198
+ handler: (req) => handleGetProviderBillingDrilldown(req),
199
+ },
200
+ {
201
+ ...authRoutes.users.providerCredentials,
202
+ match: (path: string) => path === authRoutes.users.providerCredentials.path,
203
+ handler: (req) => handleListProviderCredentials(req),
204
+ },
205
+ {
206
+ ...authRoutes.users.providerCredentialLifecycle,
207
+ match: (path: string) => path === authRoutes.users.providerCredentialLifecycle.path,
208
+ handler: (req) => handleUpdateProviderCredentialLifecycle(req),
209
+ },
210
+ {
211
+ ...authRoutes.users.billingAnomalyLifecycle,
212
+ match: (path: string) => path === authRoutes.users.billingAnomalyLifecycle.path,
213
+ handler: (req) => handleUpdateBillingAnomalyLifecycle(req),
214
+ },
215
+ {
216
+ ...authRoutes.users.billingAnomalyDrilldown,
217
+ match: (path: string) => path === authRoutes.users.billingAnomalyDrilldown.path,
218
+ handler: (req) => handleGetBillingAnomalyDrilldown(req),
219
+ },
220
+ {
221
+ ...authRoutes.users.billingAnomalyAudit,
222
+ match: (path: string) => path === authRoutes.users.billingAnomalyAudit.path,
223
+ handler: (req) => handleCreateBillingAdminAuditEvent(req),
224
+ },
148
225
  {
149
226
  ...authRoutes.users.emailRetryRun,
150
227
  match: (path: string) => path === authRoutes.users.emailRetryRun.path,
@@ -1,5 +1,5 @@
1
1
  import { DB_PREFIX } from "../../database/keys";
2
- import serverDb from "../../database/server/db";
2
+ import { getServerAuthorityStore } from "../../database/server/db";
3
3
  import {
4
4
  checkAdminPermission,
5
5
  createErrorResponse,
@@ -46,6 +46,7 @@ export async function handleSendEmail(req: Request) {
46
46
  if (permissionError) return permissionError;
47
47
 
48
48
  try {
49
+ const store = getServerAuthorityStore();
49
50
  const broadcastConfig = getBroadcastConfig();
50
51
  const { subject, body, isHtml, userIds, tag } = ((req as any).body ||
51
52
  {}) as SendEmailRequest;
@@ -64,7 +65,7 @@ export async function handleSendEmail(req: Request) {
64
65
  const uniqueIds = [...new Set(userIds.map((id: string) => id.trim()).filter(Boolean))];
65
66
  for (const id of uniqueIds) {
66
67
  try {
67
- const userData = await serverDb.get(prefix + id);
68
+ const userData = await store.get(prefix + id);
68
69
  const decision = canSendEmailToUser(userData, emailTag, now);
69
70
  if (decision.allowed) {
70
71
  recipients.push({ email: String(userData.email), id });
@@ -76,7 +77,7 @@ export async function handleSendEmail(req: Request) {
76
77
  }
77
78
  }
78
79
  } else {
79
- const iter = serverDb.iterator({
80
+ const iter = store.iterator({
80
81
  gt: prefix,
81
82
  lt: prefix + "\xFF",
82
83
  });
@@ -96,7 +97,7 @@ export async function handleSendEmail(req: Request) {
96
97
  }
97
98
  }
98
99
  } finally {
99
- await iter.close();
100
+ await (iter as any).close?.();
100
101
  }
101
102
  }
102
103
 
@@ -2,7 +2,8 @@
2
2
  // 注册接口(按 IP 配额限制,默认:同一 IP 每日仅允许注册 1 个;支持灵活扩展周/月窗口)
3
3
 
4
4
  import i18nServer from "../../app/i18n/i18n.server";
5
- import serverDb from "../../database/server/db.js";
5
+ import { getServerAuthorityStore } from "../../database/server/db";
6
+ import { writeStoreOps } from "../../database/server/storeBatchCompat";
6
7
  import { signMessage } from "../../core/crypto";
7
8
  import { generateUserIdV1 } from "../../core/generateMainKey";
8
9
  import {
@@ -30,6 +31,7 @@ import {
30
31
  const logger = pino({ name: "signup" });
31
32
  const signupLocks = new Map<string, Mutex>();
32
33
  const signupIpLocks = new Map<string, Mutex>();
34
+ const getSignupStore = () => getServerAuthorityStore();
33
35
 
34
36
  function getSignupLock(userId: string): Mutex {
35
37
  let lock = signupLocks.get(userId);
@@ -85,6 +87,7 @@ function getDayKeysBackwards(days: number): string[] {
85
87
  }
86
88
 
87
89
  async function getIpDayCount(ip: string, dayKey: string): Promise<number> {
90
+ const serverDb = getSignupStore();
88
91
  try {
89
92
  const val = await serverDb.get(ABUSE_PREFIX.byIpDay(ip, dayKey));
90
93
  const n = Number(val);
@@ -124,6 +127,7 @@ async function checkIpQuotas(ip: string, t: any) {
124
127
  }
125
128
 
126
129
  async function recordIpRegistration(ip: string) {
130
+ const serverDb = getSignupStore();
127
131
  const today = getDayKey();
128
132
  const key = ABUSE_PREFIX.byIpDay(ip, today);
129
133
  let count = 0;
@@ -168,6 +172,7 @@ function generateUserId(publicKey: string, username: string, locale: string) {
168
172
  }
169
173
 
170
174
  async function checkUserExists(userId: string, t: any) {
175
+ const serverDb = getSignupStore();
171
176
  try {
172
177
  const existingUser = await serverDb.get(DB_PREFIX.USER + userId);
173
178
  if (existingUser) {
@@ -229,7 +234,8 @@ async function saveUserDataToDb(
229
234
  userSettings: any,
230
235
  userProfile: any
231
236
  ) {
232
- await serverDb.batch([
237
+ const serverDb = getSignupStore();
238
+ await writeStoreOps(serverDb, [
233
239
  { type: "put", key: DB_PREFIX.USER + userId, value: userData },
234
240
  { type: "put", key: createUserKey.settings(userId), value: userSettings },
235
241
  { type: "put", key: createUserKey.profile(userId), value: userProfile },
@@ -237,7 +243,8 @@ async function saveUserDataToDb(
237
243
  }
238
244
 
239
245
  async function rollbackUserDataFromDb(userId: string) {
240
- await serverDb.batch([
246
+ const serverDb = getSignupStore();
247
+ await writeStoreOps(serverDb, [
241
248
  { type: "del", key: DB_PREFIX.USER + userId },
242
249
  { type: "del", key: createUserKey.settings(userId) },
243
250
  { type: "del", key: createUserKey.profile(userId) },