@dataferry/sdk 0.1.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/README.md +201 -0
- package/dist/index.cjs +464 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +534 -0
- package/dist/index.d.ts +534 -0
- package/dist/index.js +433 -0
- package/dist/index.js.map +1 -0
- package/package.json +40 -0
package/README.md
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
# @dataferry/sdk
|
|
2
|
+
|
|
3
|
+
Node.js SDK for DataFerry - data export infrastructure for SaaS companies.
|
|
4
|
+
|
|
5
|
+
DataFerry helps you provide end-user data export functionality for GDPR/CCPA compliance and data portability.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @dataferry/sdk
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { Ferry } from '@dataferry/sdk';
|
|
17
|
+
|
|
18
|
+
const ferry = new Ferry({
|
|
19
|
+
apiKey: process.env.DATAFERRY_API_KEY,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
// Create a portal session for an end user
|
|
23
|
+
const session = await ferry.createPortalSession({
|
|
24
|
+
scopeId: 'user_123',
|
|
25
|
+
returnUrl: 'https://app.example.com/settings',
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// Redirect the user to the portal URL
|
|
29
|
+
// session.url -> https://portal.dataferry.dev/session/...
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Usage
|
|
33
|
+
|
|
34
|
+
### Creating Portal Sessions
|
|
35
|
+
|
|
36
|
+
The simplest way to let users export their data is through the portal:
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
// Multi-tenant: specify the scope ID (typically user ID)
|
|
40
|
+
const session = await ferry.createPortalSession({
|
|
41
|
+
scopeId: 'user_123',
|
|
42
|
+
returnUrl: 'https://app.example.com/settings',
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Single-tenant: no scopeId needed
|
|
46
|
+
const session = await ferry.createPortalSession({
|
|
47
|
+
returnUrl: 'https://app.example.com/settings',
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// With all options
|
|
51
|
+
const session = await ferry.createPortalSession({
|
|
52
|
+
scopeId: 'user_123',
|
|
53
|
+
connectionId: 'conn_abc', // Use a specific database connection
|
|
54
|
+
returnUrl: 'https://...', // Where to redirect after export
|
|
55
|
+
expiresIn: 3600, // Session duration in seconds
|
|
56
|
+
metadata: { plan: 'pro' }, // Custom metadata
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
console.log(session.url); // Redirect user here
|
|
60
|
+
console.log(session.expiresAt); // Session expiration
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Programmatic Exports
|
|
64
|
+
|
|
65
|
+
For server-to-server export workflows:
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
// Create an export job
|
|
69
|
+
const exportJob = await ferry.exports.create({
|
|
70
|
+
scopeId: 'user_123',
|
|
71
|
+
format: 'csv',
|
|
72
|
+
tables: ['users', 'posts', 'comments'],
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// Poll until complete
|
|
76
|
+
const completed = await ferry.exports.poll(exportJob.id, {
|
|
77
|
+
maxWait: 300000, // 5 minutes
|
|
78
|
+
interval: 2000, // Check every 2 seconds
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
if (completed.status === 'completed') {
|
|
82
|
+
console.log('Download URL:', completed.downloadUrl);
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Managing Database Connections
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
// List all connections
|
|
90
|
+
const connections = await ferry.connections.list();
|
|
91
|
+
|
|
92
|
+
// Create a new connection
|
|
93
|
+
const connection = await ferry.connections.create({
|
|
94
|
+
name: 'Production DB',
|
|
95
|
+
host: 'db.example.com',
|
|
96
|
+
port: '5432',
|
|
97
|
+
database: 'myapp',
|
|
98
|
+
user: 'ferry_readonly',
|
|
99
|
+
password: 'secret',
|
|
100
|
+
ssl: true,
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// Test a connection
|
|
104
|
+
const result = await ferry.connections.test(connection.id);
|
|
105
|
+
if (result.connected) {
|
|
106
|
+
console.log(`Connected to ${result.database}`);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## API Reference
|
|
112
|
+
|
|
113
|
+
### `Ferry`
|
|
114
|
+
|
|
115
|
+
The main client class.
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
const ferry = new Ferry({
|
|
119
|
+
apiKey: string, // Required: Your API key
|
|
120
|
+
baseUrl?: string, // Optional: API base URL (default: https://api.dataferry.dev)
|
|
121
|
+
timeout?: number, // Optional: Request timeout in ms (default: 30000)
|
|
122
|
+
});
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### `ferry.createPortalSession(params)`
|
|
126
|
+
|
|
127
|
+
Creates a portal session for an end user.
|
|
128
|
+
|
|
129
|
+
| Parameter | Type | Description |
|
|
130
|
+
|-----------|------|-------------|
|
|
131
|
+
| `scopeId` | `string?` | The scope ID for data filtering (optional for single-tenant) |
|
|
132
|
+
| `connectionId` | `string?` | Database connection ID (defaults to primary) |
|
|
133
|
+
| `returnUrl` | `string?` | URL to redirect after export |
|
|
134
|
+
| `expiresIn` | `number?` | Session duration in seconds |
|
|
135
|
+
| `metadata` | `object?` | Custom metadata |
|
|
136
|
+
|
|
137
|
+
Returns: `{ id: string, url: string, expiresAt: Date }`
|
|
138
|
+
|
|
139
|
+
### `ferry.exports`
|
|
140
|
+
|
|
141
|
+
Export job management.
|
|
142
|
+
|
|
143
|
+
- `create(params)` - Create a new export job
|
|
144
|
+
- `retrieve(id)` - Get export job details
|
|
145
|
+
- `list(params?)` - List export jobs
|
|
146
|
+
- `poll(id, options?)` - Wait for export to complete
|
|
147
|
+
|
|
148
|
+
### `ferry.connections`
|
|
149
|
+
|
|
150
|
+
Database connection management.
|
|
151
|
+
|
|
152
|
+
- `list()` - List all connections
|
|
153
|
+
- `create(params)` - Create a new connection
|
|
154
|
+
- `retrieve(id)` - Get connection details
|
|
155
|
+
- `update(id, params)` - Update a connection
|
|
156
|
+
- `delete(id)` - Delete a connection
|
|
157
|
+
- `test(id)` - Test a connection
|
|
158
|
+
|
|
159
|
+
### `ferry.portalSessions`
|
|
160
|
+
|
|
161
|
+
Portal session management (advanced).
|
|
162
|
+
|
|
163
|
+
- `create(params)` - Create a portal session
|
|
164
|
+
- `retrieve(id)` - Get session details
|
|
165
|
+
- `revoke(id)` - Revoke a session
|
|
166
|
+
|
|
167
|
+
## Error Handling
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
import { Ferry, FerryError } from '@dataferry/sdk';
|
|
171
|
+
|
|
172
|
+
try {
|
|
173
|
+
const session = await ferry.createPortalSession({ scopeId: 'user_123' });
|
|
174
|
+
} catch (error) {
|
|
175
|
+
if (error instanceof FerryError) {
|
|
176
|
+
console.error(`API Error: ${error.message}`);
|
|
177
|
+
console.error(`Code: ${error.code}`);
|
|
178
|
+
console.error(`Status: ${error.status}`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## TypeScript
|
|
184
|
+
|
|
185
|
+
The SDK is written in TypeScript and includes full type definitions.
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
import {
|
|
189
|
+
Ferry,
|
|
190
|
+
FerryConfig,
|
|
191
|
+
FerryError,
|
|
192
|
+
CreatePortalSessionParams,
|
|
193
|
+
PortalSessionResult,
|
|
194
|
+
ExportJob,
|
|
195
|
+
DatabaseConnection,
|
|
196
|
+
} from '@dataferry/sdk';
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## License
|
|
200
|
+
|
|
201
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,464 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
Connections: () => Connections,
|
|
24
|
+
Exports: () => Exports,
|
|
25
|
+
Ferry: () => Ferry,
|
|
26
|
+
FerryError: () => FerryError,
|
|
27
|
+
PortalSessions: () => PortalSessions
|
|
28
|
+
});
|
|
29
|
+
module.exports = __toCommonJS(index_exports);
|
|
30
|
+
|
|
31
|
+
// src/resources/portalSessions.ts
|
|
32
|
+
var PortalSessions = class {
|
|
33
|
+
constructor(client) {
|
|
34
|
+
this.client = client;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Create a new portal session for an end user
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```ts
|
|
41
|
+
* const session = await ferry.portalSessions.create({
|
|
42
|
+
* profile: 'default',
|
|
43
|
+
* scopeId: 'user_123',
|
|
44
|
+
* expiresIn: 3600,
|
|
45
|
+
* returnUrl: 'https://yourapp.com/settings',
|
|
46
|
+
* });
|
|
47
|
+
*
|
|
48
|
+
* // Redirect user to session.url
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
async create(params) {
|
|
52
|
+
return this.client.request(
|
|
53
|
+
"POST",
|
|
54
|
+
"/api/v1/portal-sessions",
|
|
55
|
+
params
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Get portal session details
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```ts
|
|
63
|
+
* const session = await ferry.portalSessions.retrieve('ps_abc123');
|
|
64
|
+
* console.log(session.scopeId, session.expiresAt);
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
async retrieve(sessionId) {
|
|
68
|
+
return this.client.request(
|
|
69
|
+
"GET",
|
|
70
|
+
`/api/v1/portal-sessions/${sessionId}`
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Revoke a portal session
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```ts
|
|
78
|
+
* await ferry.portalSessions.revoke('ps_abc123');
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
async revoke(sessionId) {
|
|
82
|
+
return this.client.request(
|
|
83
|
+
"DELETE",
|
|
84
|
+
`/api/v1/portal-sessions/${sessionId}`
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
// src/resources/exports.ts
|
|
90
|
+
var Exports = class {
|
|
91
|
+
constructor(client) {
|
|
92
|
+
this.client = client;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Create a new export job
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```ts
|
|
99
|
+
* // Create export using primary connection
|
|
100
|
+
* const exportJob = await ferry.exports.create({
|
|
101
|
+
* scopeId: 'user_123',
|
|
102
|
+
* format: 'csv',
|
|
103
|
+
* tables: ['users', 'posts', 'comments'],
|
|
104
|
+
* });
|
|
105
|
+
*
|
|
106
|
+
* // Create export using specific connection
|
|
107
|
+
* const exportJob = await ferry.exports.create({
|
|
108
|
+
* scopeId: 'user_123',
|
|
109
|
+
* connectionId: 'conn_abc123',
|
|
110
|
+
* format: 'csv',
|
|
111
|
+
* tables: ['users', 'posts'],
|
|
112
|
+
* });
|
|
113
|
+
*
|
|
114
|
+
* console.log(exportJob.id, exportJob.status);
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
async create(params) {
|
|
118
|
+
return this.client.request(
|
|
119
|
+
"POST",
|
|
120
|
+
"/api/v1/exports",
|
|
121
|
+
params
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Get export job details
|
|
126
|
+
*
|
|
127
|
+
* @example
|
|
128
|
+
* ```ts
|
|
129
|
+
* const exportJob = await ferry.exports.retrieve('exp_abc123');
|
|
130
|
+
*
|
|
131
|
+
* if (exportJob.status === 'completed') {
|
|
132
|
+
* console.log('Download:', exportJob.downloadUrl);
|
|
133
|
+
* }
|
|
134
|
+
* ```
|
|
135
|
+
*/
|
|
136
|
+
async retrieve(exportId) {
|
|
137
|
+
return this.client.request(
|
|
138
|
+
"GET",
|
|
139
|
+
`/api/v1/exports/${exportId}`
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* List exports
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```ts
|
|
147
|
+
* // List all exports
|
|
148
|
+
* const { data, meta } = await ferry.exports.list();
|
|
149
|
+
*
|
|
150
|
+
* // Filter by scope
|
|
151
|
+
* const { data } = await ferry.exports.list({ scopeId: 'user_123' });
|
|
152
|
+
*
|
|
153
|
+
* // Filter by status
|
|
154
|
+
* const { data } = await ferry.exports.list({ status: 'completed' });
|
|
155
|
+
*
|
|
156
|
+
* // Filter by connection
|
|
157
|
+
* const { data } = await ferry.exports.list({ connectionId: 'conn_abc123' });
|
|
158
|
+
* ```
|
|
159
|
+
*/
|
|
160
|
+
async list(params) {
|
|
161
|
+
return this.client.requestPaginated(
|
|
162
|
+
"/api/v1/exports",
|
|
163
|
+
params
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Wait for an export to complete
|
|
168
|
+
*
|
|
169
|
+
* @example
|
|
170
|
+
* ```ts
|
|
171
|
+
* const exportJob = await ferry.exports.create({ scopeId: 'user_123' });
|
|
172
|
+
* const completed = await ferry.exports.poll(exportJob.id, { maxWait: 300000 });
|
|
173
|
+
*
|
|
174
|
+
* if (completed.status === 'completed') {
|
|
175
|
+
* console.log('Download:', completed.downloadUrl);
|
|
176
|
+
* }
|
|
177
|
+
* ```
|
|
178
|
+
*/
|
|
179
|
+
async poll(exportId, options = {}) {
|
|
180
|
+
const maxWait = options.maxWait ?? 3e5;
|
|
181
|
+
const interval = options.interval ?? 2e3;
|
|
182
|
+
const startTime = Date.now();
|
|
183
|
+
while (Date.now() - startTime < maxWait) {
|
|
184
|
+
const exportJob = await this.retrieve(exportId);
|
|
185
|
+
if (exportJob.status === "completed" || exportJob.status === "failed" || exportJob.status === "expired") {
|
|
186
|
+
return exportJob;
|
|
187
|
+
}
|
|
188
|
+
await new Promise((resolve) => setTimeout(resolve, interval));
|
|
189
|
+
}
|
|
190
|
+
throw new Error(`Export ${exportId} did not complete within ${maxWait}ms`);
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
// src/resources/connections.ts
|
|
195
|
+
var Connections = class {
|
|
196
|
+
constructor(client) {
|
|
197
|
+
this.client = client;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* List all database connections for the organization
|
|
201
|
+
*
|
|
202
|
+
* @example
|
|
203
|
+
* ```ts
|
|
204
|
+
* const connections = await ferry.connections.list();
|
|
205
|
+
* for (const conn of connections) {
|
|
206
|
+
* console.log(conn.name);
|
|
207
|
+
* }
|
|
208
|
+
* ```
|
|
209
|
+
*/
|
|
210
|
+
async list() {
|
|
211
|
+
const result = await this.client.requestPaginated(
|
|
212
|
+
"/api/v1/connections"
|
|
213
|
+
);
|
|
214
|
+
return result.data;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Create a new database connection
|
|
218
|
+
*
|
|
219
|
+
* @example
|
|
220
|
+
* ```ts
|
|
221
|
+
* const connection = await ferry.connections.create({
|
|
222
|
+
* name: 'Production DB',
|
|
223
|
+
* host: 'db.example.com',
|
|
224
|
+
* port: '5432',
|
|
225
|
+
* database: 'myapp',
|
|
226
|
+
* user: 'ferry_readonly',
|
|
227
|
+
* password: 'secret',
|
|
228
|
+
* ssl: true,
|
|
229
|
+
* });
|
|
230
|
+
* ```
|
|
231
|
+
*/
|
|
232
|
+
async create(params) {
|
|
233
|
+
return this.client.request(
|
|
234
|
+
"POST",
|
|
235
|
+
"/api/v1/connections",
|
|
236
|
+
params
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Get a database connection by ID
|
|
241
|
+
*
|
|
242
|
+
* @example
|
|
243
|
+
* ```ts
|
|
244
|
+
* const connection = await ferry.connections.retrieve('conn_abc123');
|
|
245
|
+
* console.log(connection.host, connection.database);
|
|
246
|
+
* ```
|
|
247
|
+
*/
|
|
248
|
+
async retrieve(connectionId) {
|
|
249
|
+
return this.client.request(
|
|
250
|
+
"GET",
|
|
251
|
+
`/api/v1/connections/${connectionId}`
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Update a database connection
|
|
256
|
+
*
|
|
257
|
+
* @example
|
|
258
|
+
* ```ts
|
|
259
|
+
* const connection = await ferry.connections.update('conn_abc123', {
|
|
260
|
+
* name: 'Production DB (Updated)',
|
|
261
|
+
* });
|
|
262
|
+
* ```
|
|
263
|
+
*/
|
|
264
|
+
async update(connectionId, params) {
|
|
265
|
+
return this.client.request(
|
|
266
|
+
"PUT",
|
|
267
|
+
`/api/v1/connections/${connectionId}`,
|
|
268
|
+
params
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Delete a database connection
|
|
273
|
+
*
|
|
274
|
+
* @example
|
|
275
|
+
* ```ts
|
|
276
|
+
* const result = await ferry.connections.delete('conn_abc123');
|
|
277
|
+
* console.log(result.deleted); // true
|
|
278
|
+
* ```
|
|
279
|
+
*/
|
|
280
|
+
async delete(connectionId) {
|
|
281
|
+
return this.client.request(
|
|
282
|
+
"DELETE",
|
|
283
|
+
`/api/v1/connections/${connectionId}`
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Test a database connection
|
|
288
|
+
*
|
|
289
|
+
* @example
|
|
290
|
+
* ```ts
|
|
291
|
+
* const result = await ferry.connections.test('conn_abc123');
|
|
292
|
+
* if (result.connected) {
|
|
293
|
+
* console.log(`Connected to ${result.database} as ${result.user}`);
|
|
294
|
+
* } else {
|
|
295
|
+
* console.error(`Connection failed: ${result.error}`);
|
|
296
|
+
* }
|
|
297
|
+
* ```
|
|
298
|
+
*/
|
|
299
|
+
async test(connectionId) {
|
|
300
|
+
return this.client.request(
|
|
301
|
+
"POST",
|
|
302
|
+
`/api/v1/connections/${connectionId}/test`
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
// src/client.ts
|
|
308
|
+
var Ferry = class {
|
|
309
|
+
apiKey;
|
|
310
|
+
baseUrl;
|
|
311
|
+
timeout;
|
|
312
|
+
/** Portal session management */
|
|
313
|
+
portalSessions;
|
|
314
|
+
/** Export management */
|
|
315
|
+
exports;
|
|
316
|
+
/** Database connection management */
|
|
317
|
+
connections;
|
|
318
|
+
constructor(config) {
|
|
319
|
+
this.apiKey = config.apiKey;
|
|
320
|
+
this.baseUrl = config.baseUrl ?? "https://api.dataferry.dev";
|
|
321
|
+
this.timeout = config.timeout ?? 3e4;
|
|
322
|
+
this.portalSessions = new PortalSessions(this);
|
|
323
|
+
this.exports = new Exports(this);
|
|
324
|
+
this.connections = new Connections(this);
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Create a portal session for an end user to export their data.
|
|
328
|
+
*
|
|
329
|
+
* This is the primary method for initiating a data export. It creates a
|
|
330
|
+
* secure session and returns a URL where the user can select and download
|
|
331
|
+
* their data.
|
|
332
|
+
*
|
|
333
|
+
* @example
|
|
334
|
+
* ```typescript
|
|
335
|
+
* const ferry = new Ferry({ apiKey: 'your-api-key' });
|
|
336
|
+
*
|
|
337
|
+
* // Create a session for a specific user
|
|
338
|
+
* const session = await ferry.createPortalSession({
|
|
339
|
+
* profile: 'default',
|
|
340
|
+
* scopeId: 'user_123',
|
|
341
|
+
* returnUrl: 'https://app.example.com/settings',
|
|
342
|
+
* });
|
|
343
|
+
*
|
|
344
|
+
* // Redirect the user to the portal
|
|
345
|
+
* res.redirect(session.url);
|
|
346
|
+
* ```
|
|
347
|
+
*
|
|
348
|
+
* @example
|
|
349
|
+
* ```typescript
|
|
350
|
+
* // Single-tenant mode (no scopeId required)
|
|
351
|
+
* const session = await ferry.createPortalSession({
|
|
352
|
+
* profile: 'default',
|
|
353
|
+
* returnUrl: 'https://app.example.com/settings',
|
|
354
|
+
* });
|
|
355
|
+
* ```
|
|
356
|
+
*/
|
|
357
|
+
async createPortalSession(params) {
|
|
358
|
+
const request = { profile: params.profile };
|
|
359
|
+
if (params.scopeId !== void 0) {
|
|
360
|
+
request.scopeId = params.scopeId;
|
|
361
|
+
}
|
|
362
|
+
if (params.returnUrl !== void 0) {
|
|
363
|
+
request.returnUrl = params.returnUrl;
|
|
364
|
+
}
|
|
365
|
+
if (params.expiresIn !== void 0) {
|
|
366
|
+
request.expiresIn = params.expiresIn;
|
|
367
|
+
}
|
|
368
|
+
if (params.email !== void 0) {
|
|
369
|
+
request.email = params.email;
|
|
370
|
+
}
|
|
371
|
+
if (params.metadata !== void 0) {
|
|
372
|
+
request.metadata = params.metadata;
|
|
373
|
+
}
|
|
374
|
+
const response = await this.portalSessions.create(request);
|
|
375
|
+
return {
|
|
376
|
+
id: response.id,
|
|
377
|
+
url: response.url,
|
|
378
|
+
expiresAt: response.expiresAt
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Make an authenticated API request
|
|
383
|
+
*/
|
|
384
|
+
async request(method, path, body) {
|
|
385
|
+
const url = `${this.baseUrl}${path}`;
|
|
386
|
+
const headers = {
|
|
387
|
+
"Content-Type": "application/json",
|
|
388
|
+
Authorization: `Basic ${Buffer.from(this.apiKey + ":").toString("base64")}`
|
|
389
|
+
};
|
|
390
|
+
const controller = new AbortController();
|
|
391
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
392
|
+
try {
|
|
393
|
+
const fetchOptions = {
|
|
394
|
+
method,
|
|
395
|
+
headers,
|
|
396
|
+
signal: controller.signal
|
|
397
|
+
};
|
|
398
|
+
if (body) {
|
|
399
|
+
fetchOptions.body = JSON.stringify(body);
|
|
400
|
+
}
|
|
401
|
+
const response = await fetch(url, fetchOptions);
|
|
402
|
+
const data = await response.json();
|
|
403
|
+
if (!response.ok || !data.success) {
|
|
404
|
+
const error = new FerryError(
|
|
405
|
+
data.error?.message ?? "An error occurred",
|
|
406
|
+
data.error?.code ?? "UNKNOWN_ERROR",
|
|
407
|
+
response.status
|
|
408
|
+
);
|
|
409
|
+
throw error;
|
|
410
|
+
}
|
|
411
|
+
return data.data;
|
|
412
|
+
} finally {
|
|
413
|
+
clearTimeout(timeoutId);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* Make a paginated API request
|
|
418
|
+
*/
|
|
419
|
+
async requestPaginated(path, params) {
|
|
420
|
+
const searchParams = new URLSearchParams();
|
|
421
|
+
if (params) {
|
|
422
|
+
for (const [key, value] of Object.entries(params)) {
|
|
423
|
+
if (value !== void 0) {
|
|
424
|
+
searchParams.set(key, String(value));
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
const url = searchParams.toString() ? `${path}?${searchParams}` : path;
|
|
429
|
+
const response = await fetch(`${this.baseUrl}${url}`, {
|
|
430
|
+
headers: {
|
|
431
|
+
Authorization: `Basic ${Buffer.from(this.apiKey + ":").toString("base64")}`
|
|
432
|
+
}
|
|
433
|
+
});
|
|
434
|
+
const result = await response.json();
|
|
435
|
+
if (!response.ok || !result.success) {
|
|
436
|
+
throw new FerryError(
|
|
437
|
+
result.error?.message ?? "An error occurred",
|
|
438
|
+
result.error?.code ?? "UNKNOWN_ERROR",
|
|
439
|
+
response.status
|
|
440
|
+
);
|
|
441
|
+
}
|
|
442
|
+
return {
|
|
443
|
+
data: result.data,
|
|
444
|
+
meta: result.meta
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
};
|
|
448
|
+
var FerryError = class extends Error {
|
|
449
|
+
constructor(message, code, status) {
|
|
450
|
+
super(message);
|
|
451
|
+
this.code = code;
|
|
452
|
+
this.status = status;
|
|
453
|
+
this.name = "FerryError";
|
|
454
|
+
}
|
|
455
|
+
};
|
|
456
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
457
|
+
0 && (module.exports = {
|
|
458
|
+
Connections,
|
|
459
|
+
Exports,
|
|
460
|
+
Ferry,
|
|
461
|
+
FerryError,
|
|
462
|
+
PortalSessions
|
|
463
|
+
});
|
|
464
|
+
//# sourceMappingURL=index.cjs.map
|