nolo-cli 0.1.40 → 0.1.41

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 (412) hide show
  1. package/agent-runtime/hybridRecordStore.ts +5 -3
  2. package/ai/agent/_executeModel.ts +146 -0
  3. package/ai/agent/agentSlice.ts +556 -1
  4. package/ai/agent/appWorkingMemory.ts +126 -0
  5. package/ai/agent/buildEditingContext.ts +378 -0
  6. package/ai/agent/buildSystemPrompt.ts +585 -0
  7. package/ai/agent/canvasEditingContext.ts +49 -0
  8. package/ai/agent/cleanAgentMessages.ts +140 -0
  9. package/ai/agent/cliChatClient.ts +153 -0
  10. package/ai/agent/cliExecutor.ts +65 -6
  11. package/ai/agent/contextCompiler.ts +107 -0
  12. package/ai/agent/contextLayerContract.ts +44 -0
  13. package/ai/agent/createAgentSchema.ts +272 -0
  14. package/ai/agent/currentTimeContext.ts +65 -0
  15. package/ai/agent/executeToolCall.ts +58 -0
  16. package/ai/agent/fetchAgentContexts.ts +42 -0
  17. package/ai/agent/generatePrompt.ts +3 -0
  18. package/ai/agent/getFullChatContextKeys.ts +168 -0
  19. package/ai/agent/guidedCreation/capabilities.ts +84 -0
  20. package/ai/agent/guidedCreation/types.ts +38 -0
  21. package/ai/agent/isLiveAudioOnlyAgent.ts +26 -0
  22. package/ai/agent/liveAudioModel.ts +2 -0
  23. package/ai/agent/pageBuilderHandoffRules.ts +75 -0
  24. package/ai/agent/persistMessageWithFixedId.ts +37 -0
  25. package/ai/agent/planSlice.ts +259 -0
  26. package/ai/agent/referenceUtils.ts +229 -0
  27. package/ai/agent/runAgentBackground.ts +310 -0
  28. package/ai/agent/runAgentClientLoop.ts +164 -0
  29. package/ai/agent/runtimeGuidance.ts +116 -0
  30. package/ai/agent/serverOrigin.ts +7 -0
  31. package/ai/agent/startParallelAgentStreams.ts +424 -0
  32. package/ai/agent/startupProtocol.ts +53 -0
  33. package/ai/agent/streamAgentChatTurn.ts +2001 -0
  34. package/ai/agent/streamAgentChatTurnUtils.ts +860 -0
  35. package/ai/agent/toolFailureGuard.ts +99 -0
  36. package/ai/agent/types.ts +73 -0
  37. package/ai/agent/utils/imageOutput.ts +37 -0
  38. package/ai/agent/utils/publicImageAgentMode.ts +26 -0
  39. package/ai/ai.locale.ts +1095 -0
  40. package/ai/chat/accumulateToolCallChunks.ts +126 -0
  41. package/ai/chat/fetchUtils.ts +143 -0
  42. package/ai/chat/inlineImageUrlsForCustomProvider.ts +117 -0
  43. package/ai/chat/parseApiError.ts +67 -0
  44. package/ai/chat/parseMultilineSSE.ts +95 -0
  45. package/ai/chat/sendOpenAICompletionsRequest.ts +897 -0
  46. package/ai/chat/sendOpenAIResponseRequest.ts +720 -0
  47. package/ai/chat/serverProxyRetry.ts +102 -0
  48. package/ai/chat/shouldUseServerProxy.ts +18 -0
  49. package/ai/chat/streamRetry.ts +46 -0
  50. package/ai/chat/updateTotalUsage.ts +89 -0
  51. package/ai/context/buildReferenceContext.ts +437 -0
  52. package/ai/context/retention.ts +165 -0
  53. package/ai/context/tokenUtils.ts +78 -0
  54. package/ai/llm/agentCapabilities.ts +74 -0
  55. package/ai/llm/deepinfra.ts +79 -0
  56. package/ai/llm/fireworks.ts +68 -0
  57. package/ai/llm/generateRequestBody.ts +165 -0
  58. package/ai/llm/getModelContextWindow.ts +93 -0
  59. package/ai/llm/getPricing.ts +252 -0
  60. package/ai/llm/imagePricing.ts +66 -0
  61. package/ai/llm/isResponseAPIModel.ts +13 -0
  62. package/ai/llm/kimi.ts +23 -0
  63. package/ai/llm/mimo.ts +99 -0
  64. package/ai/llm/mistral.ts +21 -0
  65. package/ai/llm/models.ts +45 -0
  66. package/ai/llm/openrouterModels.ts +6 -0
  67. package/ai/llm/providers.ts +313 -0
  68. package/ai/llm/reasoningModels.ts +27 -0
  69. package/ai/llm/types.ts +82 -0
  70. package/ai/llm/usageRequestOptions.ts +59 -0
  71. package/ai/memory/queryShared.ts +161 -0
  72. package/ai/memory/recentRelationshipRecap.ts +247 -0
  73. package/ai/memory/remember.ts +167 -0
  74. package/ai/memory/store.ts +20 -0
  75. package/ai/memory/storeShared.ts +76 -0
  76. package/ai/memory/types.ts +46 -0
  77. package/ai/memory/understanding.ts +349 -0
  78. package/ai/memory/understandingGreeting.ts +264 -0
  79. package/ai/policy/personalizationDialog.ts +333 -0
  80. package/ai/policy/runtimePolicy.ts +454 -0
  81. package/ai/policy/selfUpdateFields.ts +48 -0
  82. package/ai/policy/types.ts +64 -0
  83. package/ai/skills/referenceRuntime.ts +274 -0
  84. package/ai/skills/skillDiagnostics.ts +251 -0
  85. package/ai/skills/skillDocBuilder.ts +139 -0
  86. package/ai/skills/skillSummaryMarker.ts +26 -0
  87. package/ai/token/calculatePrice.ts +576 -0
  88. package/ai/token/missingUsageEstimate.ts +42 -0
  89. package/ai/token/normalizeUsage.ts +124 -0
  90. package/ai/token/openaiImageGenerationUsage.ts +56 -0
  91. package/ai/token/prepareTokenUsageData.ts +93 -0
  92. package/ai/token/resolveBillingTarget.ts +52 -0
  93. package/ai/token/saveTokenRecord.ts +53 -0
  94. package/ai/token/types.ts +103 -0
  95. package/ai/tools/agent/agentTools.ts +235 -0
  96. package/ai/tools/agent/agentUpdateShared.ts +311 -0
  97. package/ai/tools/agent/callAgentTool.ts +139 -0
  98. package/ai/tools/agent/createAgentTool.ts +512 -0
  99. package/ai/tools/agent/createDialogTool.ts +69 -0
  100. package/ai/tools/agent/createSkillAgentTool.ts +62 -0
  101. package/ai/tools/agent/parallelBudget.ts +221 -0
  102. package/ai/tools/agent/prepareAgentDraftTool.ts +159 -0
  103. package/ai/tools/agent/presets/appBuilderPreset.ts +154 -0
  104. package/ai/tools/agent/runLlmTool.ts +96 -0
  105. package/ai/tools/agent/runStreamingAgentTool.ts +73 -0
  106. package/ai/tools/agent/skillAgentArgs.ts +106 -0
  107. package/ai/tools/agent/startAgentDialogTool.ts +53 -0
  108. package/ai/tools/agent/streamParallelAgentsTool.ts +123 -0
  109. package/ai/tools/agent/updateAgentTool.ts +96 -0
  110. package/ai/tools/agent/updateSelfTool.ts +113 -0
  111. package/ai/tools/amazonProductScraperTool.ts +86 -0
  112. package/ai/tools/apifyActorClient.ts +45 -0
  113. package/ai/tools/appEditGuard.ts +372 -0
  114. package/ai/tools/appReadSnapshot.ts +153 -0
  115. package/ai/tools/appTools.ts +1549 -0
  116. package/ai/tools/applyEditTool.ts +259 -0
  117. package/ai/tools/applyLineEditsTool.ts +315 -0
  118. package/ai/tools/browserTools/click.ts +33 -0
  119. package/ai/tools/browserTools/closeSession.ts +29 -0
  120. package/ai/tools/browserTools/common.ts +27 -0
  121. package/ai/tools/browserTools/openSession.ts +48 -0
  122. package/ai/tools/browserTools/readContent.ts +38 -0
  123. package/ai/tools/browserTools/selectOption.ts +46 -0
  124. package/ai/tools/browserTools/typeText.ts +42 -0
  125. package/ai/tools/category/createCategoryTool.ts +66 -0
  126. package/ai/tools/category/queryContentsByCategoryTool.ts +69 -0
  127. package/ai/tools/category/updateContentCategoryTool.ts +75 -0
  128. package/ai/tools/cfBrowserTools.ts +319 -0
  129. package/ai/tools/cfSpeechToTextTool.ts +49 -0
  130. package/ai/tools/checkEnvTool.ts +102 -0
  131. package/ai/tools/cloudflareCrawlTool.ts +289 -0
  132. package/ai/tools/codeSearchTool.ts +123 -0
  133. package/ai/tools/codeTools.ts +101 -0
  134. package/ai/tools/convertMarxistsBookTool.ts +103 -0
  135. package/ai/tools/createDocTool.ts +132 -0
  136. package/ai/tools/createSkillDocTool.ts +155 -0
  137. package/ai/tools/createWorkflowTool.ts +154 -0
  138. package/ai/tools/delayTool.ts +31 -0
  139. package/ai/tools/deleteSpacesTool.ts +325 -0
  140. package/ai/tools/deleteSpacesToolModel.ts +159 -0
  141. package/ai/tools/devReloadUtils.ts +29 -0
  142. package/ai/tools/dialogMessageSearch.ts +137 -0
  143. package/ai/tools/doctorSkillTool.ts +72 -0
  144. package/ai/tools/ecommerceScraperTool.ts +86 -0
  145. package/ai/tools/emailTools.ts +549 -0
  146. package/ai/tools/evalSkillTool.ts +92 -0
  147. package/ai/tools/exaSearchTool.ts +63 -0
  148. package/ai/tools/execShellTool.ts +266 -0
  149. package/ai/tools/executeSqlTool.ts +192 -0
  150. package/ai/tools/fetchWebpageSupport.ts +333 -0
  151. package/ai/tools/fetchWebpageTool.ts +97 -0
  152. package/ai/tools/geminiImagePreviewTool.ts +386 -0
  153. package/ai/tools/generateDocxTool.ts +215 -0
  154. package/ai/tools/googleSearchScraperTool.ts +106 -0
  155. package/ai/tools/importDataTool.ts +133 -0
  156. package/ai/tools/importSkillTool.ts +162 -0
  157. package/ai/tools/index.ts +2308 -0
  158. package/ai/tools/jdProductScraperTool.ts +821 -0
  159. package/ai/tools/listUserSpacesTool.ts +113 -0
  160. package/ai/tools/localFilesTool.ts +276 -0
  161. package/ai/tools/marxistsOfflineBook.ts +253 -0
  162. package/ai/tools/modelUsageTools.ts +206 -0
  163. package/ai/tools/noloWorkspaceReadTools.ts +467 -0
  164. package/ai/tools/olmOcrTool.ts +33 -0
  165. package/ai/tools/openaiImageTool.ts +267 -0
  166. package/ai/tools/prepareTools.ts +23 -0
  167. package/ai/tools/readDocTool.ts +88 -0
  168. package/ai/tools/readFileTool.ts +214 -0
  169. package/ai/tools/readTool.ts +194 -0
  170. package/ai/tools/readXPostTool.ts +229 -0
  171. package/ai/tools/readXhsProfileTool.ts +627 -0
  172. package/ai/tools/rememberMemoryTool.ts +84 -0
  173. package/ai/tools/remotionVideoTool.ts +151 -0
  174. package/ai/tools/searchDialogMessagesTool.ts +222 -0
  175. package/ai/tools/searchWorkspaceTool.ts +259 -0
  176. package/ai/tools/skillFollowup.ts +86 -0
  177. package/ai/tools/surfWeatherTool.ts +169 -0
  178. package/ai/tools/table/addTableRowTool.ts +217 -0
  179. package/ai/tools/table/createTableTool.ts +315 -0
  180. package/ai/tools/table/rowTools.ts +386 -0
  181. package/ai/tools/table/schemaTools.ts +244 -0
  182. package/ai/tools/table/shareTableTool.ts +148 -0
  183. package/ai/tools/table/toolShared.ts +129 -0
  184. package/ai/tools/taobaoTmallProductScraperTool.ts +49 -0
  185. package/ai/tools/toolApiClient.ts +279 -0
  186. package/ai/tools/toolResultError.ts +42 -0
  187. package/ai/tools/toolRunSlice.ts +303 -0
  188. package/ai/tools/toolSchemaCompatibility.ts +53 -0
  189. package/ai/tools/uiAskChoiceTool.ts +104 -0
  190. package/ai/tools/updateContentTitleTool.ts +84 -0
  191. package/ai/tools/updateDocTool.ts +105 -0
  192. package/ai/tools/updateUserPreferenceProfileTool.ts +153 -0
  193. package/ai/tools/wereadGatewayTool.ts +152 -0
  194. package/ai/tools/whisperTool.ts +76 -0
  195. package/ai/tools/writeFileTool.ts +213 -0
  196. package/ai/tools/youtubeScraperTool.ts +116 -0
  197. package/ai/tools/ziweiChartTool.ts +678 -0
  198. package/ai/types.ts +55 -0
  199. package/ai/workflow/workflowExecutor.ts +323 -0
  200. package/ai/workflow/workflowSlice.ts +73 -0
  201. package/ai/workflow/workflowTypes.ts +106 -0
  202. package/app/actions/syncAppRecord.ts +73 -0
  203. package/app/constants/animationSets.ts +21 -0
  204. package/app/constants/appEditor.ts +99 -0
  205. package/app/favorite/favoriteSlice.ts +690 -0
  206. package/app/favorite/type.ts +43 -0
  207. package/app/hooks/deleteDbKey.ts +233 -0
  208. package/app/i18n/client.ts +13 -0
  209. package/app/i18n/i18n.base.ts +14 -0
  210. package/app/i18n/i18n.config.ts +77 -0
  211. package/app/i18n/index.ts +15 -0
  212. package/app/i18n/mapLanguage.ts +11 -0
  213. package/app/i18n/translations/appBuilder.locale.ts +453 -0
  214. package/app/i18n/translations/error.locale.ts +246 -0
  215. package/app/i18n/translations/interface.locale.ts +2174 -0
  216. package/app/i18n/translations/pricing.locale.ts +397 -0
  217. package/app/i18n/translations/privacy.locale.ts +168 -0
  218. package/app/i18n/translations/seo.locale.ts +129 -0
  219. package/app/i18n/translations/terms.locale.ts +124 -0
  220. package/app/i18n/types.ts +6 -0
  221. package/app/notifications/model.ts +77 -0
  222. package/app/notifications/notificationSlice.ts +141 -0
  223. package/app/reducer.ts +36 -0
  224. package/app/settings/dbActionThunks.ts +34 -0
  225. package/app/settings/defaultSpacePreference.ts +87 -0
  226. package/app/settings/settingSlice.tsx +1212 -0
  227. package/app/settings/settingsRecord.ts +8 -0
  228. package/app/stateViews/runtime.ts +90 -0
  229. package/app/store.ts +55 -0
  230. package/app/theme/colors.ts +280 -0
  231. package/app/theme/fontPreference.ts +77 -0
  232. package/app/theme/theme.config.ts +120 -0
  233. package/app/theme/themeModeBootstrap.ts +123 -0
  234. package/app/types/appSummary.ts +114 -0
  235. package/app/types.ts +358 -0
  236. package/app/utils/appKeys.ts +55 -0
  237. package/app/utils/async.ts +28 -0
  238. package/app/utils/desktopAgentRuntimeTurnClient.ts +73 -0
  239. package/app/utils/env.ts +17 -0
  240. package/app/utils/fileUtils.ts +229 -0
  241. package/app/utils/imageUtils.ts +274 -0
  242. package/app/utils/myContentItems.ts +289 -0
  243. package/app/utils/retryAfter.ts +36 -0
  244. package/app/utils/retryFetch.ts +61 -0
  245. package/app/utils/toast.ts +3 -0
  246. package/auth/action/signUpAction.ts +227 -0
  247. package/auth/adminPermissions.ts +18 -0
  248. package/auth/authSlice.ts +531 -0
  249. package/auth/client/loginRequest.ts +14 -0
  250. package/auth/resetAuthScopedClientState.ts +27 -0
  251. package/auth/routes.ts +178 -0
  252. package/auth/token.ts +63 -0
  253. package/auth/types.ts +40 -0
  254. package/chat/chat.locale.ts +813 -0
  255. package/chat/dialog/actions/addCybotAction.ts +52 -0
  256. package/chat/dialog/actions/addReferenceKeysAction.ts +62 -0
  257. package/chat/dialog/actions/builtinDialogLlm.ts +35 -0
  258. package/chat/dialog/actions/cleanupCliSession.ts +40 -0
  259. package/chat/dialog/actions/createDialogAction.ts +379 -0
  260. package/chat/dialog/actions/createScheduledTaskAction.ts +78 -0
  261. package/chat/dialog/actions/handleSendMessageAction.ts +197 -0
  262. package/chat/dialog/actions/handleSendMessageResolver.ts +27 -0
  263. package/chat/dialog/actions/removeCybotAction.ts +6 -0
  264. package/chat/dialog/actions/removeDialogAgentAction.ts +44 -0
  265. package/chat/dialog/actions/replacePrimaryCybotAction.ts +6 -0
  266. package/chat/dialog/actions/setPrimaryDialogAgentAction.ts +52 -0
  267. package/chat/dialog/actions/updateDialogSummaryAction.ts +430 -0
  268. package/chat/dialog/actions/updateDialogTitleAction.ts +151 -0
  269. package/chat/dialog/actions/updateDialogTitlePolicy.ts +30 -0
  270. package/chat/dialog/actions/updateTokensAction.ts +233 -0
  271. package/chat/dialog/dialogAgents.ts +72 -0
  272. package/chat/dialog/dialogSlice.ts +872 -0
  273. package/chat/dialog/dialogTitle.ts +81 -0
  274. package/chat/dialog/dialogTokenStats.ts +12 -0
  275. package/chat/dialog/dialogUrl.ts +6 -0
  276. package/chat/dialog/goal.ts +108 -0
  277. package/chat/dialog/objectAssistantRegistry.ts +286 -0
  278. package/chat/dialog/schedule.ts +17 -0
  279. package/chat/messages/fetchAndCacheMessages.ts +119 -0
  280. package/chat/messages/fetchConvMsgs.ts +51 -0
  281. package/chat/messages/fileUrl.ts +13 -0
  282. package/chat/messages/messageAgent.ts +8 -0
  283. package/chat/messages/messageContent.ts +199 -0
  284. package/chat/messages/messageContract.ts +88 -0
  285. package/chat/messages/messageSlice.ts +1367 -0
  286. package/chat/messages/toolThunks.ts +625 -0
  287. package/cli/client/agentRun.ts +27 -8
  288. package/cli/client/localRuntimeAdapter.ts +144 -28
  289. package/client/agentRun.test.ts +52 -0
  290. package/client/agentRun.ts +27 -8
  291. package/client/localRuntimeAdapter.test.ts +437 -6
  292. package/client/localRuntimeAdapter.ts +144 -28
  293. package/core/builtinAgents.ts +209 -0
  294. package/core/config.ts +15 -0
  295. package/core/crypto.ts +51 -0
  296. package/core/generateKeyPairFromSeedV1.ts +15 -0
  297. package/core/generateMainKey.ts +22 -0
  298. package/core/init.ts +41 -0
  299. package/core/localOrigins.ts +8 -0
  300. package/core/password.ts +13 -0
  301. package/core/prefix.ts +23 -0
  302. package/create/editor/transforms/fromMarkdown/index.ts +260 -0
  303. package/create/editor/transforms/fromMarkdown/inline.ts +285 -0
  304. package/create/editor/transforms/fromMarkdown/table.ts +130 -0
  305. package/create/editor/transforms/markdownToSlate.ts +24 -0
  306. package/create/editor/transforms/slateToRenderMarkdown.ts +218 -0
  307. package/create/editor/transforms/slateToSimplifiedMarkdown.ts +224 -0
  308. package/create/editor/transforms/slateToText.ts +33 -0
  309. package/create/editor/utils/slateUtils.ts +233 -0
  310. package/create/space/addSpaceAction.ts +193 -0
  311. package/create/space/category/categoryActions.ts +427 -0
  312. package/create/space/changeSpaceAction.ts +36 -0
  313. package/create/space/constants.ts +8 -0
  314. package/create/space/content/addContentAction.ts +116 -0
  315. package/create/space/content/contentThunks.ts +90 -0
  316. package/create/space/content/deleteContentFromSpaceAction.ts +187 -0
  317. package/create/space/content/deleteMultipleContentAction.ts +112 -0
  318. package/create/space/content/moveContentAction.ts +285 -0
  319. package/create/space/content/updateContentCategoryAction.ts +154 -0
  320. package/create/space/content/updateContentTitleAction.ts +151 -0
  321. package/create/space/content/uploadAndAddFileToSpaceAction.ts +98 -0
  322. package/create/space/contentKeyUtils.ts +117 -0
  323. package/create/space/deleteSpaceAction.ts +276 -0
  324. package/create/space/fetchSpaceAction.ts +70 -0
  325. package/create/space/fetchSpaceSidebarStateAction.ts +26 -0
  326. package/create/space/loadDefaultSpaceAction.ts +57 -0
  327. package/create/space/member/addMemberAction.ts +79 -0
  328. package/create/space/member/fetchUserSpaceMembershipsAction.ts +386 -0
  329. package/create/space/member/memberThunks.ts +47 -0
  330. package/create/space/member/removeMemberAction.ts +67 -0
  331. package/create/space/resolvePreferredSpaceId.ts +113 -0
  332. package/create/space/sidebarVisibleTypes.ts +241 -0
  333. package/create/space/space.locale.ts +1087 -0
  334. package/create/space/spaceAccess.ts +182 -0
  335. package/create/space/spaceCollapsedState.ts +54 -0
  336. package/create/space/spaceKeys.ts +65 -0
  337. package/create/space/spaceSlice.ts +328 -0
  338. package/create/space/spaceThunks.ts +410 -0
  339. package/create/space/types.ts +27 -0
  340. package/create/space/updateSpaceAction.ts +107 -0
  341. package/create/space/utils/permissions.ts +47 -0
  342. package/create/types.ts +21 -0
  343. package/database/actions/agentReadResolution.ts +33 -0
  344. package/database/actions/common.ts +243 -0
  345. package/database/actions/deleteFile.ts +40 -0
  346. package/database/actions/fileContent.ts +125 -0
  347. package/database/actions/patch.ts +155 -0
  348. package/database/actions/read.ts +358 -0
  349. package/database/actions/readAndWait.ts +260 -0
  350. package/database/actions/readRequestManager.ts +120 -0
  351. package/database/actions/readResolution.ts +125 -0
  352. package/database/actions/remove.ts +94 -0
  353. package/database/actions/replication.ts +477 -0
  354. package/database/actions/upload.ts +186 -0
  355. package/database/actions/upsert.ts +56 -0
  356. package/database/actions/write.ts +146 -0
  357. package/database/authority/ownerKey.ts +80 -0
  358. package/database/authority/recordAuthority.ts +67 -0
  359. package/database/authority/userAuthorityRegistry.ts +54 -0
  360. package/database/client/fetchUserData.ts +61 -0
  361. package/database/dbActionThunks.ts +1 -0
  362. package/database/dbSlice.ts +149 -0
  363. package/database/fileRing.ts +51 -0
  364. package/database/fileStorage.ts +232 -0
  365. package/database/fileUrl.ts +34 -0
  366. package/database/keys.ts +767 -0
  367. package/database/queryPrefixes.ts +14 -0
  368. package/database/requests.ts +443 -0
  369. package/database/runtimeServerContext.ts +54 -0
  370. package/database/tenantPlacement.ts +57 -0
  371. package/database/userPreferenceRegister.ts +131 -0
  372. package/database/utils/ulid.ts +1 -0
  373. package/integrations/anthropic/anthropicModels.ts +47 -0
  374. package/integrations/deepseek/models.ts +37 -0
  375. package/integrations/google/models.ts +341 -0
  376. package/integrations/openai/chatCompletionStreamMode.ts +10 -0
  377. package/integrations/openai/filterAndCleanMessages.ts +284 -0
  378. package/integrations/openai/flexTier.ts +102 -0
  379. package/integrations/openai/generateOpenAIRequestBody.ts +274 -0
  380. package/integrations/openai/generateResponseRequestBody.ts +77 -0
  381. package/integrations/openai/models.ts +271 -0
  382. package/integrations/openai/providerBodyCompatibility.ts +23 -0
  383. package/integrations/openai/responsesHelpers.ts +297 -0
  384. package/integrations/x-reader/types.ts +109 -0
  385. package/integrations/xai/models.ts +13 -0
  386. package/integrations/xhs-reader/analyze/profileAnalyzer.ts +205 -0
  387. package/integrations/xhs-reader/backends/playwrightProfileCollector.ts +624 -0
  388. package/integrations/xhs-reader/bridge/readXhsProfileWithBridge.ts +227 -0
  389. package/integrations/xhs-reader/client/xhsWebApiClient.ts +229 -0
  390. package/integrations/xhs-reader/normalize.ts +390 -0
  391. package/integrations/xhs-reader/orchestrator.ts +178 -0
  392. package/integrations/xhs-reader/redaction.ts +68 -0
  393. package/integrations/xhs-reader/types.ts +244 -0
  394. package/integrations/xhs-reader/url.ts +57 -0
  395. package/package.json +430 -4
  396. package/render/page/createPageAction.ts +183 -0
  397. package/render/page/docSlice.ts +468 -0
  398. package/render/page/types.ts +17 -0
  399. package/render/table/createTableAction.ts +270 -0
  400. package/render/table/deleteTableAction.ts +193 -0
  401. package/render/table/fetchAndCacheTableRows.ts +174 -0
  402. package/render/table/tableSlice.ts +1106 -0
  403. package/render/table/toolValueUtils.ts +363 -0
  404. package/render/table/types.ts +252 -0
  405. package/render/table/utils/tableSerialization.ts +50 -0
  406. package/server/handlers/agentRun/types.ts +104 -0
  407. package/share/action.ts +225 -0
  408. package/share/helpers.ts +302 -0
  409. package/share/keys.ts +243 -0
  410. package/share/publicSharePolicy.ts +27 -0
  411. package/share/shareSlice.ts +53 -0
  412. package/share/types.ts +100 -0
@@ -0,0 +1,182 @@
1
+ import type { SpaceData, SpaceMemberWithSpaceInfo } from "../../app/types";
2
+ import { getIsDesktopApp } from "../../app/utils/env";
3
+ import { createSpaceKey, normalizeSpaceId } from "../space/spaceKeys";
4
+ import { fetchFromServer } from "../../database/actions/common";
5
+ import { NOLO_CLUSTER_SERVERS, normalizeKnownServerOrigin } from "../../database/config";
6
+ import { isTombstoneRecord } from "../../database/tombstones";
7
+
8
+ export interface SpaceRemoteAuth {
9
+ token: string | null;
10
+ userId: string | null;
11
+ servers: string[];
12
+ }
13
+
14
+ export interface RemoteMembershipFetchResult {
15
+ ok: boolean;
16
+ server?: string;
17
+ memberships: SpaceMemberWithSpaceInfo[];
18
+ }
19
+
20
+ const normalizeServerOrigin = (server: unknown): string | null => {
21
+ return normalizeKnownServerOrigin(server);
22
+ };
23
+
24
+ const isLocalServerOrigin = (server: string): boolean =>
25
+ /^https?:\/\/(?:localhost|127\.0\.0\.1|0\.0\.0\.0|nolotus\.local)(?::\d+)?$/i.test(server);
26
+
27
+ const resolveSpaceRemoteServers = (state: any): string[] => {
28
+ const currentServer = normalizeServerOrigin(state?.settings?.currentServer);
29
+ const normalized = [
30
+ currentServer,
31
+ ...(Array.isArray(state?.settings?.syncServers)
32
+ ? state.settings.syncServers
33
+ : []),
34
+ ]
35
+ .map(normalizeServerOrigin)
36
+ .filter((server): server is string => !!server);
37
+
38
+ if (!getIsDesktopApp()) {
39
+ return Array.from(new Set(normalized));
40
+ }
41
+
42
+ const remoteServers = normalized.filter((server) => !isLocalServerOrigin(server));
43
+ if (currentServer && isLocalServerOrigin(currentServer)) {
44
+ return Array.from(new Set([...NOLO_CLUSTER_SERVERS, ...remoteServers]));
45
+ }
46
+ if (remoteServers.length === 0) {
47
+ remoteServers.push(...NOLO_CLUSTER_SERVERS);
48
+ }
49
+
50
+ return Array.from(new Set(remoteServers));
51
+ };
52
+
53
+ export const selectSpaceRemoteAuth = (state: any): SpaceRemoteAuth => ({
54
+ token: state?.auth?.currentToken ?? null,
55
+ userId: state?.auth?.currentUser?.userId ?? null,
56
+ servers: resolveSpaceRemoteServers(state),
57
+ });
58
+
59
+ export const spaceListsUser = (spaceData: any, userId: string): boolean => {
60
+ if (!spaceData || isTombstoneRecord(spaceData)) return false;
61
+ if (spaceData.ownerId === userId) return true;
62
+ return Array.isArray(spaceData.members) && spaceData.members.includes(userId);
63
+ };
64
+
65
+ export const membershipBelongsToUser = (
66
+ membership: SpaceMemberWithSpaceInfo,
67
+ userId: string
68
+ ): boolean => !membership.userId || membership.userId === userId;
69
+
70
+ export const fetchRemoteUserSpaceMemberships = async (
71
+ server: string,
72
+ token: string | null,
73
+ userId: string,
74
+ timeoutMs = 5000
75
+ ): Promise<RemoteMembershipFetchResult> => {
76
+ if (!token) return { ok: false, memberships: [] };
77
+ const controller = new AbortController();
78
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
79
+ try {
80
+ const response = await fetch(`${server}/rpc/getUserSpaceMemberships`, {
81
+ method: "POST",
82
+ headers: {
83
+ Authorization: `Bearer ${token}`,
84
+ "Content-Type": "application/json",
85
+ },
86
+ body: JSON.stringify({ userId }),
87
+ signal: controller.signal,
88
+ });
89
+ clearTimeout(timeoutId);
90
+ if (!response.ok) {
91
+ console.error(
92
+ `Failed to fetch memberships from ${server}: ${response.statusText}`
93
+ );
94
+ return { ok: false, memberships: [] };
95
+ }
96
+ const data = await response.json();
97
+ return {
98
+ ok: true,
99
+ server,
100
+ memberships: Array.isArray(data) ? data : [],
101
+ };
102
+ } catch (error) {
103
+ clearTimeout(timeoutId);
104
+ console.error(`Error fetching memberships from ${server}:`, error);
105
+ return { ok: false, memberships: [] };
106
+ }
107
+ };
108
+
109
+ export const fetchRemoteSpace = async (
110
+ server: string,
111
+ token: string | null,
112
+ spaceId: string
113
+ ): Promise<SpaceData | null> => {
114
+ try {
115
+ const space = await fetchFromServer(
116
+ server,
117
+ createSpaceKey.space(normalizeSpaceId(spaceId)),
118
+ token ?? undefined
119
+ );
120
+ return space && typeof space === "object" ? (space as SpaceData) : null;
121
+ } catch {
122
+ return null;
123
+ }
124
+ };
125
+
126
+ export const hasActiveRemoteMembership = async (
127
+ server: string,
128
+ token: string,
129
+ userId: string,
130
+ spaceId: string
131
+ ): Promise<boolean> => {
132
+ const result = await fetchRemoteUserSpaceMemberships(server, token, userId);
133
+ if (!result.ok) return false;
134
+ const normalizedSpaceId = normalizeSpaceId(spaceId);
135
+ return result.memberships.some((membership) => {
136
+ const membershipSpaceId =
137
+ typeof membership?.spaceId === "string"
138
+ ? normalizeSpaceId(membership.spaceId)
139
+ : "";
140
+ return (
141
+ membershipSpaceId === normalizedSpaceId &&
142
+ membershipBelongsToUser(membership, userId) &&
143
+ !isTombstoneRecord(membership)
144
+ );
145
+ });
146
+ };
147
+
148
+ export const fetchAuthoritativeRemoteSpace = async ({
149
+ servers,
150
+ token,
151
+ userId,
152
+ spaceId,
153
+ }: {
154
+ servers: string[];
155
+ token: string;
156
+ userId: string;
157
+ spaceId: string;
158
+ }): Promise<SpaceData | null> => {
159
+ const normalizedSpaceId = normalizeSpaceId(spaceId);
160
+ for (const server of servers) {
161
+ const space = await fetchRemoteSpace(server, token, normalizedSpaceId);
162
+ if (!space) continue;
163
+ if (!spaceListsUser(space, userId)) {
164
+ throw new Error(`Current user is not a member of space: ${normalizedSpaceId}`);
165
+ }
166
+ if (space.ownerId !== userId) {
167
+ const hasMembership = await hasActiveRemoteMembership(
168
+ server,
169
+ token,
170
+ userId,
171
+ normalizedSpaceId
172
+ );
173
+ if (!hasMembership) {
174
+ throw new Error(
175
+ `Current user has no active membership for space: ${normalizedSpaceId}`
176
+ );
177
+ }
178
+ }
179
+ return space;
180
+ }
181
+ return null;
182
+ };
@@ -0,0 +1,54 @@
1
+ import { UNCATEGORIZED_ID } from "./constants";
2
+
3
+ type StorageLike = Pick<Storage, "getItem" | "setItem">;
4
+
5
+ const SPACE_COLLAPSE_STORAGE_PREFIX = "space-collapsed-categories:";
6
+
7
+ export const normalizeCollapsedCategories = (
8
+ value: unknown,
9
+ ): Record<string, boolean> => {
10
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
11
+ return {};
12
+ }
13
+
14
+ const entries = Object.entries(value).filter(
15
+ ([key, collapsed]) => typeof key === "string" && typeof collapsed === "boolean",
16
+ );
17
+ return Object.fromEntries(entries);
18
+ };
19
+
20
+ const storageKeyForSpace = (spaceId: string) =>
21
+ `${SPACE_COLLAPSE_STORAGE_PREFIX}${spaceId}`;
22
+
23
+ export const readStoredCollapsedCategories = (
24
+ spaceId: string,
25
+ storage: StorageLike | null | undefined,
26
+ ): Record<string, boolean> => {
27
+ if (!spaceId || !storage) return {};
28
+
29
+ try {
30
+ const raw = storage.getItem(storageKeyForSpace(spaceId));
31
+ if (!raw) return { [UNCATEGORIZED_ID]: false };
32
+ return normalizeCollapsedCategories(JSON.parse(raw));
33
+ } catch (error) {
34
+ console.warn("[Space] 读取分类折叠状态失败:", error);
35
+ return {};
36
+ }
37
+ };
38
+
39
+ export const writeStoredCollapsedCategories = (
40
+ spaceId: string,
41
+ collapsedCategories: Record<string, boolean>,
42
+ storage: StorageLike | null | undefined,
43
+ ) => {
44
+ if (!spaceId || !storage) return;
45
+
46
+ try {
47
+ storage.setItem(
48
+ storageKeyForSpace(spaceId),
49
+ JSON.stringify(normalizeCollapsedCategories(collapsedCategories)),
50
+ );
51
+ } catch (error) {
52
+ console.warn("[Space] 保存分类折叠状态失败:", error);
53
+ }
54
+ };
@@ -0,0 +1,65 @@
1
+ const SEPARATOR = "-";
2
+ const SPACE_PREFIX = "space";
3
+ const SPACE_PREFIX_WITH_SEPARATOR = `${SPACE_PREFIX}${SEPARATOR}`;
4
+
5
+ export const normalizeSpaceId = (spaceId: string) => {
6
+ if (!spaceId) return spaceId;
7
+ return spaceId.startsWith(SPACE_PREFIX_WITH_SEPARATOR)
8
+ ? spaceId.slice(SPACE_PREFIX_WITH_SEPARATOR.length)
9
+ : spaceId;
10
+ };
11
+
12
+ export const createSpaceKey = {
13
+ // 空间基础信息的key
14
+ space: (spaceId: string) => {
15
+ return [SPACE_PREFIX, normalizeSpaceId(spaceId)].join(SEPARATOR);
16
+ },
17
+
18
+ // 空间成员的key
19
+ member: (userId: string, spaceId: string) => {
20
+ return [SPACE_PREFIX, "member", userId, normalizeSpaceId(spaceId)].join(
21
+ SEPARATOR
22
+ );
23
+ },
24
+
25
+ // 查询用户所在的所有空间的范围
26
+ memberRange: (userId: string) => {
27
+ return {
28
+ start: [SPACE_PREFIX, "member", userId, ""].join(SEPARATOR),
29
+ end: [SPACE_PREFIX, "member", userId, "\uffff"].join(SEPARATOR),
30
+ };
31
+ },
32
+
33
+ /**
34
+ * 预留:未来若出现“按用户、按空间、且必须跨设备同步”的空间级偏好,
35
+ * 统一使用这个 key family。当前产品主链不要依赖它。
36
+ */
37
+ setting: (userId: string, spaceId: string) => {
38
+ return [SPACE_PREFIX, "setting", userId, normalizeSpaceId(spaceId)].join(
39
+ SEPARATOR
40
+ );
41
+ },
42
+
43
+ /**
44
+ * 预留:未来如确实需要批量读取空间级远端偏好,再使用这个范围。
45
+ */
46
+ settingRange: (userId: string) => {
47
+ return {
48
+ start: [SPACE_PREFIX, "setting", userId, ""].join(SEPARATOR),
49
+ end: [SPACE_PREFIX, "setting", userId, "\uffff"].join(SEPARATOR),
50
+ };
51
+ },
52
+
53
+ // 从成员key中提取空间key
54
+ spaceFromMember: (memberKey: string) => {
55
+ const parts = memberKey.split(SEPARATOR);
56
+ const spaceId = parts[parts.length - 1];
57
+ return [SPACE_PREFIX, spaceId].join(SEPARATOR);
58
+ },
59
+
60
+ // 从成员key中提取空间ID
61
+ spaceIdFromMember: (memberKey: string) => {
62
+ const parts = memberKey.split(SEPARATOR);
63
+ return parts[parts.length - 1];
64
+ },
65
+ };
@@ -0,0 +1,328 @@
1
+ import type { RootState } from "../../app/store";
2
+ import { asyncThunkCreator, buildCreateSlice, createSelector } from "@reduxjs/toolkit";
3
+ import { selectEntities } from "../../database/dbSlice";
4
+
5
+ import { MemberRole, type SpaceContent, type SpaceMemberWithSpaceInfo } from "../../app/types";
6
+
7
+ import { createCategoryActions } from "./category/categoryActions";
8
+ import { createContentThunks } from "./content/contentThunks";
9
+ import { createMemberThunks } from "./member/memberThunks";
10
+ import { createSpaceThunks } from "./spaceThunks";
11
+ import { SpaceState, type SpaceViewMode } from "./types";
12
+ import { UNCATEGORIZED_ID } from "./constants";
13
+
14
+ import { createSpaceKey } from "./spaceKeys";
15
+
16
+ const createSliceWithThunks = buildCreateSlice({
17
+ creators: { asyncThunk: asyncThunkCreator },
18
+ });
19
+
20
+ const VIEW_MODE_STORAGE_KEY = "nolo-space-view-mode";
21
+
22
+ const readStoredViewMode = (): SpaceViewMode => {
23
+ if (typeof window === "undefined") return "all";
24
+ try {
25
+ const stored = window.localStorage.getItem(VIEW_MODE_STORAGE_KEY);
26
+ return stored === "categories" ? "categories" : "all";
27
+ } catch {
28
+ return "all";
29
+ }
30
+ };
31
+
32
+ const initialState: SpaceState = {
33
+ currentSpaceId: null,
34
+ currentSpace: null,
35
+ memberSpaces: null,
36
+ loading: false,
37
+ initialized: false,
38
+ collapsedCategories: {},
39
+ viewMode: readStoredViewMode(),
40
+ dialogStatuses: {},
41
+ dialogEventTimestamps: {},
42
+ dialogTitles: {},
43
+ // 第一层网页体验:对话切走后仍可在 sidebar 感知其运行中/已完成。
44
+ // 多窗口/多 tab 的已读同步语义暂不在这里定义,等桌面端阶段统一设计。
45
+ unreadDialogIds: {},
46
+ };
47
+
48
+ const getSpaceUpdatedAt = (space: any): number => {
49
+ if (!space) return 0;
50
+ const value = space.updatedAt;
51
+ if (typeof value === "number" && Number.isFinite(value)) return value;
52
+ if (typeof value === "string") {
53
+ const ts = Date.parse(value);
54
+ return Number.isFinite(ts) ? ts : 0;
55
+ }
56
+ return 0;
57
+ };
58
+
59
+ const nextUpdatedAt = (prev?: number | string): number => {
60
+ const prevTs =
61
+ typeof prev === "number"
62
+ ? prev
63
+ : typeof prev === "string"
64
+ ? Date.parse(prev) || 0
65
+ : 0;
66
+ return Math.max(Date.now(), prevTs + 1);
67
+ };
68
+
69
+ const getMembershipUpdatedAt = (space: any): number => {
70
+ if (!space) return 0;
71
+ const value =
72
+ space.spaceUpdatedAt ??
73
+ space.memberUpdatedAt ??
74
+ space.updatedAt ??
75
+ space.createdAt ??
76
+ space.joinedAt;
77
+ if (typeof value === "number" && Number.isFinite(value)) return value;
78
+ if (typeof value === "string") {
79
+ const ts = Date.parse(value);
80
+ return Number.isFinite(ts) ? ts : 0;
81
+ }
82
+ return 0;
83
+ };
84
+
85
+ export const dedupeMemberSpacesById = <T extends { spaceId: string }>(
86
+ memberSpaces: T[]
87
+ ): T[] => {
88
+ const membershipMap = new Map<string, T>();
89
+ memberSpaces.forEach((space) => {
90
+ const prev = membershipMap.get(space.spaceId);
91
+ if (!prev || getMembershipUpdatedAt(space) >= getMembershipUpdatedAt(prev)) {
92
+ membershipMap.set(space.spaceId, space);
93
+ }
94
+ });
95
+ return Array.from(membershipMap.values());
96
+ };
97
+
98
+ const spaceSlice = createSliceWithThunks({
99
+ name: "space",
100
+ initialState,
101
+ reducers: (create) => ({
102
+ ...createSpaceThunks(create),
103
+ ...createCategoryActions(create),
104
+ ...createContentThunks(create),
105
+ ...createMemberThunks(create),
106
+
107
+ /** 重置 space 状态(切换用户时调用),清空旧用户数据 */
108
+ resetSpace: create.reducer((state) => {
109
+ state.currentSpaceId = null;
110
+ state.currentSpace = null;
111
+ state.memberSpaces = null;
112
+ state.collapsedCategories = {};
113
+ state.viewMode = "all";
114
+ state.initialized = false;
115
+ state.loading = false;
116
+ state.dialogStatuses = {};
117
+ state.dialogEventTimestamps = {};
118
+ state.dialogTitles = {};
119
+ state.unreadDialogIds = {};
120
+ }),
121
+
122
+ /** 切换侧边栏视图模式:全部 vs 分类 */
123
+ setViewMode: create.reducer<SpaceViewMode>((state, action) => {
124
+ state.viewMode = action.payload;
125
+ }),
126
+
127
+ /** 用本地缓存先恢复空间列表,远端校验完成后再由 fetchUserSpaceMemberships.fulfilled 覆盖。 */
128
+ hydrateMemberSpacesFromLocal: create.reducer<SpaceMemberWithSpaceInfo[]>(
129
+ (state, action) => {
130
+ if (state.memberSpaces !== null || action.payload.length === 0) return;
131
+ state.memberSpaces = dedupeMemberSpacesById(action.payload);
132
+ }
133
+ ),
134
+
135
+ /** 进入某个对话后清除其未读提示。
136
+ * 当前阶段只做“网页端切换不停止”的第一层体验:
137
+ * - 侧边栏能看到后台对话 done/failed 后有未读点
138
+ * - 真正的跨窗口/多 tab 已读同步,留到桌面端阶段再设计
139
+ */
140
+ markDialogRead: create.reducer<{ dialogId: string }>((state, action) => {
141
+ delete state.unreadDialogIds[action.payload.dialogId];
142
+ }),
143
+
144
+ /** 处理来自 SSE 的 space 实时事件,直接 patch Redux state,无需 re-fetch */
145
+ applySpaceEvent: create.reducer<{
146
+ type: string;
147
+ dialogId?: string;
148
+ dialogKey?: string;
149
+ title?: string;
150
+ status?: string;
151
+ }>((state, action) => {
152
+ const ev = action.payload;
153
+
154
+ if (ev.type === "dialog.created" && ev.dialogKey && ev.dialogId && ev.title) {
155
+ // 追加到当前 space 的 contents(侧边栏立即可见)
156
+ const now = nextUpdatedAt(state.dialogEventTimestamps[ev.dialogId]);
157
+ if (state.currentSpace) {
158
+ if (!state.currentSpace.contents) {
159
+ state.currentSpace.contents = {};
160
+ }
161
+ state.currentSpace.contents[ev.dialogKey] = {
162
+ title: ev.title,
163
+ type: "dialog" as any,
164
+ contentKey: ev.dialogKey,
165
+ pinned: false,
166
+ createdAt: now,
167
+ updatedAt: now,
168
+ };
169
+ state.currentSpace.updatedAt = now;
170
+ }
171
+ state.dialogStatuses[ev.dialogId] = "running";
172
+ state.dialogEventTimestamps[ev.dialogId] = now;
173
+ state.dialogTitles[ev.dialogId] = ev.title;
174
+ delete state.unreadDialogIds[ev.dialogId];
175
+ }
176
+
177
+ if (ev.type === "dialog.done" && ev.dialogId) {
178
+ state.dialogStatuses[ev.dialogId] = "done";
179
+ state.dialogEventTimestamps[ev.dialogId] = nextUpdatedAt(
180
+ state.dialogEventTimestamps[ev.dialogId]
181
+ );
182
+ state.unreadDialogIds[ev.dialogId] = true;
183
+ }
184
+
185
+ if (ev.type === "dialog.failed" && ev.dialogId) {
186
+ state.dialogStatuses[ev.dialogId] = "failed";
187
+ state.dialogEventTimestamps[ev.dialogId] = nextUpdatedAt(
188
+ state.dialogEventTimestamps[ev.dialogId]
189
+ );
190
+ state.unreadDialogIds[ev.dialogId] = true;
191
+ }
192
+ }),
193
+ }),
194
+ });
195
+
196
+ export const {
197
+ toggleCategoryCollapse,
198
+ setAllCategoriesCollapsed,
199
+ changeSpace,
200
+ addSpace,
201
+ deleteSpace,
202
+ updateSpace,
203
+ loadDefaultSpace,
204
+ fetchSpace,
205
+ addCategory,
206
+ deleteCategory,
207
+ updateCategoryName,
208
+ reorderCategories,
209
+ addContentToSpace,
210
+ moveContentToSpace,
211
+ deleteContentFromSpace,
212
+ deleteMultipleContent,
213
+ updateContentTitle,
214
+ updateContentCategory,
215
+ uploadAndAddFileToSpace,
216
+ fetchUserSpaceMemberships,
217
+ addMember,
218
+ removeMember,
219
+ fixSpace,
220
+ fetchSpaceSidebarState,
221
+ applySpaceEvent,
222
+ markDialogRead,
223
+ resetSpace,
224
+ setViewMode,
225
+ hydrateMemberSpacesFromLocal,
226
+ } = spaceSlice.actions;
227
+
228
+ const selectSpaceState = (state: RootState) => state.space;
229
+
230
+ export const selectCurrentSpaceId = createSelector(
231
+ selectSpaceState,
232
+ (space) => space.currentSpaceId
233
+ );
234
+
235
+ export const selectCurrentSpace = createSelector(
236
+ [
237
+ selectSpaceState,
238
+ (state: RootState) => {
239
+ const spaceState = state.space;
240
+ if (!spaceState?.currentSpaceId) return undefined;
241
+ const dbKey = createSpaceKey.space(spaceState.currentSpaceId);
242
+ return selectEntities(state)[dbKey];
243
+ },
244
+ ],
245
+ (space, spaceEntity) => {
246
+ if (!space.currentSpaceId) return null;
247
+ if (!space.currentSpace) return spaceEntity || null;
248
+ if (!spaceEntity) return space.currentSpace;
249
+ return getSpaceUpdatedAt(spaceEntity) > getSpaceUpdatedAt(space.currentSpace)
250
+ ? spaceEntity
251
+ : space.currentSpace;
252
+ }
253
+ );
254
+
255
+ export const selectAllMemberSpaces = createSelector(
256
+ selectSpaceState,
257
+ (space) => {
258
+ const memberSpaces = dedupeMemberSpacesById(space.memberSpaces || []);
259
+ return [...memberSpaces].sort((a, b) => {
260
+ return getMembershipUpdatedAt(b) - getMembershipUpdatedAt(a);
261
+ });
262
+ }
263
+ );
264
+
265
+ export const selectOwnedMemberSpaces = createSelector(
266
+ selectAllMemberSpaces,
267
+ (memberSpaces) =>
268
+ memberSpaces.filter((space) => space.role === MemberRole.OWNER)
269
+ );
270
+
271
+ export interface CrossSpaceContentItem extends SpaceContent {
272
+ spaceId: string;
273
+ spaceName: string;
274
+ }
275
+
276
+ export const selectSpaceLoading = createSelector(
277
+ selectSpaceState,
278
+ (space) => space.loading
279
+ );
280
+
281
+ export const selectSpaceInitialized = createSelector(
282
+ selectSpaceState,
283
+ (space) => space.initialized
284
+ );
285
+
286
+ export const selectCollapsedCategories = createSelector(
287
+ selectSpaceState,
288
+ (space) => space.collapsedCategories
289
+ );
290
+
291
+ export const selectIsCategoryCollapsed = (categoryId: string) =>
292
+ createSelector(
293
+ selectCollapsedCategories,
294
+ (collapsed) => collapsed[categoryId] ?? categoryId !== UNCATEGORIZED_ID
295
+ );
296
+
297
+ export const selectDialogStatuses = createSelector(
298
+ selectSpaceState,
299
+ (space) => space.dialogStatuses ?? {}
300
+ );
301
+
302
+ export const selectDialogEventTimestamps = createSelector(
303
+ selectSpaceState,
304
+ (space) => space.dialogEventTimestamps ?? {}
305
+ );
306
+
307
+ export const selectDialogTitles = createSelector(
308
+ selectSpaceState,
309
+ (space) => space.dialogTitles ?? {}
310
+ );
311
+
312
+ export const selectDialogStatus = (dialogId: string) =>
313
+ createSelector(selectDialogStatuses, (statuses) => statuses[dialogId]);
314
+
315
+ export const selectUnreadDialogIds = createSelector(
316
+ selectSpaceState,
317
+ (space) => space.unreadDialogIds ?? {}
318
+ );
319
+
320
+ export const selectIsDialogUnread = (dialogId: string) =>
321
+ createSelector(selectUnreadDialogIds, (unreadMap) => unreadMap[dialogId] === true);
322
+
323
+ export const selectViewMode = createSelector(
324
+ selectSpaceState,
325
+ (space) => space.viewMode
326
+ );
327
+
328
+ export default spaceSlice.reducer;