@base44-preview/cli 0.0.15-pr.98.72adf3c → 0.0.15-pr.99.e192f83
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/cli/index.js +441 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -4547,6 +4547,7 @@ const string$1 = (params) => {
|
|
|
4547
4547
|
};
|
|
4548
4548
|
const integer = /^-?\d+$/;
|
|
4549
4549
|
const number$1 = /^-?\d+(?:\.\d+)?$/;
|
|
4550
|
+
const boolean$1 = /^(?:true|false)$/i;
|
|
4550
4551
|
const lowercase = /^[^A-Z]*$/;
|
|
4551
4552
|
const uppercase = /^[^a-z]*$/;
|
|
4552
4553
|
|
|
@@ -5325,6 +5326,24 @@ const $ZodNumberFormat = /* @__PURE__ */ $constructor("$ZodNumberFormat", (inst,
|
|
|
5325
5326
|
$ZodCheckNumberFormat.init(inst, def);
|
|
5326
5327
|
$ZodNumber.init(inst, def);
|
|
5327
5328
|
});
|
|
5329
|
+
const $ZodBoolean = /* @__PURE__ */ $constructor("$ZodBoolean", (inst, def) => {
|
|
5330
|
+
$ZodType.init(inst, def);
|
|
5331
|
+
inst._zod.pattern = boolean$1;
|
|
5332
|
+
inst._zod.parse = (payload, _ctx) => {
|
|
5333
|
+
if (def.coerce) try {
|
|
5334
|
+
payload.value = Boolean(payload.value);
|
|
5335
|
+
} catch (_$2) {}
|
|
5336
|
+
const input = payload.value;
|
|
5337
|
+
if (typeof input === "boolean") return payload;
|
|
5338
|
+
payload.issues.push({
|
|
5339
|
+
expected: "boolean",
|
|
5340
|
+
code: "invalid_type",
|
|
5341
|
+
input,
|
|
5342
|
+
inst
|
|
5343
|
+
});
|
|
5344
|
+
return payload;
|
|
5345
|
+
};
|
|
5346
|
+
});
|
|
5328
5347
|
const $ZodUnknown = /* @__PURE__ */ $constructor("$ZodUnknown", (inst, def) => {
|
|
5329
5348
|
$ZodType.init(inst, def);
|
|
5330
5349
|
inst._zod.parse = (payload) => payload;
|
|
@@ -6379,6 +6398,13 @@ function _int(Class, params) {
|
|
|
6379
6398
|
});
|
|
6380
6399
|
}
|
|
6381
6400
|
/* @__NO_SIDE_EFFECTS__ */
|
|
6401
|
+
function _boolean(Class, params) {
|
|
6402
|
+
return new Class({
|
|
6403
|
+
type: "boolean",
|
|
6404
|
+
...normalizeParams(params)
|
|
6405
|
+
});
|
|
6406
|
+
}
|
|
6407
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
6382
6408
|
function _unknown(Class) {
|
|
6383
6409
|
return new Class({ type: "unknown" });
|
|
6384
6410
|
}
|
|
@@ -6949,6 +6975,9 @@ const numberProcessor = (schema, ctx, _json, _params) => {
|
|
|
6949
6975
|
}
|
|
6950
6976
|
if (typeof multipleOf === "number") json.multipleOf = multipleOf;
|
|
6951
6977
|
};
|
|
6978
|
+
const booleanProcessor = (_schema, _ctx, json, _params) => {
|
|
6979
|
+
json.type = "boolean";
|
|
6980
|
+
};
|
|
6952
6981
|
const neverProcessor = (_schema, _ctx, json, _params) => {
|
|
6953
6982
|
json.not = {};
|
|
6954
6983
|
};
|
|
@@ -7472,6 +7501,14 @@ const ZodNumberFormat = /* @__PURE__ */ $constructor("ZodNumberFormat", (inst, d
|
|
|
7472
7501
|
function int(params) {
|
|
7473
7502
|
return _int(ZodNumberFormat, params);
|
|
7474
7503
|
}
|
|
7504
|
+
const ZodBoolean = /* @__PURE__ */ $constructor("ZodBoolean", (inst, def) => {
|
|
7505
|
+
$ZodBoolean.init(inst, def);
|
|
7506
|
+
ZodType.init(inst, def);
|
|
7507
|
+
inst._zod.processJSONSchema = (ctx, json, params) => booleanProcessor(inst, ctx, json, params);
|
|
7508
|
+
});
|
|
7509
|
+
function boolean(params) {
|
|
7510
|
+
return _boolean(ZodBoolean, params);
|
|
7511
|
+
}
|
|
7475
7512
|
const ZodUnknown = /* @__PURE__ */ $constructor("ZodUnknown", (inst, def) => {
|
|
7476
7513
|
$ZodUnknown.init(inst, def);
|
|
7477
7514
|
ZodType.init(inst, def);
|
|
@@ -7863,6 +7900,19 @@ var AuthValidationError = class extends Error {
|
|
|
7863
7900
|
this.name = "AuthValidationError";
|
|
7864
7901
|
}
|
|
7865
7902
|
};
|
|
7903
|
+
var ConnectorApiError = class extends Error {
|
|
7904
|
+
constructor(message, cause) {
|
|
7905
|
+
super(message);
|
|
7906
|
+
this.cause = cause;
|
|
7907
|
+
this.name = "ConnectorApiError";
|
|
7908
|
+
}
|
|
7909
|
+
};
|
|
7910
|
+
var ConnectorValidationError = class extends Error {
|
|
7911
|
+
constructor(message) {
|
|
7912
|
+
super(message);
|
|
7913
|
+
this.name = "ConnectorValidationError";
|
|
7914
|
+
}
|
|
7915
|
+
};
|
|
7866
7916
|
|
|
7867
7917
|
//#endregion
|
|
7868
7918
|
//#region src/core/consts.ts
|
|
@@ -30955,7 +31005,10 @@ const theme = {
|
|
|
30955
31005
|
base44OrangeBackground: source_default.bgHex("#E86B3C"),
|
|
30956
31006
|
shinyOrange: source_default.hex("#FFD700"),
|
|
30957
31007
|
links: source_default.hex("#00D4FF"),
|
|
30958
|
-
white: source_default.white
|
|
31008
|
+
white: source_default.white,
|
|
31009
|
+
success: source_default.green,
|
|
31010
|
+
warning: source_default.yellow,
|
|
31011
|
+
error: source_default.red
|
|
30959
31012
|
},
|
|
30960
31013
|
styles: {
|
|
30961
31014
|
header: source_default.dim,
|
|
@@ -38789,6 +38842,390 @@ const siteDeployCommand = new Command("site").description("Manage site deploymen
|
|
|
38789
38842
|
await runCommand(() => deployAction(options), { requireAuth: true });
|
|
38790
38843
|
}));
|
|
38791
38844
|
|
|
38845
|
+
//#endregion
|
|
38846
|
+
//#region src/core/connectors/schema.ts
|
|
38847
|
+
/**
|
|
38848
|
+
* Response from POST /api/apps/{app_id}/external-auth/initiate
|
|
38849
|
+
*/
|
|
38850
|
+
const InitiateResponseSchema = object({
|
|
38851
|
+
redirect_url: string().optional(),
|
|
38852
|
+
connection_id: string().optional(),
|
|
38853
|
+
already_authorized: boolean().optional(),
|
|
38854
|
+
other_user_email: string().optional(),
|
|
38855
|
+
error: string().optional()
|
|
38856
|
+
});
|
|
38857
|
+
/**
|
|
38858
|
+
* Response from GET /api/apps/{app_id}/external-auth/status
|
|
38859
|
+
*/
|
|
38860
|
+
const StatusResponseSchema = object({
|
|
38861
|
+
status: _enum([
|
|
38862
|
+
"ACTIVE",
|
|
38863
|
+
"PENDING",
|
|
38864
|
+
"FAILED"
|
|
38865
|
+
]),
|
|
38866
|
+
account_email: string().optional(),
|
|
38867
|
+
error: string().optional()
|
|
38868
|
+
});
|
|
38869
|
+
/**
|
|
38870
|
+
* A connected integration from the list endpoint
|
|
38871
|
+
*/
|
|
38872
|
+
const ConnectorSchema = object({
|
|
38873
|
+
integration_type: string(),
|
|
38874
|
+
status: string(),
|
|
38875
|
+
connected_at: string().optional(),
|
|
38876
|
+
account_info: object({
|
|
38877
|
+
email: string().optional(),
|
|
38878
|
+
name: string().optional()
|
|
38879
|
+
}).optional()
|
|
38880
|
+
}).transform((data) => ({
|
|
38881
|
+
integrationType: data.integration_type,
|
|
38882
|
+
status: data.status,
|
|
38883
|
+
connectedAt: data.connected_at,
|
|
38884
|
+
accountInfo: data.account_info
|
|
38885
|
+
}));
|
|
38886
|
+
/**
|
|
38887
|
+
* Response from GET /api/apps/{app_id}/external-auth/list
|
|
38888
|
+
*/
|
|
38889
|
+
const ListResponseSchema = object({ integrations: array(ConnectorSchema) });
|
|
38890
|
+
/**
|
|
38891
|
+
* Generic API error response
|
|
38892
|
+
*/
|
|
38893
|
+
const ApiErrorSchema = object({
|
|
38894
|
+
error: string(),
|
|
38895
|
+
detail: string().optional()
|
|
38896
|
+
});
|
|
38897
|
+
|
|
38898
|
+
//#endregion
|
|
38899
|
+
//#region src/core/connectors/api.ts
|
|
38900
|
+
/**
|
|
38901
|
+
* Initiates OAuth flow for a connector integration.
|
|
38902
|
+
* Returns a redirect URL to open in the browser.
|
|
38903
|
+
*/
|
|
38904
|
+
async function initiateOAuth(integrationType, scopes = null) {
|
|
38905
|
+
const response = await getAppClient().post("external-auth/initiate", {
|
|
38906
|
+
json: {
|
|
38907
|
+
integration_type: integrationType,
|
|
38908
|
+
scopes
|
|
38909
|
+
},
|
|
38910
|
+
throwHttpErrors: false
|
|
38911
|
+
});
|
|
38912
|
+
const json = await response.json();
|
|
38913
|
+
if (!response.ok) {
|
|
38914
|
+
const errorResult = ApiErrorSchema.safeParse(json);
|
|
38915
|
+
if (errorResult.success) throw new ConnectorApiError(errorResult.data.error);
|
|
38916
|
+
throw new ConnectorApiError(`Failed to initiate OAuth: ${response.status} ${response.statusText}`);
|
|
38917
|
+
}
|
|
38918
|
+
const result = InitiateResponseSchema.safeParse(json);
|
|
38919
|
+
if (!result.success) throw new ConnectorValidationError(`Invalid initiate response from server: ${result.error.message}`);
|
|
38920
|
+
return result.data;
|
|
38921
|
+
}
|
|
38922
|
+
/**
|
|
38923
|
+
* Checks the status of an OAuth connection attempt.
|
|
38924
|
+
*/
|
|
38925
|
+
async function checkOAuthStatus(integrationType, connectionId) {
|
|
38926
|
+
const response = await getAppClient().get("external-auth/status", {
|
|
38927
|
+
searchParams: {
|
|
38928
|
+
integration_type: integrationType,
|
|
38929
|
+
connection_id: connectionId
|
|
38930
|
+
},
|
|
38931
|
+
throwHttpErrors: false
|
|
38932
|
+
});
|
|
38933
|
+
const json = await response.json();
|
|
38934
|
+
if (!response.ok) {
|
|
38935
|
+
const errorResult = ApiErrorSchema.safeParse(json);
|
|
38936
|
+
if (errorResult.success) throw new ConnectorApiError(errorResult.data.error);
|
|
38937
|
+
throw new ConnectorApiError(`Failed to check OAuth status: ${response.status} ${response.statusText}`);
|
|
38938
|
+
}
|
|
38939
|
+
const result = StatusResponseSchema.safeParse(json);
|
|
38940
|
+
if (!result.success) throw new ConnectorValidationError(`Invalid status response from server: ${result.error.message}`);
|
|
38941
|
+
return result.data;
|
|
38942
|
+
}
|
|
38943
|
+
/**
|
|
38944
|
+
* Lists all connected integrations for the current app.
|
|
38945
|
+
*/
|
|
38946
|
+
async function listConnectors() {
|
|
38947
|
+
const response = await getAppClient().get("external-auth/list", { throwHttpErrors: false });
|
|
38948
|
+
const json = await response.json();
|
|
38949
|
+
if (!response.ok) {
|
|
38950
|
+
const errorResult = ApiErrorSchema.safeParse(json);
|
|
38951
|
+
if (errorResult.success) throw new ConnectorApiError(errorResult.data.error);
|
|
38952
|
+
throw new ConnectorApiError(`Failed to list connectors: ${response.status} ${response.statusText}`);
|
|
38953
|
+
}
|
|
38954
|
+
const result = ListResponseSchema.safeParse(json);
|
|
38955
|
+
if (!result.success) throw new ConnectorValidationError(`Invalid list response from server: ${result.error.message}`);
|
|
38956
|
+
return result.data.integrations;
|
|
38957
|
+
}
|
|
38958
|
+
/**
|
|
38959
|
+
* Disconnects (soft delete) a connector integration.
|
|
38960
|
+
*/
|
|
38961
|
+
async function disconnectConnector(integrationType) {
|
|
38962
|
+
const response = await getAppClient().delete(`external-auth/integrations/${integrationType}`, { throwHttpErrors: false });
|
|
38963
|
+
if (!response.ok) {
|
|
38964
|
+
const json = await response.json();
|
|
38965
|
+
const errorResult = ApiErrorSchema.safeParse(json);
|
|
38966
|
+
if (errorResult.success) throw new ConnectorApiError(errorResult.data.error);
|
|
38967
|
+
throw new ConnectorApiError(`Failed to disconnect connector: ${response.status} ${response.statusText}`);
|
|
38968
|
+
}
|
|
38969
|
+
}
|
|
38970
|
+
|
|
38971
|
+
//#endregion
|
|
38972
|
+
//#region src/core/connectors/constants.ts
|
|
38973
|
+
/**
|
|
38974
|
+
* Supported OAuth connector integrations.
|
|
38975
|
+
* Based on apper/backend/app/external_auth/models/constants.py
|
|
38976
|
+
*/
|
|
38977
|
+
const SUPPORTED_INTEGRATIONS = [
|
|
38978
|
+
"googlecalendar",
|
|
38979
|
+
"googledrive",
|
|
38980
|
+
"gmail",
|
|
38981
|
+
"googlesheets",
|
|
38982
|
+
"googledocs",
|
|
38983
|
+
"googleslides",
|
|
38984
|
+
"slack",
|
|
38985
|
+
"notion",
|
|
38986
|
+
"salesforce",
|
|
38987
|
+
"hubspot",
|
|
38988
|
+
"linkedin",
|
|
38989
|
+
"tiktok"
|
|
38990
|
+
];
|
|
38991
|
+
/**
|
|
38992
|
+
* Display names for integrations (for CLI output)
|
|
38993
|
+
*/
|
|
38994
|
+
const INTEGRATION_DISPLAY_NAMES = {
|
|
38995
|
+
googlecalendar: "Google Calendar",
|
|
38996
|
+
googledrive: "Google Drive",
|
|
38997
|
+
gmail: "Gmail",
|
|
38998
|
+
googlesheets: "Google Sheets",
|
|
38999
|
+
googledocs: "Google Docs",
|
|
39000
|
+
googleslides: "Google Slides",
|
|
39001
|
+
slack: "Slack",
|
|
39002
|
+
notion: "Notion",
|
|
39003
|
+
salesforce: "Salesforce",
|
|
39004
|
+
hubspot: "HubSpot",
|
|
39005
|
+
linkedin: "LinkedIn",
|
|
39006
|
+
tiktok: "TikTok"
|
|
39007
|
+
};
|
|
39008
|
+
function isValidIntegration(type) {
|
|
39009
|
+
return SUPPORTED_INTEGRATIONS.includes(type);
|
|
39010
|
+
}
|
|
39011
|
+
function getIntegrationDisplayName(type) {
|
|
39012
|
+
if (isValidIntegration(type)) return INTEGRATION_DISPLAY_NAMES[type];
|
|
39013
|
+
return type;
|
|
39014
|
+
}
|
|
39015
|
+
|
|
39016
|
+
//#endregion
|
|
39017
|
+
//#region src/cli/commands/connectors/add.ts
|
|
39018
|
+
const POLL_INTERVAL_MS = 2e3;
|
|
39019
|
+
const POLL_TIMEOUT_MS = 300 * 1e3;
|
|
39020
|
+
async function promptForIntegrationType() {
|
|
39021
|
+
const selected = await ve({
|
|
39022
|
+
message: "Select an integration to connect:",
|
|
39023
|
+
options: SUPPORTED_INTEGRATIONS.map((type) => ({
|
|
39024
|
+
value: type,
|
|
39025
|
+
label: getIntegrationDisplayName(type)
|
|
39026
|
+
}))
|
|
39027
|
+
});
|
|
39028
|
+
if (pD(selected)) return null;
|
|
39029
|
+
return selected;
|
|
39030
|
+
}
|
|
39031
|
+
async function waitForOAuthCompletion(integrationType, connectionId) {
|
|
39032
|
+
let accountEmail;
|
|
39033
|
+
let error;
|
|
39034
|
+
try {
|
|
39035
|
+
await runTask("Waiting for authorization...", async (updateMessage) => {
|
|
39036
|
+
await pWaitFor(async () => {
|
|
39037
|
+
const status = await checkOAuthStatus(integrationType, connectionId);
|
|
39038
|
+
if (status.status === "ACTIVE") {
|
|
39039
|
+
accountEmail = status.account_email;
|
|
39040
|
+
return true;
|
|
39041
|
+
}
|
|
39042
|
+
if (status.status === "FAILED") {
|
|
39043
|
+
error = status.error || "Authorization failed";
|
|
39044
|
+
throw new Error(error);
|
|
39045
|
+
}
|
|
39046
|
+
updateMessage("Waiting for authorization in browser...");
|
|
39047
|
+
return false;
|
|
39048
|
+
}, {
|
|
39049
|
+
interval: POLL_INTERVAL_MS,
|
|
39050
|
+
timeout: POLL_TIMEOUT_MS
|
|
39051
|
+
});
|
|
39052
|
+
}, {
|
|
39053
|
+
successMessage: "Authorization completed!",
|
|
39054
|
+
errorMessage: "Authorization failed"
|
|
39055
|
+
});
|
|
39056
|
+
return {
|
|
39057
|
+
success: true,
|
|
39058
|
+
accountEmail
|
|
39059
|
+
};
|
|
39060
|
+
} catch (err) {
|
|
39061
|
+
if (err instanceof Error && err.message.includes("timed out")) return {
|
|
39062
|
+
success: false,
|
|
39063
|
+
error: "Authorization timed out. Please try again."
|
|
39064
|
+
};
|
|
39065
|
+
return {
|
|
39066
|
+
success: false,
|
|
39067
|
+
error: error || (err instanceof Error ? err.message : "Unknown error")
|
|
39068
|
+
};
|
|
39069
|
+
}
|
|
39070
|
+
}
|
|
39071
|
+
async function addConnector(integrationType) {
|
|
39072
|
+
let selectedType;
|
|
39073
|
+
if (!integrationType) {
|
|
39074
|
+
const prompted = await promptForIntegrationType();
|
|
39075
|
+
if (!prompted) return { outroMessage: "Cancelled" };
|
|
39076
|
+
selectedType = prompted;
|
|
39077
|
+
} else {
|
|
39078
|
+
if (!isValidIntegration(integrationType)) {
|
|
39079
|
+
const supportedList = SUPPORTED_INTEGRATIONS.join(", ");
|
|
39080
|
+
throw new Error(`Unsupported connector: ${integrationType}\nSupported connectors: ${supportedList}`);
|
|
39081
|
+
}
|
|
39082
|
+
selectedType = integrationType;
|
|
39083
|
+
}
|
|
39084
|
+
const displayName = getIntegrationDisplayName(selectedType);
|
|
39085
|
+
const initiateResponse = await runTask(`Initiating ${displayName} connection...`, async () => {
|
|
39086
|
+
return await initiateOAuth(selectedType);
|
|
39087
|
+
}, {
|
|
39088
|
+
successMessage: `${displayName} OAuth initiated`,
|
|
39089
|
+
errorMessage: `Failed to initiate ${displayName} connection`
|
|
39090
|
+
});
|
|
39091
|
+
if (initiateResponse.already_authorized) return { outroMessage: `Already connected to ${theme.styles.bold(displayName)}` };
|
|
39092
|
+
if (initiateResponse.error === "different_user" && initiateResponse.other_user_email) throw new Error(`This app is already connected to ${displayName} by ${initiateResponse.other_user_email}`);
|
|
39093
|
+
if (!initiateResponse.redirect_url || !initiateResponse.connection_id) throw new Error("Invalid response from server: missing redirect URL or connection ID");
|
|
39094
|
+
M.info(`Opening browser for ${displayName} authorization...`);
|
|
39095
|
+
await open_default(initiateResponse.redirect_url);
|
|
39096
|
+
const result = await waitForOAuthCompletion(selectedType, initiateResponse.connection_id);
|
|
39097
|
+
if (!result.success) throw new Error(result.error || "Authorization failed");
|
|
39098
|
+
const accountInfo = result.accountEmail ? ` as ${theme.styles.bold(result.accountEmail)}` : "";
|
|
39099
|
+
return { outroMessage: `Successfully connected to ${theme.styles.bold(displayName)}${accountInfo}` };
|
|
39100
|
+
}
|
|
39101
|
+
const connectorsAddCommand = new Command("connectors:add").argument("[type]", "Integration type (e.g., slack, notion, googlecalendar)").description("Connect an OAuth integration").action(async (type) => {
|
|
39102
|
+
await runCommand(() => addConnector(type), {
|
|
39103
|
+
requireAuth: true,
|
|
39104
|
+
requireAppConfig: true
|
|
39105
|
+
});
|
|
39106
|
+
});
|
|
39107
|
+
|
|
39108
|
+
//#endregion
|
|
39109
|
+
//#region src/cli/commands/connectors/list.ts
|
|
39110
|
+
function formatDate(dateString) {
|
|
39111
|
+
if (!dateString) return "-";
|
|
39112
|
+
try {
|
|
39113
|
+
return new Date(dateString).toLocaleDateString("en-US", {
|
|
39114
|
+
year: "numeric",
|
|
39115
|
+
month: "short",
|
|
39116
|
+
day: "numeric"
|
|
39117
|
+
});
|
|
39118
|
+
} catch {
|
|
39119
|
+
return dateString;
|
|
39120
|
+
}
|
|
39121
|
+
}
|
|
39122
|
+
function formatStatus(status) {
|
|
39123
|
+
const normalized = status.toLowerCase();
|
|
39124
|
+
if (normalized === "active" || normalized === "connected") return theme.colors.success("● active");
|
|
39125
|
+
if (normalized === "expired") return theme.colors.warning("● expired");
|
|
39126
|
+
if (normalized === "failed" || normalized === "disconnected") return theme.colors.error("● disconnected");
|
|
39127
|
+
return status;
|
|
39128
|
+
}
|
|
39129
|
+
async function listConnectorsCommand() {
|
|
39130
|
+
const connectors = await runTask("Fetching connectors...", async () => {
|
|
39131
|
+
return await listConnectors();
|
|
39132
|
+
}, {
|
|
39133
|
+
successMessage: "Connectors loaded",
|
|
39134
|
+
errorMessage: "Failed to fetch connectors"
|
|
39135
|
+
});
|
|
39136
|
+
if (connectors.length === 0) {
|
|
39137
|
+
M.info("No connectors configured for this app.");
|
|
39138
|
+
M.info(`Run ${theme.styles.bold("base44 connectors:add")} to connect an integration.`);
|
|
39139
|
+
return { outroMessage: "" };
|
|
39140
|
+
}
|
|
39141
|
+
console.log();
|
|
39142
|
+
console.log(theme.styles.bold("Connected Integrations:"));
|
|
39143
|
+
console.log();
|
|
39144
|
+
const headers = [
|
|
39145
|
+
"Type",
|
|
39146
|
+
"Account",
|
|
39147
|
+
"Status",
|
|
39148
|
+
"Connected"
|
|
39149
|
+
];
|
|
39150
|
+
const colWidths = [
|
|
39151
|
+
20,
|
|
39152
|
+
30,
|
|
39153
|
+
15,
|
|
39154
|
+
15
|
|
39155
|
+
];
|
|
39156
|
+
const headerRow = headers.map((h$2, i$1) => h$2.padEnd(colWidths[i$1])).join(" ");
|
|
39157
|
+
console.log(theme.styles.dim(headerRow));
|
|
39158
|
+
console.log(theme.styles.dim("─".repeat(headerRow.length)));
|
|
39159
|
+
for (const connector of connectors) {
|
|
39160
|
+
const type = getIntegrationDisplayName(connector.integrationType).padEnd(colWidths[0]);
|
|
39161
|
+
const account = (connector.accountInfo?.email || connector.accountInfo?.name || "-").padEnd(colWidths[1]);
|
|
39162
|
+
const status = formatStatus(connector.status);
|
|
39163
|
+
const connected = formatDate(connector.connectedAt).padEnd(colWidths[3]);
|
|
39164
|
+
console.log(`${type} ${account} ${status.padEnd(colWidths[2] + 10)} ${connected}`);
|
|
39165
|
+
}
|
|
39166
|
+
console.log();
|
|
39167
|
+
return { outroMessage: `${connectors.length} connector${connectors.length === 1 ? "" : "s"} configured` };
|
|
39168
|
+
}
|
|
39169
|
+
const connectorsListCommand = new Command("connectors:list").description("List all connected OAuth integrations").action(async () => {
|
|
39170
|
+
await runCommand(listConnectorsCommand, {
|
|
39171
|
+
requireAuth: true,
|
|
39172
|
+
requireAppConfig: true
|
|
39173
|
+
});
|
|
39174
|
+
});
|
|
39175
|
+
|
|
39176
|
+
//#endregion
|
|
39177
|
+
//#region src/cli/commands/connectors/remove.ts
|
|
39178
|
+
async function promptForConnectorToRemove(connectors) {
|
|
39179
|
+
const selected = await ve({
|
|
39180
|
+
message: "Select a connector to remove:",
|
|
39181
|
+
options: connectors.map((c$1) => ({
|
|
39182
|
+
value: c$1.integrationType,
|
|
39183
|
+
label: `${getIntegrationDisplayName(c$1.integrationType)}${c$1.accountInfo?.email ? ` (${c$1.accountInfo.email})` : ""}`
|
|
39184
|
+
}))
|
|
39185
|
+
});
|
|
39186
|
+
if (pD(selected)) return null;
|
|
39187
|
+
return selected;
|
|
39188
|
+
}
|
|
39189
|
+
async function removeConnectorCommand(integrationType) {
|
|
39190
|
+
const connectors = await runTask("Fetching connectors...", async () => {
|
|
39191
|
+
return await listConnectors();
|
|
39192
|
+
}, {
|
|
39193
|
+
successMessage: "Connectors loaded",
|
|
39194
|
+
errorMessage: "Failed to fetch connectors"
|
|
39195
|
+
});
|
|
39196
|
+
if (connectors.length === 0) return { outroMessage: "No connectors to remove" };
|
|
39197
|
+
let selectedType;
|
|
39198
|
+
if (!integrationType) {
|
|
39199
|
+
const prompted = await promptForConnectorToRemove(connectors);
|
|
39200
|
+
if (!prompted) return { outroMessage: "Cancelled" };
|
|
39201
|
+
selectedType = prompted;
|
|
39202
|
+
} else {
|
|
39203
|
+
if (!isValidIntegration(integrationType)) throw new Error(`Invalid connector type: ${integrationType}`);
|
|
39204
|
+
if (!connectors.some((c$1) => c$1.integrationType === integrationType)) throw new Error(`No ${getIntegrationDisplayName(integrationType)} connector found for this app`);
|
|
39205
|
+
selectedType = integrationType;
|
|
39206
|
+
}
|
|
39207
|
+
const displayName = getIntegrationDisplayName(selectedType);
|
|
39208
|
+
const connector = connectors.find((c$1) => c$1.integrationType === selectedType);
|
|
39209
|
+
const shouldRemove = await ye({
|
|
39210
|
+
message: `Disconnect ${displayName}${connector?.accountInfo?.email ? ` (${connector.accountInfo.email})` : ""}?`,
|
|
39211
|
+
initialValue: false
|
|
39212
|
+
});
|
|
39213
|
+
if (pD(shouldRemove) || !shouldRemove) return { outroMessage: "Cancelled" };
|
|
39214
|
+
await runTask(`Disconnecting ${displayName}...`, async () => {
|
|
39215
|
+
await disconnectConnector(selectedType);
|
|
39216
|
+
}, {
|
|
39217
|
+
successMessage: `${displayName} disconnected`,
|
|
39218
|
+
errorMessage: `Failed to disconnect ${displayName}`
|
|
39219
|
+
});
|
|
39220
|
+
return { outroMessage: `Successfully disconnected ${theme.styles.bold(displayName)}` };
|
|
39221
|
+
}
|
|
39222
|
+
const connectorsRemoveCommand = new Command("connectors:remove").argument("[type]", "Integration type to remove (e.g., slack, notion)").description("Disconnect an OAuth integration").action(async (type) => {
|
|
39223
|
+
await runCommand(() => removeConnectorCommand(type), {
|
|
39224
|
+
requireAuth: true,
|
|
39225
|
+
requireAppConfig: true
|
|
39226
|
+
});
|
|
39227
|
+
});
|
|
39228
|
+
|
|
38792
39229
|
//#endregion
|
|
38793
39230
|
//#region package.json
|
|
38794
39231
|
var version = "0.0.15";
|
|
@@ -38808,6 +39245,9 @@ program.addCommand(linkCommand);
|
|
|
38808
39245
|
program.addCommand(entitiesPushCommand);
|
|
38809
39246
|
program.addCommand(functionsDeployCommand);
|
|
38810
39247
|
program.addCommand(siteDeployCommand);
|
|
39248
|
+
program.addCommand(connectorsAddCommand);
|
|
39249
|
+
program.addCommand(connectorsListCommand);
|
|
39250
|
+
program.addCommand(connectorsRemoveCommand);
|
|
38811
39251
|
program.parse();
|
|
38812
39252
|
|
|
38813
39253
|
//#endregion
|
package/package.json
CHANGED