@expresscsv/sdk 0.1.4 → 0.1.5
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 +279 -120
- package/package.json +1 -1
- package/dist/.dts/errors.d.ts +0 -6
- package/dist/.dts/index.d.ts +0 -207
package/README.md
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @expresscsv/sdk
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@expresscsv/sdk)
|
|
4
|
+
[](https://github.com/nicholasgriffintn/expresscsv/blob/main/LICENSE)
|
|
5
|
+
|
|
6
|
+
A TypeScript SDK for embedding the [ExpressCSV](https://expresscsv.com) CSV import widget into any web application. Define a schema, open the widget, and receive validated, typed data in chunks.
|
|
4
7
|
|
|
5
8
|
## Installation
|
|
6
9
|
|
|
@@ -15,191 +18,347 @@ npm install @expresscsv/sdk
|
|
|
15
18
|
yarn add @expresscsv/sdk
|
|
16
19
|
```
|
|
17
20
|
|
|
18
|
-
|
|
21
|
+
> **Looking for React?** Use [`@expresscsv/react`](https://www.npmjs.com/package/@expresscsv/react) for a hook-based integration.
|
|
19
22
|
|
|
20
|
-
|
|
23
|
+
## Quick Start
|
|
21
24
|
|
|
22
25
|
```typescript
|
|
23
|
-
import { CSVImporter } from "@expresscsv/sdk";
|
|
26
|
+
import { CSVImporter, x } from "@expresscsv/sdk";
|
|
24
27
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
+
const schema = x.row({
|
|
29
|
+
name: x.string().label("Full Name"),
|
|
30
|
+
email: x.string().email().label("Email Address"),
|
|
31
|
+
age: x.number().label("Age").min(18).max(120),
|
|
28
32
|
});
|
|
29
33
|
|
|
30
|
-
|
|
31
|
-
|
|
34
|
+
const importer = new CSVImporter({
|
|
35
|
+
schema,
|
|
36
|
+
publishableKey: "your-publishable-key",
|
|
37
|
+
importIdentifier: "user-import",
|
|
38
|
+
title: "Import Users",
|
|
39
|
+
});
|
|
32
40
|
|
|
33
|
-
//
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
41
|
+
// Open the widget and process data in chunks
|
|
42
|
+
importer.open({
|
|
43
|
+
onData: (chunk, next) => {
|
|
44
|
+
console.log(`Chunk ${chunk.currentChunkIndex + 1}/${chunk.totalChunks}`);
|
|
45
|
+
console.log("Records:", chunk.records);
|
|
46
|
+
// Process your validated, typed records here
|
|
47
|
+
next();
|
|
48
|
+
},
|
|
49
|
+
onComplete: () => {
|
|
50
|
+
console.log("All chunks processed successfully");
|
|
51
|
+
},
|
|
52
|
+
onError: (error) => {
|
|
53
|
+
console.error("Import failed:", error);
|
|
38
54
|
},
|
|
39
55
|
});
|
|
40
|
-
|
|
41
|
-
// Clean up when done
|
|
42
|
-
importer.close();
|
|
43
56
|
```
|
|
44
57
|
|
|
45
|
-
|
|
58
|
+
Your `publishableKey` is available from the [ExpressCSV dashboard](https://expresscsv.com). Two key types are available: **production** keys for live usage, and **dev/testing** keys that provide unlimited test imports.
|
|
46
59
|
|
|
47
|
-
|
|
60
|
+
## Webhook Delivery
|
|
48
61
|
|
|
49
|
-
|
|
50
|
-
import { CSVImporter, x } from "@expresscsv/sdk";
|
|
62
|
+
Deliver imported data directly to your backend via webhook instead of (or in addition to) a local callback:
|
|
51
63
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
64
|
+
```typescript
|
|
65
|
+
importer.open({
|
|
66
|
+
webhook: {
|
|
67
|
+
url: "https://api.example.com/webhooks/csv-import",
|
|
68
|
+
method: "POST",
|
|
69
|
+
headers: {
|
|
70
|
+
Authorization: "Bearer your-api-token",
|
|
71
|
+
},
|
|
72
|
+
metadata: {
|
|
73
|
+
source: "web-app",
|
|
74
|
+
userId: "user-123",
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
onComplete: () => {
|
|
78
|
+
console.log("Webhook delivery initiated");
|
|
79
|
+
},
|
|
80
|
+
onError: (error) => {
|
|
81
|
+
console.error("Delivery error:", error);
|
|
82
|
+
},
|
|
58
83
|
});
|
|
84
|
+
```
|
|
59
85
|
|
|
60
|
-
|
|
61
|
-
const importer = new CSVImporter({
|
|
62
|
-
title: "User Import",
|
|
63
|
-
fields: schema,
|
|
64
|
-
onResults: (data) => {
|
|
65
|
-
// data is fully typed based on your schema
|
|
66
|
-
console.log(`Imported ${data.length} users`);
|
|
67
|
-
|
|
68
|
-
// Access properties with full type safety
|
|
69
|
-
data.forEach(user => {
|
|
70
|
-
console.log(`Name: ${user.name}, Email: ${user.email}`);
|
|
71
|
-
if (user.age) {
|
|
72
|
-
console.log(`Age: ${user.age + 1}`); // Numbers are typed correctly
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
});
|
|
86
|
+
### Combined Local Callback and Webhook
|
|
77
87
|
|
|
78
|
-
|
|
79
|
-
importer.onResults = (data) => {
|
|
80
|
-
// Process the validated data
|
|
81
|
-
processUsers(data);
|
|
82
|
-
};
|
|
88
|
+
You can use both `onData` and `webhook` simultaneously:
|
|
83
89
|
|
|
84
|
-
|
|
85
|
-
|
|
90
|
+
```typescript
|
|
91
|
+
importer.open({
|
|
92
|
+
chunkSize: 500,
|
|
93
|
+
onData: async (chunk, next) => {
|
|
94
|
+
await saveToLocalDatabase(chunk.records);
|
|
95
|
+
next();
|
|
96
|
+
},
|
|
97
|
+
webhook: {
|
|
98
|
+
url: "https://api.example.com/webhooks/csv-import",
|
|
99
|
+
headers: { Authorization: "Bearer your-api-token" },
|
|
100
|
+
},
|
|
101
|
+
onComplete: () => {
|
|
102
|
+
console.log("Local processing and webhook delivery complete");
|
|
103
|
+
},
|
|
104
|
+
});
|
|
86
105
|
```
|
|
87
106
|
|
|
88
|
-
|
|
107
|
+
## Preloading
|
|
89
108
|
|
|
90
|
-
By default, the SDK preloads the widget in
|
|
109
|
+
By default, the SDK preloads the widget in a hidden iframe for instant display when `open()` is called. This provides the best user experience.
|
|
91
110
|
|
|
92
111
|
```typescript
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
const schema = x.row({
|
|
96
|
-
name: x.string().humanLabel("Full Name"),
|
|
97
|
-
email: x.email().humanLabel("Email Address"),
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
// Preload is enabled by default - widget loads in background
|
|
112
|
+
// Preload is enabled by default
|
|
101
113
|
const importer = new CSVImporter({
|
|
102
114
|
schema,
|
|
115
|
+
publishableKey: "your-publishable-key",
|
|
103
116
|
importIdentifier: "user-import",
|
|
104
|
-
title: "User Import",
|
|
105
117
|
});
|
|
106
118
|
|
|
107
|
-
// Later,
|
|
108
|
-
|
|
119
|
+
// Later, the widget appears instantly
|
|
120
|
+
importer.open({ onData: (chunk, next) => { /* ... */ next(); } });
|
|
109
121
|
```
|
|
110
122
|
|
|
111
|
-
To disable
|
|
123
|
+
To disable preloading:
|
|
112
124
|
|
|
113
125
|
```typescript
|
|
114
126
|
const importer = new CSVImporter({
|
|
115
127
|
schema,
|
|
128
|
+
publishableKey: "your-publishable-key",
|
|
116
129
|
importIdentifier: "user-import",
|
|
117
|
-
|
|
118
|
-
preload: false, // Opt-out of preload
|
|
130
|
+
preload: false,
|
|
119
131
|
});
|
|
120
132
|
```
|
|
121
133
|
|
|
134
|
+
## Schema Builder
|
|
135
|
+
|
|
136
|
+
The `x` schema builder provides a type-safe, fluent API for defining your CSV structure.
|
|
137
|
+
|
|
138
|
+
### Field Types
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
import { x } from "@expresscsv/sdk";
|
|
142
|
+
|
|
143
|
+
const schema = x.row({
|
|
144
|
+
// Strings with validation
|
|
145
|
+
name: x.string().label("Full Name").min(2).max(100),
|
|
146
|
+
email: x.string().email().label("Email"),
|
|
147
|
+
website: x.string().url().label("Website").optional(),
|
|
148
|
+
|
|
149
|
+
// Numbers with constraints
|
|
150
|
+
age: x.number().label("Age").min(0).max(150).integer(),
|
|
151
|
+
salary: x.number().currency("USD").label("Salary").min(0),
|
|
152
|
+
|
|
153
|
+
// Boolean
|
|
154
|
+
isActive: x.boolean().label("Active"),
|
|
155
|
+
|
|
156
|
+
// Dates and times
|
|
157
|
+
startDate: x.date().label("Start Date"),
|
|
158
|
+
createdAt: x.datetime().label("Created At"),
|
|
159
|
+
|
|
160
|
+
// Single selection (requires { label, value } objects)
|
|
161
|
+
role: x.select([
|
|
162
|
+
{ label: "Admin", value: "admin" },
|
|
163
|
+
{ label: "Editor", value: "editor" },
|
|
164
|
+
{ label: "Viewer", value: "viewer" },
|
|
165
|
+
]).label("Role"),
|
|
166
|
+
|
|
167
|
+
// Multi-selection
|
|
168
|
+
tags: x.multiselect([
|
|
169
|
+
{ label: "Engineering", value: "eng" },
|
|
170
|
+
{ label: "Design", value: "design" },
|
|
171
|
+
{ label: "Marketing", value: "mkt" },
|
|
172
|
+
]).label("Tags"),
|
|
173
|
+
});
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Common Modifiers
|
|
177
|
+
|
|
178
|
+
All field types support:
|
|
179
|
+
|
|
180
|
+
| Modifier | Description |
|
|
181
|
+
|---|---|
|
|
182
|
+
| `.label(text)` | User-facing label shown in the widget |
|
|
183
|
+
| `.description(text)` | Help text for the field |
|
|
184
|
+
| `.example(text)` | Example value shown as placeholder |
|
|
185
|
+
| `.optional()` | Makes the field optional (default is required) |
|
|
186
|
+
| `.refine(fn)` | Custom validation function |
|
|
187
|
+
|
|
188
|
+
### String Modifiers
|
|
189
|
+
|
|
190
|
+
| Modifier | Description |
|
|
191
|
+
|---|---|
|
|
192
|
+
| `.email()` | Validates email format |
|
|
193
|
+
| `.url()` | Validates URL format |
|
|
194
|
+
| `.uuid()` | Validates UUID format |
|
|
195
|
+
| `.ip()` | Validates IP address |
|
|
196
|
+
| `.phone()` | Validates phone number |
|
|
197
|
+
| `.regex(pattern)` | Matches a regular expression |
|
|
198
|
+
| `.min(n)` | Minimum string length |
|
|
199
|
+
| `.max(n)` | Maximum string length |
|
|
200
|
+
| `.length(n)` | Exact string length |
|
|
201
|
+
| `.includes(str)` | Must contain substring |
|
|
202
|
+
| `.startsWith(str)` | Must start with prefix |
|
|
203
|
+
| `.endsWith(str)` | Must end with suffix |
|
|
204
|
+
|
|
205
|
+
### Number Modifiers
|
|
206
|
+
|
|
207
|
+
| Modifier | Description |
|
|
208
|
+
|---|---|
|
|
209
|
+
| `.min(n)` | Minimum value |
|
|
210
|
+
| `.max(n)` | Maximum value |
|
|
211
|
+
| `.integer()` | Must be a whole number |
|
|
212
|
+
| `.multipleOf(n)` | Must be a multiple of n |
|
|
213
|
+
| `.currency(code)` | Formats as currency (e.g. `"USD"`) |
|
|
214
|
+
| `.percentage()` | Formats as percentage |
|
|
215
|
+
|
|
122
216
|
## API Reference
|
|
123
217
|
|
|
124
|
-
###
|
|
218
|
+
### `CSVImporter`
|
|
125
219
|
|
|
126
|
-
|
|
127
|
-
|------------------|------------------------|----------|---------|--------------------------------------------|
|
|
128
|
-
| schema | ExType | Yes | - | Schema definition for CSV field validation |
|
|
129
|
-
| importIdentifier | string | Yes | - | Unique identifier for this import |
|
|
130
|
-
| title | string | No | - | Title to display in the widget |
|
|
131
|
-
| publishableKey | string | Yes | - | Publishable key for webhook authentication |
|
|
132
|
-
| debug | boolean | No | false | Enable debug logging |
|
|
133
|
-
| developerMode | boolean | No | false | Enable developer mode features |
|
|
134
|
-
| preload | boolean | No | true | Preload widget in background for instant display. Set to `false` to disable |
|
|
220
|
+
#### Constructor
|
|
135
221
|
|
|
136
|
-
|
|
222
|
+
```typescript
|
|
223
|
+
new CSVImporter(options: SDKOptions)
|
|
224
|
+
```
|
|
137
225
|
|
|
138
|
-
|
|
226
|
+
| Option | Type | Required | Default | Description |
|
|
227
|
+
|---|---|---|---|---|
|
|
228
|
+
| `schema` | Schema | Yes | - | Schema definition created with `x.row()` |
|
|
229
|
+
| `publishableKey` | `string` | Yes | - | Your publishable key from the [dashboard](https://expresscsv.com) |
|
|
230
|
+
| `importIdentifier` | `string` | Yes | - | Unique identifier for this import type |
|
|
231
|
+
| `title` | `string` | No | - | Title shown in the widget header |
|
|
232
|
+
| `preload` | `boolean` | No | `true` | Preload widget for instant display |
|
|
233
|
+
| `debug` | `boolean` | No | `false` | Enable debug logging |
|
|
234
|
+
| `developerMode` | `boolean` | No | `false` | Enable developer mode features |
|
|
235
|
+
| `theme` | `ECSVTheme` | No | - | Custom theme configuration |
|
|
236
|
+
| `colorMode` | `ColorModeConfig` | No | - | Light/dark mode settings |
|
|
237
|
+
| `customCSS` | `string` | No | - | Custom CSS to inject into the widget |
|
|
238
|
+
| `fonts` | `Record<string, ECSVFontSource>` | No | - | Custom font sources |
|
|
239
|
+
| `stepDisplay` | `'progressBar' \| 'segmented' \| 'numbered'` | No | `'progressBar'` | Step indicator style |
|
|
240
|
+
| `previewSchemaBeforeUpload` | `boolean` | No | `true` | Show schema preview before upload |
|
|
241
|
+
| `templateDownload` | `TemplateDownloadConfig` | No | - | Template download configuration |
|
|
242
|
+
| `saveSession` | `boolean` | No | - | Persist session state |
|
|
243
|
+
| `locale` | `DeepPartial<ExpressCSVLocaleInput>` | No | - | Localization overrides |
|
|
244
|
+
|
|
245
|
+
#### `open(options)`
|
|
246
|
+
|
|
247
|
+
Opens the widget and begins the import flow. At least one of `onData` or `webhook` must be provided.
|
|
139
248
|
|
|
140
|
-
|
|
249
|
+
```typescript
|
|
250
|
+
importer.open(options: OpenOptions): void
|
|
251
|
+
```
|
|
141
252
|
|
|
142
|
-
|
|
253
|
+
| Option | Type | Required | Description |
|
|
254
|
+
|---|---|---|---|
|
|
255
|
+
| `onData` | `(chunk: RecordsChunk<T>, next: () => void) => void` | * | Callback for each chunk of records. Call `next()` to continue. |
|
|
256
|
+
| `webhook` | `WebhookConfig` | * | Webhook endpoint for server-side delivery |
|
|
257
|
+
| `chunkSize` | `number` | No | Records per chunk (default: 1000) |
|
|
258
|
+
| `onComplete` | `() => void` | No | Called when all chunks have been processed |
|
|
259
|
+
| `onCancel` | `() => void` | No | Called when the user cancels the import |
|
|
260
|
+
| `onError` | `(error: Error) => void` | No | Called when an error occurs |
|
|
261
|
+
| `onWidgetOpen` | `() => void` | No | Called when the widget opens |
|
|
262
|
+
| `onWidgetClose` | `(reason: string) => void` | No | Called when the widget closes |
|
|
263
|
+
| `onStepChange` | `(stepId, previousStepId?) => void` | No | Called when the wizard step changes |
|
|
143
264
|
|
|
144
|
-
|
|
265
|
+
\* At least one of `onData` or `webhook` is required.
|
|
145
266
|
|
|
146
|
-
#### `close()
|
|
267
|
+
#### `close(reason?)`
|
|
147
268
|
|
|
148
269
|
Closes the widget and cleans up resources.
|
|
149
270
|
|
|
150
|
-
|
|
271
|
+
```typescript
|
|
272
|
+
await importer.close(reason?: 'user_close' | 'cancel' | 'complete' | 'error'): Promise<void>
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
#### Status Methods
|
|
276
|
+
|
|
277
|
+
| Method | Returns | Description |
|
|
278
|
+
|---|---|---|
|
|
279
|
+
| `getState()` | `WidgetState` | Current widget state |
|
|
280
|
+
| `getIsReady()` | `boolean` | Whether the widget is ready or open |
|
|
281
|
+
| `getIsOpen()` | `boolean` | Whether the widget is currently open |
|
|
282
|
+
| `getConnectionStatus()` | `boolean` | Whether the iframe connection is active |
|
|
283
|
+
| `getCanRestart()` | `boolean` | Whether the widget can be restarted |
|
|
284
|
+
| `getLastError()` | `Error \| null` | Last error, if any |
|
|
285
|
+
| `getStatus()` | `object` | Comprehensive status snapshot |
|
|
286
|
+
| `getVersion()` | `string` | SDK version |
|
|
151
287
|
|
|
152
|
-
|
|
288
|
+
#### `resetWidget()`
|
|
153
289
|
|
|
154
|
-
|
|
290
|
+
Resets the widget state. Returns `Promise<void>`.
|
|
155
291
|
|
|
156
|
-
|
|
292
|
+
#### `restart(newOptions?)`
|
|
157
293
|
|
|
158
|
-
|
|
294
|
+
Restarts the widget, optionally with updated options. Returns `Promise<void>`.
|
|
159
295
|
|
|
160
|
-
|
|
161
|
-
|--------------|----------------------|------------------------------------------------|
|
|
162
|
-
| onConnected | () => void | Called when connection is established |
|
|
163
|
-
| onError | (error: Error) => void | Called when an error occurs |
|
|
164
|
-
| onClose | () => void | Called when the widget is closed |
|
|
165
|
-
| onResults | (data: T[]) => void | Called with schema-validated CSV data |
|
|
296
|
+
### `RecordsChunk<T>`
|
|
166
297
|
|
|
167
|
-
|
|
298
|
+
The object passed to `onData` callbacks:
|
|
168
299
|
|
|
169
|
-
|
|
300
|
+
```typescript
|
|
301
|
+
interface RecordsChunk<T> {
|
|
302
|
+
records: T[];
|
|
303
|
+
totalChunks: number;
|
|
304
|
+
currentChunkIndex: number;
|
|
305
|
+
totalRecords: number;
|
|
306
|
+
}
|
|
307
|
+
```
|
|
170
308
|
|
|
171
|
-
|
|
309
|
+
### `WebhookConfig`
|
|
172
310
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
311
|
+
```typescript
|
|
312
|
+
interface WebhookConfig {
|
|
313
|
+
url: string;
|
|
314
|
+
headers?: Record<string, string>;
|
|
315
|
+
method?: "POST" | "PUT" | "PATCH";
|
|
316
|
+
timeout?: number;
|
|
317
|
+
retries?: number;
|
|
318
|
+
metadata?: Record<string, unknown>;
|
|
319
|
+
}
|
|
320
|
+
```
|
|
177
321
|
|
|
178
|
-
|
|
322
|
+
## TypeScript
|
|
179
323
|
|
|
180
|
-
|
|
181
|
-
- `.required(boolean)` - Marks a field as required
|
|
182
|
-
- `.minLength(number)` - Sets minimum length for string fields
|
|
183
|
-
- `.maxLength(number)` - Sets maximum length for string fields
|
|
184
|
-
- `.min(number)` - Sets minimum value for number fields
|
|
185
|
-
- `.max(number)` - Sets maximum value for number fields
|
|
324
|
+
The SDK is written in TypeScript and provides full type inference from your schema:
|
|
186
325
|
|
|
187
|
-
|
|
326
|
+
```typescript
|
|
327
|
+
import { CSVImporter, x, type Infer } from "@expresscsv/sdk";
|
|
188
328
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
329
|
+
const schema = x.row({
|
|
330
|
+
name: x.string(),
|
|
331
|
+
age: x.number(),
|
|
332
|
+
email: x.string().email().optional(),
|
|
333
|
+
});
|
|
192
334
|
|
|
193
|
-
|
|
194
|
-
|
|
335
|
+
type Row = Infer<typeof schema>;
|
|
336
|
+
// { name: string; age: number; email?: string }
|
|
195
337
|
|
|
196
|
-
|
|
197
|
-
|
|
338
|
+
const importer = new CSVImporter({
|
|
339
|
+
schema,
|
|
340
|
+
publishableKey: "your-publishable-key",
|
|
341
|
+
importIdentifier: "user-import",
|
|
342
|
+
});
|
|
198
343
|
|
|
199
|
-
|
|
200
|
-
|
|
344
|
+
importer.open({
|
|
345
|
+
onData: (chunk, next) => {
|
|
346
|
+
// chunk.records is fully typed as Row[]
|
|
347
|
+
for (const row of chunk.records) {
|
|
348
|
+
console.log(row.name); // string
|
|
349
|
+
console.log(row.age); // number
|
|
350
|
+
console.log(row.email); // string | undefined
|
|
351
|
+
}
|
|
352
|
+
next();
|
|
353
|
+
},
|
|
354
|
+
});
|
|
201
355
|
```
|
|
202
356
|
|
|
357
|
+
## Resources
|
|
358
|
+
|
|
359
|
+
- [ExpressCSV Dashboard](https://expresscsv.com) -- manage your imports and API keys
|
|
360
|
+
- [`@expresscsv/react`](https://www.npmjs.com/package/@expresscsv/react) -- React hook wrapper
|
|
361
|
+
|
|
203
362
|
## License
|
|
204
363
|
|
|
205
|
-
|
|
364
|
+
[MIT](./LICENSE)
|
package/package.json
CHANGED
package/dist/.dts/errors.d.ts
DELETED
package/dist/.dts/index.d.ts
DELETED
|
@@ -1,207 +0,0 @@
|
|
|
1
|
-
import { type ExRow, type ExRowShape, type ExType, type Infer, x } from '@expresscsv/fields';
|
|
2
|
-
import { WidgetMode, WidgetState } from '@expresscsv/iframe-comm';
|
|
3
|
-
import type { ExBaseDef } from '@expresscsv/fields';
|
|
4
|
-
import type { ColorModeConfig, ECSVFontSource, ECSVTheme } from '@expresscsv/theme';
|
|
5
|
-
export { ImportCancelledError } from './errors';
|
|
6
|
-
/**
|
|
7
|
-
* A chunk of records passed to the onData callback
|
|
8
|
-
*/
|
|
9
|
-
export interface RecordsChunk<T> {
|
|
10
|
-
/** The records in this chunk */
|
|
11
|
-
records: T[];
|
|
12
|
-
/** Total number of chunks */
|
|
13
|
-
totalChunks: number;
|
|
14
|
-
/** Current chunk index (0-based) */
|
|
15
|
-
currentChunkIndex: number;
|
|
16
|
-
/** Total number of records across all chunks */
|
|
17
|
-
totalRecords: number;
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Webhook configuration for remote delivery of results
|
|
21
|
-
*/
|
|
22
|
-
export interface WebhookConfig {
|
|
23
|
-
/** The URL to send webhook requests to */
|
|
24
|
-
url: string;
|
|
25
|
-
/** Optional HTTP headers to include in the request */
|
|
26
|
-
headers?: Record<string, string>;
|
|
27
|
-
/** HTTP method to use (default: 'POST') */
|
|
28
|
-
method?: 'POST' | 'PUT' | 'PATCH';
|
|
29
|
-
/** Request timeout in milliseconds (default: 30000) */
|
|
30
|
-
timeout?: number;
|
|
31
|
-
/** Number of retry attempts on failure (default: 0) */
|
|
32
|
-
retries?: number;
|
|
33
|
-
/** Arbitrary developer-provided metadata */
|
|
34
|
-
metadata?: Record<string, unknown>;
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Type helper that requires at least one of the specified keys to be present
|
|
38
|
-
*/
|
|
39
|
-
type RequireAtLeastOne<T, Keys extends keyof T = keyof T> = Pick<T, Exclude<keyof T, Keys>> & {
|
|
40
|
-
[K in Keys]-?: Required<Pick<T, K>> & Partial<Pick<T, Exclude<Keys, K>>>;
|
|
41
|
-
}[Keys];
|
|
42
|
-
/**
|
|
43
|
-
* Base delivery options - at least one must be provided
|
|
44
|
-
*/
|
|
45
|
-
interface DeliveryOptionsBase<T> {
|
|
46
|
-
/** Local callback for processing chunks */
|
|
47
|
-
onData?: (chunk: RecordsChunk<T>, next: () => void) => void | Promise<void>;
|
|
48
|
-
/** Webhook configuration for remote delivery */
|
|
49
|
-
webhook?: WebhookConfig;
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Delivery options - requires at least one of onData or webhook
|
|
53
|
-
*/
|
|
54
|
-
export type DeliveryOptions<T> = RequireAtLeastOne<DeliveryOptionsBase<T>, 'onData' | 'webhook'>;
|
|
55
|
-
/**
|
|
56
|
-
* Options for the open() method
|
|
57
|
-
* Requires at least one of onData or webhook for delivery
|
|
58
|
-
*/
|
|
59
|
-
export type OpenOptions<T> = RequireAtLeastOne<DeliveryOptionsBase<T>, 'onData' | 'webhook'> & {
|
|
60
|
-
/** Number of records per chunk (default: 1000) */
|
|
61
|
-
chunkSize?: number;
|
|
62
|
-
/** Called when all chunks have been processed */
|
|
63
|
-
onComplete?: () => void;
|
|
64
|
-
/** Called when the user cancels the import */
|
|
65
|
-
onCancel?: () => void;
|
|
66
|
-
/** Called when an error occurs */
|
|
67
|
-
onError?: (error: Error) => void;
|
|
68
|
-
/** Called when the widget opens */
|
|
69
|
-
onWidgetOpen?: () => void;
|
|
70
|
-
/** Called when the step changes in the wizard */
|
|
71
|
-
onStepChange?: (stepId: ExpressCSVStep, previousStepId?: ExpressCSVStep) => void;
|
|
72
|
-
/** Called when the widget closes */
|
|
73
|
-
onWidgetClose?: (reason: 'user_close' | 'cancel' | 'complete' | 'error') => void;
|
|
74
|
-
};
|
|
75
|
-
export type InferCSVImporter<TSchema extends ExType<unknown, ExBaseDef, unknown>> = CSVImporter<TSchema>;
|
|
76
|
-
export type { ColorModeConfig, ColorModePref, ECSVFontSource, ECSVTheme, TailwindThemeVars, } from '@expresscsv/theme';
|
|
77
|
-
export interface SDKOptions<TSchema extends ExType<unknown, ExBaseDef, unknown>> {
|
|
78
|
-
schema: TSchema;
|
|
79
|
-
publishableKey: string;
|
|
80
|
-
importIdentifier: string;
|
|
81
|
-
title?: string;
|
|
82
|
-
debug?: boolean;
|
|
83
|
-
developerMode?: boolean;
|
|
84
|
-
preload?: boolean;
|
|
85
|
-
theme?: ECSVTheme;
|
|
86
|
-
colorMode?: ColorModeConfig;
|
|
87
|
-
customCSS?: string;
|
|
88
|
-
fonts?: Record<string, ECSVFontSource>;
|
|
89
|
-
stepDisplay?: 'progressBar' | 'segmented' | 'numbered';
|
|
90
|
-
previewSchemaBeforeUpload?: boolean;
|
|
91
|
-
templateDownload?: TemplateDownloadConfig;
|
|
92
|
-
saveSession?: boolean;
|
|
93
|
-
locale?: DeepPartial<ExpressCSVLocaleInput>;
|
|
94
|
-
}
|
|
95
|
-
declare class CSVImporter<TSchema extends ExType<unknown, ExBaseDef, unknown> = ExRow<ExRowShape>> {
|
|
96
|
-
private options;
|
|
97
|
-
private iframe;
|
|
98
|
-
private container;
|
|
99
|
-
private connection;
|
|
100
|
-
private connectionState;
|
|
101
|
-
private debug;
|
|
102
|
-
private developerMode;
|
|
103
|
-
private importIdentifier;
|
|
104
|
-
private sessionId;
|
|
105
|
-
private _destroyTimer;
|
|
106
|
-
private _beforeUnloadHandler;
|
|
107
|
-
private widgetUrl;
|
|
108
|
-
private widgetState;
|
|
109
|
-
private widgetMode;
|
|
110
|
-
private canRestart;
|
|
111
|
-
private lastError;
|
|
112
|
-
private openOptions;
|
|
113
|
-
private cachedSchemaJson;
|
|
114
|
-
private initCompletePromise;
|
|
115
|
-
private resolveInitComplete;
|
|
116
|
-
constructor(options: SDKOptions<TSchema>);
|
|
117
|
-
/**
|
|
118
|
-
* Enhanced state management
|
|
119
|
-
*/
|
|
120
|
-
private setState;
|
|
121
|
-
private updateDerivedState;
|
|
122
|
-
private handleError;
|
|
123
|
-
private waitForEvent;
|
|
124
|
-
/**
|
|
125
|
-
* Open the import flow with chunk-based data processing.
|
|
126
|
-
* Automatically opens the widget if not already open.
|
|
127
|
-
*
|
|
128
|
-
* @param options Configuration including onData callback for processing chunks
|
|
129
|
-
*/
|
|
130
|
-
open(options: OpenOptions<Infer<TSchema>>): void;
|
|
131
|
-
/**
|
|
132
|
-
* Create import session on backend with configuration
|
|
133
|
-
* Idempotent: safe to call multiple times with same sessionId
|
|
134
|
-
*/
|
|
135
|
-
private createImportSession;
|
|
136
|
-
/**
|
|
137
|
-
* Deliver results to webhook endpoint via backend API
|
|
138
|
-
* Chunks data using SDK-determined chunk size (independent of customer's chunkSize)
|
|
139
|
-
*/
|
|
140
|
-
private deliverToWebhook;
|
|
141
|
-
/**
|
|
142
|
-
* Send a single chunk to backend webhook API with retry logic
|
|
143
|
-
*/
|
|
144
|
-
private sendChunkToBackend;
|
|
145
|
-
/**
|
|
146
|
-
* Process results in chunks, calling onData and/or webhook for each chunk with backpressure control
|
|
147
|
-
*/
|
|
148
|
-
private processResultsInChunks;
|
|
149
|
-
/**
|
|
150
|
-
* Initialize the iframe and connection.
|
|
151
|
-
* @param hidden Whether to create the iframe hidden (for preload) or visible (for normal open)
|
|
152
|
-
*/
|
|
153
|
-
private initializeIframe;
|
|
154
|
-
private log;
|
|
155
|
-
private error;
|
|
156
|
-
/**
|
|
157
|
-
* Add beforeunload event listener to warn users about losing progress
|
|
158
|
-
*/
|
|
159
|
-
private addBeforeUnloadListener;
|
|
160
|
-
/**
|
|
161
|
-
* Remove beforeunload event listener
|
|
162
|
-
*/
|
|
163
|
-
private removeBeforeUnloadListener;
|
|
164
|
-
private waitForIframeLoad;
|
|
165
|
-
private setupConnectionAndInit;
|
|
166
|
-
openWidget(options?: {
|
|
167
|
-
reset?: boolean;
|
|
168
|
-
}): Promise<void>;
|
|
169
|
-
/**
|
|
170
|
-
* Makes a hidden container visible for instant display of preloaded iframe
|
|
171
|
-
*/
|
|
172
|
-
private makeContainerVisible;
|
|
173
|
-
private setupMessageHandlers;
|
|
174
|
-
private createAndAppendIframe;
|
|
175
|
-
private destroy;
|
|
176
|
-
close(reason?: 'user_close' | 'cancel' | 'complete' | 'error'): Promise<void>;
|
|
177
|
-
resetWidget(): Promise<void>;
|
|
178
|
-
restart(newOptions?: Partial<SDKOptions<TSchema>>): Promise<void>;
|
|
179
|
-
private handleWidgetClosed;
|
|
180
|
-
private hideContainer;
|
|
181
|
-
getConnectionStatus(): boolean;
|
|
182
|
-
getState(): WidgetState;
|
|
183
|
-
getMode(): WidgetMode;
|
|
184
|
-
getIsReady(): boolean;
|
|
185
|
-
getIsOpen(): boolean;
|
|
186
|
-
getCanRestart(): boolean;
|
|
187
|
-
getLastError(): Error | null;
|
|
188
|
-
getStatus(): {
|
|
189
|
-
state: WidgetState;
|
|
190
|
-
mode: WidgetMode;
|
|
191
|
-
isReady: boolean;
|
|
192
|
-
isOpen: boolean;
|
|
193
|
-
canRestart: boolean;
|
|
194
|
-
hasError: boolean;
|
|
195
|
-
lastError: Error | null;
|
|
196
|
-
connectionStatus: boolean;
|
|
197
|
-
};
|
|
198
|
-
getVersion(): string;
|
|
199
|
-
}
|
|
200
|
-
export { x };
|
|
201
|
-
export type { Infer, ExType } from '@expresscsv/fields';
|
|
202
|
-
export type { ExBaseDef } from '@expresscsv/fields';
|
|
203
|
-
export type { ExpressCSVStep } from '@expresscsv/core';
|
|
204
|
-
export type { ExpressCSVLocaleInput, DeepPartial } from '@expresscsv/core';
|
|
205
|
-
export { WidgetState, WidgetMode } from '@expresscsv/iframe-comm';
|
|
206
|
-
import type { DeepPartial, ExpressCSVLocaleInput, ExpressCSVStep, TemplateDownloadConfig } from '@expresscsv/core';
|
|
207
|
-
export { CSVImporter };
|