fluxmail 0.19.1 → 0.21.0
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/dist/accounts/oauthCallback.d.ts +6 -3
- package/dist/accounts/oauthCallback.d.ts.map +1 -1
- package/dist/accounts/oauthCallback.js +8 -6
- package/dist/accounts/oauthCallback.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +101 -12
- package/dist/cli.js.map +1 -1
- package/dist/cliCloudAuth.d.ts +48 -0
- package/dist/cliCloudAuth.d.ts.map +1 -0
- package/dist/cliCloudAuth.js +254 -0
- package/dist/cliCloudAuth.js.map +1 -0
- package/dist/cliCloudClient.d.ts +29 -0
- package/dist/cliCloudClient.d.ts.map +1 -0
- package/dist/cliCloudClient.js +154 -0
- package/dist/cliCloudClient.js.map +1 -0
- package/dist/cliInstances.d.ts +39 -4
- package/dist/cliInstances.d.ts.map +1 -1
- package/dist/cliInstances.js +76 -8
- package/dist/cliInstances.js.map +1 -1
- package/dist/cliMail.d.ts.map +1 -1
- package/dist/cliMail.js +54 -143
- package/dist/cliMail.js.map +1 -1
- package/dist/cliMailBackend.d.ts +125 -0
- package/dist/cliMailBackend.d.ts.map +1 -0
- package/dist/cliMailBackend.js +354 -0
- package/dist/cliMailBackend.js.map +1 -0
- package/dist/cliOutput.d.ts.map +1 -1
- package/dist/cliOutput.js +19 -2
- package/dist/cliOutput.js.map +1 -1
- package/dist/context.d.ts +3 -0
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +14 -1
- package/dist/context.js.map +1 -1
- package/dist/feedback.d.ts +13 -29
- package/dist/feedback.d.ts.map +1 -1
- package/dist/feedback.js +2 -1
- package/dist/feedback.js.map +1 -1
- package/dist/http/admin.d.ts.map +1 -1
- package/dist/http/admin.js +4 -2
- package/dist/http/admin.js.map +1 -1
- package/dist/http/app.d.ts +2 -0
- package/dist/http/app.d.ts.map +1 -1
- package/dist/http/app.js +4 -1
- package/dist/http/app.js.map +1 -1
- package/dist/http/rest.d.ts +2 -0
- package/dist/http/rest.d.ts.map +1 -1
- package/dist/http/rest.js +17 -9
- package/dist/http/rest.js.map +1 -1
- package/dist/lifecycle.d.ts.map +1 -1
- package/dist/lifecycle.js +1 -0
- package/dist/lifecycle.js.map +1 -1
- package/dist/mcp/attachmentContent.d.ts +1 -1
- package/dist/mcp/attachmentContent.d.ts.map +1 -1
- package/dist/mcp/buildServer.d.ts +3 -0
- package/dist/mcp/buildServer.d.ts.map +1 -1
- package/dist/mcp/buildServer.js +44 -10
- package/dist/mcp/buildServer.js.map +1 -1
- package/dist/mcp/outputSchemas.d.ts +193 -3065
- package/dist/mcp/outputSchemas.d.ts.map +1 -1
- package/dist/mcp/outputSchemas.js +11 -1
- package/dist/mcp/outputSchemas.js.map +1 -1
- package/dist/sendAt.d.ts +4 -0
- package/dist/sendAt.d.ts.map +1 -0
- package/dist/sendAt.js +10 -0
- package/dist/sendAt.js.map +1 -0
- package/dist/service/emailService.d.ts.map +1 -1
- package/dist/service/emailService.js +21 -2
- package/dist/service/emailService.js.map +1 -1
- package/dist/service/publicErrors.d.ts.map +1 -1
- package/dist/service/publicErrors.js +14 -12
- package/dist/service/publicErrors.js.map +1 -1
- package/dist/storage/fileLock.d.ts +2 -0
- package/dist/storage/fileLock.d.ts.map +1 -1
- package/dist/storage/fileLock.js +25 -4
- package/dist/storage/fileLock.js.map +1 -1
- package/dist/telemetry.d.ts +5 -0
- package/dist/telemetry.d.ts.map +1 -1
- package/dist/telemetry.js +17 -2
- package/dist/telemetry.js.map +1 -1
- package/dist/updateNotifier.d.ts +34 -1
- package/dist/updateNotifier.d.ts.map +1 -1
- package/dist/updateNotifier.js +71 -1
- package/dist/updateNotifier.js.map +1 -1
- package/package.json +8 -9
|
@@ -25,8 +25,9 @@ export interface LoopbackFlowOptions {
|
|
|
25
25
|
onCallback?: (source: OAuthCallbackSource) => void;
|
|
26
26
|
}
|
|
27
27
|
export declare const DEFAULT_OAUTH_CALLBACK_TIMEOUT_MS: number;
|
|
28
|
+
type OAuthCallbackProvider = 'gmail' | 'outlook' | 'cloud';
|
|
28
29
|
interface CallbackFlowParams<T> {
|
|
29
|
-
provider:
|
|
30
|
+
provider: OAuthCallbackProvider;
|
|
30
31
|
redirectUri: string;
|
|
31
32
|
host: string;
|
|
32
33
|
port: number;
|
|
@@ -34,14 +35,16 @@ interface CallbackFlowParams<T> {
|
|
|
34
35
|
authUrl: string;
|
|
35
36
|
onAuthUrl: (url: string, context: OAuthAuthUrlContext) => void;
|
|
36
37
|
/** Exchanges the code and stores the account. Its errors end the flow. */
|
|
37
|
-
complete: (code: string) => Promise<{
|
|
38
|
+
complete: (code: string, callback: URL) => Promise<{
|
|
38
39
|
email: string;
|
|
39
40
|
value: T;
|
|
40
41
|
}>;
|
|
42
|
+
/** The browser page's heading after `complete` succeeds. */
|
|
43
|
+
successTitle?: (email: string) => string;
|
|
41
44
|
options?: LoopbackFlowOptions;
|
|
42
45
|
}
|
|
43
46
|
/** Explains a busy callback port, including the Docker Compose case where the container owns it. */
|
|
44
|
-
export declare function callbackPortInUseError(error: Error, port: number, provider:
|
|
47
|
+
export declare function callbackPortInUseError(error: Error, port: number, provider: OAuthCallbackProvider): Error;
|
|
45
48
|
/**
|
|
46
49
|
* Waits for the OAuth redirect on the loopback listener and, when a terminal
|
|
47
50
|
* is available, for the same callback URL pasted into it. The first callback
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauthCallback.d.ts","sourceRoot":"","sources":["../../src/accounts/oauthCallback.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAG5C,kFAAkF;AAClF,MAAM,MAAM,mBAAmB,GAAG,UAAU,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEpE;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,QAAQ,CAAC;IAChB,qEAAqE;IACrE,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC;AAED,MAAM,WAAW,mBAAmB;IAClC,oEAAoE;IACpE,SAAS,EAAE,OAAO,CAAC;IACnB,2DAA2D;IAC3D,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,8BAA8B;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8FAA8F;IAC9F,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,mBAAmB,KAAK,IAAI,CAAC;CACpD;AAED,eAAO,MAAM,iCAAiC,QAAiB,CAAC;AAEhE,UAAU,kBAAkB,CAAC,CAAC;IAC5B,QAAQ,EAAE,
|
|
1
|
+
{"version":3,"file":"oauthCallback.d.ts","sourceRoot":"","sources":["../../src/accounts/oauthCallback.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAG5C,kFAAkF;AAClF,MAAM,MAAM,mBAAmB,GAAG,UAAU,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEpE;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,QAAQ,CAAC;IAChB,qEAAqE;IACrE,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC;AAED,MAAM,WAAW,mBAAmB;IAClC,oEAAoE;IACpE,SAAS,EAAE,OAAO,CAAC;IACnB,2DAA2D;IAC3D,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,8BAA8B;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8FAA8F;IAC9F,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,mBAAmB,KAAK,IAAI,CAAC;CACpD;AAED,eAAO,MAAM,iCAAiC,QAAiB,CAAC;AAEhE,KAAK,qBAAqB,GAAG,OAAO,GAAG,SAAS,GAAG,OAAO,CAAC;AAE3D,UAAU,kBAAkB,CAAC,CAAC;IAC5B,QAAQ,EAAE,qBAAqB,CAAC;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAC;IAC/D,0EAA0E;IAC1E,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,KAAK,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,CAAC,CAAA;KAAE,CAAC,CAAC;IAChF,4DAA4D;IAC5D,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACzC,OAAO,CAAC,EAAE,mBAAmB,CAAC;CAC/B;AAwED,oGAAoG;AACpG,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,qBAAqB,GAAG,KAAK,CAWzG;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,MAAM,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CA2LjF"}
|
|
@@ -3,7 +3,7 @@ import { createInterface } from 'node:readline';
|
|
|
3
3
|
import { EmailError } from '@fluxmail/core';
|
|
4
4
|
export const DEFAULT_OAUTH_CALLBACK_TIMEOUT_MS = 10 * 60 * 1000;
|
|
5
5
|
function providerName(provider) {
|
|
6
|
-
return
|
|
6
|
+
return { gmail: 'Google', outlook: 'Microsoft', cloud: 'Fluxmail Cloud' }[provider];
|
|
7
7
|
}
|
|
8
8
|
function checkCallback(url, params, callbackPath) {
|
|
9
9
|
if (url.pathname !== callbackPath)
|
|
@@ -62,6 +62,8 @@ function timeoutError(params, timeoutMs) {
|
|
|
62
62
|
export function callbackPortInUseError(error, port, provider) {
|
|
63
63
|
if (error.code !== 'EADDRINUSE')
|
|
64
64
|
return error;
|
|
65
|
+
if (provider === 'cloud')
|
|
66
|
+
return new Error(`OAuth callback port ${port} is already in use. Try again.`, { cause: error });
|
|
65
67
|
return new Error(`OAuth callback port ${port} is already in use.\n\n` +
|
|
66
68
|
'If Fluxmail is running with Docker Compose, connect the account inside the container:\n\n' +
|
|
67
69
|
` docker compose exec fluxmail fluxmail accounts add ${provider}\n\n` +
|
|
@@ -125,11 +127,11 @@ export function runOAuthCallbackFlow(params) {
|
|
|
125
127
|
return claimed || settled;
|
|
126
128
|
}
|
|
127
129
|
/** Exchange a claimed code, then report the outcome to whichever path supplied it. */
|
|
128
|
-
async function exchange(source, code) {
|
|
130
|
+
async function exchange(source, code, callback) {
|
|
129
131
|
claimed = true;
|
|
130
132
|
params.options?.onCallback?.(source);
|
|
131
133
|
try {
|
|
132
|
-
const { email, value } = await params.complete(code);
|
|
134
|
+
const { email, value } = await params.complete(code, callback);
|
|
133
135
|
settle(() => resolve(value));
|
|
134
136
|
return { email };
|
|
135
137
|
}
|
|
@@ -169,9 +171,9 @@ export function runOAuthCallbackFlow(params) {
|
|
|
169
171
|
respond(response, 400, `${check.message} You can close this tab.`);
|
|
170
172
|
return;
|
|
171
173
|
}
|
|
172
|
-
const outcome = await exchange('listener', check.code);
|
|
174
|
+
const outcome = await exchange('listener', check.code, url);
|
|
173
175
|
if (outcome.email !== undefined) {
|
|
174
|
-
respond(response, 200, callbackPage(`${outcome.email} is connected to Fluxmail`, 'The account is ready to use.'), true);
|
|
176
|
+
respond(response, 200, callbackPage(params.successTitle?.(outcome.email) ?? `${outcome.email} is connected to Fluxmail`, 'The account is ready to use.'), true);
|
|
175
177
|
return;
|
|
176
178
|
}
|
|
177
179
|
const failure = failureMessage(outcome.error);
|
|
@@ -205,7 +207,7 @@ export function runOAuthCallbackFlow(params) {
|
|
|
205
207
|
settle(() => reject(check.error));
|
|
206
208
|
return;
|
|
207
209
|
}
|
|
208
|
-
await exchange('pasted', check.code);
|
|
210
|
+
await exchange('pasted', check.code, url);
|
|
209
211
|
}
|
|
210
212
|
lines?.on('line', (line) => void handlePastedLine(line));
|
|
211
213
|
lines?.on('close', () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauthCallback.js","sourceRoot":"","sources":["../../src/accounts/oauthCallback.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAuB,MAAM,WAAW,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AA+B5C,MAAM,CAAC,MAAM,iCAAiC,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"oauthCallback.js","sourceRoot":"","sources":["../../src/accounts/oauthCallback.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAQA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAQA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AA8B1C,OAAO,EAAe,KAAK,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAgBpE,OAAO,EASL,KAAK,gBAAgB,EACtB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAQL,KAAK,SAAS,EAEf,MAAM,gBAAgB,CAAC;AAuCxB,OAAO,EAIL,KAAK,wBAAwB,EAC9B,MAAM,qBAAqB,CAAC;AA8C7B,UAAU,iBAAiB;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB;AAcD,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,iBAAiB,EAAE,gBAAgB,UAAQ,GAAG,gBAAgB,CAuB/G;AAED,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,iBAAiB,EACvB,QAAQ,EAAE,IAAI,CAAC,UAAU,EAAE,mBAAmB,CAAC,GAC9C,gBAAgB,CAQlB;AA0LD,MAAM,WAAW,iBAAiB;IAChC,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,qBAAqB,CAAC,EAAE,wBAAwB,CAAC;IACjD,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CACrD;AAyJD,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,KAAK,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAatF;AAED,UAAU,cAAc;IACtB,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC;CACnD;AAUD,wBAAsB,2BAA2B,IAAI,OAAO,CAAC,IAAI,CAAC,CAQjE;AAED,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAExE;AAED,mFAAmF;AACnF,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,iBAAsB,GAAG,OAAO,CA+jEzE;AAED,wBAAsB,MAAM,CAAC,IAAI,GAAE,SAAS,MAAM,EAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAQlF"}
|
package/dist/cli.js
CHANGED
|
@@ -10,6 +10,7 @@ import { Command } from 'commander';
|
|
|
10
10
|
import { serve } from '@hono/node-server';
|
|
11
11
|
import { serveStdio, StdioServerTransport } from '@modelcontextprotocol/server/stdio';
|
|
12
12
|
import { EmailError, isEmailError } from '@fluxmail/core';
|
|
13
|
+
import { PERMISSION_PRESET_NAMES } from '@fluxmail/core/mcp';
|
|
13
14
|
import { createContext } from './context.js';
|
|
14
15
|
import { RuntimeLifecycle } from './lifecycle.js';
|
|
15
16
|
import { configTomlPath, createConfigurationService, deploymentToml, readLoggingSettings, resolveDataDir, resolveStoreLocation, writeDeploymentConfig, } from './config.js';
|
|
@@ -29,13 +30,15 @@ import { VERSION } from './version.js';
|
|
|
29
30
|
import { inspectStoreCompatibility, MIN_SUPPORTED_STORE_FORMAT, openDb, openReadonlyDb, } from './storage/db.js';
|
|
30
31
|
import { customPermissionPolicy, ADMIN_CAPABILITIES, DEFAULT_PERMISSION_POLICY, DEFAULT_PERMISSION_PROFILE, isNamedPermissionProfile, MCP_CAPABILITIES, NAMED_PERMISSION_PROFILES, permissionPolicyForProfile, } from './permissions.js';
|
|
31
32
|
import { captureOperation, getTelemetry, installTelemetryStreamEndHandler, isTelemetryEnabled, setTelemetryEnabled, shutdownTelemetry, telemetryDisabledInAnyEnvironment, } from './telemetry.js';
|
|
32
|
-
import { apiErrorCode, CliCanceledError, apiRequestId, clearSessionToken, instanceClient, loadInstanceConfig, removeInstance, resolveInstance, resolveStdioInstance, saveLocalInstance, saveRemoteInstance, saveSessionToken, setRequestDeadlineMs, useInstance, } from './cliInstances.js';
|
|
33
|
+
import { cloudManagementError, apiErrorCode, CliCanceledError, apiRequestId, clearSessionToken, instanceClient, loadInstanceConfig, removeInstance, resolveInstance, resolveStdioInstance, saveLocalInstance, saveRemoteInstance, saveSessionToken, setRequestDeadlineMs, useInstance, validateRemoteServerUrl, } from './cliInstances.js';
|
|
34
|
+
import { DEFAULT_CLOUD_ORIGIN, loginToCloud, logoutOfCloud, openInBrowser, replaceCloudSession, } from './cliCloudAuth.js';
|
|
35
|
+
import { CloudMailBackend, mailBackend } from './cliMailBackend.js';
|
|
33
36
|
import { cliExitCode, parseOutputFormat, printOutput } from './cliOutput.js';
|
|
34
37
|
import { CliStartupError, cliStartupDiagnostics } from './cliStartupDiagnostics.js';
|
|
35
38
|
import { authenticateBearer, isBootstrapComplete, normalizeAndValidatePassword, recoverAdminPassword, setupInitialAdmin, } from './auth.js';
|
|
36
39
|
import { recordAdminAuditEvent } from './storage/adminAudit.js';
|
|
37
40
|
import { canManageOwnedAccount } from './authorization.js';
|
|
38
|
-
import { createCliUpdateNotifier } from './updateNotifier.js';
|
|
41
|
+
import { createCliUpdateNotifier, startMcpUpdateCheck, } from './updateNotifier.js';
|
|
39
42
|
import { registerMailCommands } from './cliMail.js';
|
|
40
43
|
import { accountInventoryProperties, connectionFailureKind, configuredOAuthAppKind, connectionProperties, instanceUsageProperties, } from './accounts/telemetry.js';
|
|
41
44
|
import { flushLogging, escapeLogTextForConsole, getLogger, logCodedFailure, logFailure, readLocalLogs, shutdownLogging, } from './logging.js';
|
|
@@ -407,7 +410,7 @@ export function createCliProgram(options = {}) {
|
|
|
407
410
|
program
|
|
408
411
|
.name('fluxmail')
|
|
409
412
|
.description('Fluxmail, a self-hosted email API with MCP, REST, and CLI access')
|
|
410
|
-
.option('--instance <name>', 'Use a named local or
|
|
413
|
+
.option('--instance <name>', 'Use a named local, remote, or Fluxmail Cloud instance')
|
|
411
414
|
.option('-a, --mail-account <id-or-email>', 'Use an email account by ID or address')
|
|
412
415
|
.option('--format <format>', 'Output format: json, table, or ndjson', 'json')
|
|
413
416
|
.option('--timeout <seconds>', 'Request deadline in seconds (1 to 300)', '30')
|
|
@@ -459,7 +462,8 @@ export function createCliProgram(options = {}) {
|
|
|
459
462
|
setRequestDeadlineMs(Number(program.opts().timeout) * 1000);
|
|
460
463
|
const command = commandPath(actionCommand);
|
|
461
464
|
const updateNotifierEnabled = program.opts().updateNotifier;
|
|
462
|
-
|
|
465
|
+
// Servers run their own update checks.
|
|
466
|
+
if (updateNotifierEnabled && actionCommand.name() !== 'stdio' && actionCommand.name() !== 'serve') {
|
|
463
467
|
try {
|
|
464
468
|
const notifier = options.updateNotifierFactory?.();
|
|
465
469
|
if (notifier)
|
|
@@ -510,6 +514,17 @@ export function createCliProgram(options = {}) {
|
|
|
510
514
|
initialExitCode: process.exitCode,
|
|
511
515
|
logger: getLogger(dataDir, mode, logging),
|
|
512
516
|
});
|
|
517
|
+
if (mode === 'cli') {
|
|
518
|
+
try {
|
|
519
|
+
const config = loadInstanceConfig();
|
|
520
|
+
const kind = config.instances[selectedInstance() ?? config.active ?? '']?.kind;
|
|
521
|
+
if (kind === 'cloud')
|
|
522
|
+
recordCliOperationProperties(program, { instance_kind: kind });
|
|
523
|
+
}
|
|
524
|
+
catch {
|
|
525
|
+
// The command action reports an unreadable profile file.
|
|
526
|
+
}
|
|
527
|
+
}
|
|
513
528
|
const [group, action] = command.split(' ');
|
|
514
529
|
const alreadyStructured = ['folders', 'labels', 'emails', 'threads', 'drafts', 'scheduled', 'attachments'].includes(group ?? '') ||
|
|
515
530
|
command === 'accounts list' ||
|
|
@@ -572,6 +587,52 @@ export function createCliProgram(options = {}) {
|
|
|
572
587
|
}
|
|
573
588
|
}
|
|
574
589
|
});
|
|
590
|
+
async function cloudLogin(name, existing, opts) {
|
|
591
|
+
recordCliOperationProperties(program, { instance_kind: 'cloud' });
|
|
592
|
+
if (existing && existing.kind !== 'cloud') {
|
|
593
|
+
throw new EmailError('invalid_request', `Instance "${name}" is not a Fluxmail Cloud profile. Choose another name.`);
|
|
594
|
+
}
|
|
595
|
+
if (opts.email || opts.enroll || opts.reset) {
|
|
596
|
+
throw new EmailError('invalid_request', '--email, --enroll, and --reset do not apply to Fluxmail Cloud.');
|
|
597
|
+
}
|
|
598
|
+
if (opts.apiKey && opts.profile) {
|
|
599
|
+
throw new EmailError('invalid_request', 'An API key has its own permissions, so --profile does not apply.');
|
|
600
|
+
}
|
|
601
|
+
const preset = opts.profile ?? 'full';
|
|
602
|
+
if (!PERMISSION_PRESET_NAMES.includes(preset)) {
|
|
603
|
+
throw new EmailError('invalid_request', '--profile must be read-only, read-write, or full.');
|
|
604
|
+
}
|
|
605
|
+
const serverUrl = validateRemoteServerUrl(opts.server ?? existing?.serverUrl ?? DEFAULT_CLOUD_ORIGIN);
|
|
606
|
+
const profile = { kind: 'cloud', serverUrl };
|
|
607
|
+
if (opts.apiKey) {
|
|
608
|
+
const key = (process.env.FLUXMAIL_CLOUD_API_KEY ?? (await hiddenPrompt('Cloud API key'))).trim();
|
|
609
|
+
if (!key.startsWith('fm_'))
|
|
610
|
+
throw new EmailError('invalid_request', 'Fluxmail Cloud API keys start with fm_.');
|
|
611
|
+
// Check the key before it replaces a working session.
|
|
612
|
+
await new CloudMailBackend(name, profile, key).status();
|
|
613
|
+
await replaceCloudSession(name, { kind: 'key', key, serverUrl });
|
|
614
|
+
}
|
|
615
|
+
else {
|
|
616
|
+
await loginToCloud({
|
|
617
|
+
instance: name,
|
|
618
|
+
serverUrl,
|
|
619
|
+
preset: preset,
|
|
620
|
+
flow: process.stdin.isTTY
|
|
621
|
+
? { paste: { input: process.stdin, write: (message) => console.error(message) } }
|
|
622
|
+
: undefined,
|
|
623
|
+
onAuthUrl: (url, { pasteEnabled }) => {
|
|
624
|
+
console.error(`Sign in to Fluxmail Cloud and approve access:\n\n ${url}\n`);
|
|
625
|
+
if (pasteEnabled) {
|
|
626
|
+
console.error('If your browser runs on another computer, paste the URL it lands on here.');
|
|
627
|
+
}
|
|
628
|
+
if (process.stdout.isTTY)
|
|
629
|
+
openInBrowser(url);
|
|
630
|
+
},
|
|
631
|
+
});
|
|
632
|
+
}
|
|
633
|
+
useInstance(name);
|
|
634
|
+
console.log(`Logged in to ${name}.`);
|
|
635
|
+
}
|
|
575
636
|
program
|
|
576
637
|
.command('setup')
|
|
577
638
|
.description('Create the first local administrator or claim a migrated administrator')
|
|
@@ -614,11 +675,14 @@ export function createCliProgram(options = {}) {
|
|
|
614
675
|
});
|
|
615
676
|
program
|
|
616
677
|
.command('login')
|
|
617
|
-
.description('Log in to a local or remote instance')
|
|
678
|
+
.description('Log in to a local or remote instance, or to Fluxmail Cloud')
|
|
618
679
|
.option('--server <url>', 'Add or update a remote instance')
|
|
619
680
|
.option('--email <email>', 'Member email')
|
|
620
681
|
.option('--enroll', 'Use a one-time enrollment code')
|
|
621
682
|
.option('--reset', 'Use a one-time password reset code')
|
|
683
|
+
.option('--cloud', 'Log in to Fluxmail Cloud in a browser')
|
|
684
|
+
.option('--api-key', 'With --cloud, use a Cloud API key instead of a browser')
|
|
685
|
+
.option('--profile <profile>', 'With --cloud, the permissions to request: read-only, read-write, or full')
|
|
622
686
|
.action(async (opts) => {
|
|
623
687
|
try {
|
|
624
688
|
if (opts.enroll && opts.reset) {
|
|
@@ -626,6 +690,18 @@ export function createCliProgram(options = {}) {
|
|
|
626
690
|
}
|
|
627
691
|
const requestedInstance = selectedInstance();
|
|
628
692
|
const instanceConfig = loadInstanceConfig();
|
|
693
|
+
const namedProfile = instanceConfig.instances[requestedInstance ?? instanceConfig.active ?? ''];
|
|
694
|
+
if (opts.cloud || (namedProfile?.kind === 'cloud' && !opts.server)) {
|
|
695
|
+
const name = requestedInstance ?? (namedProfile?.kind === 'cloud' ? instanceConfig.active : 'cloud');
|
|
696
|
+
await cloudLogin(name, instanceConfig.instances[name], opts);
|
|
697
|
+
return;
|
|
698
|
+
}
|
|
699
|
+
if (opts.apiKey || opts.profile) {
|
|
700
|
+
throw new EmailError('invalid_request', '--api-key and --profile require --cloud.');
|
|
701
|
+
}
|
|
702
|
+
if (opts.server && requestedInstance && namedProfile?.kind === 'cloud') {
|
|
703
|
+
throw new EmailError('invalid_request', `Instance "${requestedInstance}" is a Fluxmail Cloud profile.`);
|
|
704
|
+
}
|
|
629
705
|
if (!opts.server &&
|
|
630
706
|
!instanceConfig.instances.local &&
|
|
631
707
|
(requestedInstance === 'local' || (!requestedInstance && Object.keys(instanceConfig.instances).length === 0))) {
|
|
@@ -669,6 +745,13 @@ export function createCliProgram(options = {}) {
|
|
|
669
745
|
.action(async () => {
|
|
670
746
|
try {
|
|
671
747
|
const selected = resolveInstance(selectedInstance());
|
|
748
|
+
if (selected.profile.kind === 'cloud') {
|
|
749
|
+
const { revoked } = await logoutOfCloud(selected.name);
|
|
750
|
+
console.log(revoked
|
|
751
|
+
? `Logged out of ${selected.name}.`
|
|
752
|
+
: `Removed the credentials for ${selected.name}. To end access, revoke it at ${selected.profile.serverUrl}.`);
|
|
753
|
+
return;
|
|
754
|
+
}
|
|
672
755
|
const response = await instanceClient(selected.name).request('/api/v1/auth/logout', { method: 'POST' });
|
|
673
756
|
if (!response.ok && response.status !== 401) {
|
|
674
757
|
throw new EmailError('invalid_request', `Logout failed with HTTP ${response.status}.`);
|
|
@@ -690,7 +773,7 @@ export function createCliProgram(options = {}) {
|
|
|
690
773
|
name,
|
|
691
774
|
active: config.active === name ? '*' : '',
|
|
692
775
|
kind: profile.kind,
|
|
693
|
-
url: profile.kind === '
|
|
776
|
+
url: profile.kind === 'local' ? '' : profile.serverUrl,
|
|
694
777
|
}));
|
|
695
778
|
const width = (values) => Math.max(...values.map((value) => value.length));
|
|
696
779
|
const nameWidth = width(['NAME', ...rows.map((row) => row.name)]);
|
|
@@ -835,6 +918,8 @@ export function createCliProgram(options = {}) {
|
|
|
835
918
|
warnLicense(ctx.db, console.log);
|
|
836
919
|
ctx.licenseController.start();
|
|
837
920
|
ctx.scheduler.start();
|
|
921
|
+
if (program.opts().updateNotifier)
|
|
922
|
+
ctx.updateCheck.start();
|
|
838
923
|
}
|
|
839
924
|
catch (error) {
|
|
840
925
|
finishCliOperation(program, 'error', apiErrorCode(error), error);
|
|
@@ -881,6 +966,9 @@ export function createCliProgram(options = {}) {
|
|
|
881
966
|
telemetry: ctx.telemetry,
|
|
882
967
|
transport: 'stdio',
|
|
883
968
|
logger: ctx.logger,
|
|
969
|
+
...(program.opts().updateNotifier
|
|
970
|
+
? { availableUpdate: startMcpUpdateCheck() }
|
|
971
|
+
: {}),
|
|
884
972
|
};
|
|
885
973
|
installTelemetrySignalHandlers();
|
|
886
974
|
installStdioShutdownHandler(process.stdin);
|
|
@@ -945,8 +1033,7 @@ export function createCliProgram(options = {}) {
|
|
|
945
1033
|
.description('List available sender addresses')
|
|
946
1034
|
.action(async (accountId) => {
|
|
947
1035
|
try {
|
|
948
|
-
|
|
949
|
-
console.log(JSON.stringify(identities, null, 2));
|
|
1036
|
+
console.log(JSON.stringify(await mailBackend(selectedInstance()).listSendAs(accountId), null, 2));
|
|
950
1037
|
}
|
|
951
1038
|
catch (err) {
|
|
952
1039
|
failCliOperation(program, err);
|
|
@@ -1037,6 +1124,10 @@ export function createCliProgram(options = {}) {
|
|
|
1037
1124
|
return;
|
|
1038
1125
|
}
|
|
1039
1126
|
const selected = resolveInstance(selectedInstance());
|
|
1127
|
+
if (selected.profile.kind === 'cloud') {
|
|
1128
|
+
failCliOperation(program, cloudManagementError(selected.profile, '/mailboxes'));
|
|
1129
|
+
return;
|
|
1130
|
+
}
|
|
1040
1131
|
// A remote instance reconnects an IMAP mailbox that matches the address,
|
|
1041
1132
|
// so without --reauthorize only the server knows which one this is.
|
|
1042
1133
|
const reauthorize = opts.reauthorize !== undefined
|
|
@@ -1369,8 +1460,7 @@ export function createCliProgram(options = {}) {
|
|
|
1369
1460
|
.description('List connected accounts')
|
|
1370
1461
|
.action(async () => {
|
|
1371
1462
|
try {
|
|
1372
|
-
|
|
1373
|
-
printOutput({ data: all }, selectedFormat());
|
|
1463
|
+
printOutput({ data: await mailBackend(selectedInstance()).listAccounts() }, selectedFormat());
|
|
1374
1464
|
}
|
|
1375
1465
|
catch (err) {
|
|
1376
1466
|
failCliOperation(program, err);
|
|
@@ -2141,8 +2231,7 @@ export function createCliProgram(options = {}) {
|
|
|
2141
2231
|
.description('Show mailbox and provider status for the selected instance')
|
|
2142
2232
|
.action(async () => {
|
|
2143
2233
|
try {
|
|
2144
|
-
|
|
2145
|
-
printOutput({ data: status }, selectedFormat());
|
|
2234
|
+
printOutput({ data: await mailBackend(selectedInstance()).status() }, selectedFormat());
|
|
2146
2235
|
}
|
|
2147
2236
|
catch (err) {
|
|
2148
2237
|
failCliOperation(program, err);
|