@expresscsv/sdk 0.1.26 → 1.0.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 CHANGED
@@ -36,21 +36,20 @@ const schema = x.row({
36
36
  const importer = new CSVImporter({
37
37
  schema,
38
38
  getSessionToken: async () => fetchSessionToken(),
39
- importIdentifier: "user-import",
39
+ importNamespace: "user-import",
40
40
  title: "Import Users",
41
41
  });
42
42
 
43
43
  // Open the importer and process data in chunks
44
44
  importer.open({
45
45
  onData: (chunk, next) => {
46
- console.log(`Chunk ${chunk.currentChunkIndex + 1}/${chunk.totalChunks}`);
46
+ console.log(`Chunk ${chunk.chunkIndex + 1}/${chunk.totalChunks}`);
47
47
  console.log("Session:", chunk.sessionId);
48
- console.log("Idempotency key:", chunk.chunkIdempotencyKey);
49
48
  console.log("Records:", chunk.records);
50
49
  // Process your validated, typed records here
51
50
  next();
52
51
  },
53
- onComplete: ({ sessionId }) => {
52
+ onComplete: ({ sessionId, deliveryId }) => {
54
53
  console.log("All chunks processed successfully for", sessionId);
55
54
  },
56
55
  onError: (error, { sessionId }) => {
@@ -69,18 +68,19 @@ ExpressCSV delivers imported data through `onData`. Your app receives validated
69
68
 
70
69
  ```typescript
71
70
  importer.open({
72
- chunkSize: 500,
71
+ chunkSize: { unit: "kb", value: 500 },
73
72
  onData: async (chunk, next) => {
74
- const response = await fetch("/api/import-users/chunks", {
73
+ const response = await fetch("/your-api/import-users/chunks", {
75
74
  method: "POST",
76
75
  headers: {
77
76
  "Content-Type": "application/json",
77
+ Authorization: `Bearer ${accessToken}`,
78
78
  },
79
79
  body: JSON.stringify({
80
80
  sessionId: chunk.sessionId,
81
- chunkIdempotencyKey: chunk.chunkIdempotencyKey,
81
+ deliveryId: chunk.deliveryId,
82
+ chunkIndex: chunk.chunkIndex,
82
83
  records: chunk.records,
83
- currentChunkIndex: chunk.currentChunkIndex,
84
84
  totalChunks: chunk.totalChunks,
85
85
  totalRecords: chunk.totalRecords,
86
86
  }),
@@ -92,8 +92,15 @@ importer.open({
92
92
 
93
93
  next();
94
94
  },
95
- onComplete: ({ sessionId }) => {
96
- console.log("Import complete for", sessionId);
95
+ onComplete: async ({ sessionId, deliveryId }) => {
96
+ await fetch("/your-api/import-users/complete", {
97
+ method: "POST",
98
+ headers: {
99
+ "Content-Type": "application/json",
100
+ Authorization: `Bearer ${accessToken}`,
101
+ },
102
+ body: JSON.stringify({ sessionId, deliveryId }),
103
+ });
97
104
  },
98
105
  });
99
106
  ```
@@ -102,12 +109,13 @@ Each delivered chunk includes:
102
109
 
103
110
  - `records`
104
111
  - `sessionId`
105
- - `chunkIdempotencyKey`
106
- - `currentChunkIndex`
112
+ - `deliveryId`
113
+ - `chunkIndex`
107
114
  - `totalChunks`
108
115
  - `totalRecords`
109
116
 
110
- Use `sessionId` and `chunkIdempotencyKey` to stage writes safely and deduplicate retries from your own app logic.
117
+ Each time the user finishes the import, ExpressCSV creates a new `deliveryId` for that `sessionId`. Your `onData` code can fail, and the user can retry delivery without starting the import over. Store chunks by `(sessionId, deliveryId, chunkIndex)`, then finalize the `deliveryId` from `onComplete` after all of its chunks are accepted.
118
+
111
119
 
112
120
  ## Preloading
113
121
 
@@ -118,7 +126,7 @@ By default, the SDK preloads the importer in a hidden iframe for instant display
118
126
  const importer = new CSVImporter({
119
127
  schema,
120
128
  getSessionToken: async () => fetchSessionToken(),
121
- importIdentifier: "user-import",
129
+ importNamespace: "user-import",
122
130
  });
123
131
 
124
132
  // Later, the importer appears instantly
@@ -131,7 +139,7 @@ To disable preloading (there will be a brief loading screen instead):
131
139
  const importer = new CSVImporter({
132
140
  schema,
133
141
  getSessionToken: async () => fetchSessionToken(),
134
- importIdentifier: "user-import",
142
+ importNamespace: "user-import",
135
143
  preload: false,
136
144
  });
137
145
  ```
@@ -155,7 +163,7 @@ const candidateSchema = x.row({
155
163
  const importer = new CSVImporter({
156
164
  schema: candidateSchema,
157
165
  getSessionToken: async () => fetchSessionToken(),
158
- importIdentifier: "candidate-import",
166
+ importNamespace: "candidate-import",
159
167
  templateDownload: {
160
168
  source: "generate",
161
169
  formats: ["csv", "xlsx"],
@@ -179,10 +187,10 @@ Customize the importer's appearance with the `theme`, `colorMode`, `customCSS`,
179
187
  Use the `theme` option to override CSS variables (colors, radius, typography). Pass either a single theme (applies to both light and dark) or a dual-mode theme with separate light/dark values:
180
188
 
181
189
  ```typescript
182
- import { CSVImporter, x, type ECSVTheme } from "@expresscsv/sdk";
190
+ import { CSVImporter, x, type Theme } from "@expresscsv/sdk";
183
191
 
184
192
  // Single theme (both modes)
185
- const theme: ECSVTheme = {
193
+ const theme: Theme = {
186
194
  primary: "#4F46E5",
187
195
  "primary-foreground": "#ffffff",
188
196
  background: "#ffffff",
@@ -193,7 +201,7 @@ const theme: ECSVTheme = {
193
201
  };
194
202
 
195
203
  // Dual-mode (light and dark)
196
- const dualTheme: ECSVTheme = {
204
+ const dualTheme: Theme = {
197
205
  modes: {
198
206
  light: {
199
207
  primary: "#4F46E5",
@@ -211,7 +219,7 @@ const dualTheme: ECSVTheme = {
211
219
  const importer = new CSVImporter({
212
220
  schema,
213
221
  getSessionToken: async () => fetchSessionToken(),
214
- importIdentifier: "user-import",
222
+ importNamespace: "user-import",
215
223
  theme,
216
224
  });
217
225
  ```
@@ -255,7 +263,7 @@ Control light/dark mode with `colorMode`:
255
263
  const importer = new CSVImporter({
256
264
  schema,
257
265
  getSessionToken: async () => fetchSessionToken(),
258
- importIdentifier: "user-import",
266
+ importNamespace: "user-import",
259
267
  colorMode: "system", // 'light' | 'dark' | 'system'
260
268
  });
261
269
  ```
@@ -268,7 +276,7 @@ Inject custom CSS for fine-grained styling overrides.
268
276
  const importer = new CSVImporter({
269
277
  schema,
270
278
  getSessionToken: async () => fetchSessionToken(),
271
- importIdentifier: "user-import",
279
+ importNamespace: "user-import",
272
280
  customCSS: `
273
281
  .ecsv [data-step="upload"] {
274
282
  border-radius: 1rem;
@@ -288,7 +296,7 @@ Load custom fonts via the `fonts` option:
288
296
  const importer = new CSVImporter({
289
297
  schema,
290
298
  getSessionToken: async () => fetchSessionToken(),
291
- importIdentifier: "user-import",
299
+ importNamespace: "user-import",
292
300
  fonts: {
293
301
  title: { source: "google", name: "Space Grotesk", weights: [400, 600, 700] },
294
302
  body: { source: "custom", url: "https://example.com/font.woff2", format: "woff2" },
@@ -411,7 +419,6 @@ All field types support:
411
419
  |---|---|
412
420
  | `.label(text)` | User-facing label shown in the importer |
413
421
  | `.description(text)` | Help text for the field |
414
- | `.example(text)` | Example value shown as placeholder |
415
422
  | `.optional()` | Makes the field optional (default is required) |
416
423
  | `.refine(fn)` | Custom validation function |
417
424
 
@@ -551,26 +558,26 @@ new CSVImporter(options: SDKOptions)
551
558
  |---|---|---|---|---|
552
559
  | `schema` | Schema | Yes | - | Schema definition created with `x.row()` |
553
560
  | `getSessionToken` | `() => Promise<string>` | Yes | - | Async callback that asks your backend for a short-lived importer session token |
554
- | `importIdentifier` | `string` | Yes | - | Unique identifier for this import type |
561
+ | `importNamespace` | `string` | Yes | - | Stable namespace string your app assigns to this importer configuration. Keep it the same for the same workflow; use a different value for different importers. |
555
562
  | `title` | `string` | No | - | Title shown in the importer header |
556
563
  | `preload` | `boolean` | No | `true` | Preload the importer for instant display |
557
564
  | `debug` | `boolean` | No | `false` | Enable debug logging |
558
- | `theme` | `ECSVTheme` | No | - | Custom theme configuration |
565
+ | `theme` | `Theme` | No | - | Custom theme configuration |
559
566
  | `colorMode` | `ColorModePref` | No | - | Light/dark mode (`'light'`, `'dark'`, or `'system'`) |
560
567
  | `customCSS` | `string` | No | - | Custom CSS to inject into the importer |
561
- | `fonts` | `Record<string, ECSVFontSource>` | No | - | Custom font sources |
568
+ | `fonts` | `Record<string, FontSource>` | No | - | Custom font sources |
562
569
  | `stepDisplay` | `'progressBar' \| 'segmented' \| 'numbered'` | No | `'progressBar'` | Step indicator style |
563
570
  | `previewSchemaBeforeUpload` | `boolean` | No | `true` | Show schema preview before upload |
564
- | `columnMatching` | `{ type: "managed"; exact?: boolean; caseInsensitive?: boolean; normalized?: boolean; inference?: boolean } \| { type: "custom"; match: (...) => Promise<...> }` | No | `undefined` | Configure managed column matching or provide a custom matcher |
565
- | `promptedEdits` | `{ type: "managed" } \| { type: "custom"; edit: (...) => Promise<...> }` | No | `undefined` | Enable managed prompted edits or provide a custom edit handler |
571
+ | `columnMatching` | `{ type: "managed"; exact?: boolean; caseInsensitive?: boolean; normalized?: boolean; inference?: boolean } \| { type: "custom"; columnMatchHandler: (...) => Promise<...> }` | No | `undefined` | Configure managed column matching or provide a custom matcher |
572
+ | `promptedEdits` | `{ type: "managed" } \| { type: "custom"; promptedEditHandler: (...) => Promise<...> }` | No | `undefined` | Enable managed prompted edits or provide a custom edit handler |
566
573
  | `templateDownload` | `TemplateDownloadOptions<TSchema>` | No | - | Template download configuration with optional schema-typed example rows |
567
- | `sessionRecovery` | `SessionRecoveryOptions` | No | - | Enable Recovered Sessions with the built-in local backend or a custom adapter implementing `get`, `set`, and `remove` |
574
+ | `sessionRecovery` | `SessionRecoveryOptions` | No | - | Enable Recovered sessions with the built-in local backend or a custom adapter implementing `get`, `set`, and `remove` |
568
575
  | `locale` | `DeepPartial<ExpressCSVLocaleInput>` | No | - | Localization overrides |
569
576
  | `disableStatusStep` | `boolean` | No | - | Skip the success/error status screen |
570
577
 
571
578
  #### `open(options)`
572
579
 
573
- Opens the importer and begins the import flow.
580
+ Opens the importer.
574
581
 
575
582
  ```typescript
576
583
  importer.open(options: OpenOptions): void
@@ -579,13 +586,12 @@ importer.open(options: OpenOptions): void
579
586
  | Option | Type | Required | Description |
580
587
  |---|---|---|---|
581
588
  | `onData` | `(chunk: RecordsChunk<T>, next: () => void) => void` | Yes | Callback for each delivered chunk of records. Call `next()` after your backend accepts the current chunk. |
582
- | `chunkSize` | `number` | No | Records per chunk (default: 1000) |
589
+ | `chunkSize` | `ChunkSize` | No | Delivery packet size. Defaults to `{ unit: "kb", value: 500 }`. `kb` uses decimal kilobytes (`1 KB = 1000 bytes`). Use `{ unit: "kb", value: 500 }` for KB or `{ unit: "rows", value: 500 }` for row counts. Zero or negative values send all records in one chunk. |
583
590
  | `onComplete` | `(context: { sessionId: string }) => void` | No | Called when all chunks have been processed |
584
591
  | `onCancel` | `(context: { sessionId: string }) => void` | No | Called when the user cancels the import |
585
592
  | `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 |
588
- | `onStepChange` | `(stepId, previousStepId?) => void` | No | Called when the wizard step changes |
593
+ | `onOpen` | `(context: { sessionId: string }) => void` | No | Called when the importer opens |
594
+ | `onStepChange` | `(stepId, previousStepId?) => void` | No | Called when the importer step changes |
589
595
 
590
596
  #### `close(reason?)`
591
597
 
@@ -601,13 +607,13 @@ await importer.close(reason?: 'user_close' | 'cancel' | 'complete' | 'error'): P
601
607
 
602
608
  | Method | Returns | Description |
603
609
  |---|---|---|
604
- | `getState()` | `ImporterState` | Current importer lifecycle state |
610
+ | `getStatus()` | `ImporterStatus` | Current importer lifecycle status |
605
611
  | `getIsReady()` | `boolean` | Whether the importer is ready or open |
606
612
  | `getIsOpen()` | `boolean` | Whether the importer is currently open |
607
613
  | `getConnectionStatus()` | `boolean` | Whether the iframe connection is active |
608
614
  | `getCanRestart()` | `boolean` | Whether the importer can be restarted |
609
615
  | `getLastError()` | `Error \| null` | Last error, if any |
610
- | `getStatus()` | `object` | Comprehensive status snapshot |
616
+ | `getStatusSnapshot()` | `object` | Comprehensive status snapshot |
611
617
 
612
618
  #### `restart(newOptions?)`
613
619
 
@@ -621,10 +627,10 @@ The object passed to `onData` callbacks:
621
627
  interface RecordsChunk<T> {
622
628
  records: T[]; // Automatically typed to your schema
623
629
  totalChunks: number;
624
- currentChunkIndex: number;
630
+ chunkIndex: number;
625
631
  totalRecords: number;
626
632
  sessionId: string;
627
- chunkIdempotencyKey: string;
633
+ deliveryId: string;
628
634
  }
629
635
  ```
630
636
 
@@ -647,7 +653,7 @@ type Row = Infer<typeof schema>;
647
653
  const importer = new CSVImporter({
648
654
  schema,
649
655
  getSessionToken: async () => fetchSessionToken(),
650
- importIdentifier: "user-import",
656
+ importNamespace: "user-import",
651
657
  });
652
658
 
653
659
  importer.open({
package/dist/index.d.cts CHANGED
@@ -4,6 +4,18 @@ declare interface BICOptions {
4
4
 
5
5
  declare type BooleanControlType = 'toggle' | 'checkbox' | 'dropdown';
6
6
 
7
+ export declare type ChunkSize = {
8
+ /** Size quota unit. */
9
+ unit: 'kb';
10
+ /** KB quota. Values <= 0 send all rows in one chunk. */
11
+ value: number;
12
+ } | {
13
+ /** Chunk by row count. */
14
+ unit: 'rows';
15
+ /** Rows per chunk. Values <= 0 send all rows in one chunk. */
16
+ value: number;
17
+ };
18
+
7
19
  /**
8
20
  * Color mode preference
9
21
  */
@@ -14,6 +26,10 @@ export declare interface ColumnMatch<TTargetField extends string = string> {
14
26
  targetField: TTargetField;
15
27
  }
16
28
 
29
+ export declare type ColumnMatchHandler<TSchema extends ExType<unknown, ExBaseDef, unknown> = ExRow<ExRowShape>> = ColumnMatchingFn<SchemaFieldName<TSchema>>;
30
+
31
+ export declare type ColumnMatchHandlerResult<TSchema extends ExType<unknown, ExBaseDef, unknown> = ExRow<ExRowShape>> = ColumnMatchingResult<SchemaFieldName<TSchema>>;
32
+
17
33
  export declare type ColumnMatchingFn<TTargetField extends string = string> = (data: ColumnMatchingParams) => Promise<ColumnMatchingResult<TTargetField>>;
18
34
 
19
35
  export declare type ColumnMatchingOptions<TSchema extends ExType<unknown, ExBaseDef, unknown> = ExRow<ExRowShape>> = ManagedColumnMatchingOptions | CustomColumnMatchingOptions<TSchema>;
@@ -1275,7 +1291,7 @@ export declare class CSVImporter<TSchema extends ExType<unknown, ExBaseDef, unkn
1275
1291
  private connection;
1276
1292
  private connectionState;
1277
1293
  private debug;
1278
- private importIdentifier;
1294
+ private importNamespace;
1279
1295
  private sessionId;
1280
1296
  private currentSessionToken;
1281
1297
  private currentSessionTokenExpiresAt;
@@ -1285,13 +1301,15 @@ export declare class CSVImporter<TSchema extends ExType<unknown, ExBaseDef, unkn
1285
1301
  private _beforeUnloadHandler;
1286
1302
  private importerUrl;
1287
1303
  private appUrl;
1288
- private importerState;
1304
+ private status;
1289
1305
  private importerMode;
1290
1306
  private canRestart;
1291
1307
  private lastError;
1292
- private stateChangeListeners;
1308
+ private statusChangeListeners;
1293
1309
  private lastTerminalSessionState;
1294
1310
  private openOptions;
1311
+ /** Mirrors the active delivery while slicing one `event:results` batch into chunks. */
1312
+ private deliveryIdForActiveBatch;
1295
1313
  private cachedSchemaJson;
1296
1314
  private initCompletePromise;
1297
1315
  private resolveInitComplete;
@@ -1301,16 +1319,22 @@ export declare class CSVImporter<TSchema extends ExType<unknown, ExBaseDef, unkn
1301
1319
  private getCustomStorageRpcHandler;
1302
1320
  private getCustomFeatureRpcHandler;
1303
1321
  /**
1304
- * Enhanced state management
1322
+ * Enhanced status management
1305
1323
  */
1306
- private setState;
1324
+ private setStatus;
1307
1325
  private updateDerivedState;
1308
1326
  private createSessionId;
1309
1327
  private getOrCreateSessionId;
1310
1328
  private getImportSessionContext;
1311
- private getChunkIdempotencyKey;
1329
+ private getImportDeliveryContext;
1312
1330
  private createRecordsChunk;
1331
+ private normalizeChunkSize;
1332
+ private getRecordsChunkByteLength;
1333
+ private groupResultsIntoChunks;
1334
+ private groupResultsByByteQuota;
1335
+ private buildByteQuotaChunks;
1313
1336
  private handleError;
1337
+ private completeOpenLifecycleForClose;
1314
1338
  private sendImportProgress;
1315
1339
  private waitForEvent;
1316
1340
  private fetchImporterSessionToken;
@@ -1327,7 +1351,7 @@ export declare class CSVImporter<TSchema extends ExType<unknown, ExBaseDef, unkn
1327
1351
  private sendStartupErrorToImporter;
1328
1352
  private bootstrapImporterSession;
1329
1353
  /**
1330
- * Open the import flow with chunk-based data processing.
1354
+ * Open the importer with chunk-based data processing.
1331
1355
  * Automatically opens the importer if not already open.
1332
1356
  *
1333
1357
  * @param options Configuration including onData callback for processing chunks
@@ -1342,6 +1366,7 @@ export declare class CSVImporter<TSchema extends ExType<unknown, ExBaseDef, unkn
1342
1366
  * Process results in chunks, calling onData with backpressure control
1343
1367
  */
1344
1368
  private processResultsInChunks;
1369
+ private parseImporterResultsPayload;
1345
1370
  /**
1346
1371
  * Initialize the iframe and connection.
1347
1372
  * @param hidden Whether to create the iframe hidden (for preload) or visible (for normal open)
@@ -1369,21 +1394,21 @@ export declare class CSVImporter<TSchema extends ExType<unknown, ExBaseDef, unkn
1369
1394
  private setupMessageHandlers;
1370
1395
  private createAndAppendIframe;
1371
1396
  private destroy;
1372
- close(reason?: 'user_close' | 'cancel' | 'complete' | 'error'): Promise<void>;
1397
+ close(reason?: ImporterCloseReason): Promise<void>;
1373
1398
  private resetImporter;
1374
1399
  restart(newOptions?: Partial<SDKOptions<TSchema>>): Promise<void>;
1375
1400
  private handleImporterClosed;
1376
1401
  private hideContainer;
1377
1402
  getConnectionStatus(): boolean;
1378
- subscribeToStateChanges(listener: StateChangeListener): () => void;
1379
- getState(): ImporterState;
1403
+ subscribeToStatusChanges(listener: StatusChangeListener): () => void;
1404
+ getStatus(): ImporterStatus;
1380
1405
  getMode(): ImporterMode;
1381
1406
  getIsReady(): boolean;
1382
1407
  getIsOpen(): boolean;
1383
1408
  getCanRestart(): boolean;
1384
1409
  getLastError(): Error | null;
1385
- getStatus(): {
1386
- state: ImporterState;
1410
+ getStatusSnapshot(): {
1411
+ status: ImporterStatus;
1387
1412
  mode: ImporterMode;
1388
1413
  isReady: boolean;
1389
1414
  isOpen: boolean;
@@ -2039,12 +2064,12 @@ declare const CurrencyCodes: readonly [{
2039
2064
 
2040
2065
  export declare type CustomColumnMatchingOptions<TSchema extends ExType<unknown, ExBaseDef, unknown> = ExRow<ExRowShape>> = {
2041
2066
  type: 'custom';
2042
- match: ColumnMatchingFn<SchemaFieldName<TSchema>>;
2067
+ columnMatchHandler: ColumnMatchHandler<TSchema>;
2043
2068
  };
2044
2069
 
2045
2070
  export declare type CustomPromptedEditsOptions<TSchema extends ExType<unknown, ExBaseDef, unknown> = ExRow<ExRowShape>> = {
2046
2071
  type: 'custom';
2047
- edit: PromptedEditsFn<SchemaFieldName<TSchema>>;
2072
+ promptedEditHandler: PromptedEditHandler<TSchema>;
2048
2073
  };
2049
2074
 
2050
2075
  export declare type CustomSessionRecoveryOptions = {
@@ -2062,39 +2087,6 @@ export declare type DeepPartial<T> = {
2062
2087
  [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
2063
2088
  };
2064
2089
 
2065
- /**
2066
- * Font source configuration for custom fonts
2067
- */
2068
- export declare type ECSVFontSource = {
2069
- source: 'google';
2070
- name: string;
2071
- weights?: (number | string)[];
2072
- } | {
2073
- source: 'custom';
2074
- url: string;
2075
- format?: 'woff2' | 'woff';
2076
- };
2077
-
2078
- /**
2079
- * Theme - can be either dual-mode (light/dark) or single-mode (applies to both)
2080
- */
2081
- export declare type ECSVTheme = ECSVThemeWithModes | ECSVThemeSingle;
2082
-
2083
- /**
2084
- * Single theme that applies to both light and dark modes
2085
- */
2086
- declare type ECSVThemeSingle = TailwindThemeVars;
2087
-
2088
- /**
2089
- * Theme with light and dark mode support
2090
- */
2091
- declare interface ECSVThemeWithModes {
2092
- modes: {
2093
- light: TailwindThemeVars;
2094
- dark: TailwindThemeVars;
2095
- };
2096
- }
2097
-
2098
2090
  export declare interface ExBaseDef {
2099
2091
  typeName: string;
2100
2092
  }
@@ -3170,11 +3162,6 @@ declare interface ExpressCSVLocale {
3170
3162
  /** User-facing locale type where every leaf is a plain `string`. */
3171
3163
  export declare type ExpressCSVLocaleInput = StripBrand<ExpressCSVLocale>;
3172
3164
 
3173
- /**
3174
- * Core step identifiers for the CSV import wizard
3175
- */
3176
- export declare type ExpressCSVStep = 'upload' | 'select-sheet' | 'select-header' | 'match-columns' | 'match-options' | 'review';
3177
-
3178
3165
  declare type ExPrimitiveType = ExString | ExNumber | ExCurrencyNumber | ExPercentageNumber | ExBoolean | ExDate | ExTime | ExDatetime | ExSelect<string | number> | ExMultiselect<string | number> | ExOptionalPrimitiveType;
3179
3166
 
3180
3167
  declare class ExRow<T extends ExRowShape> extends ExType<{
@@ -3630,6 +3617,19 @@ export declare abstract class ExType<Output, Def extends ExBaseDef, Input = Outp
3630
3617
  protected _addCheck(type: string, params?: Record<string, unknown>, message?: string): ValidatorCheck;
3631
3618
  }
3632
3619
 
3620
+ /**
3621
+ * Font source configuration for custom fonts
3622
+ */
3623
+ export declare type FontSource = {
3624
+ source: 'google';
3625
+ name: string;
3626
+ weights?: (number | string)[];
3627
+ } | {
3628
+ source: 'custom';
3629
+ url: string;
3630
+ format?: 'woff2' | 'woff';
3631
+ };
3632
+
3633
3633
  declare interface GTINOptions {
3634
3634
  message?: string;
3635
3635
  }
@@ -3646,6 +3646,13 @@ export declare class ImportCancelledError extends Error {
3646
3646
  constructor(message?: string);
3647
3647
  }
3648
3648
 
3649
+ export declare interface ImportDeliveryContext extends ImportSessionContext {
3650
+ /** Stable ID for the delivery attempt that completed or failed */
3651
+ deliveryId: string;
3652
+ }
3653
+
3654
+ declare type ImporterCloseReason = 'user_close' | 'cancel' | 'complete' | 'error';
3655
+
3649
3656
  /**
3650
3657
  * Importer preload mode
3651
3658
  */
@@ -3654,10 +3661,15 @@ export declare enum ImporterMode {
3654
3661
  PRELOAD = "preload"
3655
3662
  }
3656
3663
 
3664
+ export declare type ImportErrorContext = ImportSessionContext & {
3665
+ /** Present when an error occurs while delivering records */
3666
+ deliveryId?: string;
3667
+ };
3668
+
3657
3669
  /**
3658
- * Importer lifecycle state
3670
+ * Importer lifecycle status
3659
3671
  */
3660
- export declare enum ImporterState {
3672
+ export declare enum ImporterStatus {
3661
3673
  UNINITIALIZED = "uninitialized",
3662
3674
  INITIALIZING = "initializing",
3663
3675
  READY = "ready",
@@ -3669,8 +3681,13 @@ export declare enum ImporterState {
3669
3681
  DESTROYED = "destroyed"
3670
3682
  }
3671
3683
 
3684
+ /**
3685
+ * Core step identifiers for the CSV importer
3686
+ */
3687
+ export declare type ImporterStep = 'upload' | 'select-sheet' | 'select-header' | 'match-columns' | 'match-options' | 'review';
3688
+
3672
3689
  export declare interface ImportSessionContext {
3673
- /** Generated session ID for the current import run */
3690
+ /** Stable ID that groups one import run across chunks and lifecycle callbacks */
3674
3691
  sessionId: string;
3675
3692
  }
3676
3693
 
@@ -3708,20 +3725,18 @@ declare interface MultiselectOptions {
3708
3725
  export declare type OpenOptions<T> = {
3709
3726
  /** Callback for processing delivered chunks */
3710
3727
  onData: (chunk: RecordsChunk<T>, next: () => void) => void | Promise<void>;
3711
- /** Number of records per chunk (default: 1000) */
3712
- chunkSize?: number;
3728
+ /** Chunk size by KB quota or row count. Defaults to 500 KB. Values <= 0 send one chunk. */
3729
+ chunkSize?: ChunkSize;
3713
3730
  /** Called when all chunks have been processed */
3714
- onComplete?: (context: ImportSessionContext) => void;
3731
+ onComplete?: (context: ImportDeliveryContext) => void;
3715
3732
  /** Called when the user cancels the import */
3716
3733
  onCancel?: (context: ImportSessionContext) => void;
3717
3734
  /** Called when an error occurs */
3718
- onError?: (error: Error, context: ImportSessionContext) => void;
3735
+ onError?: (error: Error, context: ImportErrorContext) => void;
3719
3736
  /** Called when the importer opens */
3720
- onImporterOpen?: () => void;
3721
- /** Called when the importer closes */
3722
- onImporterClose?: (reason: 'user_close' | 'cancel' | 'complete' | 'error') => void;
3723
- /** Called when the step changes in the wizard */
3724
- onStepChange?: (stepId: ExpressCSVStep, previousStepId?: ExpressCSVStep) => void;
3737
+ onOpen?: (context: ImportSessionContext) => void;
3738
+ /** Called when the importer step changes */
3739
+ onStepChange?: (stepId: ImporterStep, previousStepId?: ImporterStep) => void;
3725
3740
  };
3726
3741
 
3727
3742
  declare interface PersistedImportSessionData {
@@ -3750,7 +3765,6 @@ declare interface PrimitiveExBaseDef extends ExBaseDef {
3750
3765
  columnNameAliases?: string[];
3751
3766
  description?: string;
3752
3767
  label?: string;
3753
- example?: string;
3754
3768
  message?: string;
3755
3769
  checks?: ValidatorCheck[];
3756
3770
  defaultValue?: unknown | (() => unknown);
@@ -3778,13 +3792,6 @@ declare abstract class PrimitiveExType<Output, Def extends PrimitiveExBaseDef, I
3778
3792
  * @returns The type instance for method chaining
3779
3793
  */
3780
3794
  label(text: string): this;
3781
- /**
3782
- * Sets an example value for this field
3783
- *
3784
- * @param text - Example text
3785
- * @returns The type instance for method chaining
3786
- */
3787
- example(text: string): this;
3788
3795
  /**
3789
3796
  * Adds a custom refinement validator to this field.
3790
3797
  *
@@ -3827,6 +3834,10 @@ declare abstract class PrimitiveExType<Output, Def extends PrimitiveExBaseDef, I
3827
3834
  protected _replaceOrAddCheck(check: ValidatorCheck, existingIndex: number): void;
3828
3835
  }
3829
3836
 
3837
+ export declare type PromptedEditHandler<TSchema extends ExType<unknown, ExBaseDef, unknown> = ExRow<ExRowShape>> = PromptedEditsFn<SchemaFieldName<TSchema>>;
3838
+
3839
+ export declare type PromptedEditResult<TSchema extends ExType<unknown, ExBaseDef, unknown> = ExRow<ExRowShape>> = PromptedEditsResult<SchemaFieldName<TSchema>>;
3840
+
3830
3841
  export declare type PromptedEditsChange<TField extends string = string> = {
3831
3842
  type: 'add';
3832
3843
  values: Partial<Record<TField, unknown>>;
@@ -3882,14 +3893,14 @@ export declare interface RecordsChunk<T> {
3882
3893
  records: T[];
3883
3894
  /** Total number of chunks */
3884
3895
  totalChunks: number;
3885
- /** Current chunk index (0-based) */
3886
- currentChunkIndex: number;
3896
+ /** Chunk index within this delivery (0-based) */
3897
+ chunkIndex: number;
3887
3898
  /** Total number of records across all chunks */
3888
3899
  totalRecords: number;
3889
- /** Generated session ID for the current import run */
3900
+ /** Stable ID that groups one import run across chunks and lifecycle callbacks */
3890
3901
  sessionId: string;
3891
- /** Stable per-chunk idempotency key */
3892
- chunkIdempotencyKey: string;
3902
+ /** Stable ID for this delivery attempt within the import session */
3903
+ deliveryId: string;
3893
3904
  }
3894
3905
 
3895
3906
  export declare type RecoveredSession = PersistedImportSessionData;
@@ -3925,19 +3936,20 @@ declare type RefineResultItem = {
3925
3936
  };
3926
3937
  };
3927
3938
 
3928
- declare type SchemaFieldName<TSchema extends ExType<unknown, ExBaseDef, unknown>> = Extract<keyof Infer<TSchema>, string>;
3939
+ export declare type SchemaFieldName<TSchema extends ExType<unknown, ExBaseDef, unknown>> = Extract<keyof Infer<TSchema>, string>;
3929
3940
 
3930
3941
  export declare interface SDKOptions<TSchema extends ExType<unknown, ExBaseDef, unknown>> {
3931
3942
  schema: TSchema;
3932
3943
  getSessionToken: () => Promise<string>;
3933
- importIdentifier: string;
3944
+ /** Stable namespace string your app assigns to this importer configuration or workflow */
3945
+ importNamespace: string;
3934
3946
  title?: string;
3935
3947
  debug?: boolean;
3936
3948
  preload?: boolean;
3937
- theme?: ECSVTheme;
3949
+ theme?: Theme;
3938
3950
  colorMode?: ColorModePref;
3939
3951
  customCSS?: string;
3940
- fonts?: Record<string, ECSVFontSource>;
3952
+ fonts?: Record<string, FontSource>;
3941
3953
  stepDisplay?: 'progressBar' | 'segmented' | 'numbered';
3942
3954
  previewSchemaBeforeUpload?: boolean;
3943
3955
  columnMatching?: ColumnMatchingOptions<TSchema>;
@@ -3964,7 +3976,7 @@ export declare type SessionRecoveryKey = PersistedImportSessionKey;
3964
3976
 
3965
3977
  export declare type SessionRecoveryOptions = LocalSessionRecoveryOptions | CustomSessionRecoveryOptions;
3966
3978
 
3967
- declare type StateChangeListener = (state: ImporterState) => void;
3979
+ declare type StatusChangeListener = (status: ImporterStatus) => void;
3968
3980
 
3969
3981
  declare type StripBrand<T> = {
3970
3982
  [K in keyof T]: T[K] extends TemplateString<string> ? string : T[K] extends object ? StripBrand<T[K]> : T[K];
@@ -4038,6 +4050,26 @@ declare type TemplateString<TVars extends string = string> = string & {
4038
4050
  readonly __vars: TVars;
4039
4051
  };
4040
4052
 
4053
+ /**
4054
+ * Theme - can be either dual-mode (light/dark) or single-mode (applies to both)
4055
+ */
4056
+ export declare type Theme = ThemeWithModes | ThemeSingle;
4057
+
4058
+ /**
4059
+ * Single theme that applies to both light and dark modes
4060
+ */
4061
+ declare type ThemeSingle = TailwindThemeVars;
4062
+
4063
+ /**
4064
+ * Theme with light and dark mode support
4065
+ */
4066
+ declare interface ThemeWithModes {
4067
+ modes: {
4068
+ light: TailwindThemeVars;
4069
+ dark: TailwindThemeVars;
4070
+ };
4071
+ }
4072
+
4041
4073
  /**
4042
4074
  * Time validation options
4043
4075
  */