nolo-cli 0.1.29 → 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 (329) 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/agentCreateCustomCommands.ts +9 -4
  13. package/agentDialogsCommands.ts +4 -3
  14. package/agentDoctorCommands.ts +3 -3
  15. package/agentListCommands.ts +3 -3
  16. package/agentMachineCommands.ts +6 -6
  17. package/agentPullCommand.ts +4 -12
  18. package/agentRecordCommands.ts +5 -3
  19. package/agentRecordHelpers.ts +42 -23
  20. package/agentRunCommand.ts +2 -6
  21. package/agentRunParsing.ts +18 -5
  22. package/agentRuntimeLocal.ts +10 -0
  23. package/agentUnpublishCommands.ts +3 -2
  24. package/ai/agent/agentRunDialogLineage.ts +56 -0
  25. package/ai/agent/agentSlice.ts +45 -10
  26. package/ai/agent/avatarUtils.ts +1 -1
  27. package/ai/agent/buildSystemPrompt.ts +1 -2
  28. package/ai/agent/cliExecutor.ts +330 -19
  29. package/ai/agent/createAgentSchema.ts +22 -0
  30. package/ai/agent/hooks/fetchPublicAgents.ts +14 -39
  31. package/ai/agent/hooks/usePublicAgents.ts +90 -192
  32. package/ai/agent/publicAgentCatalog.ts +359 -0
  33. package/ai/agent/publicAgentIdentity.ts +76 -0
  34. package/ai/agent/server/fetchPublicAgents.ts +21 -46
  35. package/ai/agent/serverOrigin.ts +7 -0
  36. package/ai/agent/streamAgentChatTurn.ts +23 -21
  37. package/ai/agent/streamAgentChatTurnUtils.ts +292 -6
  38. package/ai/agent/types.ts +2 -0
  39. package/ai/agent/web/agentDisplayUtils.ts +171 -0
  40. package/ai/agent/web/useAgentModelAvatarComponent.ts +32 -0
  41. package/ai/ai.locale.ts +8 -0
  42. package/ai/chat/sendOpenAICompletionsRequest.native.ts +15 -0
  43. package/ai/chat/sendOpenAICompletionsRequest.ts +93 -1
  44. package/ai/chat/sendOpenAIResponseRequest.ts +86 -9
  45. package/ai/chat/updateTotalUsage.ts +7 -0
  46. package/ai/llm/deepinfra.ts +30 -15
  47. package/ai/llm/mistral.ts +3 -4
  48. package/ai/llm/providers.ts +2 -0
  49. package/ai/llm/types.ts +15 -0
  50. package/ai/memory/capture.ts +3 -3
  51. package/ai/memory/consolidate.ts +2 -2
  52. package/ai/memory/delete.ts +4 -3
  53. package/ai/memory/query.ts +3 -3
  54. package/ai/memory/remember.ts +2 -2
  55. package/ai/memory/store.ts +3 -3
  56. package/ai/memory/storeShared.ts +3 -2
  57. package/ai/policy/commercialMultiplier.ts +16 -0
  58. package/ai/token/billingAdminAuditEvent.ts +68 -0
  59. package/ai/token/billingAdminAuditEventWriter.ts +41 -0
  60. package/ai/token/billingAnomaly.ts +90 -0
  61. package/ai/token/billingAnomalyLifecycle.ts +54 -0
  62. package/ai/token/billingAnomalyLifecycleWriter.ts +44 -0
  63. package/ai/token/billingAnomalyWriter.ts +41 -0
  64. package/ai/token/calculatePrice.ts +3 -2
  65. package/ai/token/deepinfraReconciliation.ts +153 -0
  66. package/ai/token/deepinfraRequestIdQuery.ts +92 -0
  67. package/ai/token/externalToolCost.ts +54 -41
  68. package/ai/token/missingUsageEstimate.ts +12 -3
  69. package/ai/token/normalizeUsage.ts +45 -5
  70. package/ai/token/openaiReconciliation.ts +188 -0
  71. package/ai/token/providerBillableEvent.ts +84 -0
  72. package/ai/token/providerBillableEventWriter.ts +36 -0
  73. package/ai/token/providerBillingAnomalyDrilldown.ts +308 -0
  74. package/ai/token/providerBillingDrilldown.ts +361 -0
  75. package/ai/token/providerBillingHealthReport.ts +366 -0
  76. package/ai/token/providerCall.ts +144 -0
  77. package/ai/token/providerCallSweeper.ts +168 -0
  78. package/ai/token/providerCallWriter.ts +33 -0
  79. package/ai/token/providerCredential.ts +89 -0
  80. package/ai/token/providerCredentialAnomaly.ts +154 -0
  81. package/ai/token/providerCredentialLifecycle.ts +59 -0
  82. package/ai/token/providerCredentialLifecycleWriter.ts +44 -0
  83. package/ai/token/providerCredentialRegistry.ts +83 -0
  84. package/ai/token/providerCredentialRegistryCommand.ts +97 -0
  85. package/ai/token/providerCredentialRegistryList.ts +124 -0
  86. package/ai/token/providerCredentialRegistryResolver.ts +150 -0
  87. package/ai/token/providerCredentialRegistryWriter.ts +41 -0
  88. package/ai/token/providerCredentialRotationCommand.ts +102 -0
  89. package/ai/token/providerCredentialRuntime.ts +56 -0
  90. package/ai/token/providerDispatchIntent.ts +67 -0
  91. package/ai/token/providerDispatchIntentWriter.ts +36 -0
  92. package/ai/token/providerGateway.ts +260 -0
  93. package/ai/token/providerReconciliation.ts +148 -0
  94. package/ai/token/providerReconciliationLocal.ts +97 -0
  95. package/ai/token/providerReconciliationRunner.ts +165 -0
  96. package/ai/token/providerReconciliationWriter.ts +41 -0
  97. package/ai/token/ratingResult.ts +202 -0
  98. package/ai/token/ratingResultWriter.ts +33 -0
  99. package/ai/token/serverDialogProjection.ts +5 -3
  100. package/ai/token/serverTokenWriter.ts +11 -3
  101. package/ai/token/types.ts +10 -0
  102. package/ai/tools/agent/callAgentTool.ts +3 -4
  103. package/ai/tools/agent/presets/appBuilderPreset.ts +5 -7
  104. package/ai/tools/agent/runStreamingAgentTool.ts +1 -2
  105. package/ai/tools/agent/streamParallelAgentsTool.ts +2 -3
  106. package/ai/tools/readXPostTool.ts +1 -5
  107. package/app/admin/adminPages.ts +9 -0
  108. package/app/i18n/i18n.config.ts +5 -0
  109. package/app/i18n/translations/pricing.locale.ts +397 -0
  110. package/app/utils/desktopAgentRuntimeStatusClient.ts +5 -4
  111. package/app/utils/desktopAgentRuntimeTurnClient.ts +4 -1
  112. package/app/utils/imageUtils.ts +64 -34
  113. package/auth/adminPermissions.ts +18 -0
  114. package/auth/authSlice.ts +26 -12
  115. package/auth/hooks/useFetchUsers.ts +3 -0
  116. package/auth/routes.ts +46 -0
  117. package/auth/server/accessActivity.ts +4 -3
  118. package/auth/server/adminPermissions.ts +43 -0
  119. package/auth/server/adminUsageReport.ts +375 -0
  120. package/auth/server/billingAnomalies.ts +235 -0
  121. package/auth/server/billingUsageReport.ts +41 -2
  122. package/auth/server/creatorEarningCreditConversion.ts +10 -2
  123. package/auth/server/deduct.ts +14 -7
  124. package/auth/server/delete.ts +10 -2
  125. package/auth/server/disable.ts +4 -3
  126. package/auth/server/emailAutomation.ts +7 -5
  127. package/auth/server/emailDbConfig.ts +4 -2
  128. package/auth/server/emailDelivery.ts +24 -20
  129. package/auth/server/emailDeliveryGuards.ts +10 -7
  130. package/auth/server/emailPreferences.ts +6 -4
  131. package/auth/server/emailReport.ts +6 -4
  132. package/auth/server/emailRuntimeConfig.ts +3 -3
  133. package/auth/server/emailScenarioNotifications.ts +9 -8
  134. package/auth/server/enable.ts +4 -3
  135. package/auth/server/getRechargeHistory.ts +3 -2
  136. package/auth/server/getUser.ts +3 -2
  137. package/auth/server/gptProAccess.ts +44 -0
  138. package/auth/server/inviteReward.ts +10 -7
  139. package/auth/server/listusers.ts +6 -4
  140. package/auth/server/login.ts +2 -2
  141. package/auth/server/productEntitlements.ts +7 -4
  142. package/auth/server/productPurchase.ts +10 -2
  143. package/auth/server/providerBillingDrilldown.ts +47 -0
  144. package/auth/server/providerBillingHealth.ts +71 -0
  145. package/auth/server/providerCredentials.ts +136 -0
  146. package/auth/server/recharge.ts +14 -8
  147. package/auth/server/revokeSessions.ts +4 -3
  148. package/auth/server/route.ts +77 -0
  149. package/auth/server/sendEmail.ts +5 -4
  150. package/auth/server/signup.ts +10 -3
  151. package/auth/server/token.ts +53 -55
  152. package/auth/server/tokenUsageBilling.ts +18 -7
  153. package/auth/server/usageManagementAccess.ts +43 -0
  154. package/auth/server/usageReport.ts +59 -0
  155. package/auth/types.ts +12 -0
  156. package/auth/utils.ts +24 -22
  157. package/authCommands.ts +36 -2
  158. package/buildPublish.ts +3 -1
  159. package/buildPublishArtifactAssembly.ts +62 -1
  160. package/buildPublishImportAnalysis.ts +21 -16
  161. package/chat/dialog/dialogLaunchScope.ts +32 -0
  162. package/chat/dialog/objectAssistantRegistry.ts +2 -2
  163. package/chat/dialog/useCreateDialog.ts +1 -1
  164. package/chat/hooks/useChatInput.ts +41 -10
  165. package/chat/messages/messageSlice.ts +5 -1
  166. package/chat/messages/pendingAttachmentParts.ts +28 -2
  167. package/chat/messages/sendFirstMessage.ts +76 -79
  168. package/chat/messages/types.ts +9 -0
  169. package/chat/messages/web/streamingMarkdownModel.ts +41 -0
  170. package/chat/messages/web/useStreamingReveal.ts +91 -0
  171. package/chat/web/messageInputAgentUi.ts +94 -6
  172. package/cliEnvHelpers.ts +68 -13
  173. package/cliRuntimeDoctorReport.ts +193 -0
  174. package/client/agentConfigResolver.test.ts +0 -2
  175. package/client/agentRun.test.ts +171 -10
  176. package/client/agentRun.ts +44 -637
  177. package/client/agentRunInput.ts +10 -0
  178. package/client/agentRunLocalExecutor.ts +179 -0
  179. package/client/agentRunServerTransport.ts +394 -0
  180. package/client/agentRunTaskRunRecorder.ts +176 -0
  181. package/client/localRuntimeAdapter.test.ts +236 -9
  182. package/client/localRuntimeAdapter.ts +221 -23
  183. package/client/localToolPolicy.test.ts +28 -4
  184. package/connector-experimental/daemonLauncher.ts +38 -4
  185. package/connectorRunArtifact.ts +34 -10
  186. package/connectorWebSocketTarget.ts +40 -15
  187. package/core/builtinAgents.ts +155 -11
  188. package/create/space/contentLabels.ts +1 -1
  189. package/create/space/contentTypeMeta.ts +3 -2
  190. package/create/space/sidebarVisibleTypes.ts +27 -0
  191. package/create/space/space.locale.ts +76 -4
  192. package/database/actions/agentReadResolution.ts +2 -8
  193. package/database/actions/read.ts +11 -9
  194. package/database/actions/readAndWait.ts +10 -5
  195. package/database/server/agentDelegation.ts +3 -2
  196. package/database/server/authorityStoreConformance.ts +209 -0
  197. package/database/server/authorityStoreTypes.ts +31 -0
  198. package/database/server/coreDataProxy.ts +1 -1
  199. package/database/server/dataHandlers.ts +13 -5
  200. package/database/server/db.ts +15 -34
  201. package/database/server/delete.ts +88 -71
  202. package/database/server/emailRepository.ts +11 -9
  203. package/database/server/fileService.ts +2 -1
  204. package/database/server/legacyServerDb.ts +58 -0
  205. package/database/server/levelAuthorityStore.ts +75 -0
  206. package/database/server/memoryAuthorityStore.ts +133 -0
  207. package/database/server/patch.ts +13 -12
  208. package/database/server/query.ts +3 -2
  209. package/database/server/read.ts +33 -30
  210. package/database/server/resourceAccess.ts +7 -5
  211. package/database/server/serverStoreFactory.ts +124 -0
  212. package/database/server/spaceMemberAuthority.ts +3 -2
  213. package/database/server/storeBatchCompat.ts +37 -0
  214. package/database/server/testAuthorityStore.ts +76 -0
  215. package/database/server/write.ts +29 -27
  216. package/dialogReadCommands.ts +2 -1
  217. package/dialogStatusCommands.ts +2 -1
  218. package/integrations/anthropic/anthropicModels.ts +12 -12
  219. package/integrations/deepseek/models.ts +67 -67
  220. package/integrations/google/models.ts +111 -53
  221. package/integrations/openai/models.ts +22 -22
  222. package/integrations/xai/models.ts +1 -1
  223. package/localRuntimeDb.ts +39 -2
  224. package/machineCommandPrompts.ts +2 -0
  225. package/machineCommands.ts +193 -62
  226. package/machineStatusCommands.ts +4 -12
  227. package/machineWsRunDispatch.ts +80 -15
  228. package/machineWsSession.ts +46 -2
  229. package/noloReadBridgePrompt.ts +16 -0
  230. package/package.json +114 -21
  231. package/pageCreateCommands.ts +2 -2
  232. package/pageDeleteCommands.ts +3 -3
  233. package/pageReadCommands.ts +3 -3
  234. package/pageUpdateCommands.ts +3 -3
  235. package/render/layout/mainLayoutViewMode.ts +25 -0
  236. package/render/page/server/createPage.ts +3 -1
  237. package/render/page/server/handleCreatePage.ts +2 -11
  238. package/runtimeDoctorCommands.ts +18 -69
  239. package/server/api/methods.ts +34 -12
  240. package/server/api/tableHandlers.ts +6 -3
  241. package/server/authenticateToken.ts +47 -2
  242. package/server/billingLedgerRoutes.ts +15 -0
  243. package/server/buildManifest.ts +54 -0
  244. package/server/coreReadiness.ts +34 -25
  245. package/server/coreRuntime.ts +15 -10
  246. package/server/handlers/activityStatsHandler.ts +5 -2
  247. package/server/handlers/agentEmailRegistrationE2EHandler.ts +25 -23
  248. package/server/handlers/agentRun/agentLookup.ts +1 -7
  249. package/server/handlers/agentRun/autonomousRuntime.ts +11 -10
  250. package/server/handlers/agentRun/builtinAgents.ts +12 -88
  251. package/server/handlers/agentRun/continueDialogContext.ts +15 -3
  252. package/server/handlers/agentRun/{inheritedDialogPrompt.ts → conversationReference.ts} +3 -3
  253. package/server/handlers/agentRun/dialogLookup.ts +4 -3
  254. package/server/handlers/agentRun/index.ts +864 -404
  255. package/server/handlers/agentRun/localRuntimeBootstrap.ts +17 -1
  256. package/server/handlers/agentRun/loop.ts +920 -508
  257. package/server/handlers/agentRun/machineConnector.ts +56 -8
  258. package/server/handlers/agentRun/machineRunAudit.ts +3 -2
  259. package/server/handlers/agentRun/modelUsageToolHandlers.ts +13 -10
  260. package/server/handlers/agentRun/requestContext.ts +12 -8
  261. package/server/handlers/agentRun/runtimeExecutionContext.ts +15 -3
  262. package/server/handlers/agentRun/runtimePreparation.ts +26 -24
  263. package/server/handlers/agentRun/runtimeRouting.ts +25 -40
  264. package/server/handlers/agentRun/runtimeSystemMessages.ts +65 -0
  265. package/server/handlers/agentRun/saveDialog.ts +97 -87
  266. package/server/handlers/agentRun/taskRunToolHandler.ts +9 -7
  267. package/server/handlers/agentRun/toolExecutor.ts +42 -78
  268. package/server/handlers/agentRun/types.ts +2 -1
  269. package/server/handlers/appDeployStatusStore.ts +17 -10
  270. package/server/handlers/appDomainHandler.ts +21 -15
  271. package/server/handlers/appLegacyInfraCleanup.ts +5 -2
  272. package/server/handlers/appSandboxHandler.ts +29 -8
  273. package/server/handlers/appSpaceAccess.ts +15 -8
  274. package/server/handlers/chatHandler.ts +22 -2
  275. package/server/handlers/chatUpstreamRetry.ts +225 -2
  276. package/server/handlers/connector/connectorConnectionRegistry.ts +55 -7
  277. package/server/handlers/connector/connectorWebSocket.ts +14 -10
  278. package/server/handlers/desktopAgentRuntimeAdapter.ts +4 -4
  279. package/server/handlers/desktopAgentRuntimeHostCapabilities.ts +25 -0
  280. package/server/handlers/desktopAgentRuntimeReadiness.ts +62 -0
  281. package/server/handlers/desktopAgentRuntimeStatusHandler.ts +38 -30
  282. package/server/handlers/desktopAgentRuntimeTurnHandler.ts +7 -3
  283. package/server/handlers/desktopAgentRuntimeTurnService.ts +39 -45
  284. package/server/handlers/desktopLlamaRuntimeHandler.ts +85 -51
  285. package/server/handlers/desktopUpdaterHandler.ts +132 -24
  286. package/server/handlers/favoriteHandlers.ts +8 -2
  287. package/server/handlers/getDialogBillingHandler.ts +4 -3
  288. package/server/handlers/getTransactionsHandler.ts +5 -2
  289. package/server/handlers/machines/machineBinding.ts +1 -0
  290. package/server/handlers/machines/machineHandlers.ts +0 -14
  291. package/server/handlers/machines/machineInstallAssets.ts +4 -2
  292. package/server/handlers/notificationEmitter.ts +5 -3
  293. package/server/handlers/notificationsHandler.ts +5 -2
  294. package/server/handlers/providerCallsRecentHandler.ts +234 -0
  295. package/server/handlers/providerReconciliationRunHandler.ts +180 -0
  296. package/server/handlers/providerRequestIdsHandler.ts +105 -0
  297. package/server/handlers/tableAccess.ts +6 -2
  298. package/server/handlers/tableToolHandlers.ts +28 -14
  299. package/server/handlers/userSecretsHandler.ts +17 -6
  300. package/server/handlers/versionHandler.ts +9 -4
  301. package/server/handlers/versionStore.ts +18 -10
  302. package/server/html/ssrPreload.ts +5 -3
  303. package/server/payments/crypto/cryptoUsdcBasePaymentProvider.ts +11 -8
  304. package/server/payments/crypto/cryptoUsdcBaseScanner.ts +12 -7
  305. package/server/payments/crypto/cryptoUsdtTronPaymentProvider.ts +11 -8
  306. package/server/payments/crypto/cryptoUsdtTronScanner.ts +9 -7
  307. package/server/payments/waffo/waffoPaymentProvider.ts +12 -9
  308. package/server/runtimeRole.ts +15 -0
  309. package/server/scheduler/scheduledTaskRuntime.ts +4 -2
  310. package/server/scheduler/schedulerService.ts +2 -2
  311. package/server/taskRunBridgeRoutes.ts +8 -5
  312. package/share/server/fetchCommunityShares.ts +1 -1
  313. package/share/server/helpers.ts +19 -17
  314. package/share/server/importShare.ts +9 -13
  315. package/share/server/listCommunityShares.ts +4 -4
  316. package/share/server/purchaseDoc.ts +8 -16
  317. package/share/server/readCommunityShareCover.ts +3 -2
  318. package/share/server/readSharedTable.ts +14 -13
  319. package/share/server/tableReplication.ts +42 -39
  320. package/spaceAttachCommands.ts +135 -0
  321. package/spaceCategoryCommands.ts +6 -6
  322. package/spaceCommands.ts +3 -3
  323. package/spaceDeleteCommands.ts +2 -2
  324. package/spaceInternalCommandEntries.ts +2 -0
  325. package/spaceReadCommands.ts +3 -3
  326. package/tableMetaCommands.ts +2 -2
  327. package/taskRunCommand.ts +11 -0
  328. package/ai/agent/runtimeServerBase.ts +0 -37
  329. package/server/handlers/desktopAgentRuntimeHostFacts.ts +0 -40
@@ -0,0 +1,209 @@
1
+ import { describe, expect, it } from "bun:test";
2
+
3
+ import type { AuthorityStore } from "./authorityStoreTypes";
4
+
5
+ type FakeLevelOp = { type: "put" | "del"; key: string; value?: unknown };
6
+
7
+ type FakeNotFoundError = Error & { notFound: true };
8
+
9
+ const createNotFoundError = (): FakeNotFoundError => {
10
+ const error = new Error("NotFound") as FakeNotFoundError;
11
+ error.notFound = true;
12
+ return error;
13
+ };
14
+
15
+ export class FakeAuthorityBacking {
16
+ location = "/tmp/authority-conformance";
17
+ status = "closed";
18
+ private readonly data = new Map<string, unknown>();
19
+
20
+ async open() {
21
+ this.status = "open";
22
+ }
23
+
24
+ async close() {
25
+ this.status = "closed";
26
+ }
27
+
28
+ async get(key: string) {
29
+ if (!this.data.has(key)) {
30
+ throw createNotFoundError();
31
+ }
32
+ return this.data.get(key);
33
+ }
34
+
35
+ async put(key: string, value: unknown) {
36
+ this.data.set(key, value);
37
+ }
38
+
39
+ async del(key: string) {
40
+ this.data.delete(key);
41
+ }
42
+
43
+ batch(ops?: FakeLevelOp[]) {
44
+ if (Array.isArray(ops)) {
45
+ return Promise.resolve().then(async () => {
46
+ for (const op of ops) {
47
+ if (op.type === "put") {
48
+ await this.put(op.key, op.value);
49
+ } else {
50
+ await this.del(op.key);
51
+ }
52
+ }
53
+ });
54
+ }
55
+
56
+ const buffered: FakeLevelOp[] = [];
57
+ return {
58
+ put: (key: string, value: unknown) => {
59
+ buffered.push({ type: "put", key, value });
60
+ },
61
+ del: (key: string) => {
62
+ buffered.push({ type: "del", key });
63
+ },
64
+ write: async () => {
65
+ await this.batch(buffered);
66
+ },
67
+ };
68
+ }
69
+
70
+ async *iterator(options: {
71
+ gte?: string;
72
+ lte?: string;
73
+ lt?: string;
74
+ reverse?: boolean;
75
+ } = {}) {
76
+ const keys = Array.from(this.data.keys()).sort();
77
+ if (options.reverse) keys.reverse();
78
+ for (const key of keys) {
79
+ if (options.gte && key < options.gte) continue;
80
+ if (options.lte && key > options.lte) continue;
81
+ if (options.lt && key >= options.lt) continue;
82
+ yield [key, this.data.get(key)] as [string, unknown];
83
+ }
84
+ }
85
+ }
86
+
87
+ type CreateStore = () => Promise<{
88
+ backing: FakeAuthorityBacking;
89
+ store: AuthorityStore;
90
+ }>;
91
+
92
+ export function runAuthorityStoreConformanceSuite(
93
+ label: string,
94
+ createStore: CreateStore,
95
+ options: {
96
+ expectedLocation?: string;
97
+ } = {}
98
+ ) {
99
+ const expectedLocation =
100
+ options.expectedLocation ?? "/tmp/authority-conformance";
101
+
102
+ describe(label, () => {
103
+ it("preserves open/close status, location, and NotFound semantics", async () => {
104
+ const { store } = await createStore();
105
+
106
+ expect(store.status).toBe("closed");
107
+ expect(store.location).toBe(expectedLocation);
108
+
109
+ await store.open();
110
+ expect(store.status).toBe("open");
111
+
112
+ await expect(store.get("missing")).rejects.toMatchObject({
113
+ message: "NotFound",
114
+ notFound: true,
115
+ });
116
+
117
+ await store.close();
118
+ expect(store.status).toBe("closed");
119
+ });
120
+
121
+ it("supports direct put/get/del writes", async () => {
122
+ const { store } = await createStore();
123
+
124
+ await store.put("alpha", { value: 1 });
125
+ await store.put("beta", { value: 2 });
126
+
127
+ expect(await store.get("alpha")).toEqual({ value: 1 });
128
+ expect(await store.get("beta")).toEqual({ value: 2 });
129
+
130
+ await store.del("alpha");
131
+ await expect(store.get("alpha")).rejects.toMatchObject({
132
+ message: "NotFound",
133
+ notFound: true,
134
+ });
135
+ });
136
+
137
+ it("supports array-style batchWrite with mixed put/del operations", async () => {
138
+ const { store } = await createStore();
139
+
140
+ await store.batchWrite([
141
+ { type: "put", key: "alpha", value: 1 },
142
+ { type: "put", key: "beta", value: 2 },
143
+ { type: "del", key: "alpha" },
144
+ ]);
145
+
146
+ await expect(store.get("alpha")).rejects.toMatchObject({
147
+ message: "NotFound",
148
+ notFound: true,
149
+ });
150
+ expect(await store.get("beta")).toBe(2);
151
+ });
152
+
153
+ it("supports builder-style createBatch writes", async () => {
154
+ const { store } = await createStore();
155
+
156
+ await store.put("alpha", 1);
157
+
158
+ const batch = store.createBatch();
159
+ batch.put("beta", 2);
160
+ batch.del("alpha");
161
+ batch.put("gamma", 3);
162
+ await batch.write();
163
+
164
+ await expect(store.get("alpha")).rejects.toMatchObject({
165
+ message: "NotFound",
166
+ notFound: true,
167
+ });
168
+ expect(await store.get("beta")).toBe(2);
169
+ expect(await store.get("gamma")).toBe(3);
170
+ });
171
+
172
+ it("preserves ordered iterator range semantics", async () => {
173
+ const { store } = await createStore();
174
+
175
+ await store.put("a", 1);
176
+ await store.put("b", 2);
177
+ await store.put("c", 3);
178
+
179
+ const scanned: Array<[string, unknown]> = [];
180
+ for await (const entry of store.iterator({ gte: "a", lt: "c" })) {
181
+ scanned.push(entry);
182
+ }
183
+
184
+ expect(scanned).toEqual([
185
+ ["a", 1],
186
+ ["b", 2],
187
+ ]);
188
+ });
189
+
190
+ it("preserves reverse iterator semantics within a bounded range", async () => {
191
+ const { store } = await createStore();
192
+
193
+ await store.put("a", 1);
194
+ await store.put("b", 2);
195
+ await store.put("c", 3);
196
+
197
+ const scanned: string[] = [];
198
+ for await (const [key] of store.iterator({
199
+ gte: "a",
200
+ lte: "c",
201
+ reverse: true,
202
+ })) {
203
+ scanned.push(key);
204
+ }
205
+
206
+ expect(scanned).toEqual(["c", "b", "a"]);
207
+ });
208
+ });
209
+ }
@@ -0,0 +1,31 @@
1
+ export type AuthorityBatchOperation =
2
+ | { type: "put"; key: string; value: unknown }
3
+ | { type: "del"; key: string };
4
+
5
+ export type AuthorityIteratorOptions = {
6
+ gte?: string;
7
+ lte?: string;
8
+ lt?: string;
9
+ reverse?: boolean;
10
+ };
11
+
12
+ export interface AuthorityBatchWriter {
13
+ put(key: string, value: unknown): void;
14
+ del(key: string): void;
15
+ write(): Promise<void>;
16
+ }
17
+
18
+ export interface AuthorityStore {
19
+ readonly location?: string;
20
+ readonly status?: string;
21
+ open(): Promise<void>;
22
+ close(): Promise<void>;
23
+ get<T = any>(key: string): Promise<T>;
24
+ put(key: string, value: unknown): Promise<void>;
25
+ del(key: string): Promise<void>;
26
+ batchWrite(ops: AuthorityBatchOperation[]): Promise<void>;
27
+ createBatch(): AuthorityBatchWriter;
28
+ iterator(
29
+ options?: AuthorityIteratorOptions
30
+ ): AsyncIterableIterator<[string, unknown]>;
31
+ }
@@ -1,4 +1,4 @@
1
- import { classifyCoreDataKey } from "./coreDataOwnership";
1
+ import { classifyCoreDataKey } from "./coreDataOwnership";
2
2
 
3
3
  const normalizeOrigin = (value: string | URL | null | undefined): string => {
4
4
  try {
@@ -1,5 +1,6 @@
1
1
  import { pino } from "pino";
2
- import serverDb from "./db";
2
+ import { getServerAuthorityStore } from "./db";
3
+ import { writeStoreOps } from "./storeBatchCompat";
3
4
  import { chargeTokenUsageWithLedger } from "../../auth/server/tokenUsageBilling";
4
5
 
5
6
  const logger = pino({ name: "dataHandlers" });
@@ -11,12 +12,18 @@ export const handleToken = async (
11
12
  customKey?: string,
12
13
  actionUserId?: string,
13
14
  ) => {
15
+ const store = getServerAuthorityStore();
14
16
  const isStatsKey = customKey.includes("token-stats");
15
- await serverDb.put(customKey, data);
17
+ await store.put(customKey, data);
16
18
 
17
19
  if (!isStatsKey && data.cost && data.cost > 0) {
18
20
  try {
19
21
  const txId = `token-${customKey}`;
22
+ const billingStore = {
23
+ get: (key: string) => store.get(key),
24
+ batch: (ops: Array<{ type: "put"; key: string; value: unknown }>) =>
25
+ writeStoreOps(store, ops),
26
+ };
20
27
  logger.info({
21
28
  event: "token_split_ledger_charge_start",
22
29
  userId: data.userId,
@@ -24,7 +31,7 @@ export const handleToken = async (
24
31
  txId,
25
32
  });
26
33
  const chargeResult = await chargeTokenUsageWithLedger({
27
- store: serverDb,
34
+ store: billingStore,
28
35
  userId: data.userId,
29
36
  tokenKey: customKey,
30
37
  tokenRecord: data,
@@ -77,9 +84,10 @@ export const handleToken = async (
77
84
  };
78
85
 
79
86
  export const handleCybot = async (data: any, res: any, customKey: string) => {
87
+ const store = getServerAuthorityStore();
80
88
  try {
81
- await serverDb.put(customKey, data);
82
- const savedData = await serverDb.get(customKey);
89
+ await store.put(customKey, data);
90
+ const savedData = await store.get(customKey);
83
91
 
84
92
  const isDataMatch = JSON.stringify(data) === JSON.stringify(savedData);
85
93
  if (!isDataMatch) {
@@ -1,37 +1,17 @@
1
1
  // 文件路径: packages/database/server/db.ts
2
2
 
3
- import { Level } from "level";
4
- import path from "path";
5
- import fs from "fs";
6
3
  import { ensureDbOpen } from "./ensureDbOpen";
7
4
  import { resolveServerDbPath } from "./dbPath";
5
+ import type { LegacyServerDb } from "./legacyServerDb";
6
+ import type { AuthorityStore } from "./authorityStoreTypes";
7
+ import { getOrCreateServerStoreRuntime } from "./serverStoreFactory";
8
8
 
9
9
  const DB_PATH = resolveServerDbPath();
10
10
 
11
- // 确保目录存在
12
- if (!fs.existsSync(path.dirname(DB_PATH))) {
13
- fs.mkdirSync(path.dirname(DB_PATH), { recursive: true });
14
- }
15
-
16
11
  console.log("数据库配置:");
17
12
  console.log("- 当前工作目录:", process.cwd());
18
13
  console.log("- 数据库路径:", DB_PATH);
19
14
 
20
- // 安全 JSON 编码:解码失败时返回 null 而非抛异常,防止损坏记录导致进程崩溃
21
- const safeJsonEncoding = {
22
- name: "safe-json",
23
- format: "utf8" as const,
24
- encode: (data: any) => JSON.stringify(data),
25
- decode: (data: string) => {
26
- try {
27
- return JSON.parse(data);
28
- } catch {
29
- console.warn("[LevelDB] Corrupted value:", data?.substring?.(0, 60));
30
- return null;
31
- }
32
- },
33
- };
34
-
35
15
  export function isServerDbLockError(error: unknown): boolean {
36
16
  const queue: unknown[] = [error];
37
17
  const seen = new Set<unknown>();
@@ -55,13 +35,11 @@ export function isServerDbLockError(error: unknown): boolean {
55
35
  return false;
56
36
  }
57
37
 
58
- // 单例实例:挂在 globalThis 上,--hot 模式下模块重新求值时复用同一实例,避免 LevelDB 锁冲突
59
- if (!(globalThis as any).__serverDb) {
60
- (globalThis as any).__serverDb = new Level<string, any>(DB_PATH, {
61
- valueEncoding: safeJsonEncoding,
62
- });
63
- }
64
- const serverDb: Level<string, any> = (globalThis as any).__serverDb;
38
+ const {
39
+ authorityStore,
40
+ serverDb,
41
+ }: { authorityStore: AuthorityStore; serverDb: LegacyServerDb } =
42
+ getOrCreateServerStoreRuntime(DB_PATH);
65
43
 
66
44
  console.log("- LevelDB实际路径:", serverDb.location);
67
45
 
@@ -70,6 +48,9 @@ export default serverDb;
70
48
 
71
49
  // 具名导出:需要的时候可以引用
72
50
  export { serverDb };
51
+ export function getServerAuthorityStore() {
52
+ return authorityStore;
53
+ }
73
54
 
74
55
  /**
75
56
  * 确保数据库处于 open 状态。
@@ -77,11 +58,11 @@ export { serverDb };
77
58
  * - 其他状态:尝试 open,一旦失败抛错
78
59
  */
79
60
  export async function ensureServerDbOpen() {
80
- const status = (serverDb as any).status;
61
+ const status = authorityStore.status;
81
62
  if (status === "open") return;
82
63
 
83
64
  try {
84
- await ensureDbOpen(serverDb);
65
+ await ensureDbOpen(authorityStore);
85
66
  if (status !== "opening") {
86
67
  console.log("✅ LevelDB 已打开");
87
68
  }
@@ -106,11 +87,11 @@ export async function openServerDb() {
106
87
  * 优雅关机时关闭 DB
107
88
  */
108
89
  export async function closeServerDb() {
109
- const status = (serverDb as any).status;
90
+ const status = authorityStore.status;
110
91
  if (status !== "open") return;
111
92
 
112
93
  try {
113
- await serverDb.close();
94
+ await authorityStore.close();
114
95
  console.log("✅ LevelDB 已关闭");
115
96
  } catch (err) {
116
97
  console.error("❌ 关闭 LevelDB 失败:", err);
@@ -1,6 +1,6 @@
1
1
  // 文件: database/server/delete.ts
2
2
 
3
- import serverDb from "./db";
3
+ import { getServerAuthorityStore } from "./db";
4
4
  import { DataType } from "../../create/types";
5
5
  import { deleteMessages } from "../../chat/messages/deleteMessages";
6
6
  import { deleteTable } from "../table/deleteTable";
@@ -15,13 +15,14 @@ import {
15
15
  } from "../keys";
16
16
  import { buildTombstoneRecord, isTombstoneRecord } from "../tombstones";
17
17
  import { canDeleteSpaceMemberRecord, parseSpaceMemberKey } from "./spaceMemberAuthority";
18
- import {
19
- bootstrapReplicatedTable,
20
- findActiveLiveShareByTable,
21
- isLiveTableShareRecord,
22
- patchShareMeta,
23
- replicateSharedTableMutation,
24
- } from "../../share/server/tableReplication";
18
+ import {
19
+ bootstrapReplicatedTable,
20
+ findActiveLiveShareByTable,
21
+ isLiveTableShareRecord,
22
+ patchShareMeta,
23
+ replicateSharedTableMutation,
24
+ } from "../../share/server/tableReplication";
25
+ import { createStoreBatch, writeStoreOps } from "./storeBatchCompat";
25
26
 
26
27
  type DeleteRequest = Request & {
27
28
  // 视你的路由库而定,这里假定有 params.id
@@ -48,7 +49,7 @@ const getRequestOrigin = (req: Request): string => {
48
49
  }
49
50
  };
50
51
 
51
- const getForwardHeaders = (req: any): Record<string, string> => {
52
+ const getForwardHeaders = (req: any): Record<string, string> => {
52
53
  const headers: Record<string, string> = {
53
54
  "Content-Type": "application/json",
54
55
  };
@@ -62,14 +63,15 @@ const getForwardHeaders = (req: any): Record<string, string> => {
62
63
  headers.Authorization = authHeader;
63
64
  }
64
65
  return headers;
65
- };
66
-
67
- const findLiveTableSharesByDbKey = async (tableDbKey: string) => {
68
- const shares: any[] = [];
69
- for await (const [dbKey, value] of serverDb.iterator({
70
- gte: "share-",
71
- lte: "share-\uffff",
72
- })) {
66
+ };
67
+
68
+ const findLiveTableSharesByDbKey = async (tableDbKey: string) => {
69
+ const store = getServerAuthorityStore();
70
+ const shares: any[] = [];
71
+ for await (const [dbKey, value] of store.iterator({
72
+ gte: "share-",
73
+ lte: "share-\uffff",
74
+ })) {
73
75
  if (
74
76
  isLiveTableShareRecord(value, tableDbKey)
75
77
  ) {
@@ -135,18 +137,33 @@ const canSystemUserDeletePublicCybot = (
135
137
  return isPublicCybotKey && isSystemUser;
136
138
  };
137
139
 
138
- const canSystemAdminDeleteCommunityShare = (
139
- dbKey: string,
140
- actionUserId: string | undefined,
141
- data: any
140
+ const canSystemAdminDeleteCommunityShare = (
141
+ dbKey: string,
142
+ actionUserId: string | undefined,
143
+ data: any
142
144
  ): boolean => {
143
145
  if (!isSystemAdmin(actionUserId)) return false;
144
- if (!shareKey.isShareKey(dbKey)) return false;
145
- return data?.meta?.visibility === "community";
146
- };
147
-
148
- export const handleDelete = async (req: DeleteRequest) => {
149
- try {
146
+ if (!shareKey.isShareKey(dbKey)) return false;
147
+ return data?.meta?.visibility === "community";
148
+ };
149
+
150
+ const createDeleteCompatDb = (store = getServerAuthorityStore()) => ({
151
+ batch: (
152
+ ops?: Array<{ type: "put" | "del"; key: string; value?: unknown }>
153
+ ) => {
154
+ if (Array.isArray(ops)) {
155
+ return writeStoreOps(store, ops);
156
+ }
157
+ return createStoreBatch(store);
158
+ },
159
+ iterator: (options: { gte: string; lte: string }) => store.iterator(options),
160
+ del: (key: string) => store.del(key),
161
+ });
162
+
163
+ export const handleDelete = async (req: DeleteRequest) => {
164
+ const store = getServerAuthorityStore();
165
+ const deleteCompatDb = createDeleteCompatDb(store);
166
+ try {
150
167
  const authResult = await authenticateRequest(req);
151
168
  const actionUserId = authResult instanceof Response ? undefined : authResult.userId;
152
169
 
@@ -154,10 +171,10 @@ export const handleDelete = async (req: DeleteRequest) => {
154
171
  const url = new URL(req.url);
155
172
  const type = url.searchParams.get("type");
156
173
 
157
- // 1. 删除消息的专用分支
158
- if (type === "messages") {
159
- try {
160
- const result = await deleteMessages(serverDb, id);
174
+ // 1. 删除消息的专用分支
175
+ if (type === "messages") {
176
+ try {
177
+ const result = await deleteMessages(deleteCompatDb, id);
161
178
  return new Response(JSON.stringify(result), {
162
179
  status: 200,
163
180
  headers: CORS_HEADERS,
@@ -174,11 +191,11 @@ export const handleDelete = async (req: DeleteRequest) => {
174
191
  }
175
192
 
176
193
  // 1.5 删除整张表(meta + 所有行 + 所有索引)的专用分支
177
- if (type === "table") {
178
- // 先拿 meta 数据做权限校验
179
- let meta;
180
- try {
181
- meta = await serverDb.get(id);
194
+ if (type === "table") {
195
+ // 先拿 meta 数据做权限校验
196
+ let meta;
197
+ try {
198
+ meta = await store.get(id);
182
199
  } catch (err: any) {
183
200
  if (err.notFound) {
184
201
  return new Response(JSON.stringify({ message: "Table already deleted", processingIds: [] }), {
@@ -209,10 +226,10 @@ export const handleDelete = async (req: DeleteRequest) => {
209
226
  );
210
227
  }
211
228
 
212
- await propagateTableDeleteToReplicas(req, id);
213
-
214
- // 真正执行整表删除
215
- const { processingIds } = await deleteTable(serverDb, id);
229
+ await propagateTableDeleteToReplicas(req, id);
230
+
231
+ // 真正执行整表删除
232
+ const { processingIds } = await deleteTable(deleteCompatDb, id);
216
233
 
217
234
  return new Response(
218
235
  JSON.stringify({
@@ -226,10 +243,10 @@ export const handleDelete = async (req: DeleteRequest) => {
226
243
  );
227
244
  }
228
245
 
229
- // 2. 删除通用数据(单 key 删除)
230
- let data;
231
- try {
232
- data = await serverDb.get(id);
246
+ // 2. 删除通用数据(单 key 删除)
247
+ let data;
248
+ try {
249
+ data = await store.get(id);
233
250
  } catch (err: any) {
234
251
  if (err.notFound) {
235
252
  return new Response(
@@ -287,16 +304,16 @@ export const handleDelete = async (req: DeleteRequest) => {
287
304
  );
288
305
  }
289
306
 
290
- // Share 记录 → 物理删除(主记录 + 所有索引键);通用记录 → tombstone
291
- if (isShareRecord) {
292
- const indexes = shareKey.allIndexKeysFromShare(id, data);
293
- const batch = serverDb.batch();
294
- batch.del(id);
295
- for (const ik of indexes) batch.del(ik);
296
- await batch.write();
297
- } else {
298
- await serverDb.put(id, buildTombstoneRecord(data, new Date().toISOString()));
299
- }
307
+ // Share 记录 → 物理删除(主记录 + 所有索引键);通用记录 → tombstone
308
+ if (isShareRecord) {
309
+ const indexes = shareKey.allIndexKeysFromShare(id, data);
310
+ const batch = store.createBatch();
311
+ batch.del(id);
312
+ for (const ik of indexes) batch.del(ik);
313
+ await batch.write();
314
+ } else {
315
+ await store.put(id, buildTombstoneRecord(data, new Date().toISOString()));
316
+ }
300
317
 
301
318
  if (
302
319
  data?.type === DataType.TABLE_ROW &&
@@ -411,15 +428,15 @@ export const handleDelete = async (req: DeleteRequest) => {
411
428
  invalidatePublicAgentsCache();
412
429
  }
413
430
 
414
- // 如果被删除的是 Agent,则级联清理所有的收藏关系及统计
415
- if (isAgentKey(id)) {
416
- const { start, end } = createFavoriteKey.userRangeOfAgentKey(id);
417
- const batch = serverDb.batch();
418
-
419
- for await (const [reverseKey] of serverDb.iterator({
420
- gte: start,
421
- lte: end,
422
- })) {
431
+ // 如果被删除的是 Agent,则级联清理所有的收藏关系及统计
432
+ if (isAgentKey(id)) {
433
+ const { start, end } = createFavoriteKey.userRangeOfAgentKey(id);
434
+ const batch = store.createBatch();
435
+
436
+ for await (const [reverseKey] of store.iterator({
437
+ gte: start,
438
+ lte: end,
439
+ })) {
423
440
  if (!reverseKey.startsWith(start)) continue;
424
441
 
425
442
  // reverseKey: fav-agent-key-by-agent-{agentKey}-{userId}
@@ -439,14 +456,14 @@ export const handleDelete = async (req: DeleteRequest) => {
439
456
 
440
457
  // 如果被删除的是 Dialog,则级联清理该对话下的所有消息
441
458
  // Dialog Key 结构: dialog-{userId}-{dialogId} (3 parts)
442
- const parts = id.split("-");
443
- if (parts[0] === "dialog" && parts.length === 3) {
444
- const dialogId = parts[2];
445
- if (dialogId) {
446
- console.log(`[Delete] Cascading messages for dialog: ${dialogId}`);
447
- await deleteMessages(serverDb, dialogId);
448
- }
449
- }
459
+ const parts = id.split("-");
460
+ if (parts[0] === "dialog" && parts.length === 3) {
461
+ const dialogId = parts[2];
462
+ if (dialogId) {
463
+ console.log(`[Delete] Cascading messages for dialog: ${dialogId}`);
464
+ await deleteMessages(deleteCompatDb, dialogId);
465
+ }
466
+ }
450
467
  }
451
468
 
452
469
  return new Response(
@@ -8,15 +8,17 @@ import type {
8
8
  } from "../email";
9
9
  import { emailKey } from "../keys";
10
10
  import type { ApiContext, ApiError } from "../../server/api/types";
11
- import {
12
- type EmailProvider,
13
- type EmailProviderSendResult,
14
- } from "../../server/email/provider";
15
- import { getEmailProvider } from "../../server/email/providerRegistry";
16
- import { authorizeActorRecordAccess } from "./actorAccess";
17
- import { agentDelegationKey } from "./agentDelegation";
18
- import serverDb from "./db";
19
- import { resolveKeyOwnerId } from "./writeAuthority";
11
+ import {
12
+ type EmailProvider,
13
+ type EmailProviderSendResult,
14
+ } from "../../server/email/provider";
15
+ import { getEmailProvider } from "../../server/email/providerRegistry";
16
+ import { authorizeActorRecordAccess } from "./actorAccess";
17
+ import { agentDelegationKey } from "./agentDelegation";
18
+ import { getServerAuthorityStore } from "./db";
19
+ import { resolveKeyOwnerId } from "./writeAuthority";
20
+
21
+ const serverDb = getServerAuthorityStore();
20
22
 
21
23
  type CreateEmailRecordInput = {
22
24
  ownerId: string;
@@ -3,12 +3,13 @@
3
3
  import path from "path";
4
4
  import { mkdir } from "node:fs/promises";
5
5
  import { ulid } from "ulid";
6
- import serverDb from "./db";
6
+ import { getServerAuthorityStore } from "./db";
7
7
  import { blobKey, fileKey, fileIdIndexKey, fileStatKey } from "../keys";
8
8
  import { isTombstoneRecord } from "../tombstones";
9
9
  import { DataType } from "../../create/types";
10
10
 
11
11
  const UPLOAD_DIR = path.join(process.cwd(), "data", "uploads");
12
+ const serverDb = getServerAuthorityStore();
12
13
 
13
14
  type JsonRecord = Record<string, any>;
14
15