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