@expresscsv/sdk 0.1.21 → 0.1.23
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 +82 -224
- package/dist/index.d.cts +121 -109
- package/dist/index.d.mts +121 -109
- package/dist/index.d.ts +121 -109
- package/dist/index.js +2 -2
- package/dist/index.mjs +2 -2
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/@expresscsv/sdk)
|
|
4
4
|

|
|
5
5
|
|
|
6
|
-
A TypeScript SDK for embedding the [ExpressCSV](https://expresscsv.com) CSV
|
|
6
|
+
A TypeScript SDK for embedding the [ExpressCSV](https://expresscsv.com) CSV importer into any web application. Define a schema, open the importer, and receive validated, typed data in chunks.
|
|
7
7
|
|
|
8
8
|
If you want to define schemas in shared or backend code without any frontend dependencies, use [`@expresscsv/schemas`](https://www.npmjs.com/package/@expresscsv/schemas) for the schema definition itself, then pass that schema into `@expresscsv/sdk`.
|
|
9
9
|
|
|
@@ -35,223 +35,93 @@ const schema = x.row({
|
|
|
35
35
|
|
|
36
36
|
const importer = new CSVImporter({
|
|
37
37
|
schema,
|
|
38
|
-
|
|
38
|
+
getSessionToken: async () => fetchSessionToken(),
|
|
39
39
|
importIdentifier: "user-import",
|
|
40
40
|
title: "Import Users",
|
|
41
41
|
});
|
|
42
42
|
|
|
43
|
-
// Open the
|
|
43
|
+
// Open the importer and process data in chunks
|
|
44
44
|
importer.open({
|
|
45
45
|
onData: (chunk, next) => {
|
|
46
46
|
console.log(`Chunk ${chunk.currentChunkIndex + 1}/${chunk.totalChunks}`);
|
|
47
|
+
console.log("Session:", chunk.sessionId);
|
|
48
|
+
console.log("Idempotency key:", chunk.chunkIdempotencyKey);
|
|
47
49
|
console.log("Records:", chunk.records);
|
|
48
50
|
// Process your validated, typed records here
|
|
49
51
|
next();
|
|
50
52
|
},
|
|
51
|
-
onComplete: () => {
|
|
52
|
-
console.log("All chunks processed successfully");
|
|
53
|
+
onComplete: ({ sessionId }) => {
|
|
54
|
+
console.log("All chunks processed successfully for", sessionId);
|
|
53
55
|
},
|
|
54
|
-
onError: (error) => {
|
|
55
|
-
console.error("Import failed
|
|
56
|
+
onError: (error, { sessionId }) => {
|
|
57
|
+
console.error("Import failed for", sessionId, error);
|
|
56
58
|
},
|
|
57
59
|
});
|
|
58
60
|
```
|
|
59
61
|
|
|
60
62
|
If your schema is assembled dynamically at runtime, still use `x.row(...)`. Just note that dynamic schema assembly can widen TypeScript inference, so use it intentionally when you need runtime-driven columns.
|
|
61
63
|
|
|
62
|
-
|
|
64
|
+
Have your backend keep the ExpressCSV secret key, call the ExpressCSV session-creation endpoint, and return a short-lived importer session token to the browser via `getSessionToken`. The SDK opens the importer immediately, then completes the initial session bootstrap in the background.
|
|
63
65
|
|
|
64
|
-
##
|
|
66
|
+
## Delivery
|
|
65
67
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
```typescript
|
|
69
|
-
importer.open({
|
|
70
|
-
webhook: {
|
|
71
|
-
url: "https://api.example.com/webhooks/csv-import",
|
|
72
|
-
method: "POST",
|
|
73
|
-
headers: {
|
|
74
|
-
Authorization: "Bearer your-api-token",
|
|
75
|
-
},
|
|
76
|
-
metadata: {
|
|
77
|
-
source: "web-app",
|
|
78
|
-
userId: "user-123",
|
|
79
|
-
},
|
|
80
|
-
},
|
|
81
|
-
onComplete: () => {
|
|
82
|
-
console.log("Webhook delivery initiated");
|
|
83
|
-
},
|
|
84
|
-
onError: (error) => {
|
|
85
|
-
console.error("Delivery error:", error);
|
|
86
|
-
},
|
|
87
|
-
});
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
### Webhook Payload Structure
|
|
91
|
-
|
|
92
|
-
Each chunk is delivered as a JSON `POST` (or whichever method you configured) to your endpoint. The request body has this shape:
|
|
93
|
-
|
|
94
|
-
```typescript
|
|
95
|
-
interface WebhookPayload {
|
|
96
|
-
/** Imported records for this chunk, matching your schema */
|
|
97
|
-
records: Record<string, unknown>[];
|
|
98
|
-
/** 0-based index of the current chunk */
|
|
99
|
-
chunkIndex: number;
|
|
100
|
-
/** Total number of chunks in this delivery */
|
|
101
|
-
totalChunks: number;
|
|
102
|
-
/** Total number of records across all chunks */
|
|
103
|
-
totalRecords: number;
|
|
104
|
-
/** Present only if you passed `metadata` in `WebhookConfig` */
|
|
105
|
-
metadata?: Record<string, unknown>;
|
|
106
|
-
/** Delivery context added by ExpressCSV */
|
|
107
|
-
delivery: {
|
|
108
|
-
publishableKey: string;
|
|
109
|
-
environmentName: string;
|
|
110
|
-
environmentType: string;
|
|
111
|
-
teamSlug: string;
|
|
112
|
-
importIdentifier: string;
|
|
113
|
-
deliveryId: string;
|
|
114
|
-
timestamp: string; // ISO 8601
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
When you already have a schema, prefer `InferWebhookPayload<typeof schema>` from `@expresscsv/schemas` instead of rewriting this object shape by hand.
|
|
120
|
-
|
|
121
|
-
Example payload:
|
|
122
|
-
|
|
123
|
-
```json
|
|
124
|
-
{
|
|
125
|
-
"records": [
|
|
126
|
-
{ "name": "Alice Johnson", "email": "alice@example.com", "age": 32 },
|
|
127
|
-
{ "name": "Bob Smith", "email": "bob@example.com", "age": 45 }
|
|
128
|
-
],
|
|
129
|
-
"chunkIndex": 0,
|
|
130
|
-
"totalChunks": 3,
|
|
131
|
-
"totalRecords": 2500,
|
|
132
|
-
"metadata": {
|
|
133
|
-
"source": "web-app",
|
|
134
|
-
"userId": "user-123"
|
|
135
|
-
},
|
|
136
|
-
"delivery": {
|
|
137
|
-
"publishableKey": "pk_live_abc123",
|
|
138
|
-
"environmentName": "Production",
|
|
139
|
-
"environmentType": "production",
|
|
140
|
-
"teamSlug": "my-team",
|
|
141
|
-
"importIdentifier": "user-import",
|
|
142
|
-
"deliveryId": "del_abc123",
|
|
143
|
-
"timestamp": "2026-03-02T14:30:00.000Z"
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
The request includes a `Content-Type: application/json` header plus any custom `headers` you specified in `WebhookConfig`.
|
|
149
|
-
|
|
150
|
-
### Handling Webhooks on Your Server
|
|
151
|
-
|
|
152
|
-
Your endpoint should return a **2xx** status code to acknowledge each chunk. Non-2xx responses trigger the following retry behaviour:
|
|
153
|
-
|
|
154
|
-
- **5xx** and **429** responses are retried automatically (up to 5 attempts per chunk).
|
|
155
|
-
- **4xx** responses (except 429) are treated as permanent failures and are **not** retried.
|
|
156
|
-
|
|
157
|
-
Chunks are delivered **serially** — the next chunk is only sent after the previous one succeeds.
|
|
158
|
-
|
|
159
|
-
If your schema is defined in shared or backend code with `@expresscsv/schemas`, you can reuse the built-in webhook payload helper when handling deliveries:
|
|
160
|
-
|
|
161
|
-
```typescript
|
|
162
|
-
import express from "express";
|
|
163
|
-
import type { InferWebhookPayload } from "@expresscsv/schemas";
|
|
164
|
-
import { employeeSchema } from "../shared/employee-schema";
|
|
165
|
-
|
|
166
|
-
const app = express();
|
|
167
|
-
app.use(express.json());
|
|
168
|
-
|
|
169
|
-
app.post("/webhooks/csv-import", async (req, res) => {
|
|
170
|
-
const payload = req.body as InferWebhookPayload<typeof employeeSchema>;
|
|
171
|
-
|
|
172
|
-
await db.insertMany("users", payload.records);
|
|
173
|
-
|
|
174
|
-
res.status(200).json({ ok: true });
|
|
175
|
-
});
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
Below is a minimal Express.js example:
|
|
179
|
-
|
|
180
|
-
```typescript
|
|
181
|
-
import express from "express";
|
|
182
|
-
|
|
183
|
-
const app = express();
|
|
184
|
-
app.use(express.json());
|
|
185
|
-
|
|
186
|
-
app.post("/webhooks/csv-import", async (req, res) => {
|
|
187
|
-
const token = req.headers.authorization;
|
|
188
|
-
if (token !== "Bearer your-api-token") {
|
|
189
|
-
return res.status(401).json({ error: "Unauthorized" });
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
const { records, chunkIndex, totalChunks, totalRecords, metadata, delivery } =
|
|
193
|
-
req.body;
|
|
194
|
-
|
|
195
|
-
try {
|
|
196
|
-
// Process the records — e.g. insert into your database
|
|
197
|
-
await db.insertMany("users", records);
|
|
198
|
-
|
|
199
|
-
console.log(
|
|
200
|
-
`Chunk ${chunkIndex + 1}/${totalChunks} processed ` +
|
|
201
|
-
`(${records.length} records, delivery ${delivery.deliveryId})`
|
|
202
|
-
);
|
|
203
|
-
|
|
204
|
-
res.status(200).json({ success: true });
|
|
205
|
-
} catch (error) {
|
|
206
|
-
// Return 500 so ExpressCSV retries this chunk
|
|
207
|
-
console.error("Failed to process chunk:", error);
|
|
208
|
-
res.status(500).json({ error: "Internal server error" });
|
|
209
|
-
}
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
app.listen(3000);
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
**Tips:**
|
|
216
|
-
|
|
217
|
-
- Use `delivery.deliveryId` and `chunkIndex` to **deduplicate** retried chunks (the same chunk may be delivered more than once on retry).
|
|
218
|
-
- Use `chunkIndex` and `totalChunks` to track progress and know when the full import is complete (`chunkIndex === totalChunks - 1` for the last chunk).
|
|
219
|
-
- Store `metadata` alongside imported records if you need to correlate the import with a specific user or action in your app.
|
|
220
|
-
|
|
221
|
-
### Combined Local Callback and Webhook
|
|
222
|
-
|
|
223
|
-
You can use both `onData` and `webhook` simultaneously:
|
|
68
|
+
ExpressCSV delivers imported data through `onData`. Your app receives validated chunks in the browser and can forward them to your backend using whatever request shape fits your stack.
|
|
224
69
|
|
|
225
70
|
```typescript
|
|
226
71
|
importer.open({
|
|
227
72
|
chunkSize: 500,
|
|
228
73
|
onData: async (chunk, next) => {
|
|
229
|
-
await
|
|
74
|
+
const response = await fetch("/api/import-users/chunks", {
|
|
75
|
+
method: "POST",
|
|
76
|
+
headers: {
|
|
77
|
+
"Content-Type": "application/json",
|
|
78
|
+
},
|
|
79
|
+
body: JSON.stringify({
|
|
80
|
+
sessionId: chunk.sessionId,
|
|
81
|
+
chunkIdempotencyKey: chunk.chunkIdempotencyKey,
|
|
82
|
+
records: chunk.records,
|
|
83
|
+
currentChunkIndex: chunk.currentChunkIndex,
|
|
84
|
+
totalChunks: chunk.totalChunks,
|
|
85
|
+
totalRecords: chunk.totalRecords,
|
|
86
|
+
}),
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
if (!response.ok) {
|
|
90
|
+
throw new Error("Backend rejected this import chunk");
|
|
91
|
+
}
|
|
92
|
+
|
|
230
93
|
next();
|
|
231
94
|
},
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
headers: { Authorization: "Bearer your-api-token" },
|
|
235
|
-
},
|
|
236
|
-
onComplete: () => {
|
|
237
|
-
console.log("Local processing and webhook delivery complete");
|
|
95
|
+
onComplete: ({ sessionId }) => {
|
|
96
|
+
console.log("Import complete for", sessionId);
|
|
238
97
|
},
|
|
239
98
|
});
|
|
240
99
|
```
|
|
241
100
|
|
|
101
|
+
Each delivered chunk includes:
|
|
102
|
+
|
|
103
|
+
- `records`
|
|
104
|
+
- `sessionId`
|
|
105
|
+
- `chunkIdempotencyKey`
|
|
106
|
+
- `currentChunkIndex`
|
|
107
|
+
- `totalChunks`
|
|
108
|
+
- `totalRecords`
|
|
109
|
+
|
|
110
|
+
Use `sessionId` and `chunkIdempotencyKey` to stage writes safely and deduplicate retries from your own app logic.
|
|
111
|
+
|
|
242
112
|
## Preloading
|
|
243
113
|
|
|
244
|
-
By default, the SDK preloads the
|
|
114
|
+
By default, the SDK preloads the importer in a hidden iframe for instant display when `open()` is called. This provides the best user experience while the initial session bootstrap continues in the background.
|
|
245
115
|
|
|
246
116
|
```typescript
|
|
247
117
|
// Preload is enabled by default
|
|
248
118
|
const importer = new CSVImporter({
|
|
249
119
|
schema,
|
|
250
|
-
|
|
120
|
+
getSessionToken: async () => fetchSessionToken(),
|
|
251
121
|
importIdentifier: "user-import",
|
|
252
122
|
});
|
|
253
123
|
|
|
254
|
-
// Later, the
|
|
124
|
+
// Later, the importer appears instantly
|
|
255
125
|
importer.open({ onData: (chunk, next) => { /* ... */ next(); } });
|
|
256
126
|
```
|
|
257
127
|
|
|
@@ -260,7 +130,7 @@ To disable preloading (there will be a brief loading screen instead):
|
|
|
260
130
|
```typescript
|
|
261
131
|
const importer = new CSVImporter({
|
|
262
132
|
schema,
|
|
263
|
-
|
|
133
|
+
getSessionToken: async () => fetchSessionToken(),
|
|
264
134
|
importIdentifier: "user-import",
|
|
265
135
|
preload: false,
|
|
266
136
|
});
|
|
@@ -284,7 +154,7 @@ const candidateSchema = x.row({
|
|
|
284
154
|
|
|
285
155
|
const importer = new CSVImporter({
|
|
286
156
|
schema: candidateSchema,
|
|
287
|
-
|
|
157
|
+
getSessionToken: async () => fetchSessionToken(),
|
|
288
158
|
importIdentifier: "candidate-import",
|
|
289
159
|
templateDownload: {
|
|
290
160
|
source: "generate",
|
|
@@ -302,7 +172,7 @@ const importer = new CSVImporter({
|
|
|
302
172
|
|
|
303
173
|
## Theming and Styling
|
|
304
174
|
|
|
305
|
-
Customize the
|
|
175
|
+
Customize the importer's appearance with the `theme`, `colorMode`, `customCSS`, and `fonts` options.
|
|
306
176
|
|
|
307
177
|
### Theme
|
|
308
178
|
|
|
@@ -340,7 +210,7 @@ const dualTheme: ECSVTheme = {
|
|
|
340
210
|
|
|
341
211
|
const importer = new CSVImporter({
|
|
342
212
|
schema,
|
|
343
|
-
|
|
213
|
+
getSessionToken: async () => fetchSessionToken(),
|
|
344
214
|
importIdentifier: "user-import",
|
|
345
215
|
theme,
|
|
346
216
|
});
|
|
@@ -384,7 +254,7 @@ Control light/dark mode with `colorMode`:
|
|
|
384
254
|
```typescript
|
|
385
255
|
const importer = new CSVImporter({
|
|
386
256
|
schema,
|
|
387
|
-
|
|
257
|
+
getSessionToken: async () => fetchSessionToken(),
|
|
388
258
|
importIdentifier: "user-import",
|
|
389
259
|
colorMode: "system", // 'light' | 'dark' | 'system'
|
|
390
260
|
});
|
|
@@ -397,7 +267,7 @@ Inject custom CSS for fine-grained styling overrides.
|
|
|
397
267
|
```typescript
|
|
398
268
|
const importer = new CSVImporter({
|
|
399
269
|
schema,
|
|
400
|
-
|
|
270
|
+
getSessionToken: async () => fetchSessionToken(),
|
|
401
271
|
importIdentifier: "user-import",
|
|
402
272
|
customCSS: `
|
|
403
273
|
.ecsv [data-step="upload"] {
|
|
@@ -417,7 +287,7 @@ Load custom fonts via the `fonts` option:
|
|
|
417
287
|
```typescript
|
|
418
288
|
const importer = new CSVImporter({
|
|
419
289
|
schema,
|
|
420
|
-
|
|
290
|
+
getSessionToken: async () => fetchSessionToken(),
|
|
421
291
|
importIdentifier: "user-import",
|
|
422
292
|
fonts: {
|
|
423
293
|
title: { source: "google", name: "Space Grotesk", weights: [400, 600, 700] },
|
|
@@ -434,7 +304,7 @@ const importer = new CSVImporter({
|
|
|
434
304
|
|
|
435
305
|
The `x` schema builder provides a type-safe, fluent API for defining your CSV structure.
|
|
436
306
|
|
|
437
|
-
For apps that share schema definitions with backend code
|
|
307
|
+
For apps that share schema definitions with backend code, prefer defining the schema in `@expresscsv/schemas` and importing it into your frontend. That keeps schema authoring free of importer/runtime dependencies.
|
|
438
308
|
|
|
439
309
|
### Field Types
|
|
440
310
|
|
|
@@ -539,7 +409,7 @@ All field types support:
|
|
|
539
409
|
|
|
540
410
|
| Modifier | Description |
|
|
541
411
|
|---|---|
|
|
542
|
-
| `.label(text)` | User-facing label shown in the
|
|
412
|
+
| `.label(text)` | User-facing label shown in the importer |
|
|
543
413
|
| `.description(text)` | Help text for the field |
|
|
544
414
|
| `.example(text)` | Example value shown as placeholder |
|
|
545
415
|
| `.optional()` | Makes the field optional (default is required) |
|
|
@@ -590,7 +460,7 @@ x.string().refine(
|
|
|
590
460
|
)
|
|
591
461
|
```
|
|
592
462
|
|
|
593
|
-
**Object-returning validator** — inline `valid`, `message`, and an optional `suggestedFix` the
|
|
463
|
+
**Object-returning validator** — inline `valid`, `message`, and an optional `suggestedFix` the importer can offer the user:
|
|
594
464
|
|
|
595
465
|
```typescript
|
|
596
466
|
x.string().refine((value) => ({
|
|
@@ -657,7 +527,7 @@ x.string().refineBatch((values) => {
|
|
|
657
527
|
|
|
658
528
|
### `suggestedFix`
|
|
659
529
|
|
|
660
|
-
Both `.refine()` and `.refineBatch()` support returning a `suggestedFix` object that the
|
|
530
|
+
Both `.refine()` and `.refineBatch()` support returning a `suggestedFix` object that the importer offers as a one-click fix for the user:
|
|
661
531
|
|
|
662
532
|
```typescript
|
|
663
533
|
interface SuggestedFix {
|
|
@@ -680,24 +550,27 @@ new CSVImporter(options: SDKOptions)
|
|
|
680
550
|
| Option | Type | Required | Default | Description |
|
|
681
551
|
|---|---|---|---|---|
|
|
682
552
|
| `schema` | Schema | Yes | - | Schema definition created with `x.row()` |
|
|
683
|
-
| `
|
|
553
|
+
| `getSessionToken` | `() => Promise<string>` | Yes | - | Async callback that asks your backend for a short-lived importer session token |
|
|
684
554
|
| `importIdentifier` | `string` | Yes | - | Unique identifier for this import type |
|
|
685
|
-
| `title` | `string` | No | - | Title shown in the
|
|
686
|
-
| `preload` | `boolean` | No | `true` | Preload
|
|
555
|
+
| `title` | `string` | No | - | Title shown in the importer header |
|
|
556
|
+
| `preload` | `boolean` | No | `true` | Preload the importer for instant display |
|
|
687
557
|
| `debug` | `boolean` | No | `false` | Enable debug logging |
|
|
688
558
|
| `theme` | `ECSVTheme` | No | - | Custom theme configuration |
|
|
689
559
|
| `colorMode` | `ColorModePref` | No | - | Light/dark mode (`'light'`, `'dark'`, or `'system'`) |
|
|
690
|
-
| `customCSS` | `string` | No | - | Custom CSS to inject into the
|
|
560
|
+
| `customCSS` | `string` | No | - | Custom CSS to inject into the importer |
|
|
691
561
|
| `fonts` | `Record<string, ECSVFontSource>` | No | - | Custom font sources |
|
|
692
562
|
| `stepDisplay` | `'progressBar' \| 'segmented' \| 'numbered'` | No | `'progressBar'` | Step indicator style |
|
|
693
563
|
| `previewSchemaBeforeUpload` | `boolean` | No | `true` | Show schema preview before upload |
|
|
564
|
+
| `aiColumnMatching` | `boolean` | No | `true` | Enable AI-assisted column matching |
|
|
565
|
+
| `aiTransform` | `boolean` | No | `true` | Enable AI-assisted transform generation |
|
|
694
566
|
| `templateDownload` | `TemplateDownloadOptions<TSchema>` | No | - | Template download configuration with optional schema-typed example rows |
|
|
695
|
-
| `
|
|
567
|
+
| `storage` | `{ type: "local" } \| { type: "custom", ... }` | No | - | Enable Recovered Sessions with the built-in local backend or a custom adapter implementing `get`, `set`, and `remove` |
|
|
696
568
|
| `locale` | `DeepPartial<ExpressCSVLocaleInput>` | No | - | Localization overrides |
|
|
569
|
+
| `disableStatusStep` | `boolean` | No | - | Skip the success/error status screen |
|
|
697
570
|
|
|
698
571
|
#### `open(options)`
|
|
699
572
|
|
|
700
|
-
Opens the
|
|
573
|
+
Opens the importer and begins the import flow.
|
|
701
574
|
|
|
702
575
|
```typescript
|
|
703
576
|
importer.open(options: OpenOptions): void
|
|
@@ -705,21 +578,18 @@ importer.open(options: OpenOptions): void
|
|
|
705
578
|
|
|
706
579
|
| Option | Type | Required | Description |
|
|
707
580
|
|---|---|---|---|
|
|
708
|
-
| `onData` | `(chunk: RecordsChunk<T>, next: () => void) => void` |
|
|
709
|
-
| `webhook` | `WebhookConfig` | * | Webhook endpoint for server-side delivery |
|
|
581
|
+
| `onData` | `(chunk: RecordsChunk<T>, next: () => void) => void` | Yes | Callback for each delivered chunk of records. Call `next()` to continue. |
|
|
710
582
|
| `chunkSize` | `number` | No | Records per chunk (default: 1000) |
|
|
711
|
-
| `onComplete` | `() => void` | No | Called when all chunks have been processed |
|
|
712
|
-
| `onCancel` | `() => void` | No | Called when the user cancels the import |
|
|
713
|
-
| `onError` | `(error: Error) => void` | No | Called when an error occurs |
|
|
714
|
-
| `
|
|
715
|
-
| `
|
|
583
|
+
| `onComplete` | `(context: { sessionId: string }) => void` | No | Called when all chunks have been processed |
|
|
584
|
+
| `onCancel` | `(context: { sessionId: string }) => void` | No | Called when the user cancels the import |
|
|
585
|
+
| `onError` | `(error: Error, context: { sessionId: string }) => void` | No | Called when an error occurs |
|
|
586
|
+
| `onImporterOpen` | `() => void` | No | Called when the importer opens |
|
|
587
|
+
| `onImporterClose` | `(reason: 'user_close' \| 'cancel' \| 'complete' \| 'error') => void` | No | Called when the importer closes |
|
|
716
588
|
| `onStepChange` | `(stepId, previousStepId?) => void` | No | Called when the wizard step changes |
|
|
717
589
|
|
|
718
|
-
\* At least one of `onData` or `webhook` is required.
|
|
719
|
-
|
|
720
590
|
#### `close(reason?)`
|
|
721
591
|
|
|
722
|
-
Closes the
|
|
592
|
+
Closes the importer and cleans up resources.
|
|
723
593
|
|
|
724
594
|
```typescript
|
|
725
595
|
await importer.close(reason?: 'user_close' | 'cancel' | 'complete' | 'error'): Promise<void>
|
|
@@ -731,18 +601,17 @@ await importer.close(reason?: 'user_close' | 'cancel' | 'complete' | 'error'): P
|
|
|
731
601
|
|
|
732
602
|
| Method | Returns | Description |
|
|
733
603
|
|---|---|---|
|
|
734
|
-
| `getState()` | `
|
|
735
|
-
| `getIsReady()` | `boolean` | Whether the
|
|
736
|
-
| `getIsOpen()` | `boolean` | Whether the
|
|
604
|
+
| `getState()` | `ImporterState` | Current importer lifecycle state |
|
|
605
|
+
| `getIsReady()` | `boolean` | Whether the importer is ready or open |
|
|
606
|
+
| `getIsOpen()` | `boolean` | Whether the importer is currently open |
|
|
737
607
|
| `getConnectionStatus()` | `boolean` | Whether the iframe connection is active |
|
|
738
|
-
| `getCanRestart()` | `boolean` | Whether the
|
|
608
|
+
| `getCanRestart()` | `boolean` | Whether the importer can be restarted |
|
|
739
609
|
| `getLastError()` | `Error \| null` | Last error, if any |
|
|
740
610
|
| `getStatus()` | `object` | Comprehensive status snapshot |
|
|
741
|
-
| `getVersion()` | `string` | SDK version |
|
|
742
611
|
|
|
743
612
|
#### `restart(newOptions?)`
|
|
744
613
|
|
|
745
|
-
Restarts the
|
|
614
|
+
Restarts the importer, optionally with updated options. Returns `Promise<void>`.
|
|
746
615
|
|
|
747
616
|
### `RecordsChunk<T>`
|
|
748
617
|
|
|
@@ -754,19 +623,8 @@ interface RecordsChunk<T> {
|
|
|
754
623
|
totalChunks: number;
|
|
755
624
|
currentChunkIndex: number;
|
|
756
625
|
totalRecords: number;
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
### `WebhookConfig`
|
|
761
|
-
|
|
762
|
-
```typescript
|
|
763
|
-
interface WebhookConfig {
|
|
764
|
-
url: string;
|
|
765
|
-
headers?: Record<string, string>;
|
|
766
|
-
method?: "POST" | "PUT" | "PATCH";
|
|
767
|
-
timeout?: number;
|
|
768
|
-
retries?: number;
|
|
769
|
-
metadata?: Record<string, unknown>;
|
|
626
|
+
sessionId: string;
|
|
627
|
+
chunkIdempotencyKey: string;
|
|
770
628
|
}
|
|
771
629
|
```
|
|
772
630
|
|
|
@@ -788,7 +646,7 @@ type Row = Infer<typeof schema>;
|
|
|
788
646
|
|
|
789
647
|
const importer = new CSVImporter({
|
|
790
648
|
schema,
|
|
791
|
-
|
|
649
|
+
getSessionToken: async () => fetchSessionToken(),
|
|
792
650
|
importIdentifier: "user-import",
|
|
793
651
|
});
|
|
794
652
|
|