@dev-fastn-ai/react-core 2.4.12 → 2.4.14

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
@@ -156,6 +156,8 @@ interface Connector {
156
156
  imageUri?: string;
157
157
  status: ConnectorStatus;
158
158
  actions: ConnectorAction[];
159
+ isMultiConnection?: boolean;
160
+ connectorsDetails?: Record<string, any> | null;
159
161
  }
160
162
 
161
163
  enum ConnectorStatus {
@@ -167,7 +169,8 @@ enum ConnectorStatus {
167
169
  interface ConnectorAction {
168
170
  name: string;
169
171
  actionType: ConnectorActionType | string;
170
- onClick?: () => Promise<ConnectorActionResult>;
172
+ onClick?: (args?: { connectionId?: string; connectionIds?: string[] }) => Promise<ConnectorActionResult>;
173
+ onSubmit?: (formData: Record<string, Primitive>, args?: { connectionId?: string; connectionIds?: string[] }) => Promise<ConnectorActionResult>;
171
174
  }
172
175
 
173
176
  interface ConnectorActionResult {
@@ -1223,6 +1226,139 @@ function MultiLevelSelectForm() {
1223
1226
 
1224
1227
  ---
1225
1228
 
1229
+ ### **Multi-Connection Support**
1230
+
1231
+ Some connectors support multiple simultaneous connections (e.g. connecting to multiple workspaces or accounts). When `connector.isMultiConnection` is `true`, you can add and remove individual connections.
1232
+
1233
+ #### Detecting Multi-Connection Connectors
1234
+
1235
+ ```tsx
1236
+ function ConnectorCard({ connector }) {
1237
+ const isMultiConn = connector.isMultiConnection;
1238
+ const isActive = connector.status === "ACTIVE";
1239
+
1240
+ const handleActionClick = (action) => {
1241
+ if (action.actionType === "ACTIVATION" && isMultiConn && isActive) {
1242
+ // Connector is already active — show a "Manage Connections" UI
1243
+ // instead of the normal activation flow
1244
+ openManageConnectionsModal();
1245
+ } else {
1246
+ // Normal activation/deactivation flow
1247
+ action.onClick?.();
1248
+ }
1249
+ };
1250
+
1251
+ // ...
1252
+ }
1253
+ ```
1254
+
1255
+ #### Adding a New Connection
1256
+
1257
+ Pass a `connectionId` when activating to create a named connection:
1258
+
1259
+ ```tsx
1260
+ // Non-form action (direct OAuth or no-input activation)
1261
+ const activateAction = connector.actions.find(a => a.actionType === "ACTIVATION");
1262
+ await activateAction?.onClick?.({ connectionId: "my-new-connection" });
1263
+
1264
+ // Form-based action (connector requires input fields)
1265
+ await activateAction?.onSubmit?.(formData, { connectionId: "my-new-connection" });
1266
+ ```
1267
+
1268
+ The `connectionId` is sent in the API request body as `connections: ["my-new-connection"]`.
1269
+
1270
+ #### Disconnecting a Specific Connection
1271
+
1272
+ Pass both the connection name and its connector ID keys when deactivating:
1273
+
1274
+ ```tsx
1275
+ const deactivateAction = connector.actions.find(a => a.actionType === "DEACTIVATION");
1276
+
1277
+ await deactivateAction?.onClick?.({
1278
+ connectionId: "my-connection-name", // the connection name
1279
+ connectionIds: ["_knexa_e494e021-4f8d-..."], // connector ID keys from connectorsDetails
1280
+ });
1281
+ ```
1282
+
1283
+ #### Reading Existing Connections
1284
+
1285
+ Existing connections are in `connector.connectorsDetails?.connectionsIds` — a map of connector ID keys to arrays of connection names:
1286
+
1287
+ ```tsx
1288
+ const connectionsIds = connector.connectorsDetails?.connectionsIds;
1289
+
1290
+ // Example structure:
1291
+ // {
1292
+ // "_knexa_e494e021-...": ["default", "my-connection"],
1293
+ // "_knexa_abc12345-...": ["my-connection"]
1294
+ // }
1295
+
1296
+ // Process into a deduplicated list:
1297
+ const connectionMap = new Map();
1298
+ if (connectionsIds) {
1299
+ Object.entries(connectionsIds).forEach(([key, names]) => {
1300
+ names.forEach((name) => {
1301
+ if (connectionMap.has(name)) {
1302
+ connectionMap.get(name).keys.push(key);
1303
+ } else {
1304
+ connectionMap.set(name, { name, keys: [key] });
1305
+ }
1306
+ });
1307
+ });
1308
+ }
1309
+ const connections = Array.from(connectionMap.values());
1310
+ // connections = [{ name: "default", keys: ["_knexa_e494e021-..."] }, ...]
1311
+ ```
1312
+
1313
+ #### Full Example: Manage Connections Modal
1314
+
1315
+ ```tsx
1316
+ function ManageConnectionsModal({ connector, onClose }) {
1317
+ const [connectionName, setConnectionName] = useState("");
1318
+
1319
+ const activateAction = connector.actions.find(a => a.actionType === "ACTIVATION");
1320
+ const deactivateAction = connector.actions.find(a => a.actionType === "DEACTIVATION");
1321
+
1322
+ // Process existing connections from connectorsDetails
1323
+ const connectionsIds = connector.connectorsDetails?.connectionsIds;
1324
+ const connections = processConnections(connectionsIds); // deduplicated list
1325
+
1326
+ const handleConnect = async () => {
1327
+ const connId = connectionName.trim();
1328
+ if (!connId) return;
1329
+ await activateAction?.onClick?.({ connectionId: connId });
1330
+ setConnectionName("");
1331
+ };
1332
+
1333
+ const handleDisconnect = async (connName, connIdKeys) => {
1334
+ await deactivateAction?.onClick?.({
1335
+ connectionId: connName,
1336
+ connectionIds: connIdKeys,
1337
+ });
1338
+ };
1339
+
1340
+ return (
1341
+ <div>
1342
+ {/* Add new connection */}
1343
+ <input value={connectionName} onChange={e => setConnectionName(e.target.value)} />
1344
+ <button onClick={handleConnect}>Connect</button>
1345
+
1346
+ {/* List existing connections */}
1347
+ {connections.map(conn => (
1348
+ <div key={conn.name}>
1349
+ <span>{conn.name}</span>
1350
+ <button onClick={() => handleDisconnect(conn.name, conn.keys)}>
1351
+ Disconnect
1352
+ </button>
1353
+ </div>
1354
+ ))}
1355
+ </div>
1356
+ );
1357
+ }
1358
+ ```
1359
+
1360
+ ---
1361
+
1226
1362
  ### **Error Handling and Loading States**
1227
1363
 
1228
1364
  ```tsx
@@ -1,6 +1,6 @@
1
1
  import { QueryClient } from "@tanstack/react-query";
2
- import { Fastn } from "@fastn-ai/core";
3
- import type { FastnConfig } from "@fastn-ai/core";
2
+ import { Fastn } from "@dev-fastn-ai/core";
3
+ import type { FastnConfig } from "@dev-fastn-ai/core";
4
4
  export declare const FastnProvider: ({ children, config, queryClient, }: {
5
5
  children: React.ReactNode;
6
6
  config: FastnConfig;
@@ -1,2 +1,2 @@
1
- import { GetConfigurationFormInput } from "@fastn-ai/core";
2
- export declare const useConfigurationForm: (input: GetConfigurationFormInput) => import("@tanstack/react-query").UseQueryResult<import("@fastn-ai/core").ConfigurationForm, Error>;
1
+ import { GetConfigurationFormInput } from "@dev-fastn-ai/core";
2
+ export declare const useConfigurationForm: (input: GetConfigurationFormInput) => import("@tanstack/react-query").UseQueryResult<import("@dev-fastn-ai/core").ConfigurationForm, Error>;
@@ -1,2 +1,2 @@
1
- import { GetConfigurationsInput } from "@fastn-ai/core";
2
- export declare const useConfigurations: (input: GetConfigurationsInput) => import("@tanstack/react-query").UseQueryResult<import("@fastn-ai/core").Configuration[], Error>;
1
+ import { GetConfigurationsInput } from "@dev-fastn-ai/core";
2
+ export declare const useConfigurations: (input: GetConfigurationsInput) => import("@tanstack/react-query").UseQueryResult<import("@dev-fastn-ai/core").Configuration[], Error>;
@@ -1,4 +1,4 @@
1
- import type { ConnectorField, SelectOption, FormData } from "@fastn-ai/core";
1
+ import type { ConnectorField, SelectOption, FormData } from "@dev-fastn-ai/core";
2
2
  /**
3
3
  * Custom hook to manage async select field options with search, pagination, and error handling using React Query.
4
4
  *
package/dist/index.cjs.js CHANGED
@@ -3,7 +3,7 @@
3
3
  var jsxRuntime = require('react/jsx-runtime');
4
4
  var react = require('react');
5
5
  var reactQuery = require('@tanstack/react-query');
6
- var core = require('@fastn-ai/core');
6
+ var core = require('@dev-fastn-ai/core');
7
7
 
8
8
  const FastnContext = react.createContext(null);
9
9
  const FastnProvider = ({ children, config, queryClient, }) => {
package/dist/index.d.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as _tanstack_react_query from '@tanstack/react-query';
3
3
  import { QueryClient } from '@tanstack/react-query';
4
- import * as _fastn_ai_core from '@fastn-ai/core';
5
- import { FastnConfig, GetConfigurationsInput, GetConfigurationFormInput, ConnectorField, FormData, SelectOption } from '@fastn-ai/core';
6
- export * from '@fastn-ai/core';
4
+ import * as _dev_fastn_ai_core from '@dev-fastn-ai/core';
5
+ import { FastnConfig, GetConfigurationsInput, GetConfigurationFormInput, ConnectorField, FormData, SelectOption } from '@dev-fastn-ai/core';
6
+ export * from '@dev-fastn-ai/core';
7
7
 
8
8
  declare const FastnProvider: ({ children, config, queryClient, }: {
9
9
  children: React.ReactNode;
@@ -11,11 +11,11 @@ declare const FastnProvider: ({ children, config, queryClient, }: {
11
11
  queryClient?: QueryClient;
12
12
  }) => react_jsx_runtime.JSX.Element;
13
13
 
14
- declare const useConfigurations: (input: GetConfigurationsInput) => _tanstack_react_query.UseQueryResult<_fastn_ai_core.Configuration[], Error>;
14
+ declare const useConfigurations: (input: GetConfigurationsInput) => _tanstack_react_query.UseQueryResult<_dev_fastn_ai_core.Configuration[], Error>;
15
15
 
16
- declare const useConfigurationForm: (input: GetConfigurationFormInput) => _tanstack_react_query.UseQueryResult<_fastn_ai_core.ConfigurationForm, Error>;
16
+ declare const useConfigurationForm: (input: GetConfigurationFormInput) => _tanstack_react_query.UseQueryResult<_dev_fastn_ai_core.ConfigurationForm, Error>;
17
17
 
18
- declare const useConnectors: () => _tanstack_react_query.UseQueryResult<_fastn_ai_core.Connector[], Error>;
18
+ declare const useConnectors: () => _tanstack_react_query.UseQueryResult<_dev_fastn_ai_core.Connector[], Error>;
19
19
 
20
20
  /**
21
21
  * Custom hook to manage async select field options with search, pagination, and error handling using React Query.
package/dist/index.esm.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
2
  import { createContext, useMemo, useContext, useEffect, useState, useCallback } from 'react';
3
3
  import { QueryClientProvider, QueryClient, useQuery, useQueryClient, useInfiniteQuery } from '@tanstack/react-query';
4
- import { Fastn } from '@fastn-ai/core';
5
- export * from '@fastn-ai/core';
4
+ import { Fastn } from '@dev-fastn-ai/core';
5
+ export * from '@dev-fastn-ai/core';
6
6
 
7
7
  const FastnContext = createContext(null);
8
8
  const FastnProvider = ({ children, config, queryClient, }) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dev-fastn-ai/react-core",
3
- "version": "2.4.12",
3
+ "version": "2.4.14",
4
4
  "description": "React hooks and components for integrating Fastn AI connector marketplace into your applications. Built on top of @fastn-ai/core with React Query for optimal performance.",
5
5
  "main": "dist/index.cjs.js",
6
6
  "module": "dist/index.esm.js",
@@ -52,14 +52,14 @@
52
52
  "license": "MIT",
53
53
  "repository": {
54
54
  "type": "git",
55
- "url": "https://github.com/dev-fastn-ai/react-core.git"
55
+ "url": "https://github.com/fastn-ai/react-core.git"
56
56
  },
57
57
  "bugs": {
58
- "url": "https://github.com/dev-fastn-ai/react-core/issues"
58
+ "url": "https://github.com/fastn-ai/react-core/issues"
59
59
  },
60
60
  "homepage": "https://docs.fastn.ai",
61
61
  "dependencies": {
62
- "@dev-fastn-ai/core": "^2.0.7",
62
+ "@dev-fastn-ai/core": "^2.4.14",
63
63
  "@fastn-ai/core": "^1.0.8",
64
64
  "@types/lodash": "^4.17.20",
65
65
  "lodash": "^4.17.21"
@@ -89,4 +89,4 @@
89
89
  "publishConfig": {
90
90
  "access": "public"
91
91
  }
92
- }
92
+ }