@base44-preview/cli 0.0.15-pr.99.76064e9 → 0.0.15-pr.99.a46f627

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 CHANGED
@@ -70,6 +70,36 @@ base44 deploy
70
70
  |---------|-------------|
71
71
  | `base44 site deploy` | Deploy built site files to Base44 hosting |
72
72
 
73
+ ### Connectors
74
+
75
+ Manage OAuth integrations to connect your app with external services.
76
+
77
+ | Command | Description |
78
+ |---------|-------------|
79
+ | `base44 connectors:add [type]` | Connect an OAuth integration (opens browser for auth) |
80
+ | `base44 connectors:list` | List all connected integrations |
81
+ | `base44 connectors:remove [type]` | Disconnect an integration |
82
+ | `base44 connectors:remove [type] --hard` | Permanently remove an integration |
83
+
84
+ **Supported integrations:** Slack, Google Calendar, Google Drive, Gmail, Google Sheets, Google Docs, Google Slides, Notion, Salesforce, HubSpot, LinkedIn, TikTok
85
+
86
+ **Example:**
87
+ ```bash
88
+ # Connect Slack (opens browser for OAuth)
89
+ base44 connectors:add slack
90
+
91
+ # List connected integrations
92
+ base44 connectors:list
93
+
94
+ # Disconnect Slack
95
+ base44 connectors:remove slack
96
+ ```
97
+
98
+ Once connected, use the SDK's `connectors.getAccessToken()` to retrieve tokens:
99
+ ```javascript
100
+ const token = await base44.connectors.getAccessToken("slack");
101
+ ```
102
+
73
103
  ## Configuration
74
104
 
75
105
  ### Project Configuration
package/dist/cli/index.js CHANGED
@@ -38971,6 +38971,19 @@ async function disconnectConnector(integrationType) {
38971
38971
  throw new ConnectorApiError(`Failed to disconnect connector: ${response.status} ${response.statusText}`);
38972
38972
  }
38973
38973
  }
38974
+ /**
38975
+ * Removes (hard delete) a connector integration.
38976
+ * This permanently removes the connector and cannot be undone.
38977
+ */
38978
+ async function removeConnector(integrationType) {
38979
+ const response = await getAppClient().delete(`external-auth/integrations/${integrationType}/remove`, { throwHttpErrors: false });
38980
+ if (!response.ok) {
38981
+ const json = await response.json();
38982
+ const errorResult = ApiErrorSchema.safeParse(json);
38983
+ if (errorResult.success) throw new ConnectorApiError(errorResult.data.error);
38984
+ throw new ConnectorApiError(`Failed to remove connector: ${response.status} ${response.statusText}`);
38985
+ }
38986
+ }
38974
38987
 
38975
38988
  //#endregion
38976
38989
  //#region src/core/connectors/constants.ts
@@ -39111,24 +39124,11 @@ const connectorsAddCommand = new Command("connectors:add").argument("[type]", "I
39111
39124
 
39112
39125
  //#endregion
39113
39126
  //#region src/cli/commands/connectors/list.ts
39114
- function formatDate(dateString) {
39115
- if (!dateString) return "-";
39116
- try {
39117
- return new Date(dateString).toLocaleDateString("en-US", {
39118
- year: "numeric",
39119
- month: "short",
39120
- day: "numeric"
39121
- });
39122
- } catch {
39123
- return dateString;
39124
- }
39125
- }
39126
- function formatStatus(status) {
39127
- const normalized = status.toLowerCase();
39128
- if (normalized === "active" || normalized === "connected") return theme.colors.success("● active");
39129
- if (normalized === "expired") return theme.colors.warning("● expired");
39130
- if (normalized === "failed" || normalized === "disconnected") return theme.colors.error("● disconnected");
39131
- return status;
39127
+ function formatConnectorLine(connector) {
39128
+ const name$1 = getIntegrationDisplayName(connector.integrationType);
39129
+ const account = connector.accountInfo?.email || connector.accountInfo?.name;
39130
+ const status = connector.status.toLowerCase();
39131
+ return `${status === "active" ? theme.colors.success("●") : theme.colors.error("")} ${name$1}${account ? ` - ${account}` : ""}${status !== "active" ? theme.styles.dim(` (${status})`) : ""}`;
39132
39132
  }
39133
39133
  async function listConnectorsCommand() {
39134
39134
  const connectors = await runTask("Fetching connectors...", async () => {
@@ -39143,30 +39143,7 @@ async function listConnectorsCommand() {
39143
39143
  return { outroMessage: "" };
39144
39144
  }
39145
39145
  console.log();
39146
- console.log(theme.styles.bold("Connected Integrations:"));
39147
- console.log();
39148
- const headers = [
39149
- "Type",
39150
- "Account",
39151
- "Status",
39152
- "Connected"
39153
- ];
39154
- const colWidths = [
39155
- 20,
39156
- 30,
39157
- 15,
39158
- 15
39159
- ];
39160
- const headerRow = headers.map((h$2, i$1) => h$2.padEnd(colWidths[i$1])).join(" ");
39161
- console.log(theme.styles.dim(headerRow));
39162
- console.log(theme.styles.dim("─".repeat(headerRow.length)));
39163
- for (const connector of connectors) {
39164
- const type = getIntegrationDisplayName(connector.integrationType).padEnd(colWidths[0]);
39165
- const account = (connector.accountInfo?.email || connector.accountInfo?.name || "-").padEnd(colWidths[1]);
39166
- const status = formatStatus(connector.status);
39167
- const connected = formatDate(connector.connectedAt).padEnd(colWidths[3]);
39168
- console.log(`${type} ${account} ${status.padEnd(colWidths[2] + 10)} ${connected}`);
39169
- }
39146
+ for (const connector of connectors) console.log(formatConnectorLine(connector));
39170
39147
  console.log();
39171
39148
  return { outroMessage: `${connectors.length} connector${connectors.length === 1 ? "" : "s"} configured` };
39172
39149
  }
@@ -39190,7 +39167,8 @@ async function promptForConnectorToRemove(connectors) {
39190
39167
  if (pD(selected)) return null;
39191
39168
  return selected;
39192
39169
  }
39193
- async function removeConnectorCommand(integrationType) {
39170
+ async function removeConnectorCommand(integrationType, options = {}) {
39171
+ const isHardDelete = options.hard === true;
39194
39172
  const connectors = await runTask("Fetching connectors...", async () => {
39195
39173
  return await listConnectors();
39196
39174
  }, {
@@ -39210,21 +39188,23 @@ async function removeConnectorCommand(integrationType) {
39210
39188
  }
39211
39189
  const displayName = getIntegrationDisplayName(selectedType);
39212
39190
  const connector = connectors.find((c$1) => c$1.integrationType === selectedType);
39191
+ const accountInfo = connector?.accountInfo?.email ? ` (${connector.accountInfo.email})` : "";
39213
39192
  const shouldRemove = await ye({
39214
- message: `Disconnect ${displayName}${connector?.accountInfo?.email ? ` (${connector.accountInfo.email})` : ""}?`,
39193
+ message: `${isHardDelete ? "Permanently remove" : "Disconnect"} ${displayName}${accountInfo}?`,
39215
39194
  initialValue: false
39216
39195
  });
39217
39196
  if (pD(shouldRemove) || !shouldRemove) return { outroMessage: "Cancelled" };
39218
- await runTask(`Disconnecting ${displayName}...`, async () => {
39219
- await disconnectConnector(selectedType);
39197
+ await runTask(isHardDelete ? `Removing ${displayName}...` : `Disconnecting ${displayName}...`, async () => {
39198
+ if (isHardDelete) await removeConnector(selectedType);
39199
+ else await disconnectConnector(selectedType);
39220
39200
  }, {
39221
- successMessage: `${displayName} disconnected`,
39222
- errorMessage: `Failed to disconnect ${displayName}`
39201
+ successMessage: isHardDelete ? `${displayName} removed` : `${displayName} disconnected`,
39202
+ errorMessage: isHardDelete ? `Failed to remove ${displayName}` : `Failed to disconnect ${displayName}`
39223
39203
  });
39224
- return { outroMessage: `Successfully disconnected ${theme.styles.bold(displayName)}` };
39204
+ return { outroMessage: `Successfully ${isHardDelete ? "removed" : "disconnected"} ${theme.styles.bold(displayName)}` };
39225
39205
  }
39226
- const connectorsRemoveCommand = new Command("connectors:remove").argument("[type]", "Integration type to remove (e.g., slack, notion)").description("Disconnect an OAuth integration").action(async (type) => {
39227
- await runCommand(() => removeConnectorCommand(type), {
39206
+ const connectorsRemoveCommand = new Command("connectors:remove").argument("[type]", "Integration type to remove (e.g., slack, notion)").option("--hard", "Permanently remove the connector (cannot be undone)").description("Disconnect an OAuth integration").action(async (type, options) => {
39207
+ await runCommand(() => removeConnectorCommand(type, options), {
39228
39208
  requireAuth: true,
39229
39209
  requireAppConfig: true
39230
39210
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@base44-preview/cli",
3
- "version": "0.0.15-pr.99.76064e9",
3
+ "version": "0.0.15-pr.99.a46f627",
4
4
  "description": "Base44 CLI - Unified interface for managing Base44 applications",
5
5
  "type": "module",
6
6
  "main": "./dist/cli/index.js",