nolo-cli 0.1.12 → 0.1.14

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 (323) hide show
  1. package/README.md +54 -2
  2. package/agent-runtime/hostAdapter.ts +53 -0
  3. package/agent-runtime/index.ts +28 -0
  4. package/agent-runtime/localLoop.ts +62 -0
  5. package/agent-runtime/runtimeDecision.ts +70 -0
  6. package/agent-runtime/types.ts +87 -0
  7. package/agentRuntimeCommands.ts +141 -22
  8. package/agentRuntimeLocal.ts +7 -0
  9. package/ai/agent/_executeModel.ts +118 -0
  10. package/ai/agent/agentSlice.ts +545 -0
  11. package/ai/agent/appWorkingMemory.ts +126 -0
  12. package/ai/agent/avatarUtils.ts +24 -0
  13. package/ai/agent/buildEditingContext.ts +373 -0
  14. package/ai/agent/buildSystemPrompt.ts +532 -0
  15. package/ai/agent/cleanAgentMessages.ts +140 -0
  16. package/ai/agent/cliChatClient.ts +119 -0
  17. package/ai/agent/contextCompiler.ts +107 -0
  18. package/ai/agent/contextLayerContract.ts +44 -0
  19. package/ai/agent/createAgentSchema.ts +234 -0
  20. package/ai/agent/executeToolCall.ts +58 -0
  21. package/ai/agent/fetchAgentContexts.ts +42 -0
  22. package/ai/agent/generatePrompt.ts +3 -0
  23. package/ai/agent/getFullChatContextKeys.ts +168 -0
  24. package/ai/agent/hooks/fetchPublicAgents.ts +133 -0
  25. package/ai/agent/hooks/useAgentConfig.ts +61 -0
  26. package/ai/agent/hooks/useAgentDialog.ts +35 -0
  27. package/ai/agent/hooks/useAgentFormValidation.ts +202 -0
  28. package/ai/agent/hooks/usePublicAgents.ts +473 -0
  29. package/ai/agent/persistMessageWithFixedId.ts +37 -0
  30. package/ai/agent/planSlice.ts +259 -0
  31. package/ai/agent/referenceUtils.ts +229 -0
  32. package/ai/agent/runAgentBackground.ts +238 -0
  33. package/ai/agent/runAgentClientLoop.ts +138 -0
  34. package/ai/agent/runtimeGuidance.ts +97 -0
  35. package/ai/agent/runtimeServerBase.ts +37 -0
  36. package/ai/agent/server/fetchPublicAgents.ts +128 -0
  37. package/ai/agent/startParallelAgentStreams.ts +424 -0
  38. package/ai/agent/startupProtocol.ts +53 -0
  39. package/ai/agent/streamAgentChatTurn.ts +1299 -0
  40. package/ai/agent/streamAgentChatTurnUtils.ts +738 -0
  41. package/ai/agent/types.ts +71 -0
  42. package/ai/agent/utils/imageOutput.ts +39 -0
  43. package/ai/agent/utils/publicImageAgentMode.ts +26 -0
  44. package/ai/agent/utils/sortUtils.ts +250 -0
  45. package/ai/agent/web/referencePickerUtils.ts +146 -0
  46. package/ai/agent.ts +2 -0
  47. package/ai/ai.locale.ts +1083 -0
  48. package/ai/chat/accumulateToolCallChunks.ts +95 -0
  49. package/ai/chat/fetchUtils.native.ts +276 -0
  50. package/ai/chat/fetchUtils.ts +153 -0
  51. package/ai/chat/inlineImageUrlsForCustomProvider.ts +117 -0
  52. package/ai/chat/parseApiError.ts +64 -0
  53. package/ai/chat/parseMultilineSSE.ts +95 -0
  54. package/ai/chat/sendOpenAICompletionsRequest.native.ts +682 -0
  55. package/ai/chat/sendOpenAICompletionsRequest.ts +712 -0
  56. package/ai/chat/sendOpenAIResponseRequest.ts +512 -0
  57. package/ai/chat/shouldUseServerProxy.ts +18 -0
  58. package/ai/chat/sseClient.native.ts +91 -0
  59. package/ai/chat/sseClient.ts +67 -0
  60. package/ai/chat/streamReader.native.ts +31 -0
  61. package/ai/chat/streamReader.ts +62 -0
  62. package/ai/chat/updateTotalUsage.ts +72 -0
  63. package/ai/context/buildReferenceContext.ts +437 -0
  64. package/ai/context/calculateContextUsage.ts +133 -0
  65. package/ai/context/retention.ts +165 -0
  66. package/ai/context/tokenUtils.ts +78 -0
  67. package/ai/index.ts +1 -0
  68. package/ai/llm/agentCapabilities.ts +74 -0
  69. package/ai/llm/calculateGeminiImageTokens.ts +57 -0
  70. package/ai/llm/deepinfra.ts +28 -0
  71. package/ai/llm/fireworks.ts +68 -0
  72. package/ai/llm/generateRequestBody.ts +165 -0
  73. package/ai/llm/getModelContextWindow.ts +84 -0
  74. package/ai/llm/getNoloKey.ts +37 -0
  75. package/ai/llm/getPricing.ts +232 -0
  76. package/ai/llm/hooks/useModelPricing.ts +75 -0
  77. package/ai/llm/imagePricing.ts +66 -0
  78. package/ai/llm/isResponseAPIModel.ts +13 -0
  79. package/ai/llm/kimi.ts +18 -0
  80. package/ai/llm/mimo.ts +71 -0
  81. package/ai/llm/mistral.ts +22 -0
  82. package/ai/llm/modelAvatar.ts +427 -0
  83. package/ai/llm/models.ts +45 -0
  84. package/ai/llm/openrouterModels.ts +141 -0
  85. package/ai/llm/providers.ts +307 -0
  86. package/ai/llm/reasoningModels.ts +28 -0
  87. package/ai/llm/types.ts +59 -0
  88. package/ai/llm/usageRequestOptions.ts +59 -0
  89. package/ai/memory/capture.ts +148 -0
  90. package/ai/memory/consolidate.ts +104 -0
  91. package/ai/memory/delete.ts +147 -0
  92. package/ai/memory/overlay.ts +84 -0
  93. package/ai/memory/query.ts +38 -0
  94. package/ai/memory/queryShared.ts +160 -0
  95. package/ai/memory/rank.ts +105 -0
  96. package/ai/memory/recentRelationshipRecap.ts +247 -0
  97. package/ai/memory/remember.ts +167 -0
  98. package/ai/memory/runtime.ts +76 -0
  99. package/ai/memory/store.ts +20 -0
  100. package/ai/memory/storeShared.ts +76 -0
  101. package/ai/memory/types.ts +46 -0
  102. package/ai/memory/understanding.ts +349 -0
  103. package/ai/memory/understandingGreeting.ts +264 -0
  104. package/ai/messages/type.ts +20 -0
  105. package/ai/policy/personalizationDialog.ts +333 -0
  106. package/ai/policy/runtimePolicy.ts +440 -0
  107. package/ai/policy/selfUpdateFields.ts +48 -0
  108. package/ai/policy/types.ts +64 -0
  109. package/ai/skills/referenceRuntime.ts +274 -0
  110. package/ai/skills/skillDiagnostics.ts +251 -0
  111. package/ai/skills/skillDocBuilder.ts +139 -0
  112. package/ai/skills/skillDocProtocol.ts +434 -0
  113. package/ai/skills/skillReferenceSummary.ts +63 -0
  114. package/ai/skills/skillSummaryMarker.ts +26 -0
  115. package/ai/token/calculatePrice.ts +546 -0
  116. package/ai/token/db.ts +98 -0
  117. package/ai/token/externalToolCost.ts +321 -0
  118. package/ai/token/hooks/useRecords.ts +65 -0
  119. package/ai/token/missingUsageEstimate.ts +42 -0
  120. package/ai/token/modelUsageQuery.ts +252 -0
  121. package/ai/token/normalizeUsage.ts +84 -0
  122. package/ai/token/openaiImageGenerationUsage.ts +56 -0
  123. package/ai/token/prepareTokenUsageData.ts +88 -0
  124. package/ai/token/query.ts +88 -0
  125. package/ai/token/queryUserTokens.ts +59 -0
  126. package/ai/token/resolveBillingTarget.ts +52 -0
  127. package/ai/token/saveTokenRecord.ts +53 -0
  128. package/ai/token/serverDialogProjection.ts +78 -0
  129. package/ai/token/serverTokenWriter.ts +143 -0
  130. package/ai/token/stats.ts +21 -0
  131. package/ai/token/tokenThunks.ts +24 -0
  132. package/ai/token/types.ts +93 -0
  133. package/ai/tools/agent/agentTools.ts +176 -0
  134. package/ai/tools/agent/agentUpdateShared.ts +311 -0
  135. package/ai/tools/agent/callAgentTool.ts +139 -0
  136. package/ai/tools/agent/createAgentTool.ts +512 -0
  137. package/ai/tools/agent/createDialogTool.ts +69 -0
  138. package/ai/tools/agent/createSkillAgentTool.ts +62 -0
  139. package/ai/tools/agent/parallelBudget.ts +221 -0
  140. package/ai/tools/agent/presets/appBuilderPreset.ts +147 -0
  141. package/ai/tools/agent/runLlmTool.ts +96 -0
  142. package/ai/tools/agent/runStreamingAgentTool.ts +73 -0
  143. package/ai/tools/agent/skillAgentArgs.ts +106 -0
  144. package/ai/tools/agent/skillAgentPreset.ts +89 -0
  145. package/ai/tools/agent/streamParallelAgentsTool.ts +122 -0
  146. package/ai/tools/agent/updateAgentTool.ts +96 -0
  147. package/ai/tools/agent/updateSelfTool.ts +113 -0
  148. package/ai/tools/amazonProductScraperTool.ts +86 -0
  149. package/ai/tools/apifyActorClient.ts +45 -0
  150. package/ai/tools/appEditGuard.ts +372 -0
  151. package/ai/tools/appReadSnapshot.ts +153 -0
  152. package/ai/tools/appTools.ts +1549 -0
  153. package/ai/tools/applyEditTool.ts +256 -0
  154. package/ai/tools/applyLineEditsTool.ts +312 -0
  155. package/ai/tools/browserTools/click.ts +33 -0
  156. package/ai/tools/browserTools/closeSession.ts +29 -0
  157. package/ai/tools/browserTools/common.ts +27 -0
  158. package/ai/tools/browserTools/openSession.ts +48 -0
  159. package/ai/tools/browserTools/readContent.ts +38 -0
  160. package/ai/tools/browserTools/selectOption.ts +46 -0
  161. package/ai/tools/browserTools/typeText.ts +42 -0
  162. package/ai/tools/category/createCategoryTool.ts +66 -0
  163. package/ai/tools/category/queryContentsByCategoryTool.ts +69 -0
  164. package/ai/tools/category/updateContentCategoryTool.ts +75 -0
  165. package/ai/tools/cfBrowserTools.ts +319 -0
  166. package/ai/tools/cfSpeechToTextTool.ts +49 -0
  167. package/ai/tools/checkEnvTool.ts +65 -0
  168. package/ai/tools/cloudflareCrawlTool.ts +289 -0
  169. package/ai/tools/codeSearchTool.ts +111 -0
  170. package/ai/tools/codeTools.ts +101 -0
  171. package/ai/tools/createDocTool.ts +132 -0
  172. package/ai/tools/createPlanTool.ts +999 -0
  173. package/ai/tools/createSkillDocTool.ts +155 -0
  174. package/ai/tools/createWorkflowTool.ts +154 -0
  175. package/ai/tools/deepseekOcrTool.ts +34 -0
  176. package/ai/tools/delayTool.ts +31 -0
  177. package/ai/tools/deleteSpacesTool.ts +325 -0
  178. package/ai/tools/deleteSpacesToolModel.ts +159 -0
  179. package/ai/tools/devReloadUtils.ts +29 -0
  180. package/ai/tools/dialogMessageSearch.ts +137 -0
  181. package/ai/tools/doctorSkillTool.ts +72 -0
  182. package/ai/tools/ecommerceScraperTool.ts +86 -0
  183. package/ai/tools/emailTools.ts +549 -0
  184. package/ai/tools/evalSkillTool.ts +92 -0
  185. package/ai/tools/exaSearchTool.ts +64 -0
  186. package/ai/tools/execBashTool.ts +379 -0
  187. package/ai/tools/executeSqlTool.ts +192 -0
  188. package/ai/tools/fetchWebpageSupport.ts +309 -0
  189. package/ai/tools/fetchWebpageTool.ts +84 -0
  190. package/ai/tools/geminiImagePreviewTool.ts +361 -0
  191. package/ai/tools/generateDocxTool.ts +215 -0
  192. package/ai/tools/googleSearchScraperTool.ts +106 -0
  193. package/ai/tools/importDataTool.ts +133 -0
  194. package/ai/tools/importSkillTool.ts +162 -0
  195. package/ai/tools/index.ts +1927 -0
  196. package/ai/tools/listFilesTool.ts +82 -0
  197. package/ai/tools/listUserSpacesTool.ts +113 -0
  198. package/ai/tools/modelUsageTools.ts +199 -0
  199. package/ai/tools/olmOcrTool.ts +34 -0
  200. package/ai/tools/openaiImageTool.ts +267 -0
  201. package/ai/tools/prepareTools.ts +23 -0
  202. package/ai/tools/readDocTool.ts +84 -0
  203. package/ai/tools/readFileTool.ts +211 -0
  204. package/ai/tools/readTool.ts +163 -0
  205. package/ai/tools/readXPostTool.ts +233 -0
  206. package/ai/tools/rememberMemoryTool.ts +84 -0
  207. package/ai/tools/remotionVideoTool.ts +151 -0
  208. package/ai/tools/searchDialogMessagesTool.ts +222 -0
  209. package/ai/tools/searchRepoTool.ts +115 -0
  210. package/ai/tools/searchWorkspaceTool.ts +259 -0
  211. package/ai/tools/skillFollowup.ts +86 -0
  212. package/ai/tools/surfWeatherTool.ts +169 -0
  213. package/ai/tools/table/addTableRowTool.ts +217 -0
  214. package/ai/tools/table/createTableTool.ts +315 -0
  215. package/ai/tools/table/rowTools.ts +366 -0
  216. package/ai/tools/table/schemaTools.ts +244 -0
  217. package/ai/tools/table/shareTableTool.ts +148 -0
  218. package/ai/tools/table/toolShared.ts +129 -0
  219. package/ai/tools/toolApiClient.ts +198 -0
  220. package/ai/tools/toolNameAliases.ts +57 -0
  221. package/ai/tools/toolResultError.ts +42 -0
  222. package/ai/tools/toolRunSlice.ts +303 -0
  223. package/ai/tools/toolSchemaCompatibility.ts +53 -0
  224. package/ai/tools/toolVisibility.ts +4 -0
  225. package/ai/tools/types.ts +20 -0
  226. package/ai/tools/uiAskChoiceTool.ts +104 -0
  227. package/ai/tools/updateContentTitleTool.ts +84 -0
  228. package/ai/tools/updateDocTool.ts +105 -0
  229. package/ai/tools/updateUserPreferenceProfileTool.ts +145 -0
  230. package/ai/tools/whisperTool.ts +77 -0
  231. package/ai/tools/writeFileTool.ts +210 -0
  232. package/ai/tools/youtubeScraperTool.ts +116 -0
  233. package/ai/tools/ziweiChartTool.ts +678 -0
  234. package/ai/types.ts +55 -0
  235. package/ai/workflow/workflowExecutor.ts +323 -0
  236. package/ai/workflow/workflowSlice.ts +73 -0
  237. package/ai/workflow/workflowTypes.ts +106 -0
  238. package/authCommands.ts +185 -21
  239. package/client/agentRun.test.ts +240 -0
  240. package/client/agentRun.ts +182 -19
  241. package/client/compactDialog.test.ts +238 -0
  242. package/client/compactDialog.ts +5 -2
  243. package/client/localRuntimeAdapter.test.ts +135 -0
  244. package/client/localRuntimeAdapter.ts +244 -0
  245. package/client/profileConfig.test.ts +40 -0
  246. package/client/streamingOutput.test.ts +22 -0
  247. package/client/streamingOutput.ts +38 -0
  248. package/commandRegistry.ts +11 -2
  249. package/connector-experimental/index.ts +5 -0
  250. package/database/actions/cacheMergedUserData.ts +64 -0
  251. package/database/actions/common.ts +242 -0
  252. package/database/actions/deleteFile.ts +40 -0
  253. package/database/actions/fetchUserData.ts +16 -0
  254. package/database/actions/fileContent.ts +125 -0
  255. package/database/actions/patch.ts +155 -0
  256. package/database/actions/read.ts +337 -0
  257. package/database/actions/readAndWait.ts +224 -0
  258. package/database/actions/readRequestManager.ts +120 -0
  259. package/database/actions/remove.ts +94 -0
  260. package/database/actions/replication.ts +366 -0
  261. package/database/actions/upload.ts +174 -0
  262. package/database/actions/upsert.ts +56 -0
  263. package/database/actions/write.ts +126 -0
  264. package/database/client/db.native.ts +73 -0
  265. package/database/client/db.ts +51 -0
  266. package/database/client/fetchUserData.ts +61 -0
  267. package/database/client/handleError.ts +19 -0
  268. package/database/client/queryRequest.ts +21 -0
  269. package/database/config.ts +21 -0
  270. package/database/dbActionThunks.ts +1 -0
  271. package/database/dbSlice.ts +149 -0
  272. package/database/email.ts +42 -0
  273. package/database/fileRing.ts +51 -0
  274. package/database/fileSharding.ts +70 -0
  275. package/database/fileStorage.native.ts +92 -0
  276. package/database/fileStorage.ts +232 -0
  277. package/database/fileUrl.ts +34 -0
  278. package/database/hooks/useUserData.ts +489 -0
  279. package/database/index.ts +1 -0
  280. package/database/keys.ts +765 -0
  281. package/database/queryPrefixes.ts +14 -0
  282. package/database/requests.ts +443 -0
  283. package/database/runtimeServerContext.ts +35 -0
  284. package/database/server/MemoryDB.ts +76 -0
  285. package/database/server/actorAccess.ts +76 -0
  286. package/database/server/agentDelegation.ts +124 -0
  287. package/database/server/coreDataOwnership.ts +13 -0
  288. package/database/server/coreDataProxy.ts +76 -0
  289. package/database/server/cybotReadonly.ts +18 -0
  290. package/database/server/dataHandlers.ts +111 -0
  291. package/database/server/db.ts +118 -0
  292. package/database/server/dbPath.ts +20 -0
  293. package/database/server/delete.ts +499 -0
  294. package/database/server/emailRepository.ts +1480 -0
  295. package/database/server/ensureDbOpen.ts +12 -0
  296. package/database/server/fileRead.ts +337 -0
  297. package/database/server/fileService.ts +436 -0
  298. package/database/server/handleTransaction.ts +86 -0
  299. package/database/server/patch.ts +282 -0
  300. package/database/server/query.ts +138 -0
  301. package/database/server/read.ts +325 -0
  302. package/database/server/resourceAccess.ts +211 -0
  303. package/database/server/routes.ts +110 -0
  304. package/database/server/spaceMemberAuthority.ts +67 -0
  305. package/database/server/upload.ts +159 -0
  306. package/database/server/write.ts +494 -0
  307. package/database/server/writeAuthority.ts +133 -0
  308. package/database/sqliteDb.ts +46 -0
  309. package/database/table/deleteTable.ts +120 -0
  310. package/database/tenantPlacement.ts +57 -0
  311. package/database/tombstones.ts +52 -0
  312. package/database/userDataLoadDecision.ts +17 -0
  313. package/database/userDataMerge.ts +95 -0
  314. package/database/userPreferenceRegister.ts +108 -0
  315. package/database/utils/dbPath.ts +47 -0
  316. package/database/utils/ulid.native.ts +6 -0
  317. package/database/utils/ulid.ts +1 -0
  318. package/index.ts +25 -15
  319. package/localRuntimeDb.ts +28 -0
  320. package/package.json +16 -4
  321. package/runtimeModeArgs.ts +33 -0
  322. package/tui/readlineWorkspace.ts +1 -0
  323. package/tui/session.ts +22 -0
@@ -0,0 +1,92 @@
1
+
2
+ /**
3
+ * React Native 端的"文件存储"实现
4
+ *
5
+ * 由于 RN 环境没有 IndexedDB,且直接将文件存入 LevelDB 性能较差(虽然可行但不是最佳实践),
6
+ * 这里我们采用折衷方案:
7
+ * 1. 假设文件已经存在于设备文件系统中(例如相册选择的临时路径,或者下载后的路径)。
8
+ * 2. 我们只存储 fileId -> localUri 的映射关系到 LevelDB 中。
9
+ * 3. 读取时返回这个映射,让上层通过 Image.source 或 RNFS 读取。
10
+ *
11
+ * 注意:如果原始文件被系统清理(如 tmp 目录),这个引用会失效。
12
+ * 理想情况下应该 copy 到 DocumentDirectory,但为了避免引入 react-native-fs 依赖导致需要 rebuild,
13
+ * 暂时先存储路径映射。
14
+ */
15
+
16
+ import { getDb } from "./client/db";
17
+
18
+ // 在 RN 中,File 对象通常是 { uri, name, type, size } 的结构
19
+ export interface RNFile {
20
+ uri: string;
21
+ name: string;
22
+ type: string;
23
+ size: number;
24
+ }
25
+
26
+ export interface StoredFileRecord {
27
+ id: string;
28
+ uri: string; // 替代 blob
29
+ size: number;
30
+ type: string;
31
+ createdAt: string;
32
+ }
33
+
34
+ const FILE_PREFIX = "local-file-ref:";
35
+
36
+ export const saveFileToIndexedDb = async (
37
+ fileId: string,
38
+ file: File | Blob | RNFile
39
+ ): Promise<void> => {
40
+ try {
41
+ const db = getDb();
42
+ if (!db) {
43
+ console.warn("[fileStorage.native] Database not initialized");
44
+ return;
45
+ }
46
+
47
+ // 检查是否为 RN 文件结构
48
+ const uri = (file as any).uri;
49
+ if (!uri) {
50
+ console.warn("[fileStorage.native] File object missing URI, cannot store reference", file);
51
+ return;
52
+ }
53
+
54
+ const record: StoredFileRecord = {
55
+ id: fileId,
56
+ uri: uri,
57
+ size: (file as any).size || 0,
58
+ type: (file as any).type || "application/octet-stream",
59
+ createdAt: new Date().toISOString(),
60
+ };
61
+
62
+ await db.put(`${FILE_PREFIX}${fileId}`, record);
63
+ console.log(`[fileStorage.native] Saved file reference: ${fileId} -> ${uri}`);
64
+ } catch (err) {
65
+ console.error("[fileStorage.native] Failed to save file reference:", err);
66
+ }
67
+ };
68
+
69
+ export const loadFileFromIndexedDb = async (
70
+ fileId: string
71
+ ): Promise<StoredFileRecord | null> => {
72
+ try {
73
+ const db = getDb();
74
+ if (!db) return null;
75
+
76
+ const record = await db.get(`${FILE_PREFIX}${fileId}`);
77
+ return record as StoredFileRecord;
78
+ } catch (err) {
79
+ // LevelDB throws if key not found
80
+ return null;
81
+ }
82
+ };
83
+
84
+ export const deleteFileFromIndexedDb = async (fileId: string): Promise<void> => {
85
+ try {
86
+ const db = getDb();
87
+ if (!db) return;
88
+ await db.del(`${FILE_PREFIX}${fileId}`);
89
+ } catch (err) {
90
+ console.warn("[fileStorage.native] Failed to delete file reference:", err);
91
+ }
92
+ };
@@ -0,0 +1,232 @@
1
+ // 文件路径: database/fileStorage.ts
2
+
3
+ /**
4
+ * 浏览器端文件存储(IndexedDB)
5
+ *
6
+ * 设计:
7
+ * - 库名: "nolo-file-storage"
8
+ * - 表名: "files"
9
+ * - 主键: "id" (即 fileId / BlobId)
10
+ *
11
+ * 存储内容:
12
+ * {
13
+ * id: string; // fileId
14
+ * blob: Blob; // 文件数据
15
+ * size: number;
16
+ * type: string; // MIME
17
+ * createdAt: string; // ISO 时间
18
+ * }
19
+ */
20
+
21
+ const DB_NAME = "nolo-file-storage";
22
+ const STORE_NAME = "files";
23
+ const DB_VERSION = 1;
24
+
25
+ export interface StoredFileRecord {
26
+ id: string;
27
+ blob: Blob;
28
+ size: number;
29
+ type: string;
30
+ createdAt: string;
31
+ }
32
+
33
+ let dbPromise: Promise<IDBDatabase> | null = null;
34
+
35
+ const openFileDb = (): Promise<IDBDatabase> => {
36
+ if (dbPromise) return dbPromise;
37
+
38
+ if (typeof indexedDB === "undefined") {
39
+ console.warn(
40
+ "[fileStorage] indexedDB is not available in this environment. File caching is disabled."
41
+ );
42
+ dbPromise = Promise.reject(
43
+ new Error("indexedDB is not available in this environment")
44
+ );
45
+ return dbPromise;
46
+ }
47
+
48
+ dbPromise = new Promise((resolve, reject) => {
49
+ const request = indexedDB.open(DB_NAME, DB_VERSION);
50
+
51
+ request.onerror = () => {
52
+ console.error("[fileStorage] Failed to open IndexedDB:", request.error);
53
+ reject(request.error);
54
+ };
55
+
56
+ request.onupgradeneeded = () => {
57
+ const db = request.result;
58
+ if (!db.objectStoreNames.contains(STORE_NAME)) {
59
+ const store = db.createObjectStore(STORE_NAME, {
60
+ keyPath: "id",
61
+ });
62
+ store.createIndex("createdAt", "createdAt", { unique: false });
63
+ }
64
+ };
65
+
66
+ request.onsuccess = () => {
67
+ const db = request.result;
68
+ db.onversionchange = () => {
69
+ db.close();
70
+ console.warn(
71
+ "[fileStorage] IndexedDB version change detected, closing old connection."
72
+ );
73
+ };
74
+ resolve(db);
75
+ };
76
+ });
77
+
78
+ return dbPromise;
79
+ };
80
+
81
+ /**
82
+ * 将文件 (File/Blob) 存入 IndexedDB
83
+ * - key = fileId
84
+ */
85
+ export const saveFileToIndexedDb = async (
86
+ fileId: string,
87
+ file: File | Blob
88
+ ): Promise<void> => {
89
+ try {
90
+ const db = await openFileDb();
91
+ const tx = db.transaction(STORE_NAME, "readwrite");
92
+ const store = tx.objectStore(STORE_NAME);
93
+
94
+ const blob = file instanceof Blob ? file : new Blob([file]);
95
+
96
+ const record: StoredFileRecord = {
97
+ id: fileId,
98
+ blob,
99
+ size: blob.size,
100
+ type: blob.type || "application/octet-stream",
101
+ createdAt: new Date().toISOString(),
102
+ };
103
+
104
+ const request = store.put(record);
105
+
106
+ await new Promise<void>((resolve, reject) => {
107
+ request.onsuccess = () => {
108
+ console.debug(
109
+ "[fileStorage] Saved file to IndexedDB:",
110
+ fileId,
111
+ "size=",
112
+ record.size,
113
+ "type=",
114
+ record.type
115
+ );
116
+ resolve();
117
+ };
118
+ request.onerror = () => {
119
+ console.error(
120
+ "[fileStorage] Failed to save file to IndexedDB:",
121
+ fileId,
122
+ request.error
123
+ );
124
+ reject(request.error);
125
+ };
126
+ });
127
+
128
+ await new Promise<void>((resolve, reject) => {
129
+ tx.oncomplete = () => resolve();
130
+ tx.onerror = () => reject(tx.error);
131
+ tx.onabort = () => reject(tx.error);
132
+ });
133
+ } catch (err) {
134
+ console.warn(
135
+ "[fileStorage] saveFileToIndexedDb error (non-fatal, caching disabled for this file):",
136
+ err
137
+ );
138
+ }
139
+ };
140
+
141
+ /**
142
+ * 从 IndexedDB 中读取文件
143
+ * - key = fileId
144
+ */
145
+ export const loadFileFromIndexedDb = async (
146
+ fileId: string
147
+ ): Promise<StoredFileRecord | null> => {
148
+ try {
149
+ const db = await openFileDb();
150
+ const tx = db.transaction(STORE_NAME, "readonly");
151
+ const store = tx.objectStore(STORE_NAME);
152
+
153
+ const request = store.get(fileId);
154
+
155
+ const record = await new Promise<StoredFileRecord | null>(
156
+ (resolve, reject) => {
157
+ request.onsuccess = () => {
158
+ const result = request.result as StoredFileRecord | undefined;
159
+ if (result) {
160
+ console.debug(
161
+ "[fileStorage] Loaded file from IndexedDB:",
162
+ fileId,
163
+ "size=",
164
+ result.size,
165
+ "type=",
166
+ result.type
167
+ );
168
+ } else {
169
+ console.debug(
170
+ "[fileStorage] No local file found in IndexedDB for id:",
171
+ fileId
172
+ );
173
+ }
174
+ resolve(result ?? null);
175
+ };
176
+ request.onerror = () => {
177
+ console.error(
178
+ "[fileStorage] Failed to load file from IndexedDB:",
179
+ fileId,
180
+ request.error
181
+ );
182
+ reject(request.error);
183
+ };
184
+ }
185
+ );
186
+
187
+ return record ?? null;
188
+ } catch (err) {
189
+ console.warn(
190
+ "[fileStorage] loadFileFromIndexedDb error, treat as cache miss:",
191
+ err
192
+ );
193
+ return null;
194
+ }
195
+ };
196
+
197
+ /**
198
+ * 从 IndexedDB 中删除文件
199
+ * - key = fileId
200
+ */
201
+ export const deleteFileFromIndexedDb = async (fileId: string): Promise<void> => {
202
+ try {
203
+ const db = await openFileDb();
204
+ const tx = db.transaction(STORE_NAME, "readwrite");
205
+ const store = tx.objectStore(STORE_NAME);
206
+
207
+ const request = store.delete(fileId);
208
+
209
+ await new Promise<void>((resolve, reject) => {
210
+ request.onsuccess = () => {
211
+ console.debug("[fileStorage] Deleted file from IndexedDB:", fileId);
212
+ resolve();
213
+ };
214
+ request.onerror = () => {
215
+ console.error(
216
+ "[fileStorage] Failed to delete file from IndexedDB:",
217
+ fileId,
218
+ request.error
219
+ );
220
+ reject(request.error);
221
+ };
222
+ });
223
+
224
+ await new Promise<void>((resolve, reject) => {
225
+ tx.oncomplete = () => resolve();
226
+ tx.onerror = () => reject(tx.error);
227
+ tx.onabort = () => reject(tx.error);
228
+ });
229
+ } catch (err) {
230
+ console.warn("[fileStorage] deleteFileFromIndexedDb error:", err);
231
+ }
232
+ };
@@ -0,0 +1,34 @@
1
+ import { API_ENDPOINTS } from "./config";
2
+
3
+ const normalizeServerOrigin = (
4
+ serverOrigin: string | undefined | null
5
+ ): string => {
6
+ if (typeof serverOrigin !== "string") return "";
7
+ return serverOrigin.trim().replace(/\/+$/, "");
8
+ };
9
+
10
+ const normalizeFileId = (fileId: string | undefined | null): string => {
11
+ if (typeof fileId !== "string") return "";
12
+ return fileId.trim();
13
+ };
14
+
15
+ export const buildDatabaseFileContentUrl = (
16
+ serverOrigin: string | undefined | null,
17
+ fileId: string | undefined | null
18
+ ): string | null => {
19
+ const normalizedServer = normalizeServerOrigin(serverOrigin);
20
+ const normalizedFileId = normalizeFileId(fileId);
21
+
22
+ if (!normalizedServer || !normalizedFileId) {
23
+ return null;
24
+ }
25
+
26
+ return `${normalizedServer}${API_ENDPOINTS.DATABASE}/file/content/${normalizedFileId}`;
27
+ };
28
+
29
+ export const isLocalDatabaseFileContentUrl = (
30
+ url: string | null | undefined
31
+ ): boolean => {
32
+ if (typeof url !== "string" || !url) return false;
33
+ return url.includes("localhost") || url.includes("127.0.0.1");
34
+ };