nolo-cli 0.1.13 → 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.
- package/README.md +9 -2
- package/agent-runtime/hostAdapter.ts +53 -0
- package/agent-runtime/index.ts +28 -0
- package/agent-runtime/localLoop.ts +62 -0
- package/agent-runtime/runtimeDecision.ts +70 -0
- package/agent-runtime/types.ts +87 -0
- package/agentRuntimeCommands.ts +139 -22
- package/agentRuntimeLocal.ts +7 -0
- package/ai/agent/_executeModel.ts +118 -0
- package/ai/agent/agentSlice.ts +544 -1
- package/ai/agent/appWorkingMemory.ts +126 -0
- package/ai/agent/avatarUtils.ts +24 -0
- package/ai/agent/buildEditingContext.ts +373 -0
- package/ai/agent/buildSystemPrompt.ts +532 -0
- package/ai/agent/cleanAgentMessages.ts +140 -0
- package/ai/agent/cliChatClient.ts +119 -0
- package/ai/agent/contextCompiler.ts +107 -0
- package/ai/agent/contextLayerContract.ts +44 -0
- package/ai/agent/createAgentSchema.ts +234 -0
- package/ai/agent/executeToolCall.ts +58 -0
- package/ai/agent/fetchAgentContexts.ts +42 -0
- package/ai/agent/generatePrompt.ts +3 -0
- package/ai/agent/getFullChatContextKeys.ts +168 -0
- package/ai/agent/hooks/fetchPublicAgents.ts +133 -0
- package/ai/agent/hooks/useAgentConfig.ts +61 -0
- package/ai/agent/hooks/useAgentDialog.ts +35 -0
- package/ai/agent/hooks/useAgentFormValidation.ts +202 -0
- package/ai/agent/hooks/usePublicAgents.ts +473 -0
- package/ai/agent/persistMessageWithFixedId.ts +37 -0
- package/ai/agent/planSlice.ts +259 -0
- package/ai/agent/referenceUtils.ts +229 -0
- package/ai/agent/runAgentBackground.ts +238 -0
- package/ai/agent/runAgentClientLoop.ts +138 -0
- package/ai/agent/runtimeGuidance.ts +97 -0
- package/ai/agent/runtimeServerBase.ts +37 -0
- package/ai/agent/server/fetchPublicAgents.ts +128 -0
- package/ai/agent/startParallelAgentStreams.ts +424 -0
- package/ai/agent/startupProtocol.ts +53 -0
- package/ai/agent/streamAgentChatTurn.ts +1299 -0
- package/ai/agent/streamAgentChatTurnUtils.ts +738 -0
- package/ai/agent/types.ts +71 -0
- package/ai/agent/utils/imageOutput.ts +39 -0
- package/ai/agent/utils/publicImageAgentMode.ts +26 -0
- package/ai/agent/utils/sortUtils.ts +250 -0
- package/ai/agent/web/referencePickerUtils.ts +146 -0
- package/ai/ai.locale.ts +1083 -0
- package/ai/chat/accumulateToolCallChunks.ts +95 -0
- package/ai/chat/fetchUtils.native.ts +276 -0
- package/ai/chat/fetchUtils.ts +153 -0
- package/ai/chat/inlineImageUrlsForCustomProvider.ts +117 -0
- package/ai/chat/parseApiError.ts +64 -0
- package/ai/chat/parseMultilineSSE.ts +95 -0
- package/ai/chat/sendOpenAICompletionsRequest.native.ts +682 -0
- package/ai/chat/sendOpenAICompletionsRequest.ts +712 -0
- package/ai/chat/sendOpenAIResponseRequest.ts +512 -0
- package/ai/chat/shouldUseServerProxy.ts +18 -0
- package/ai/chat/sseClient.native.ts +91 -0
- package/ai/chat/sseClient.ts +67 -0
- package/ai/chat/streamReader.native.ts +31 -0
- package/ai/chat/streamReader.ts +62 -0
- package/ai/chat/updateTotalUsage.ts +72 -0
- package/ai/context/buildReferenceContext.ts +437 -0
- package/ai/context/calculateContextUsage.ts +133 -0
- package/ai/context/retention.ts +165 -0
- package/ai/context/tokenUtils.ts +78 -0
- package/ai/index.ts +1 -1
- package/ai/llm/agentCapabilities.ts +74 -0
- package/ai/llm/calculateGeminiImageTokens.ts +57 -0
- package/ai/llm/deepinfra.ts +28 -0
- package/ai/llm/fireworks.ts +68 -0
- package/ai/llm/generateRequestBody.ts +165 -0
- package/ai/llm/getModelContextWindow.ts +84 -0
- package/ai/llm/getNoloKey.ts +37 -0
- package/ai/llm/getPricing.ts +232 -0
- package/ai/llm/hooks/useModelPricing.ts +75 -0
- package/ai/llm/imagePricing.ts +66 -0
- package/ai/llm/isResponseAPIModel.ts +13 -0
- package/ai/llm/kimi.ts +18 -0
- package/ai/llm/mimo.ts +71 -0
- package/ai/llm/mistral.ts +22 -0
- package/ai/llm/modelAvatar.ts +427 -0
- package/ai/llm/models.ts +45 -0
- package/ai/llm/openrouterModels.ts +141 -0
- package/ai/llm/providers.ts +307 -0
- package/ai/llm/reasoningModels.ts +28 -0
- package/ai/llm/types.ts +59 -0
- package/ai/llm/usageRequestOptions.ts +59 -0
- package/ai/memory/capture.ts +148 -0
- package/ai/memory/consolidate.ts +104 -0
- package/ai/memory/delete.ts +147 -0
- package/ai/memory/overlay.ts +84 -0
- package/ai/memory/query.ts +38 -0
- package/ai/memory/queryShared.ts +160 -0
- package/ai/memory/rank.ts +105 -0
- package/ai/memory/recentRelationshipRecap.ts +247 -0
- package/ai/memory/remember.ts +167 -0
- package/ai/memory/runtime.ts +76 -0
- package/ai/memory/store.ts +20 -0
- package/ai/memory/storeShared.ts +76 -0
- package/ai/memory/types.ts +46 -0
- package/ai/memory/understanding.ts +349 -0
- package/ai/memory/understandingGreeting.ts +264 -0
- package/ai/messages/type.ts +20 -0
- package/ai/policy/personalizationDialog.ts +333 -0
- package/ai/policy/runtimePolicy.ts +440 -0
- package/ai/policy/selfUpdateFields.ts +48 -0
- package/ai/policy/types.ts +64 -0
- package/ai/skills/referenceRuntime.ts +274 -0
- package/ai/skills/skillDiagnostics.ts +251 -0
- package/ai/skills/skillDocBuilder.ts +139 -0
- package/ai/skills/skillDocProtocol.ts +434 -0
- package/ai/skills/skillReferenceSummary.ts +63 -0
- package/ai/skills/skillSummaryMarker.ts +26 -0
- package/ai/token/calculatePrice.ts +546 -0
- package/ai/token/db.ts +98 -0
- package/ai/token/externalToolCost.ts +321 -0
- package/ai/token/hooks/useRecords.ts +65 -0
- package/ai/token/missingUsageEstimate.ts +42 -0
- package/ai/token/modelUsageQuery.ts +252 -0
- package/ai/token/normalizeUsage.ts +84 -0
- package/ai/token/openaiImageGenerationUsage.ts +56 -0
- package/ai/token/prepareTokenUsageData.ts +88 -0
- package/ai/token/query.ts +88 -0
- package/ai/token/queryUserTokens.ts +59 -0
- package/ai/token/resolveBillingTarget.ts +52 -0
- package/ai/token/saveTokenRecord.ts +53 -0
- package/ai/token/serverDialogProjection.ts +78 -0
- package/ai/token/serverTokenWriter.ts +143 -0
- package/ai/token/stats.ts +21 -0
- package/ai/token/tokenThunks.ts +24 -0
- package/ai/token/types.ts +93 -0
- package/ai/tools/agent/agentTools.ts +176 -0
- package/ai/tools/agent/agentUpdateShared.ts +311 -0
- package/ai/tools/agent/callAgentTool.ts +139 -0
- package/ai/tools/agent/createAgentTool.ts +512 -0
- package/ai/tools/agent/createDialogTool.ts +69 -0
- package/ai/tools/agent/createSkillAgentTool.ts +62 -0
- package/ai/tools/agent/parallelBudget.ts +221 -0
- package/ai/tools/agent/presets/appBuilderPreset.ts +147 -0
- package/ai/tools/agent/runLlmTool.ts +96 -0
- package/ai/tools/agent/runStreamingAgentTool.ts +73 -0
- package/ai/tools/agent/skillAgentArgs.ts +106 -0
- package/ai/tools/agent/skillAgentPreset.ts +89 -0
- package/ai/tools/agent/streamParallelAgentsTool.ts +122 -0
- package/ai/tools/agent/updateAgentTool.ts +96 -0
- package/ai/tools/agent/updateSelfTool.ts +113 -0
- package/ai/tools/amazonProductScraperTool.ts +86 -0
- package/ai/tools/apifyActorClient.ts +45 -0
- package/ai/tools/appEditGuard.ts +372 -0
- package/ai/tools/appReadSnapshot.ts +153 -0
- package/ai/tools/appTools.ts +1549 -0
- package/ai/tools/applyEditTool.ts +256 -0
- package/ai/tools/applyLineEditsTool.ts +312 -0
- package/ai/tools/browserTools/click.ts +33 -0
- package/ai/tools/browserTools/closeSession.ts +29 -0
- package/ai/tools/browserTools/common.ts +27 -0
- package/ai/tools/browserTools/openSession.ts +48 -0
- package/ai/tools/browserTools/readContent.ts +38 -0
- package/ai/tools/browserTools/selectOption.ts +46 -0
- package/ai/tools/browserTools/typeText.ts +42 -0
- package/ai/tools/category/createCategoryTool.ts +66 -0
- package/ai/tools/category/queryContentsByCategoryTool.ts +69 -0
- package/ai/tools/category/updateContentCategoryTool.ts +75 -0
- package/ai/tools/cfBrowserTools.ts +319 -0
- package/ai/tools/cfSpeechToTextTool.ts +49 -0
- package/ai/tools/checkEnvTool.ts +65 -0
- package/ai/tools/cloudflareCrawlTool.ts +289 -0
- package/ai/tools/codeSearchTool.ts +111 -0
- package/ai/tools/codeTools.ts +101 -0
- package/ai/tools/createDocTool.ts +132 -0
- package/ai/tools/createPlanTool.ts +999 -0
- package/ai/tools/createSkillDocTool.ts +155 -0
- package/ai/tools/createWorkflowTool.ts +154 -0
- package/ai/tools/deepseekOcrTool.ts +34 -0
- package/ai/tools/delayTool.ts +31 -0
- package/ai/tools/deleteSpacesTool.ts +325 -0
- package/ai/tools/deleteSpacesToolModel.ts +159 -0
- package/ai/tools/devReloadUtils.ts +29 -0
- package/ai/tools/dialogMessageSearch.ts +137 -0
- package/ai/tools/doctorSkillTool.ts +72 -0
- package/ai/tools/ecommerceScraperTool.ts +86 -0
- package/ai/tools/emailTools.ts +549 -0
- package/ai/tools/evalSkillTool.ts +92 -0
- package/ai/tools/exaSearchTool.ts +64 -0
- package/ai/tools/execBashTool.ts +379 -0
- package/ai/tools/executeSqlTool.ts +192 -0
- package/ai/tools/fetchWebpageSupport.ts +309 -0
- package/ai/tools/fetchWebpageTool.ts +84 -0
- package/ai/tools/geminiImagePreviewTool.ts +361 -0
- package/ai/tools/generateDocxTool.ts +215 -0
- package/ai/tools/googleSearchScraperTool.ts +106 -0
- package/ai/tools/importDataTool.ts +133 -0
- package/ai/tools/importSkillTool.ts +162 -0
- package/ai/tools/index.ts +1927 -0
- package/ai/tools/listFilesTool.ts +82 -0
- package/ai/tools/listUserSpacesTool.ts +113 -0
- package/ai/tools/modelUsageTools.ts +199 -0
- package/ai/tools/olmOcrTool.ts +34 -0
- package/ai/tools/openaiImageTool.ts +267 -0
- package/ai/tools/prepareTools.ts +23 -0
- package/ai/tools/readDocTool.ts +84 -0
- package/ai/tools/readFileTool.ts +211 -0
- package/ai/tools/readTool.ts +163 -0
- package/ai/tools/readXPostTool.ts +233 -0
- package/ai/tools/rememberMemoryTool.ts +84 -0
- package/ai/tools/remotionVideoTool.ts +151 -0
- package/ai/tools/searchDialogMessagesTool.ts +222 -0
- package/ai/tools/searchRepoTool.ts +115 -0
- package/ai/tools/searchWorkspaceTool.ts +259 -0
- package/ai/tools/skillFollowup.ts +86 -0
- package/ai/tools/surfWeatherTool.ts +169 -0
- package/ai/tools/table/addTableRowTool.ts +217 -0
- package/ai/tools/table/createTableTool.ts +315 -0
- package/ai/tools/table/rowTools.ts +366 -0
- package/ai/tools/table/schemaTools.ts +244 -0
- package/ai/tools/table/shareTableTool.ts +148 -0
- package/ai/tools/table/toolShared.ts +129 -0
- package/ai/tools/toolApiClient.ts +198 -0
- package/ai/tools/toolNameAliases.ts +57 -0
- package/ai/tools/toolResultError.ts +42 -0
- package/ai/tools/toolRunSlice.ts +303 -0
- package/ai/tools/toolSchemaCompatibility.ts +53 -0
- package/ai/tools/toolVisibility.ts +4 -0
- package/ai/tools/types.ts +20 -0
- package/ai/tools/uiAskChoiceTool.ts +104 -0
- package/ai/tools/updateContentTitleTool.ts +84 -0
- package/ai/tools/updateDocTool.ts +105 -0
- package/ai/tools/updateUserPreferenceProfileTool.ts +145 -0
- package/ai/tools/whisperTool.ts +77 -0
- package/ai/tools/writeFileTool.ts +210 -0
- package/ai/tools/youtubeScraperTool.ts +116 -0
- package/ai/tools/ziweiChartTool.ts +678 -0
- package/ai/types.ts +55 -0
- package/ai/workflow/workflowExecutor.ts +323 -0
- package/ai/workflow/workflowSlice.ts +73 -0
- package/ai/workflow/workflowTypes.ts +106 -0
- package/client/agentRun.test.ts +240 -0
- package/client/agentRun.ts +182 -19
- package/client/compactDialog.test.ts +238 -0
- package/client/localRuntimeAdapter.test.ts +135 -0
- package/client/localRuntimeAdapter.ts +244 -0
- package/client/profileConfig.test.ts +40 -0
- package/client/streamingOutput.test.ts +22 -0
- package/client/streamingOutput.ts +38 -0
- package/commandRegistry.ts +9 -2
- package/connector-experimental/index.ts +5 -0
- package/database/actions/cacheMergedUserData.ts +64 -0
- package/database/actions/common.ts +242 -0
- package/database/actions/deleteFile.ts +40 -0
- package/database/actions/fetchUserData.ts +16 -0
- package/database/actions/fileContent.ts +125 -0
- package/database/actions/patch.ts +155 -0
- package/database/actions/read.ts +337 -0
- package/database/actions/readAndWait.ts +224 -0
- package/database/actions/readRequestManager.ts +120 -0
- package/database/actions/remove.ts +94 -0
- package/database/actions/replication.ts +366 -0
- package/database/actions/upload.ts +174 -0
- package/database/actions/upsert.ts +56 -0
- package/database/actions/write.ts +126 -0
- package/database/client/db.native.ts +73 -0
- package/database/client/db.ts +51 -0
- package/database/client/fetchUserData.ts +61 -0
- package/database/client/handleError.ts +19 -0
- package/database/client/queryRequest.ts +21 -0
- package/database/config.ts +21 -0
- package/database/dbActionThunks.ts +1 -0
- package/database/dbSlice.ts +149 -0
- package/database/email.ts +42 -0
- package/database/fileRing.ts +51 -0
- package/database/fileSharding.ts +70 -0
- package/database/fileStorage.native.ts +92 -0
- package/database/fileStorage.ts +232 -0
- package/database/fileUrl.ts +34 -0
- package/database/hooks/useUserData.ts +489 -0
- package/database/index.ts +1 -0
- package/database/keys.ts +765 -0
- package/database/queryPrefixes.ts +14 -0
- package/database/requests.ts +443 -0
- package/database/runtimeServerContext.ts +35 -0
- package/database/server/MemoryDB.ts +76 -0
- package/database/server/actorAccess.ts +76 -0
- package/database/server/agentDelegation.ts +124 -0
- package/database/server/coreDataOwnership.ts +13 -0
- package/database/server/coreDataProxy.ts +76 -0
- package/database/server/cybotReadonly.ts +18 -0
- package/database/server/dataHandlers.ts +111 -0
- package/database/server/db.ts +118 -0
- package/database/server/dbPath.ts +20 -0
- package/database/server/delete.ts +499 -0
- package/database/server/emailRepository.ts +1480 -0
- package/database/server/ensureDbOpen.ts +12 -0
- package/database/server/fileRead.ts +337 -0
- package/database/server/fileService.ts +436 -0
- package/database/server/handleTransaction.ts +86 -0
- package/database/server/patch.ts +282 -0
- package/database/server/query.ts +138 -0
- package/database/server/read.ts +325 -0
- package/database/server/resourceAccess.ts +211 -0
- package/database/server/routes.ts +110 -0
- package/database/server/spaceMemberAuthority.ts +67 -0
- package/database/server/upload.ts +159 -0
- package/database/server/write.ts +494 -0
- package/database/server/writeAuthority.ts +133 -0
- package/database/sqliteDb.ts +46 -0
- package/database/table/deleteTable.ts +120 -0
- package/database/tenantPlacement.ts +57 -0
- package/database/tombstones.ts +52 -0
- package/database/userDataLoadDecision.ts +17 -0
- package/database/userDataMerge.ts +95 -0
- package/database/userPreferenceRegister.ts +108 -0
- package/database/utils/dbPath.ts +47 -0
- package/database/utils/ulid.native.ts +6 -0
- package/database/utils/ulid.ts +1 -0
- package/index.ts +25 -15
- package/localRuntimeDb.ts +28 -0
- package/package.json +16 -4
- package/runtimeModeArgs.ts +33 -0
- package/tui/readlineWorkspace.ts +1 -0
- package/tui/session.ts +22 -0
|
@@ -0,0 +1,499 @@
|
|
|
1
|
+
// 文件: database/server/delete.ts
|
|
2
|
+
|
|
3
|
+
import serverDb from "./db";
|
|
4
|
+
import { DataType } from "create/types";
|
|
5
|
+
import { deleteMessages } from "chat/messages/deleteMessages";
|
|
6
|
+
import { deleteTable } from "database/table/deleteTable";
|
|
7
|
+
import { isSystemAdmin, nolotusId } from "core/init";
|
|
8
|
+
import { authenticateRequest } from "auth/utils";
|
|
9
|
+
import { invalidatePublicAgentsCache } from "ai/agent/server/fetchPublicAgents";
|
|
10
|
+
import {
|
|
11
|
+
createFavoriteKey,
|
|
12
|
+
createFavoriteStatsKey,
|
|
13
|
+
isAgentKey,
|
|
14
|
+
shareKey,
|
|
15
|
+
} from "database/keys";
|
|
16
|
+
import { buildTombstoneRecord, isTombstoneRecord } from "database/tombstones";
|
|
17
|
+
import { canDeleteSpaceMemberRecord, parseSpaceMemberKey } from "./spaceMemberAuthority";
|
|
18
|
+
import {
|
|
19
|
+
bootstrapReplicatedTable,
|
|
20
|
+
findActiveLiveShareByTable,
|
|
21
|
+
isLiveTableShareRecord,
|
|
22
|
+
patchShareMeta,
|
|
23
|
+
replicateSharedTableMutation,
|
|
24
|
+
} from "../../share/server/tableReplication";
|
|
25
|
+
|
|
26
|
+
type DeleteRequest = Request & {
|
|
27
|
+
// 视你的路由库而定,这里假定有 params.id
|
|
28
|
+
params: {
|
|
29
|
+
id: string;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const CORS_HEADERS: Record<string, string> = {
|
|
34
|
+
"Access-Control-Allow-Origin": "*",
|
|
35
|
+
"Content-Type": "application/json",
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const normalizeOrigin = (value: unknown): string =>
|
|
39
|
+
typeof value === "string" && value.trim().length > 0
|
|
40
|
+
? value.trim().replace(/\/+$/, "")
|
|
41
|
+
: "";
|
|
42
|
+
|
|
43
|
+
const getRequestOrigin = (req: Request): string => {
|
|
44
|
+
try {
|
|
45
|
+
return normalizeOrigin(new URL(req.url).origin);
|
|
46
|
+
} catch {
|
|
47
|
+
return "";
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const getForwardHeaders = (req: any): Record<string, string> => {
|
|
52
|
+
const headers: Record<string, string> = {
|
|
53
|
+
"Content-Type": "application/json",
|
|
54
|
+
};
|
|
55
|
+
const authHeader =
|
|
56
|
+
typeof req?.headers?.authorization === "string"
|
|
57
|
+
? req.headers.authorization
|
|
58
|
+
: typeof req?.headers?.Authorization === "string"
|
|
59
|
+
? req.headers.Authorization
|
|
60
|
+
: "";
|
|
61
|
+
if (authHeader) {
|
|
62
|
+
headers.Authorization = authHeader;
|
|
63
|
+
}
|
|
64
|
+
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
|
+
})) {
|
|
73
|
+
if (
|
|
74
|
+
isLiveTableShareRecord(value, tableDbKey)
|
|
75
|
+
) {
|
|
76
|
+
shares.push({
|
|
77
|
+
...value,
|
|
78
|
+
dbKey,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return shares;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const propagateTableDeleteToReplicas = async (req: DeleteRequest, tableDbKey: string) => {
|
|
86
|
+
const currentOrigin = getRequestOrigin(req);
|
|
87
|
+
const shares = await findLiveTableSharesByDbKey(tableDbKey);
|
|
88
|
+
const forwardHeaders = getForwardHeaders(req);
|
|
89
|
+
|
|
90
|
+
for (const share of shares) {
|
|
91
|
+
const shareOrigin = normalizeOrigin(
|
|
92
|
+
share?.meta?.originServer ?? share?.data?.originServer
|
|
93
|
+
);
|
|
94
|
+
if (shareOrigin && shareOrigin !== currentOrigin) continue;
|
|
95
|
+
|
|
96
|
+
const replicaServers = Array.isArray(share?.meta?.replicaServers)
|
|
97
|
+
? share.meta.replicaServers
|
|
98
|
+
: [];
|
|
99
|
+
for (const server of replicaServers) {
|
|
100
|
+
const normalizedServer = normalizeOrigin(server);
|
|
101
|
+
if (!normalizedServer || normalizedServer === currentOrigin) continue;
|
|
102
|
+
const response = await fetch(
|
|
103
|
+
`${normalizedServer}/api/v1/db/delete/${encodeURIComponent(tableDbKey)}?type=table`,
|
|
104
|
+
{
|
|
105
|
+
method: "DELETE",
|
|
106
|
+
headers: forwardHeaders,
|
|
107
|
+
}
|
|
108
|
+
);
|
|
109
|
+
if (!response.ok) {
|
|
110
|
+
const detail = await response.text();
|
|
111
|
+
throw new Error(
|
|
112
|
+
detail || `Replica table delete failed on ${normalizedServer}: HTTP ${response.status}`
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* 判断当前请求用户是否是「系统账号」并且在操作公共 cybot 资源。
|
|
121
|
+
*
|
|
122
|
+
* 约定:
|
|
123
|
+
* - 公共 cybot 资源 key 形如:cybot-pub-{cybotId}
|
|
124
|
+
* - 系统账号 id 为 nolotusId(来自 core/init)
|
|
125
|
+
*/
|
|
126
|
+
const canSystemUserDeletePublicCybot = (
|
|
127
|
+
dbKey: string,
|
|
128
|
+
actionUserId?: string
|
|
129
|
+
): boolean => {
|
|
130
|
+
const PUBLIC_CYBOT_KEY_PREFIX = "cybot-pub-";
|
|
131
|
+
|
|
132
|
+
const isPublicCybotKey = dbKey.startsWith(PUBLIC_CYBOT_KEY_PREFIX);
|
|
133
|
+
const isSystemUser = actionUserId === nolotusId;
|
|
134
|
+
|
|
135
|
+
return isPublicCybotKey && isSystemUser;
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
const canSystemAdminDeleteCommunityShare = (
|
|
139
|
+
dbKey: string,
|
|
140
|
+
actionUserId: string | undefined,
|
|
141
|
+
data: any
|
|
142
|
+
): boolean => {
|
|
143
|
+
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 {
|
|
150
|
+
const authResult = await authenticateRequest(req);
|
|
151
|
+
const actionUserId = authResult instanceof Response ? undefined : authResult.userId;
|
|
152
|
+
|
|
153
|
+
const { id } = req.params;
|
|
154
|
+
const url = new URL(req.url);
|
|
155
|
+
const type = url.searchParams.get("type");
|
|
156
|
+
|
|
157
|
+
// 1. 删除消息的专用分支
|
|
158
|
+
if (type === "messages") {
|
|
159
|
+
try {
|
|
160
|
+
const result = await deleteMessages(serverDb, id);
|
|
161
|
+
return new Response(JSON.stringify(result), {
|
|
162
|
+
status: 200,
|
|
163
|
+
headers: CORS_HEADERS,
|
|
164
|
+
});
|
|
165
|
+
} catch (err: any) {
|
|
166
|
+
if (err.notFound) {
|
|
167
|
+
return new Response(JSON.stringify({ message: "Messages already deleted or dialog not found", processingIds: [] }), {
|
|
168
|
+
status: 200,
|
|
169
|
+
headers: CORS_HEADERS,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
throw err;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// 1.5 删除整张表(meta + 所有行 + 所有索引)的专用分支
|
|
177
|
+
if (type === "table") {
|
|
178
|
+
// 先拿 meta 数据做权限校验
|
|
179
|
+
let meta;
|
|
180
|
+
try {
|
|
181
|
+
meta = await serverDb.get(id);
|
|
182
|
+
} catch (err: any) {
|
|
183
|
+
if (err.notFound) {
|
|
184
|
+
return new Response(JSON.stringify({ message: "Table already deleted", processingIds: [] }), {
|
|
185
|
+
status: 200,
|
|
186
|
+
headers: CORS_HEADERS,
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
throw err;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const ownerId = meta?.userId as string | undefined;
|
|
193
|
+
const ownerMissing = ownerId == null;
|
|
194
|
+
const isOwner = actionUserId != null && ownerId === actionUserId;
|
|
195
|
+
|
|
196
|
+
// 表删除只按 owner 规则来判断
|
|
197
|
+
if (!ownerMissing && !isOwner) {
|
|
198
|
+
return new Response(
|
|
199
|
+
JSON.stringify({
|
|
200
|
+
error: "Unauthorized action: You do not own this table",
|
|
201
|
+
ownerId,
|
|
202
|
+
actionUserId,
|
|
203
|
+
processingIds: [],
|
|
204
|
+
}),
|
|
205
|
+
{
|
|
206
|
+
status: 403,
|
|
207
|
+
headers: CORS_HEADERS,
|
|
208
|
+
}
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
await propagateTableDeleteToReplicas(req, id);
|
|
213
|
+
|
|
214
|
+
// 真正执行整表删除
|
|
215
|
+
const { processingIds } = await deleteTable(serverDb, id);
|
|
216
|
+
|
|
217
|
+
return new Response(
|
|
218
|
+
JSON.stringify({
|
|
219
|
+
message: "Table delete request processed",
|
|
220
|
+
processingIds,
|
|
221
|
+
}),
|
|
222
|
+
{
|
|
223
|
+
status: 200,
|
|
224
|
+
headers: CORS_HEADERS,
|
|
225
|
+
}
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// 2. 删除通用数据(单 key 删除)
|
|
230
|
+
let data;
|
|
231
|
+
try {
|
|
232
|
+
data = await serverDb.get(id);
|
|
233
|
+
} catch (err: any) {
|
|
234
|
+
if (err.notFound) {
|
|
235
|
+
return new Response(
|
|
236
|
+
JSON.stringify({
|
|
237
|
+
message: "Success (Key not found, possibly already deleted)",
|
|
238
|
+
processingIds: [id],
|
|
239
|
+
}),
|
|
240
|
+
{
|
|
241
|
+
status: 200,
|
|
242
|
+
headers: CORS_HEADERS,
|
|
243
|
+
}
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
throw err;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const isShareRecord = shareKey.isShareKey(id);
|
|
250
|
+
const ownerId = (
|
|
251
|
+
data?.userId ??
|
|
252
|
+
(isShareRecord ? data?.meta?.authorId : undefined)
|
|
253
|
+
) as string | undefined;
|
|
254
|
+
const ownerMissing = ownerId == null && !isShareRecord;
|
|
255
|
+
const isOwner = actionUserId != null && ownerId === actionUserId;
|
|
256
|
+
const canSystemUserDeletePublicCybotResource =
|
|
257
|
+
canSystemUserDeletePublicCybot(id, actionUserId);
|
|
258
|
+
const canSystemAdminDeleteCommunityShareResource =
|
|
259
|
+
canSystemAdminDeleteCommunityShare(id, actionUserId, data);
|
|
260
|
+
const canDeleteSpaceMemberResource =
|
|
261
|
+
parseSpaceMemberKey(id) !== null &&
|
|
262
|
+
(await canDeleteSpaceMemberRecord({
|
|
263
|
+
dbKey: id,
|
|
264
|
+
actionUserId,
|
|
265
|
+
}));
|
|
266
|
+
const shouldInvalidatePublicAgents =
|
|
267
|
+
id.startsWith("agent-pub-") || id.startsWith("cybot-pub-");
|
|
268
|
+
|
|
269
|
+
if (
|
|
270
|
+
ownerMissing ||
|
|
271
|
+
isOwner ||
|
|
272
|
+
canDeleteSpaceMemberResource ||
|
|
273
|
+
canSystemUserDeletePublicCybotResource ||
|
|
274
|
+
canSystemAdminDeleteCommunityShareResource
|
|
275
|
+
) {
|
|
276
|
+
if (data) {
|
|
277
|
+
if (isTombstoneRecord(data)) {
|
|
278
|
+
return new Response(
|
|
279
|
+
JSON.stringify({
|
|
280
|
+
message: "Delete request processed",
|
|
281
|
+
processingIds: [id],
|
|
282
|
+
}),
|
|
283
|
+
{
|
|
284
|
+
status: 200,
|
|
285
|
+
headers: CORS_HEADERS,
|
|
286
|
+
}
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
|
|
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
|
+
}
|
|
300
|
+
|
|
301
|
+
if (
|
|
302
|
+
data?.type === DataType.TABLE_ROW &&
|
|
303
|
+
typeof data?.tenantId === "string" &&
|
|
304
|
+
typeof data?.tableId === "string"
|
|
305
|
+
) {
|
|
306
|
+
await replicateSharedTableMutation({
|
|
307
|
+
mutation: {
|
|
308
|
+
kind: "delete",
|
|
309
|
+
dbKey: id,
|
|
310
|
+
dataType: data.type,
|
|
311
|
+
tenantId: data.tenantId,
|
|
312
|
+
tableId: data.tableId,
|
|
313
|
+
},
|
|
314
|
+
originServer: getRequestOrigin(req),
|
|
315
|
+
replicaServers: [],
|
|
316
|
+
findActiveLiveShare: findActiveLiveShareByTable,
|
|
317
|
+
putMutationToReplica: async (server, mutation) => {
|
|
318
|
+
try {
|
|
319
|
+
const response = await fetch(
|
|
320
|
+
`${server}/api/v1/db/delete/${encodeURIComponent(mutation.dbKey)}`,
|
|
321
|
+
{
|
|
322
|
+
method: "DELETE",
|
|
323
|
+
headers: getForwardHeaders(req),
|
|
324
|
+
}
|
|
325
|
+
);
|
|
326
|
+
return {
|
|
327
|
+
ok: response.ok,
|
|
328
|
+
status: response.status,
|
|
329
|
+
detail: response.ok ? "" : await response.text(),
|
|
330
|
+
};
|
|
331
|
+
} catch (error: any) {
|
|
332
|
+
return {
|
|
333
|
+
ok: false,
|
|
334
|
+
detail: error?.message ?? "Replica row delete failed",
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
},
|
|
338
|
+
reconcileReplicaTable: async ({ shareDbKey, replicaServers }) => {
|
|
339
|
+
await bootstrapReplicatedTable({
|
|
340
|
+
shareDbKey,
|
|
341
|
+
shareRecord: {
|
|
342
|
+
dbKey: shareDbKey,
|
|
343
|
+
type: DataType.TABLE,
|
|
344
|
+
data: {
|
|
345
|
+
mode: "live",
|
|
346
|
+
tableDbKey: `meta-${data.tenantId}-${data.tableId}`,
|
|
347
|
+
},
|
|
348
|
+
meta: {
|
|
349
|
+
tableDbKey: `meta-${data.tenantId}-${data.tableId}`,
|
|
350
|
+
replicaServers,
|
|
351
|
+
},
|
|
352
|
+
},
|
|
353
|
+
tableDbKey: `meta-${data.tenantId}-${data.tableId}`,
|
|
354
|
+
tableOwnerId: data.tenantId,
|
|
355
|
+
originServer: getRequestOrigin(req),
|
|
356
|
+
replicaServers,
|
|
357
|
+
thunkApi: null,
|
|
358
|
+
putRecordToServer: async (server, dbKey, record) => {
|
|
359
|
+
try {
|
|
360
|
+
const response = await fetch(`${server}/api/v1/db/write/`, {
|
|
361
|
+
method: "POST",
|
|
362
|
+
headers: getForwardHeaders(req),
|
|
363
|
+
body: JSON.stringify({
|
|
364
|
+
data: record,
|
|
365
|
+
customKey: dbKey,
|
|
366
|
+
userId:
|
|
367
|
+
record?.userId ?? record?.tenantId ?? actionUserId,
|
|
368
|
+
}),
|
|
369
|
+
});
|
|
370
|
+
return {
|
|
371
|
+
ok: response.ok,
|
|
372
|
+
status: response.status,
|
|
373
|
+
detail: response.ok ? "" : await response.text(),
|
|
374
|
+
};
|
|
375
|
+
} catch (error: any) {
|
|
376
|
+
return {
|
|
377
|
+
ok: false,
|
|
378
|
+
detail: error?.message ?? "Replica reconcile request failed",
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
},
|
|
382
|
+
resetReplicaTable: async (server, tableDbKey) => {
|
|
383
|
+
try {
|
|
384
|
+
const response = await fetch(
|
|
385
|
+
`${server}/api/v1/db/delete/${encodeURIComponent(tableDbKey)}?type=table`,
|
|
386
|
+
{
|
|
387
|
+
method: "DELETE",
|
|
388
|
+
headers: getForwardHeaders(req),
|
|
389
|
+
}
|
|
390
|
+
);
|
|
391
|
+
return {
|
|
392
|
+
ok: response.ok,
|
|
393
|
+
status: response.status,
|
|
394
|
+
detail: response.ok ? "" : await response.text(),
|
|
395
|
+
};
|
|
396
|
+
} catch (error: any) {
|
|
397
|
+
return {
|
|
398
|
+
ok: false,
|
|
399
|
+
detail: error?.message ?? "Replica table reset failed",
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
},
|
|
403
|
+
patchShareMeta,
|
|
404
|
+
});
|
|
405
|
+
},
|
|
406
|
+
patchShareMeta,
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
if (shouldInvalidatePublicAgents) {
|
|
411
|
+
invalidatePublicAgentsCache();
|
|
412
|
+
}
|
|
413
|
+
|
|
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
|
+
})) {
|
|
423
|
+
if (!reverseKey.startsWith(start)) continue;
|
|
424
|
+
|
|
425
|
+
// reverseKey: fav-agent-key-by-agent-{agentKey}-{userId}
|
|
426
|
+
const userId = reverseKey.slice(start.length);
|
|
427
|
+
if (userId) {
|
|
428
|
+
const primaryKey = createFavoriteKey.agentByKey(userId, id);
|
|
429
|
+
batch.del(primaryKey);
|
|
430
|
+
batch.del(reverseKey);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// 清理收藏统计
|
|
435
|
+
batch.del(createFavoriteStatsKey.agentByKey(id));
|
|
436
|
+
|
|
437
|
+
await batch.write();
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// 如果被删除的是 Dialog,则级联清理该对话下的所有消息
|
|
441
|
+
// 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
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
return new Response(
|
|
453
|
+
JSON.stringify({
|
|
454
|
+
message: "Delete request processed",
|
|
455
|
+
processingIds: [id],
|
|
456
|
+
}),
|
|
457
|
+
{
|
|
458
|
+
status: 200,
|
|
459
|
+
headers: CORS_HEADERS,
|
|
460
|
+
}
|
|
461
|
+
);
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// 3. 无权限
|
|
465
|
+
const forbiddenReason = !actionUserId
|
|
466
|
+
? "Missing or invalid auth token (or public key not found on this server)"
|
|
467
|
+
: `User ${actionUserId} does not match owner ${ownerId}`;
|
|
468
|
+
|
|
469
|
+
console.warn(`[Delete 403] ${forbiddenReason} for key: ${id}`);
|
|
470
|
+
|
|
471
|
+
return new Response(
|
|
472
|
+
JSON.stringify({
|
|
473
|
+
error: "Unauthorized action",
|
|
474
|
+
message: forbiddenReason,
|
|
475
|
+
ownerId,
|
|
476
|
+
actionUserId,
|
|
477
|
+
processingIds: [],
|
|
478
|
+
}),
|
|
479
|
+
{
|
|
480
|
+
status: 403,
|
|
481
|
+
headers: CORS_HEADERS,
|
|
482
|
+
}
|
|
483
|
+
);
|
|
484
|
+
} catch (error) {
|
|
485
|
+
console.error("Delete handler error:", error);
|
|
486
|
+
|
|
487
|
+
return new Response(
|
|
488
|
+
JSON.stringify({
|
|
489
|
+
error: "Internal server error",
|
|
490
|
+
message: error instanceof Error ? error.message : String(error),
|
|
491
|
+
processingIds: [],
|
|
492
|
+
}),
|
|
493
|
+
{
|
|
494
|
+
status: 500,
|
|
495
|
+
headers: CORS_HEADERS,
|
|
496
|
+
}
|
|
497
|
+
);
|
|
498
|
+
}
|
|
499
|
+
};
|