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
package/auth/server/token.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
// auth/handleToken.js
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import serverDb from "../../database/server/db";
|
|
2
|
+
import { getServerAuthorityStore } from "../../database/server/db";
|
|
3
|
+
import { authenticateToken } from "../../server/authenticateToken";
|
|
5
4
|
import { balanceLockManager } from "./locks";
|
|
6
5
|
import { recordUserAccessActivity } from "./accessActivity";
|
|
7
6
|
|
|
@@ -15,21 +14,14 @@ const getUserActivityUpdateIntervalMs = () => {
|
|
|
15
14
|
: 5 * 60 * 1000;
|
|
16
15
|
};
|
|
17
16
|
|
|
18
|
-
const getPublicKey = async (userId) => {
|
|
19
|
-
try {
|
|
20
|
-
const user = await serverDb.get(`user:${userId}`);
|
|
21
|
-
if (user?.publicKey) return user.publicKey;
|
|
22
|
-
} catch { }
|
|
23
|
-
return null;
|
|
24
|
-
};
|
|
25
|
-
|
|
26
17
|
const updateUserLastActiveAt = async (userId, metadata?: { ip?: string | null; userAgent?: string | null }) => {
|
|
18
|
+
const store = getServerAuthorityStore();
|
|
27
19
|
const key = `user:${userId}`;
|
|
28
20
|
const lock = balanceLockManager.getLock(userId);
|
|
29
21
|
let shouldRecord = false;
|
|
30
22
|
try {
|
|
31
23
|
await lock.runExclusive(async () => {
|
|
32
|
-
const user = await
|
|
24
|
+
const user = await store.get(key);
|
|
33
25
|
if (!user) return;
|
|
34
26
|
|
|
35
27
|
const now = Date.now();
|
|
@@ -57,53 +49,59 @@ const updateUserLastActiveAt = async (userId, metadata?: { ip?: string | null; u
|
|
|
57
49
|
}
|
|
58
50
|
};
|
|
59
51
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
// 两套逻辑不一致,待 token.ts 的 exp 检查统一修复后可删除此函数
|
|
63
|
-
const isTokenExpired = ({ exp, nbf }) => {
|
|
64
|
-
const now = Date.now();
|
|
65
|
-
return (exp && now > exp * 1000) || (nbf && now < nbf * 1000);
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
export async function handleToken(req, res) {
|
|
69
|
-
const token = req.headers.get("authorization")?.split(" ")[1];
|
|
70
|
-
const requestIp =
|
|
71
|
-
req.headers.get("x-nolo-client-ip")?.trim() ||
|
|
72
|
-
req.headers.get("x-forwarded-for")?.split(",")[0]?.trim() ||
|
|
73
|
-
req.headers.get("x-real-ip") ||
|
|
74
|
-
"";
|
|
75
|
-
const userAgent = req.headers.get("user-agent") || "";
|
|
76
|
-
if (!token) return handleError(res, new Error("Access denied. No token provided."), 401);
|
|
77
|
-
|
|
78
|
-
try {
|
|
79
|
-
// parseToken 使用 js-base64,正确处理中文用户名的 UTF-8 编码
|
|
80
|
-
// 原 atob 方案在中文用户名时会产生乱码,导致 userId 错误、publicKey 查找失败
|
|
81
|
-
const parsed = parseToken(token);
|
|
82
|
-
if (!parsed?.userId) return handleError(res, new Error("Invalid token format"), 401);
|
|
83
|
-
const { userId } = parsed;
|
|
84
|
-
const publicKey = await getPublicKey(userId);
|
|
85
|
-
|
|
86
|
-
if (!publicKey) return handleError(res, new Error("Public key not found"), 401);
|
|
52
|
+
const readBearerToken = (headers: { get(name: string): string | null | undefined }) =>
|
|
53
|
+
headers.get("authorization")?.split(" ")[1];
|
|
87
54
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
55
|
+
const readRequestMetadata = (headers: { get(name: string): string | null | undefined }) => ({
|
|
56
|
+
ip:
|
|
57
|
+
headers.get("x-nolo-client-ip")?.trim() ||
|
|
58
|
+
headers.get("x-forwarded-for")?.split(",")[0]?.trim() ||
|
|
59
|
+
headers.get("x-real-ip") ||
|
|
60
|
+
"",
|
|
61
|
+
userAgent: headers.get("user-agent") || "",
|
|
62
|
+
});
|
|
92
63
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
// 所以下面这行是死代码,永远不会执行
|
|
97
|
-
if (!payload) return handleError(res, new Error("Invalid token"), 401);
|
|
64
|
+
type TokenAuthResult =
|
|
65
|
+
| { ok: true; payload: any }
|
|
66
|
+
| { ok: false; error: Error; status: number };
|
|
98
67
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
68
|
+
async function authenticateRequestHeaders(
|
|
69
|
+
headers: { get(name: string): string | null | undefined }
|
|
70
|
+
): Promise<TokenAuthResult> {
|
|
71
|
+
const token = readBearerToken(headers);
|
|
72
|
+
if (!token) {
|
|
73
|
+
return {
|
|
74
|
+
ok: false,
|
|
75
|
+
error: new Error("Access denied. No token provided."),
|
|
76
|
+
status: 401,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
102
79
|
|
|
103
|
-
|
|
80
|
+
try {
|
|
81
|
+
const { userId, payload } = await authenticateToken(token);
|
|
82
|
+
const { ip, userAgent } = readRequestMetadata(headers);
|
|
83
|
+
await updateUserLastActiveAt(userId, { ip, userAgent });
|
|
84
|
+
return { ok: true, payload };
|
|
85
|
+
} catch (error: any) {
|
|
86
|
+
return {
|
|
87
|
+
ok: false,
|
|
88
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
89
|
+
status: 401,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
}
|
|
104
93
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
94
|
+
export async function handleToken(req, res) {
|
|
95
|
+
const result = await authenticateRequestHeaders(req.headers);
|
|
96
|
+
if (!result.ok) {
|
|
97
|
+
return handleError(res, result.error, result.status);
|
|
108
98
|
}
|
|
99
|
+
return result.payload;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export async function readUserFromRequest(
|
|
103
|
+
req: Pick<Request, "headers"> | { headers: { get(name: string): string | null | undefined } }
|
|
104
|
+
) {
|
|
105
|
+
const result = await authenticateRequestHeaders(req.headers);
|
|
106
|
+
return result.ok ? result.payload : null;
|
|
109
107
|
}
|
|
@@ -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 {
|
|
@@ -49,6 +50,14 @@ export type TokenUsageChargeResult =
|
|
|
49
50
|
balance?: number;
|
|
50
51
|
};
|
|
51
52
|
|
|
53
|
+
const createTokenUsageBillingStore = (authorityStore = getServerAuthorityStore()): TokenUsageBillingStore => ({
|
|
54
|
+
get: (key) => authorityStore.get(key),
|
|
55
|
+
batch: (ops) => writeStoreOps(authorityStore, ops),
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
const getDefaultTokenUsageBillingStore = (): TokenUsageBillingStore =>
|
|
59
|
+
createTokenUsageBillingStore(getServerAuthorityStore());
|
|
60
|
+
|
|
52
61
|
const getMaybe = async <T>(
|
|
53
62
|
store: TokenUsageBillingStore,
|
|
54
63
|
key: string
|
|
@@ -64,13 +73,15 @@ const isPositiveFinite = (value: unknown): value is number =>
|
|
|
64
73
|
typeof value === "number" && Number.isFinite(value) && value > 0;
|
|
65
74
|
|
|
66
75
|
export async function chargeTokenUsageWithLedger({
|
|
67
|
-
store =
|
|
76
|
+
store = getDefaultTokenUsageBillingStore(),
|
|
68
77
|
runtime = getBillingLedgerRuntime(),
|
|
69
78
|
userId,
|
|
70
79
|
tokenKey,
|
|
71
80
|
tokenRecord,
|
|
72
81
|
reason = "token_usage",
|
|
73
82
|
txId = `token-${tokenKey}`,
|
|
83
|
+
ledgerIdempotencyKey = `token:${tokenKey}`,
|
|
84
|
+
allowBuyerNegative = true,
|
|
74
85
|
nowMs = Date.now(),
|
|
75
86
|
}: {
|
|
76
87
|
store?: TokenUsageBillingStore;
|
|
@@ -80,6 +91,8 @@ export async function chargeTokenUsageWithLedger({
|
|
|
80
91
|
tokenRecord: TokenRevenueShareRecord;
|
|
81
92
|
reason?: string;
|
|
82
93
|
txId?: string;
|
|
94
|
+
ledgerIdempotencyKey?: string;
|
|
95
|
+
allowBuyerNegative?: boolean;
|
|
83
96
|
nowMs?: number;
|
|
84
97
|
}): Promise<TokenUsageChargeResult> {
|
|
85
98
|
const lock = balanceLockManager.getLock(`token-usage:${userId}:${tokenKey}`);
|
|
@@ -159,7 +172,7 @@ export async function chargeTokenUsageWithLedger({
|
|
|
159
172
|
runtime,
|
|
160
173
|
type: "usage_charge",
|
|
161
174
|
reason,
|
|
162
|
-
idempotencyKey:
|
|
175
|
+
idempotencyKey: ledgerIdempotencyKey,
|
|
163
176
|
txId,
|
|
164
177
|
entries: [
|
|
165
178
|
{
|
|
@@ -167,6 +180,7 @@ export async function chargeTokenUsageWithLedger({
|
|
|
167
180
|
ownerUserId: userId,
|
|
168
181
|
delta: -event.grossCredits,
|
|
169
182
|
startingBalance: userData.balance,
|
|
183
|
+
allowNegative: allowBuyerNegative,
|
|
170
184
|
metadata: {
|
|
171
185
|
role: "buyer_debit",
|
|
172
186
|
tokenKey,
|
|
@@ -217,10 +231,7 @@ export async function chargeTokenUsageWithLedger({
|
|
|
217
231
|
amountCredits: event.grossCredits,
|
|
218
232
|
};
|
|
219
233
|
}
|
|
220
|
-
if (
|
|
221
|
-
ledgerAppend.status === "insufficient_funds" ||
|
|
222
|
-
userData.balance < event.grossCredits
|
|
223
|
-
) {
|
|
234
|
+
if (ledgerAppend.status === "insufficient_funds") {
|
|
224
235
|
return {
|
|
225
236
|
success: false,
|
|
226
237
|
status: "insufficient_funds",
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { isSystemAdmin } from "../../core/init";
|
|
2
|
+
import { DB_PREFIX } from "../../database/keys";
|
|
3
|
+
import { getServerAuthorityStore } from "../../database/server/db";
|
|
4
|
+
import {
|
|
5
|
+
hasUsageManagementPermission,
|
|
6
|
+
mergeAdminPermissions,
|
|
7
|
+
type AdminPermissions,
|
|
8
|
+
} from "../adminPermissions";
|
|
9
|
+
|
|
10
|
+
type UserStore = {
|
|
11
|
+
get(key: string): Promise<any>;
|
|
12
|
+
put(key: string, value: any): Promise<void>;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const userKey = (userId: string) => `${DB_PREFIX.USER}${userId}`;
|
|
16
|
+
|
|
17
|
+
export async function canManageUsageReportAccess(
|
|
18
|
+
userId?: string | null,
|
|
19
|
+
store: Pick<UserStore, "get"> = getServerAuthorityStore()
|
|
20
|
+
): Promise<boolean> {
|
|
21
|
+
if (!userId) return false;
|
|
22
|
+
if (isSystemAdmin(userId)) return true;
|
|
23
|
+
const userData = await store.get(userKey(userId)).catch(() => null);
|
|
24
|
+
return hasUsageManagementPermission(userData);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export async function updateUserAdminPermissions(
|
|
28
|
+
targetUserId: string,
|
|
29
|
+
patch: Partial<AdminPermissions>,
|
|
30
|
+
store: UserStore = getServerAuthorityStore()
|
|
31
|
+
) {
|
|
32
|
+
const key = userKey(targetUserId);
|
|
33
|
+
const userData = await store.get(key).catch(() => null);
|
|
34
|
+
if (!userData) return null;
|
|
35
|
+
const adminPermissions = mergeAdminPermissions(userData.adminPermissions, patch);
|
|
36
|
+
const updatedUser = {
|
|
37
|
+
...userData,
|
|
38
|
+
adminPermissions,
|
|
39
|
+
adminPermissionsUpdatedAt: Date.now(),
|
|
40
|
+
};
|
|
41
|
+
await store.put(key, updatedUser);
|
|
42
|
+
return updatedUser;
|
|
43
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { getServerAuthorityStore } from "../../database/server/db";
|
|
2
|
+
import { buildBillingUsageReport } from "./billingUsageReport";
|
|
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)) return Number(trimmed);
|
|
15
|
+
const parsed = Date.parse(trimmed);
|
|
16
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const parseSinceDays = (value: string | null) => {
|
|
20
|
+
if (!value) return 7;
|
|
21
|
+
const parsed = Number(value);
|
|
22
|
+
if (!Number.isFinite(parsed) || parsed <= 0) return 7;
|
|
23
|
+
return Math.min(parsed, 3660);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export async function handleGetUsageReport(req: Request) {
|
|
27
|
+
if (req.method === "OPTIONS") {
|
|
28
|
+
return handleOptionsRequest();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const { userId: actionUserId } = req.user;
|
|
32
|
+
if (!(await canManageUsageReportAccess(actionUserId))) {
|
|
33
|
+
return createErrorResponse("Unauthorized: Usage management access required", 403);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
const url = new URL(req.url);
|
|
38
|
+
const now = Date.now();
|
|
39
|
+
const untilMs = parseTimestamp(url.searchParams.get("until")) ?? now;
|
|
40
|
+
const sinceMs =
|
|
41
|
+
parseTimestamp(url.searchParams.get("since")) ??
|
|
42
|
+
untilMs - parseSinceDays(url.searchParams.get("sinceDays")) * 24 * 3600_000;
|
|
43
|
+
|
|
44
|
+
if (sinceMs > untilMs) {
|
|
45
|
+
return createErrorResponse("Invalid time range", 400);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const report = await buildBillingUsageReport({
|
|
49
|
+
store: getServerAuthorityStore(),
|
|
50
|
+
sinceMs,
|
|
51
|
+
untilMs,
|
|
52
|
+
nowMs: now,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
return createSuccessResponse({ success: true, report });
|
|
56
|
+
} catch {
|
|
57
|
+
return createErrorResponse("Internal server error");
|
|
58
|
+
}
|
|
59
|
+
}
|
package/auth/types.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// auth/types.ts
|
|
2
|
+
import type { AdminPermissions } from "./adminPermissions";
|
|
2
3
|
|
|
3
4
|
export interface User {
|
|
4
5
|
userId: string;
|
|
@@ -10,6 +11,17 @@ export interface User {
|
|
|
10
11
|
locale?: string;
|
|
11
12
|
publicKey?: string;
|
|
12
13
|
tokenVersion?: number;
|
|
14
|
+
balance?: number;
|
|
15
|
+
gptProAccess?: {
|
|
16
|
+
status?: string;
|
|
17
|
+
requiredRechargeAmount?: number;
|
|
18
|
+
rechargeAmount?: number;
|
|
19
|
+
source?: string;
|
|
20
|
+
sourceTxId?: string;
|
|
21
|
+
grantedAt?: number;
|
|
22
|
+
updatedAt?: number;
|
|
23
|
+
};
|
|
24
|
+
adminPermissions?: AdminPermissions;
|
|
13
25
|
}
|
|
14
26
|
export interface TokenManager {
|
|
15
27
|
getTokens(): Promise<string[]>;
|
package/auth/utils.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// path auth/utils.ts
|
|
2
|
-
import { parseToken, verifyToken } from ".//token";
|
|
3
|
-
import { assertSessionTokenVersion } from ".//sessionTokenVersion";
|
|
4
|
-
import
|
|
5
|
-
import { WEB_AUTH_TOKEN_COOKIE } from "./tokenCookie";
|
|
2
|
+
import { parseToken, verifyToken } from ".//token";
|
|
3
|
+
import { assertSessionTokenVersion } from ".//sessionTokenVersion";
|
|
4
|
+
import { getServerAuthorityStore } from "../database/server/db";
|
|
5
|
+
import { WEB_AUTH_TOKEN_COOKIE } from "./tokenCookie";
|
|
6
6
|
|
|
7
7
|
export const CORS_HEADERS_AUTH = {
|
|
8
8
|
"Access-Control-Allow-Origin": "*",
|
|
@@ -11,22 +11,24 @@ export const CORS_HEADERS_AUTH = {
|
|
|
11
11
|
"Access-Control-Max-Age": "86400",
|
|
12
12
|
};
|
|
13
13
|
|
|
14
|
-
export const authErrorResponse = (
|
|
15
|
-
msg: string,
|
|
16
|
-
code: string,
|
|
14
|
+
export const authErrorResponse = (
|
|
15
|
+
msg: string,
|
|
16
|
+
code: string,
|
|
17
17
|
status: number = 500
|
|
18
18
|
): Response =>
|
|
19
19
|
new Response(JSON.stringify({ error: { message: msg, code } }), {
|
|
20
20
|
status,
|
|
21
21
|
headers: { "Content-Type": "application/json", ...CORS_HEADERS_AUTH },
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const getAuthUtilsStore = () => getServerAuthorityStore();
|
|
25
|
+
|
|
26
|
+
const getPublicKey = async (userId: string) => {
|
|
27
|
+
try {
|
|
28
|
+
const u = await getAuthUtilsStore().get(`user:${userId}`);
|
|
29
|
+
if (!u?.publicKey || u.balance <= 0 || u.isDisabled) {
|
|
30
|
+
return { publicKey: null, isValid: false };
|
|
31
|
+
}
|
|
30
32
|
return { publicKey: u.publicKey, isValid: true };
|
|
31
33
|
} catch (e) {
|
|
32
34
|
return { publicKey: null, isValid: false };
|
|
@@ -66,13 +68,13 @@ export const authenticateRequest = async (
|
|
|
66
68
|
);
|
|
67
69
|
}
|
|
68
70
|
|
|
69
|
-
const { publicKey, isValid } = await getPublicKey(userIdFromTokenHeader);
|
|
70
|
-
if (!isValid || !publicKey) {
|
|
71
|
-
return authErrorResponse("Invalid account.", "AUTH_ACCOUNT_INVALID", 401);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const user = await
|
|
75
|
-
const decodedTokenData = verifyToken(token, publicKey);
|
|
71
|
+
const { publicKey, isValid } = await getPublicKey(userIdFromTokenHeader);
|
|
72
|
+
if (!isValid || !publicKey) {
|
|
73
|
+
return authErrorResponse("Invalid account.", "AUTH_ACCOUNT_INVALID", 401);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const user = await getAuthUtilsStore().get(`user:${userIdFromTokenHeader}`);
|
|
77
|
+
const decodedTokenData = verifyToken(token, publicKey);
|
|
76
78
|
assertSessionTokenVersion(decodedTokenData, user);
|
|
77
79
|
if (!decodedTokenData) {
|
|
78
80
|
return authErrorResponse(
|
package/authCommands.ts
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
loadProfileConfig,
|
|
10
10
|
saveDefaultProfile,
|
|
11
11
|
} from "./client/profileConfig";
|
|
12
|
+
import { parseUserIdFromAuthToken } from "./cliEnvHelpers";
|
|
12
13
|
import { DEFAULT_NOLO_SERVER_URL } from "./defaultServer";
|
|
13
14
|
|
|
14
15
|
function getArg(args: string[], flag: string) {
|
|
@@ -67,17 +68,47 @@ async function saveTokenLogin(args: {
|
|
|
67
68
|
configPath: string;
|
|
68
69
|
serverUrl: string;
|
|
69
70
|
authToken: string;
|
|
71
|
+
fetchImpl: typeof fetch;
|
|
70
72
|
output: Pick<Console, "log">;
|
|
71
73
|
error: Pick<Console, "error">;
|
|
72
74
|
}) {
|
|
73
|
-
|
|
75
|
+
const authToken = args.authToken.trim();
|
|
76
|
+
if (!authToken) {
|
|
74
77
|
args.error.error("No auth token provided.");
|
|
75
78
|
return 1;
|
|
76
79
|
}
|
|
77
80
|
|
|
81
|
+
const userId = parseUserIdFromAuthToken(authToken);
|
|
82
|
+
if (!userId) {
|
|
83
|
+
args.error.error("Auth token payload is missing userId.");
|
|
84
|
+
return 1;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
const res = await args.fetchImpl(
|
|
89
|
+
`${args.serverUrl}/api/v1/db/query/${encodeURIComponent(userId)}?limit=1`,
|
|
90
|
+
{
|
|
91
|
+
method: "POST",
|
|
92
|
+
headers: {
|
|
93
|
+
Authorization: `Bearer ${authToken}`,
|
|
94
|
+
"Content-Type": "application/json",
|
|
95
|
+
},
|
|
96
|
+
body: JSON.stringify({ type: "agent" }),
|
|
97
|
+
}
|
|
98
|
+
);
|
|
99
|
+
if (res.status === 401 || res.status === 403) {
|
|
100
|
+
args.error.error(
|
|
101
|
+
`Auth token is not valid for ${args.serverUrl}. Log in against the matching server or use a token issued by that server.`
|
|
102
|
+
);
|
|
103
|
+
return 1;
|
|
104
|
+
}
|
|
105
|
+
} catch {
|
|
106
|
+
// Allow saving when the server is temporarily unreachable.
|
|
107
|
+
}
|
|
108
|
+
|
|
78
109
|
saveDefaultProfile(args.configPath, {
|
|
79
110
|
serverUrl: args.serverUrl,
|
|
80
|
-
authToken
|
|
111
|
+
authToken,
|
|
81
112
|
});
|
|
82
113
|
args.output.log(`Saved profile default -> ${args.serverUrl}`);
|
|
83
114
|
return 0;
|
|
@@ -144,6 +175,7 @@ async function runWebLogin(args: {
|
|
|
144
175
|
configPath: args.configPath,
|
|
145
176
|
serverUrl: approvedServer,
|
|
146
177
|
authToken: poll.token,
|
|
178
|
+
fetchImpl: args.fetchImpl,
|
|
147
179
|
output: args.output,
|
|
148
180
|
error: args.error,
|
|
149
181
|
});
|
|
@@ -173,6 +205,7 @@ export async function runLoginCommand(args: string[], deps: LoginCommandDeps = {
|
|
|
173
205
|
configPath,
|
|
174
206
|
serverUrl,
|
|
175
207
|
authToken: tokenArg,
|
|
208
|
+
fetchImpl: deps.fetchImpl ?? fetch,
|
|
176
209
|
output: outputTarget,
|
|
177
210
|
error: errorTarget,
|
|
178
211
|
});
|
|
@@ -187,6 +220,7 @@ export async function runLoginCommand(args: string[], deps: LoginCommandDeps = {
|
|
|
187
220
|
configPath,
|
|
188
221
|
serverUrl,
|
|
189
222
|
authToken,
|
|
223
|
+
fetchImpl: deps.fetchImpl ?? fetch,
|
|
190
224
|
output: outputTarget,
|
|
191
225
|
error: errorTarget,
|
|
192
226
|
});
|
package/buildPublish.ts
CHANGED
|
@@ -73,10 +73,12 @@ export async function buildPublishArtifact(
|
|
|
73
73
|
);
|
|
74
74
|
|
|
75
75
|
if (inlinedDeps.length > 0) {
|
|
76
|
-
publishManifest.files =
|
|
76
|
+
publishManifest.files = Array.from(new Set(resolvedFilesToCopy));
|
|
77
77
|
for (const dep of inlinedDeps) {
|
|
78
78
|
publishManifest.files.push(`${dep}/**/*.ts`);
|
|
79
79
|
}
|
|
80
|
+
} else {
|
|
81
|
+
publishManifest.files = Array.from(new Set(resolvedFilesToCopy));
|
|
80
82
|
}
|
|
81
83
|
|
|
82
84
|
if (Object.keys(externalDeps).length > 0) {
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
import { dirname, join, relative } from "node:path";
|
|
12
12
|
import {
|
|
13
13
|
collectTypeScriptSourceFiles,
|
|
14
|
+
extractLocalRelativeImports,
|
|
14
15
|
findTypeScriptFiles,
|
|
15
16
|
} from "./buildPublishImportAnalysis";
|
|
16
17
|
|
|
@@ -71,7 +72,10 @@ export async function buildPublishArtifactAssembly(
|
|
|
71
72
|
rmSync(distDir, { recursive: true, force: true });
|
|
72
73
|
mkdirSync(distDir, { recursive: true });
|
|
73
74
|
|
|
74
|
-
const resolvedFilesToCopy =
|
|
75
|
+
const resolvedFilesToCopy = expandLocalFileDependencies(
|
|
76
|
+
sourceDir,
|
|
77
|
+
resolveFilesToCopy(sourceDir, filesToCopy)
|
|
78
|
+
);
|
|
75
79
|
const workspaceDeps = collectWorkspaceDependencies(sourceDir, resolvedFilesToCopy);
|
|
76
80
|
|
|
77
81
|
for (const file of resolvedFilesToCopy) {
|
|
@@ -288,6 +292,63 @@ async function discoverExternalImportsFromInlinedFiles(
|
|
|
288
292
|
|
|
289
293
|
export { collectTypeScriptSourceFiles, findTypeScriptFiles };
|
|
290
294
|
|
|
295
|
+
export function expandLocalFileDependencies(sourceDir: string, filesToCopy: string[]): string[] {
|
|
296
|
+
const resolved = new Set(filesToCopy);
|
|
297
|
+
const pending = filesToCopy.filter((file) => file.endsWith(".ts"));
|
|
298
|
+
|
|
299
|
+
while (pending.length > 0) {
|
|
300
|
+
const relativeFilePath = pending.pop()!;
|
|
301
|
+
const absoluteFilePath = join(sourceDir, relativeFilePath);
|
|
302
|
+
if (!existsSync(absoluteFilePath)) {
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const content = readFileSync(absoluteFilePath, "utf8");
|
|
307
|
+
for (const importPath of extractLocalRelativeImports(content)) {
|
|
308
|
+
const discoveredPath = resolveLocalImportPath(sourceDir, relativeFilePath, importPath);
|
|
309
|
+
if (!discoveredPath || resolved.has(discoveredPath)) {
|
|
310
|
+
continue;
|
|
311
|
+
}
|
|
312
|
+
resolved.add(discoveredPath);
|
|
313
|
+
if (discoveredPath.endsWith(".ts")) {
|
|
314
|
+
pending.push(discoveredPath);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
return Array.from(resolved);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function resolveLocalImportPath(
|
|
323
|
+
sourceDir: string,
|
|
324
|
+
relativeFilePath: string,
|
|
325
|
+
importPath: string
|
|
326
|
+
): string | null {
|
|
327
|
+
const fileDir = dirname(join(sourceDir, relativeFilePath));
|
|
328
|
+
const importBase = join(fileDir, importPath);
|
|
329
|
+
const candidates = [
|
|
330
|
+
importBase,
|
|
331
|
+
`${importBase}.ts`,
|
|
332
|
+
`${importBase}.tsx`,
|
|
333
|
+
join(importBase, "index.ts"),
|
|
334
|
+
join(importBase, "index.tsx"),
|
|
335
|
+
`${importBase}.json`,
|
|
336
|
+
];
|
|
337
|
+
|
|
338
|
+
for (const candidate of candidates) {
|
|
339
|
+
if (!existsSync(candidate)) {
|
|
340
|
+
continue;
|
|
341
|
+
}
|
|
342
|
+
const stat = statSync(candidate);
|
|
343
|
+
if (!stat.isFile()) {
|
|
344
|
+
continue;
|
|
345
|
+
}
|
|
346
|
+
return relative(sourceDir, candidate).replace(/\\/g, "/");
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
return null;
|
|
350
|
+
}
|
|
351
|
+
|
|
291
352
|
export function resolveFilesToCopy(sourceDir: string, filesToCopy: string[]): string[] {
|
|
292
353
|
const resolved = new Set<string>();
|
|
293
354
|
|
|
@@ -11,27 +11,27 @@ function extractPackageNameFromImportPath(importPath: string): string {
|
|
|
11
11
|
return firstSlash === -1 ? importPath : importPath.slice(0, firstSlash);
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
/import\s+(?:(?:type\s+)?(?:\{[^}]*\}|\*\s+as\s+\w+|\w+)\s+from\s+)?['"]([^'"]+)['"]/g;
|
|
14
|
+
function extractModuleSpecifiers(content: string): string[] {
|
|
15
|
+
const specifiers = new Set<string>();
|
|
16
|
+
const importOrExportRegex =
|
|
17
|
+
/(?:import|export)\s+(?:(?:type\s+)?(?:\{[^}]*\}|\*\s+as\s+\w+|\w+)\s+from\s+)?['"]([^'"]+)['"]/g;
|
|
18
18
|
const dynamicImportRegex = /import\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
19
19
|
|
|
20
20
|
let match: RegExpExecArray | null;
|
|
21
|
-
while ((match =
|
|
22
|
-
|
|
23
|
-
if (
|
|
24
|
-
importPath.startsWith(".") ||
|
|
25
|
-
importPath.startsWith("node:") ||
|
|
26
|
-
importPath.startsWith("/")
|
|
27
|
-
) {
|
|
28
|
-
continue;
|
|
29
|
-
}
|
|
30
|
-
imports.add(extractPackageNameFromImportPath(importPath));
|
|
21
|
+
while ((match = importOrExportRegex.exec(content)) !== null) {
|
|
22
|
+
specifiers.add(match[1]);
|
|
31
23
|
}
|
|
32
24
|
|
|
33
25
|
while ((match = dynamicImportRegex.exec(content)) !== null) {
|
|
34
|
-
|
|
26
|
+
specifiers.add(match[1]);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return Array.from(specifiers);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function extractExternalImports(content: string): string[] {
|
|
33
|
+
const imports = new Set<string>();
|
|
34
|
+
for (const importPath of extractModuleSpecifiers(content)) {
|
|
35
35
|
if (
|
|
36
36
|
importPath.startsWith(".") ||
|
|
37
37
|
importPath.startsWith("node:") ||
|
|
@@ -41,10 +41,15 @@ export function extractExternalImports(content: string): string[] {
|
|
|
41
41
|
}
|
|
42
42
|
imports.add(extractPackageNameFromImportPath(importPath));
|
|
43
43
|
}
|
|
44
|
-
|
|
45
44
|
return Array.from(imports);
|
|
46
45
|
}
|
|
47
46
|
|
|
47
|
+
export function extractLocalRelativeImports(content: string): string[] {
|
|
48
|
+
return extractModuleSpecifiers(content).filter(
|
|
49
|
+
(importPath) => importPath.startsWith(".") && !importPath.startsWith("/")
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
48
53
|
export function extractWorkspaceDependencies(
|
|
49
54
|
manifest: Record<string, any>
|
|
50
55
|
): string[] {
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export interface DialogLaunchScopeInput {
|
|
2
|
+
routeSpaceId?: string | null;
|
|
3
|
+
recordSpaceId?: string | null;
|
|
4
|
+
currentSpaceId?: string | null;
|
|
5
|
+
viewMode?: string | null;
|
|
6
|
+
allowSidebarSpaceFallback?: boolean;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const trimSpaceId = (spaceId?: string | null): string | null => {
|
|
10
|
+
if (typeof spaceId !== "string") return null;
|
|
11
|
+
const trimmed = spaceId.trim();
|
|
12
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const resolveDialogLaunchSpaceId = ({
|
|
16
|
+
routeSpaceId,
|
|
17
|
+
recordSpaceId,
|
|
18
|
+
currentSpaceId,
|
|
19
|
+
viewMode,
|
|
20
|
+
allowSidebarSpaceFallback = false,
|
|
21
|
+
}: DialogLaunchScopeInput): string | null => {
|
|
22
|
+
const explicitSpaceId = trimSpaceId(routeSpaceId) ?? trimSpaceId(recordSpaceId);
|
|
23
|
+
if (explicitSpaceId) {
|
|
24
|
+
return explicitSpaceId;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (!allowSidebarSpaceFallback || viewMode !== "categories") {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return trimSpaceId(currentSpaceId);
|
|
32
|
+
};
|