@downcity/city 1.1.39 → 1.1.47
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 +4 -9
- package/bin/cli/Index.js +2 -0
- package/bin/cli/Index.js.map +1 -1
- package/bin/cli/agent/AgentChat.d.ts +2 -1
- package/bin/cli/agent/AgentChat.d.ts.map +1 -1
- package/bin/cli/agent/AgentChat.js +93 -214
- package/bin/cli/agent/AgentChat.js.map +1 -1
- package/bin/cli/agent/AgentChatTypes.d.ts +8 -12
- package/bin/cli/agent/AgentChatTypes.d.ts.map +1 -1
- package/bin/cli/agent/AgentHistory.js +2 -2
- package/bin/cli/agent/AgentHistory.js.map +1 -1
- package/bin/cli/agent/AgentManager.d.ts.map +1 -1
- package/bin/cli/agent/AgentManager.js +26 -27
- package/bin/cli/agent/AgentManager.js.map +1 -1
- package/bin/cli/agent/AgentManagerTypes.d.ts +2 -2
- package/bin/cli/agent/AgentManagerTypes.d.ts.map +1 -1
- package/bin/cli/agent/AgentReset.js +4 -4
- package/bin/cli/agent/AgentReset.js.map +1 -1
- package/bin/cli/agent/AgentSelection.js +6 -6
- package/bin/cli/agent/AgentSelection.js.map +1 -1
- package/bin/cli/agent/AgentSelectionTypes.d.ts +1 -1
- package/bin/cli/agent/AgentSelectionTypes.d.ts.map +1 -1
- package/bin/cli/agent/Init.js +10 -10
- package/bin/cli/agent/Init.js.map +1 -1
- package/bin/cli/agent/Restart.js +2 -2
- package/bin/cli/agent/Restart.js.map +1 -1
- package/bin/cli/agent/Run.d.ts +1 -1
- package/bin/cli/agent/Run.d.ts.map +1 -1
- package/bin/cli/agent/Run.js +37 -17
- package/bin/cli/agent/Run.js.map +1 -1
- package/bin/cli/agent/Start.js +2 -2
- package/bin/cli/agent/Start.js.map +1 -1
- package/bin/cli/agent/Stop.js +2 -2
- package/bin/cli/agent/Stop.js.map +1 -1
- package/bin/cli/control-plane/ControlPlaneProcess.js +5 -5
- package/bin/cli/control-plane/ControlPlaneProcess.js.map +1 -1
- package/bin/cli/model/ModelCreateCommand.js +1 -1
- package/bin/cli/model/ModelCreateCommand.js.map +1 -1
- package/bin/cli/model/ModelManageCommand.d.ts.map +1 -1
- package/bin/cli/model/ModelManageCommand.js +5 -3
- package/bin/cli/model/ModelManageCommand.js.map +1 -1
- package/bin/cli/model/ModelManager.js +3 -3
- package/bin/cli/model/ModelManager.js.map +1 -1
- package/bin/cli/model/ModelSupport.d.ts +0 -1
- package/bin/cli/model/ModelSupport.d.ts.map +1 -1
- package/bin/cli/model/ModelSupport.js +2 -11
- package/bin/cli/model/ModelSupport.js.map +1 -1
- package/bin/cli/shared/CliReporterTypes.d.ts +1 -1
- package/bin/cli/shared/Config.js +2 -2
- package/bin/cli/shared/Config.js.map +1 -1
- package/bin/cli/shared/Env.d.ts +1 -1
- package/bin/cli/shared/Env.d.ts.map +1 -1
- package/bin/cli/shared/Env.js +18 -149
- package/bin/cli/shared/Env.js.map +1 -1
- package/bin/cli/shared/IndexAgentCommand.d.ts.map +1 -1
- package/bin/cli/shared/IndexAgentCommand.js +3 -3
- package/bin/cli/shared/IndexAgentCommand.js.map +1 -1
- package/bin/cli/shared/IndexSupport.d.ts +3 -3
- package/bin/cli/shared/IndexSupport.d.ts.map +1 -1
- package/bin/cli/shared/IndexSupport.js +14 -8
- package/bin/cli/shared/IndexSupport.js.map +1 -1
- package/bin/cli/shared/ManagedPluginActionCommands.d.ts.map +1 -1
- package/bin/cli/shared/ManagedPluginActionCommands.js +5 -4
- package/bin/cli/shared/ManagedPluginActionCommands.js.map +1 -1
- package/bin/cli/shared/ManagedPluginRemote.d.ts.map +1 -1
- package/bin/cli/shared/ManagedPluginRemote.js +4 -4
- package/bin/cli/shared/ManagedPluginRemote.js.map +1 -1
- package/bin/cli/shared/PluginTargetSupport.d.ts +2 -2
- package/bin/cli/shared/PluginTargetSupport.d.ts.map +1 -1
- package/bin/cli/shared/PluginTargetSupport.js +19 -19
- package/bin/cli/shared/PluginTargetSupport.js.map +1 -1
- package/bin/cli/shared/Plugins.js +10 -10
- package/bin/cli/shared/Plugins.js.map +1 -1
- package/bin/cli/shared/PublicHostEnv.d.ts +1 -1
- package/bin/cli/shared/PublicHostEnv.js +2 -2
- package/bin/cli/shared/PublicHostEnv.js.map +1 -1
- package/bin/cli/shared/Terminal.d.ts +13 -0
- package/bin/cli/shared/Terminal.d.ts.map +1 -0
- package/bin/cli/shared/Terminal.js +22 -0
- package/bin/cli/shared/Terminal.js.map +1 -0
- package/bin/config/DowncitySchema.d.ts.map +1 -1
- package/bin/config/DowncitySchema.js +3 -111
- package/bin/config/DowncitySchema.js.map +1 -1
- package/bin/config/Paths.d.ts +0 -56
- package/bin/config/Paths.d.ts.map +1 -1
- package/bin/config/Paths.js +9 -51
- package/bin/config/Paths.js.map +1 -1
- package/bin/control/ControlGateway.js +1 -1
- package/bin/control/ControlGateway.js.map +1 -1
- package/bin/control/EnvApiRoutes.d.ts +1 -1
- package/bin/control/EnvApiRoutes.d.ts.map +1 -1
- package/bin/control/EnvApiRoutes.js +7 -79
- package/bin/control/EnvApiRoutes.js.map +1 -1
- package/bin/control/PlatformApiRoutes.d.ts +2 -2
- package/bin/control/PlatformApiRoutes.d.ts.map +1 -1
- package/bin/control/PlatformApiRoutes.js +2 -2
- package/bin/control/PlatformApiRoutes.js.map +1 -1
- package/bin/control/gateway/AgentActions.d.ts +2 -2
- package/bin/control/gateway/AgentActions.d.ts.map +1 -1
- package/bin/control/gateway/AgentActions.js +7 -7
- package/bin/control/gateway/AgentActions.js.map +1 -1
- package/bin/control/gateway/AgentCatalog.d.ts +3 -6
- package/bin/control/gateway/AgentCatalog.d.ts.map +1 -1
- package/bin/control/gateway/AgentCatalog.js +16 -18
- package/bin/control/gateway/AgentCatalog.js.map +1 -1
- package/bin/control/instant/InstantSessionRunner.d.ts.map +1 -1
- package/bin/control/instant/InstantSessionRunner.js +3 -1
- package/bin/control/instant/InstantSessionRunner.js.map +1 -1
- package/bin/env/ProcessEnv.d.ts +24 -0
- package/bin/env/ProcessEnv.d.ts.map +1 -0
- package/bin/env/ProcessEnv.js +41 -0
- package/bin/env/ProcessEnv.js.map +1 -0
- package/bin/http/auth/AuthEnv.d.ts +1 -1
- package/bin/http/auth/AuthEnv.js +1 -1
- package/bin/model/runtime/CreateRuntimeModel.d.ts +8 -0
- package/bin/model/runtime/CreateRuntimeModel.d.ts.map +1 -1
- package/bin/model/runtime/CreateRuntimeModel.js +43 -37
- package/bin/model/runtime/CreateRuntimeModel.js.map +1 -1
- package/bin/model/service/ModelPoolService.d.ts +1 -1
- package/bin/model/service/ModelPoolService.d.ts.map +1 -1
- package/bin/model/service/ModelPoolService.js +8 -6
- package/bin/model/service/ModelPoolService.js.map +1 -1
- package/bin/platform/store/StoreEnvRepository.d.ts +5 -49
- package/bin/platform/store/StoreEnvRepository.d.ts.map +1 -1
- package/bin/platform/store/StoreEnvRepository.js +31 -178
- package/bin/platform/store/StoreEnvRepository.js.map +1 -1
- package/bin/platform/store/StoreSchema.js +3 -44
- package/bin/platform/store/StoreSchema.js.map +1 -1
- package/bin/platform/store/index.d.ts +9 -45
- package/bin/platform/store/index.d.ts.map +1 -1
- package/bin/platform/store/index.js +12 -62
- package/bin/platform/store/index.js.map +1 -1
- package/bin/platform/store/schema.d.ts +2 -2
- package/bin/platform/store/schema.js +2 -2
- package/bin/process/daemon/Api.d.ts +1 -1
- package/bin/process/daemon/CliArgs.d.ts +1 -0
- package/bin/process/daemon/CliArgs.d.ts.map +1 -1
- package/bin/process/daemon/CliArgs.js +20 -1
- package/bin/process/daemon/CliArgs.js.map +1 -1
- package/bin/process/daemon/Client.d.ts +18 -2
- package/bin/process/daemon/Client.d.ts.map +1 -1
- package/bin/process/daemon/Client.js +70 -20
- package/bin/process/daemon/Client.js.map +1 -1
- package/bin/process/daemon/Manager.d.ts.map +1 -1
- package/bin/process/daemon/Manager.js +2 -1
- package/bin/process/daemon/Manager.js.map +1 -1
- package/bin/terminal/admin/auth-error.d.ts +34 -0
- package/bin/terminal/admin/auth-error.d.ts.map +1 -0
- package/bin/terminal/admin/auth-error.js +51 -0
- package/bin/terminal/admin/auth-error.js.map +1 -0
- package/bin/terminal/admin/commands/accounts.d.ts +6 -0
- package/bin/terminal/admin/commands/accounts.d.ts.map +1 -0
- package/bin/terminal/admin/commands/accounts.js +44 -0
- package/bin/terminal/admin/commands/accounts.js.map +1 -0
- package/bin/terminal/admin/commands/balance.d.ts +6 -0
- package/bin/terminal/admin/commands/balance.d.ts.map +1 -0
- package/bin/terminal/admin/commands/balance.js +153 -0
- package/bin/terminal/admin/commands/balance.js.map +1 -0
- package/bin/terminal/admin/commands/config.d.ts +10 -0
- package/bin/terminal/admin/commands/config.d.ts.map +1 -0
- package/bin/terminal/admin/commands/config.js +11 -0
- package/bin/terminal/admin/commands/config.js.map +1 -0
- package/bin/terminal/admin/commands/custom.d.ts +6 -0
- package/bin/terminal/admin/commands/custom.d.ts.map +1 -0
- package/bin/terminal/admin/commands/custom.js +47 -0
- package/bin/terminal/admin/commands/custom.js.map +1 -0
- package/bin/terminal/admin/commands/instruction.d.ts +9 -0
- package/bin/terminal/admin/commands/instruction.d.ts.map +1 -0
- package/bin/terminal/admin/commands/instruction.js +10 -0
- package/bin/terminal/admin/commands/instruction.js.map +1 -0
- package/bin/terminal/admin/commands/models.d.ts +14 -0
- package/bin/terminal/admin/commands/models.d.ts.map +1 -0
- package/bin/terminal/admin/commands/models.js +61 -0
- package/bin/terminal/admin/commands/models.js.map +1 -0
- package/bin/terminal/admin/commands/payment.d.ts +6 -0
- package/bin/terminal/admin/commands/payment.d.ts.map +1 -0
- package/bin/terminal/admin/commands/payment.js +59 -0
- package/bin/terminal/admin/commands/payment.js.map +1 -0
- package/bin/terminal/admin/commands/products.d.ts +6 -0
- package/bin/terminal/admin/commands/products.d.ts.map +1 -0
- package/bin/terminal/admin/commands/products.js +80 -0
- package/bin/terminal/admin/commands/products.js.map +1 -0
- package/bin/terminal/admin/commands/service-env.d.ts +11 -0
- package/bin/terminal/admin/commands/service-env.d.ts.map +1 -0
- package/bin/terminal/admin/commands/service-env.js +248 -0
- package/bin/terminal/admin/commands/service-env.js.map +1 -0
- package/bin/terminal/admin/commands/usage.d.ts +6 -0
- package/bin/terminal/admin/commands/usage.d.ts.map +1 -0
- package/bin/terminal/admin/commands/usage.js +44 -0
- package/bin/terminal/admin/commands/usage.js.map +1 -0
- package/bin/terminal/admin/loop.d.ts +6 -0
- package/bin/terminal/admin/loop.d.ts.map +1 -0
- package/bin/terminal/admin/loop.js +70 -0
- package/bin/terminal/admin/loop.js.map +1 -0
- package/bin/terminal/agent/pi-agent.d.ts +15 -0
- package/bin/terminal/agent/pi-agent.d.ts.map +1 -0
- package/bin/terminal/agent/pi-agent.js +136 -0
- package/bin/terminal/agent/pi-agent.js.map +1 -0
- package/bin/terminal/app.d.ts +13 -0
- package/bin/terminal/app.d.ts.map +1 -0
- package/bin/terminal/app.js +123 -0
- package/bin/terminal/app.js.map +1 -0
- package/bin/terminal/auth/admin.d.ts +8 -0
- package/bin/terminal/auth/admin.d.ts.map +1 -0
- package/bin/terminal/auth/admin.js +18 -0
- package/bin/terminal/auth/admin.js.map +1 -0
- package/bin/terminal/auth/mode-select.d.ts +11 -0
- package/bin/terminal/auth/mode-select.d.ts.map +1 -0
- package/bin/terminal/auth/mode-select.js +33 -0
- package/bin/terminal/auth/mode-select.js.map +1 -0
- package/bin/terminal/auth/server-switch.d.ts +22 -0
- package/bin/terminal/auth/server-switch.d.ts.map +1 -0
- package/bin/terminal/auth/server-switch.js +241 -0
- package/bin/terminal/auth/server-switch.js.map +1 -0
- package/bin/terminal/auth/user.d.ts +19 -0
- package/bin/terminal/auth/user.d.ts.map +1 -0
- package/bin/terminal/auth/user.js +261 -0
- package/bin/terminal/auth/user.js.map +1 -0
- package/bin/terminal/core/browser.d.ts +12 -0
- package/bin/terminal/core/browser.d.ts.map +1 -0
- package/bin/terminal/core/browser.js +29 -0
- package/bin/terminal/core/browser.js.map +1 -0
- package/bin/terminal/core/env.d.ts +15 -0
- package/bin/terminal/core/env.d.ts.map +1 -0
- package/bin/terminal/core/env.js +67 -0
- package/bin/terminal/core/env.js.map +1 -0
- package/bin/terminal/core/session.d.ts +97 -0
- package/bin/terminal/core/session.d.ts.map +1 -0
- package/bin/terminal/core/session.js +342 -0
- package/bin/terminal/core/session.js.map +1 -0
- package/bin/terminal/core/stripe.d.ts +26 -0
- package/bin/terminal/core/stripe.d.ts.map +1 -0
- package/bin/terminal/core/stripe.js +22 -0
- package/bin/terminal/core/stripe.js.map +1 -0
- package/bin/terminal/core/ui.d.ts +29 -0
- package/bin/terminal/core/ui.d.ts.map +1 -0
- package/bin/terminal/core/ui.js +60 -0
- package/bin/terminal/core/ui.js.map +1 -0
- package/bin/terminal/core/update.d.ts +20 -0
- package/bin/terminal/core/update.d.ts.map +1 -0
- package/bin/terminal/core/update.js +193 -0
- package/bin/terminal/core/update.js.map +1 -0
- package/bin/terminal/user/balance.d.ts +31 -0
- package/bin/terminal/user/balance.d.ts.map +1 -0
- package/bin/terminal/user/balance.js +131 -0
- package/bin/terminal/user/balance.js.map +1 -0
- package/bin/terminal/user/chat.d.ts +12 -0
- package/bin/terminal/user/chat.d.ts.map +1 -0
- package/bin/terminal/user/chat.js +70 -0
- package/bin/terminal/user/chat.js.map +1 -0
- package/bin/terminal/user/loop.d.ts +13 -0
- package/bin/terminal/user/loop.d.ts.map +1 -0
- package/bin/terminal/user/loop.js +93 -0
- package/bin/terminal/user/loop.js.map +1 -0
- package/bin/terminal/user/models.d.ts +10 -0
- package/bin/terminal/user/models.d.ts.map +1 -0
- package/bin/terminal/user/models.js +39 -0
- package/bin/terminal/user/models.js.map +1 -0
- package/bin/utils/storage.d.ts +0 -1
- package/bin/utils/storage.d.ts.map +1 -1
- package/bin/utils/storage.js +0 -6
- package/bin/utils/storage.js.map +1 -1
- package/package.json +7 -3
- package/public/app.js +3 -3
- package/src/cli/Index.ts +2 -0
- package/src/cli/agent/AgentChat.ts +113 -289
- package/src/cli/agent/AgentChatTypes.ts +8 -12
- package/src/cli/agent/AgentHistory.ts +2 -2
- package/src/cli/agent/AgentManager.ts +27 -28
- package/src/cli/agent/AgentManagerTypes.ts +2 -2
- package/src/cli/agent/AgentReset.ts +4 -4
- package/src/cli/agent/AgentSelection.ts +6 -6
- package/src/cli/agent/AgentSelectionTypes.ts +1 -1
- package/src/cli/agent/Init.ts +13 -13
- package/src/cli/agent/Restart.ts +2 -2
- package/src/cli/agent/Run.ts +38 -17
- package/src/cli/agent/Start.ts +2 -2
- package/src/cli/agent/Stop.ts +2 -2
- package/src/cli/control-plane/ControlPlaneProcess.ts +5 -5
- package/src/cli/model/ModelCreateCommand.ts +1 -1
- package/src/cli/model/ModelManageCommand.ts +5 -3
- package/src/cli/model/ModelManager.ts +3 -3
- package/src/cli/model/ModelSupport.ts +2 -10
- package/src/cli/shared/CliReporterTypes.ts +1 -1
- package/src/cli/shared/Config.ts +2 -2
- package/src/cli/shared/Env.ts +22 -230
- package/src/cli/shared/IndexAgentCommand.ts +3 -4
- package/src/cli/shared/IndexSupport.ts +16 -10
- package/src/cli/shared/ManagedPluginActionCommands.ts +4 -4
- package/src/cli/shared/ManagedPluginRemote.ts +4 -4
- package/src/cli/shared/PluginTargetSupport.ts +19 -19
- package/src/cli/shared/Plugins.ts +10 -10
- package/src/cli/shared/PublicHostEnv.ts +2 -2
- package/src/cli/shared/Terminal.ts +24 -0
- package/src/config/DowncitySchema.ts +3 -113
- package/src/config/Paths.ts +9 -90
- package/src/control/ControlGateway.ts +3 -3
- package/src/control/EnvApiRoutes.ts +7 -91
- package/src/control/PlatformApiRoutes.ts +6 -6
- package/src/control/gateway/AgentActions.ts +10 -10
- package/src/control/gateway/AgentCatalog.ts +17 -21
- package/src/control/instant/InstantSessionRunner.ts +3 -1
- package/src/env/ProcessEnv.ts +43 -0
- package/src/http/auth/AuthEnv.ts +1 -1
- package/src/model/runtime/CreateRuntimeModel.ts +54 -37
- package/src/model/service/ModelPoolService.ts +13 -11
- package/src/platform/store/StoreEnvRepository.ts +31 -234
- package/src/platform/store/StoreSchema.ts +3 -49
- package/src/platform/store/index.ts +11 -80
- package/src/platform/store/schema.ts +2 -2
- package/src/process/daemon/Api.ts +1 -1
- package/src/process/daemon/CliArgs.ts +24 -1
- package/src/process/daemon/Client.ts +90 -22
- package/src/process/daemon/Manager.ts +2 -1
- package/src/terminal/admin/auth-error.ts +62 -0
- package/src/terminal/admin/commands/accounts.ts +44 -0
- package/src/terminal/admin/commands/balance.ts +160 -0
- package/src/terminal/admin/commands/config.ts +13 -0
- package/src/terminal/admin/commands/custom.ts +46 -0
- package/src/terminal/admin/commands/instruction.ts +12 -0
- package/src/terminal/admin/commands/models.ts +64 -0
- package/src/terminal/admin/commands/payment.ts +94 -0
- package/src/terminal/admin/commands/products.ts +72 -0
- package/src/terminal/admin/commands/service-env.ts +256 -0
- package/src/terminal/admin/commands/usage.ts +44 -0
- package/src/terminal/admin/loop.ts +69 -0
- package/src/terminal/agent/pi-agent.ts +180 -0
- package/src/terminal/app.ts +120 -0
- package/src/terminal/auth/admin.ts +21 -0
- package/src/terminal/auth/mode-select.ts +38 -0
- package/src/terminal/auth/server-switch.ts +275 -0
- package/src/terminal/auth/user.ts +351 -0
- package/src/terminal/core/browser.ts +31 -0
- package/src/terminal/core/env.ts +71 -0
- package/src/terminal/core/session.ts +450 -0
- package/src/terminal/core/stripe.ts +37 -0
- package/src/terminal/core/ui.ts +84 -0
- package/src/terminal/core/update.ts +230 -0
- package/src/terminal/user/balance.ts +215 -0
- package/src/terminal/user/chat.ts +80 -0
- package/src/terminal/user/loop.ts +112 -0
- package/src/terminal/user/models.ts +43 -0
- package/src/utils/storage.ts +0 -7
- package/bin/process/rpc/Client.d.ts +0 -13
- package/bin/process/rpc/Client.d.ts.map +0 -1
- package/bin/process/rpc/Client.js +0 -98
- package/bin/process/rpc/Client.js.map +0 -1
- package/bin/process/rpc/Paths.d.ts +0 -14
- package/bin/process/rpc/Paths.d.ts.map +0 -1
- package/bin/process/rpc/Paths.js +0 -36
- package/bin/process/rpc/Paths.js.map +0 -1
- package/src/process/rpc/Client.ts +0 -113
- package/src/process/rpc/Paths.ts +0 -43
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User 鉴权模块。
|
|
3
|
+
*
|
|
4
|
+
* 登录方式不在 CLI 里写死,而是先读取 InfraRuntime 返回的 providers:
|
|
5
|
+
* 1. Email Login — 邮箱 + 密码直接登录
|
|
6
|
+
* 2. Email Register — 邮箱 + 密码注册 → 验证码 → 完成
|
|
7
|
+
* 3. 任意 OAuth Provider — 浏览器授权(完全以服务端 providers 返回为准)
|
|
8
|
+
*
|
|
9
|
+
* 已有有效 session 直接返回,不重复鉴权。
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { UserClient } from "@downcity/conduit";
|
|
13
|
+
import { select, isCancel } from "@clack/prompts";
|
|
14
|
+
import { normalizeBaseUrl } from "../core/env.js";
|
|
15
|
+
import { openBrowser } from "../core/browser.js";
|
|
16
|
+
import { readUserSession, writeUserSession, readConfig, type UserSession } from "../core/session.js";
|
|
17
|
+
import { askText, askSecret, showError, showSuccess, show } from "../core/ui.js";
|
|
18
|
+
|
|
19
|
+
export interface UserContext {
|
|
20
|
+
session: UserSession;
|
|
21
|
+
config: { model: string };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
type AuthMethod = "login" | "register" | `oauth:${string}`;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* 服务端返回的单个登录方式描述。
|
|
28
|
+
*/
|
|
29
|
+
interface AccountsProviderItem {
|
|
30
|
+
/**
|
|
31
|
+
* 登录方式标识。
|
|
32
|
+
*/
|
|
33
|
+
id?: string;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 登录方式类别。
|
|
37
|
+
*/
|
|
38
|
+
type?: string;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* 当前 InfraRuntime 是否真的启用了该登录方式。
|
|
42
|
+
*/
|
|
43
|
+
enabled?: boolean;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* 邮箱登录是否开放。
|
|
47
|
+
*/
|
|
48
|
+
login_enabled?: boolean;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* 邮箱注册是否开放。
|
|
52
|
+
*/
|
|
53
|
+
register_enabled?: boolean;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* 当登录方式不可用时的原因码。
|
|
57
|
+
*/
|
|
58
|
+
reason?: string;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* 登录菜单项。
|
|
63
|
+
*/
|
|
64
|
+
interface AuthOption {
|
|
65
|
+
/**
|
|
66
|
+
* 菜单展示文案。
|
|
67
|
+
*/
|
|
68
|
+
label: string;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* 选择后进入的鉴权方式。
|
|
72
|
+
*/
|
|
73
|
+
value: AuthMethod;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* 菜单辅助提示。
|
|
77
|
+
*/
|
|
78
|
+
hint: string;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// ===========================================================================
|
|
82
|
+
// 入口
|
|
83
|
+
// ===========================================================================
|
|
84
|
+
|
|
85
|
+
export async function userAuth(baseUrl: string): Promise<UserContext | undefined> {
|
|
86
|
+
const existing = readUserSession(normalizeBaseUrl(baseUrl));
|
|
87
|
+
if (existing) return { session: existing, config: readConfig() };
|
|
88
|
+
|
|
89
|
+
while (true) {
|
|
90
|
+
const method = await selectAuthMethod(baseUrl);
|
|
91
|
+
if (!method) return undefined;
|
|
92
|
+
|
|
93
|
+
const ctx = await doAuth(baseUrl, method);
|
|
94
|
+
if (ctx) return ctx;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async function selectAuthMethod(baseUrl: string): Promise<AuthMethod | undefined> {
|
|
99
|
+
const options = await loadAuthOptions(baseUrl);
|
|
100
|
+
if (options.length === 0) {
|
|
101
|
+
showError("No sign-in methods enabled on server.");
|
|
102
|
+
return undefined;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const selected = await select({
|
|
106
|
+
message: "Sign in",
|
|
107
|
+
options,
|
|
108
|
+
});
|
|
109
|
+
if (!selected || isCancel(selected)) return undefined;
|
|
110
|
+
return selected as AuthMethod;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async function loadAuthOptions(baseUrl: string): Promise<AuthOption[]> {
|
|
114
|
+
const client = new UserClient({ base_url: normalizeBaseUrl(baseUrl) });
|
|
115
|
+
const accounts = client.service("accounts");
|
|
116
|
+
|
|
117
|
+
try {
|
|
118
|
+
const result = await accounts.get<{ items?: AccountsProviderItem[] }>("providers");
|
|
119
|
+
return mapProvidersToOptions(result.items ?? []);
|
|
120
|
+
} catch (e) {
|
|
121
|
+
showError(`Failed to load sign-in methods: ${e instanceof Error ? e.message : String(e)}`);
|
|
122
|
+
return [];
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function mapProvidersToOptions(items: AccountsProviderItem[]): AuthOption[] {
|
|
127
|
+
const options: AuthOption[] = [];
|
|
128
|
+
|
|
129
|
+
for (const item of items) {
|
|
130
|
+
if (!item.enabled) continue;
|
|
131
|
+
|
|
132
|
+
if (item.id === "email" && item.type === "password") {
|
|
133
|
+
if (item.login_enabled !== false) {
|
|
134
|
+
options.push({ label: "Email Login", value: "login", hint: "Sign in with email + password" });
|
|
135
|
+
}
|
|
136
|
+
if (item.register_enabled !== false) {
|
|
137
|
+
options.push({ label: "Email Register", value: "register", hint: "Create a new account" });
|
|
138
|
+
}
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (item.type === "oauth" && typeof item.id === "string" && item.id.trim()) {
|
|
143
|
+
const provider = item.id.trim();
|
|
144
|
+
options.push({
|
|
145
|
+
label: formatOAuthProviderLabel(provider),
|
|
146
|
+
value: `oauth:${provider}`,
|
|
147
|
+
hint: `Sign in with ${formatOAuthProviderLabel(provider)} OAuth`,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return options;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// ===========================================================================
|
|
156
|
+
// 鉴权分发
|
|
157
|
+
// ===========================================================================
|
|
158
|
+
|
|
159
|
+
async function doAuth(baseUrl: string, method: AuthMethod): Promise<UserContext | undefined> {
|
|
160
|
+
if (method.startsWith("oauth:")) {
|
|
161
|
+
return oauthAuth(baseUrl, method.slice("oauth:".length));
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
switch (method) {
|
|
165
|
+
case "login": return emailLogin(baseUrl);
|
|
166
|
+
case "register": return emailRegister(baseUrl);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// ===========================================================================
|
|
171
|
+
// 邮箱登录
|
|
172
|
+
// ===========================================================================
|
|
173
|
+
|
|
174
|
+
interface LoginResult {
|
|
175
|
+
user_token?: string;
|
|
176
|
+
user_id?: string;
|
|
177
|
+
email?: string;
|
|
178
|
+
error?: string;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
async function emailLogin(baseUrl: string): Promise<UserContext | undefined> {
|
|
182
|
+
const email = await askText("email");
|
|
183
|
+
if (!email || !email.includes("@")) { showError("invalid email"); return undefined; }
|
|
184
|
+
|
|
185
|
+
const password = await askSecret("password");
|
|
186
|
+
if (!password) return undefined;
|
|
187
|
+
|
|
188
|
+
const client = new UserClient({ base_url: normalizeBaseUrl(baseUrl) });
|
|
189
|
+
const accounts = client.service("accounts");
|
|
190
|
+
|
|
191
|
+
try {
|
|
192
|
+
const result = await accounts.action("login").invoke<LoginResult>({ email, password });
|
|
193
|
+
if (result.error) { showError(result.error); return undefined; }
|
|
194
|
+
if (!result.user_token) { showError("login failed: no token"); return undefined; }
|
|
195
|
+
|
|
196
|
+
return saveSession(baseUrl, email, result as { user_token: string; user_id?: string });
|
|
197
|
+
} catch (e) {
|
|
198
|
+
showError(e instanceof Error ? e.message : String(e));
|
|
199
|
+
return undefined;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// ===========================================================================
|
|
204
|
+
// 邮箱注册 + 验证
|
|
205
|
+
// ===========================================================================
|
|
206
|
+
|
|
207
|
+
interface RegisterResult {
|
|
208
|
+
success?: boolean;
|
|
209
|
+
message?: string;
|
|
210
|
+
verification_token?: string;
|
|
211
|
+
user_id?: string;
|
|
212
|
+
error?: string;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
interface VerifyResult {
|
|
216
|
+
user_token?: string;
|
|
217
|
+
user_id?: string;
|
|
218
|
+
error?: string;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
async function emailRegister(baseUrl: string): Promise<UserContext | undefined> {
|
|
222
|
+
const email = await askText("email");
|
|
223
|
+
if (!email || !email.includes("@")) { showError("invalid email"); return undefined; }
|
|
224
|
+
|
|
225
|
+
const password = await askSecret("password (min 8 characters)");
|
|
226
|
+
if (!password || password.length < 8) { showError("password must be at least 8 characters"); return undefined; }
|
|
227
|
+
|
|
228
|
+
const client = new UserClient({ base_url: normalizeBaseUrl(baseUrl) });
|
|
229
|
+
const accounts = client.service("accounts");
|
|
230
|
+
|
|
231
|
+
let reg: RegisterResult;
|
|
232
|
+
try {
|
|
233
|
+
reg = await accounts.action("register").invoke<RegisterResult>({ email, password });
|
|
234
|
+
} catch (e) {
|
|
235
|
+
showError(e instanceof Error ? e.message : String(e));
|
|
236
|
+
return undefined;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (reg.error) { showError(reg.error); return undefined; }
|
|
240
|
+
if (!reg.success) { showError("registration failed"); return undefined; }
|
|
241
|
+
|
|
242
|
+
showSuccess("Verification code sent to your email");
|
|
243
|
+
show("If email delivery is unavailable, check server logs for the verification code.");
|
|
244
|
+
|
|
245
|
+
const token = await askText("verification token");
|
|
246
|
+
if (!token) return undefined;
|
|
247
|
+
|
|
248
|
+
try {
|
|
249
|
+
const verify = await accounts.action("verify-email").invoke<VerifyResult>({ token: token.trim() });
|
|
250
|
+
if (verify.error) { showError(verify.error); return undefined; }
|
|
251
|
+
if (!verify.user_token) { showError("verification failed: no token"); return undefined; }
|
|
252
|
+
|
|
253
|
+
return saveSession(baseUrl, email, verify as { user_token: string; user_id?: string });
|
|
254
|
+
} catch (e) {
|
|
255
|
+
showError(e instanceof Error ? e.message : String(e));
|
|
256
|
+
return undefined;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// ===========================================================================
|
|
261
|
+
// OAuth 登录 (GitHub / Google)
|
|
262
|
+
// ===========================================================================
|
|
263
|
+
|
|
264
|
+
interface OAuthStartResult {
|
|
265
|
+
url?: string;
|
|
266
|
+
state?: string;
|
|
267
|
+
error?: string;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
interface OAuthPollResult {
|
|
271
|
+
status?: string;
|
|
272
|
+
user_token?: string;
|
|
273
|
+
error?: string;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
async function oauthAuth(baseUrl: string, provider: string): Promise<UserContext | undefined> {
|
|
277
|
+
const client = new UserClient({ base_url: normalizeBaseUrl(baseUrl) });
|
|
278
|
+
const accounts = client.service("accounts");
|
|
279
|
+
|
|
280
|
+
let start: OAuthStartResult;
|
|
281
|
+
try {
|
|
282
|
+
start = await accounts.action("oauth/start").invoke<OAuthStartResult>({ provider });
|
|
283
|
+
} catch (e) {
|
|
284
|
+
showError(e instanceof Error ? e.message : String(e));
|
|
285
|
+
return undefined;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (start.error) { showError(start.error); return undefined; }
|
|
289
|
+
if (!start.url || !start.state) { showError("failed to start OAuth"); return undefined; }
|
|
290
|
+
|
|
291
|
+
show(`Opening browser for ${provider} authorization...`);
|
|
292
|
+
const opened = openBrowser(start.url);
|
|
293
|
+
if (!opened) showError(`Could not open browser. Please visit:\n ${start.url}`);
|
|
294
|
+
|
|
295
|
+
show("Waiting for authorization...");
|
|
296
|
+
const result = await pollOAuth(client, start.state);
|
|
297
|
+
|
|
298
|
+
if (!result || result.error) { showError(result?.error ?? "OAuth failed"); return undefined; }
|
|
299
|
+
if (!result.user_token) { showError("OAuth failed: no token"); return undefined; }
|
|
300
|
+
|
|
301
|
+
showSuccess(`${provider} login successful`);
|
|
302
|
+
return saveSession(baseUrl, `${provider}:`, result as { user_token: string; user_id?: string });
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/** 轮询 OAuth 结果(最多 3 分钟) */
|
|
306
|
+
async function pollOAuth(client: UserClient, state: string): Promise<OAuthPollResult | undefined> {
|
|
307
|
+
const accounts = client.service("accounts");
|
|
308
|
+
for (let i = 0; i < 180; i++) {
|
|
309
|
+
try {
|
|
310
|
+
const result = await accounts.get<OAuthPollResult>("oauth/result", { state });
|
|
311
|
+
if (result.error) return result;
|
|
312
|
+
if (result.status === "done") return result;
|
|
313
|
+
} catch { /* continue polling */ }
|
|
314
|
+
await sleep(1000);
|
|
315
|
+
}
|
|
316
|
+
return { error: "OAuth timed out" };
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// ===========================================================================
|
|
320
|
+
// 工具函数
|
|
321
|
+
// ===========================================================================
|
|
322
|
+
|
|
323
|
+
function saveSession(baseUrl: string, email: string, result: { user_token: string; user_id?: string }): UserContext {
|
|
324
|
+
const session: UserSession = {
|
|
325
|
+
base_url: normalizeBaseUrl(baseUrl),
|
|
326
|
+
email,
|
|
327
|
+
user_id: result.user_id ?? "",
|
|
328
|
+
product_id: "prod_downcity",
|
|
329
|
+
user_token: result.user_token,
|
|
330
|
+
};
|
|
331
|
+
writeUserSession(session);
|
|
332
|
+
showSuccess(`signed in: ${email}`);
|
|
333
|
+
return { session, config: readConfig() };
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
function sleep(ms: number): Promise<void> {
|
|
337
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
function formatOAuthProviderLabel(provider: string): string {
|
|
341
|
+
const normalized = provider.trim().toLowerCase();
|
|
342
|
+
if (!normalized) return "OAuth";
|
|
343
|
+
if (normalized === "github") return "GitHub";
|
|
344
|
+
if (normalized === "google") return "Google";
|
|
345
|
+
if (normalized === "wechat") return "WeChat";
|
|
346
|
+
return normalized
|
|
347
|
+
.split(/[_-]+/)
|
|
348
|
+
.filter(Boolean)
|
|
349
|
+
.map((part) => part.slice(0, 1).toUpperCase() + part.slice(1))
|
|
350
|
+
.join(" ");
|
|
351
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 浏览器工具模块。
|
|
3
|
+
*
|
|
4
|
+
* 关键说明(中文)
|
|
5
|
+
* - 统一封装跨平台打开默认浏览器
|
|
6
|
+
* - Stripe Checkout、OAuth 登录都复用这里,避免重复实现
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { execFileSync } from "node:child_process";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* 打开系统默认浏览器。
|
|
13
|
+
*/
|
|
14
|
+
export function openBrowser(url: string): boolean {
|
|
15
|
+
try {
|
|
16
|
+
if (process.platform === "darwin") {
|
|
17
|
+
execFileSync("open", [url], { stdio: "ignore" });
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (process.platform === "win32") {
|
|
22
|
+
execFileSync("cmd", ["/c", "start", "", url], { stdio: "ignore" });
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
execFileSync("xdg-open", [url], { stdio: "ignore" });
|
|
27
|
+
return true;
|
|
28
|
+
} catch {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 运行时工具模块。
|
|
3
|
+
*
|
|
4
|
+
* 提供 CLI 参数解析、URL 规范化等基础设施。
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// ============================================================
|
|
8
|
+
// 常量
|
|
9
|
+
// ============================================================
|
|
10
|
+
|
|
11
|
+
export const DEFAULT_HOST = "127.0.0.1";
|
|
12
|
+
export const DEFAULT_PORT = 43127;
|
|
13
|
+
export const DEFAULT_BASE_URL = `http://${DEFAULT_HOST}:${DEFAULT_PORT}`;
|
|
14
|
+
export const DEFAULT_PRODUCT_ID = "prod_downcity";
|
|
15
|
+
|
|
16
|
+
// ============================================================
|
|
17
|
+
// CLI 参数解析
|
|
18
|
+
// ============================================================
|
|
19
|
+
|
|
20
|
+
export function parseArgs(argv: string[]) {
|
|
21
|
+
const positionals: string[] = [];
|
|
22
|
+
const options: Record<string, string | boolean> = {};
|
|
23
|
+
|
|
24
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
25
|
+
const token = argv[index];
|
|
26
|
+
if (!token.startsWith("--")) { positionals.push(token); continue; }
|
|
27
|
+
|
|
28
|
+
const key = token.slice(2).replace(/-([a-z])/g, (_, l: string) => l.toUpperCase());
|
|
29
|
+
const next = argv[index + 1];
|
|
30
|
+
if (!next || next.startsWith("--")) { options[key] = true; continue; }
|
|
31
|
+
options[key] = next;
|
|
32
|
+
index += 1;
|
|
33
|
+
}
|
|
34
|
+
return { command: positionals[0] ?? "", options };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// ============================================================
|
|
38
|
+
// URL 规范化
|
|
39
|
+
// ============================================================
|
|
40
|
+
|
|
41
|
+
export function normalizeBaseUrl(baseUrl = DEFAULT_BASE_URL): string {
|
|
42
|
+
const raw = String(baseUrl).trim();
|
|
43
|
+
if (!raw) return DEFAULT_BASE_URL;
|
|
44
|
+
|
|
45
|
+
const hasProtocol = /^[a-z][a-z\d+.-]*:\/\//iu.test(raw);
|
|
46
|
+
const withProtocol = hasProtocol ? raw : `${defaultProtocol(raw)}://${raw}`;
|
|
47
|
+
const url = new URL(withProtocol);
|
|
48
|
+
|
|
49
|
+
if (!url.port && isLocalOrIp(url.hostname)) url.port = String(DEFAULT_PORT);
|
|
50
|
+
if (!url.pathname || url.pathname === "/") url.pathname = "/";
|
|
51
|
+
return url.toString().replace(/\/+$/, "");
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// ============================================================
|
|
55
|
+
// 内部辅助
|
|
56
|
+
// ============================================================
|
|
57
|
+
|
|
58
|
+
function defaultProtocol(value: string): "http" | "https" {
|
|
59
|
+
const host = value.split("/")[0] ?? "";
|
|
60
|
+
return (isLocalOrIp(host.split(":")[0] ?? "") || host.includes(":")) ? "http" : "https";
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function isLocalOrIp(value: string): boolean {
|
|
64
|
+
const host = value.replace(/^\[/u, "").replace(/\]$/u, "");
|
|
65
|
+
return host === "localhost" || isIpv4Host(host) || host.includes(":");
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function isIpv4Host(value: string): boolean {
|
|
69
|
+
const parts = value.split(".");
|
|
70
|
+
return parts.length === 4 && parts.every((p) => /^\d+$/u.test(p) && Number(p) <= 255);
|
|
71
|
+
}
|