@expresscsv/react 0.1.26 → 1.0.1

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
@@ -25,7 +25,7 @@ yarn add @expresscsv/react
25
25
  ## Quick Start
26
26
 
27
27
  ```tsx
28
- import { useExpressCSV, x } from "@expresscsv/react";
28
+ import { ImporterStatus, useExpressCSV, x } from "@expresscsv/react";
29
29
 
30
30
  const schema = x.row({
31
31
  name: x.string().label("Full Name"),
@@ -34,26 +34,26 @@ const schema = x.row({
34
34
  });
35
35
 
36
36
  function App() {
37
- const { open, isOpen } = useExpressCSV({
37
+ const { open, status } = useExpressCSV({
38
38
  schema,
39
- getSessionToken: async () => fetchSessionToken(),
40
- importIdentifier: "user-import",
39
+ getAuthToken: async () => fetchAuthToken(),
40
+ importNamespace: "user-import",
41
41
  title: "Import Users",
42
42
  });
43
43
 
44
44
  const handleImport = () => {
45
45
  open({
46
- chunkSize: 500,
46
+ chunkSize: { unit: "kb", value: 500 },
47
47
  onData: async (chunk, next) => {
48
48
  console.log(
49
- `Chunk ${chunk.currentChunkIndex + 1}/${chunk.totalChunks}`
49
+ `Chunk ${chunk.chunkIndex + 1}/${chunk.totalChunks}`
50
50
  );
51
51
  console.log("Session:", chunk.sessionId);
52
- console.log("Idempotency key:", chunk.chunkIdempotencyKey);
52
+ console.log("Delivery ID:", chunk.deliveryId);
53
53
  console.log("Records:", chunk.records);
54
54
  next();
55
55
  },
56
- onComplete: ({ sessionId }) => {
56
+ onComplete: ({ sessionId, deliveryId }) => {
57
57
  console.log("All chunks processed for", sessionId);
58
58
  },
59
59
  onCancel: ({ sessionId }) => {
@@ -66,14 +66,14 @@ function App() {
66
66
  };
67
67
 
68
68
  return (
69
- <button onClick={handleImport} disabled={isOpen}>
69
+ <button onClick={handleImport} disabled={status === ImporterStatus.OPEN}>
70
70
  Import CSV
71
71
  </button>
72
72
  );
73
73
  }
74
74
  ```
75
75
 
76
- 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`.
76
+ Have your backend keep the ExpressCSV secret key, call the ExpressCSV session-creation endpoint, and return a short-lived importer auth token to the browser via `getAuthToken`.
77
77
 
78
78
  ## Preloading
79
79
 
@@ -82,8 +82,8 @@ By default the importer preloads in a hidden iframe so it appears instantly when
82
82
  ```tsx
83
83
  const { open } = useExpressCSV({
84
84
  schema,
85
- getSessionToken: async () => fetchSessionToken(),
86
- importIdentifier: "user-import",
85
+ getAuthToken: async () => fetchAuthToken(),
86
+ importNamespace: "user-import",
87
87
  });
88
88
 
89
89
  // Importer displays instantly
@@ -102,8 +102,8 @@ To disable preloading (there will be a brief loading screen instead):
102
102
  ```tsx
103
103
  const { open } = useExpressCSV({
104
104
  schema,
105
- getSessionToken: async () => fetchSessionToken(),
106
- importIdentifier: "user-import",
105
+ getAuthToken: async () => fetchAuthToken(),
106
+ importNamespace: "user-import",
107
107
  preload: false,
108
108
  });
109
109
  ```
@@ -126,8 +126,8 @@ const candidateSchema = x.row({
126
126
 
127
127
  const { open } = useExpressCSV({
128
128
  schema: candidateSchema,
129
- getSessionToken: async () => fetchSessionToken(),
130
- importIdentifier: "candidate-import",
129
+ getAuthToken: async () => fetchAuthToken(),
130
+ importNamespace: "candidate-import",
131
131
  templateDownload: {
132
132
  source: "generate",
133
133
  formats: ["csv", "xlsx"],
@@ -151,10 +151,10 @@ Customize the importer's appearance with the `theme`, `colorMode`, `customCSS`,
151
151
  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:
152
152
 
153
153
  ```tsx
154
- import { useExpressCSV, x, type ECSVTheme } from "@expresscsv/react";
154
+ import { useExpressCSV, x, type Theme } from "@expresscsv/react";
155
155
 
156
156
  // Single theme (both modes)
157
- const theme: ECSVTheme = {
157
+ const theme: Theme = {
158
158
  primary: "#4F46E5",
159
159
  "primary-foreground": "#ffffff",
160
160
  background: "#ffffff",
@@ -165,7 +165,7 @@ const theme: ECSVTheme = {
165
165
  };
166
166
 
167
167
  // Dual-mode (light and dark)
168
- const dualTheme: ECSVTheme = {
168
+ const dualTheme: Theme = {
169
169
  modes: {
170
170
  light: {
171
171
  primary: "#4F46E5",
@@ -183,8 +183,8 @@ const dualTheme: ECSVTheme = {
183
183
  function App() {
184
184
  const { open } = useExpressCSV({
185
185
  schema,
186
- getSessionToken: async () => fetchSessionToken(),
187
- importIdentifier: "user-import",
186
+ getAuthToken: async () => fetchAuthToken(),
187
+ importNamespace: "user-import",
188
188
  theme,
189
189
  });
190
190
  // ...
@@ -229,8 +229,8 @@ Control light/dark mode with `colorMode`:
229
229
  ```tsx
230
230
  const { open } = useExpressCSV({
231
231
  schema,
232
- getSessionToken: async () => fetchSessionToken(),
233
- importIdentifier: "user-import",
232
+ getAuthToken: async () => fetchAuthToken(),
233
+ importNamespace: "user-import",
234
234
  colorMode: "system", // 'light' | 'dark' | 'system'
235
235
  });
236
236
  ```
@@ -242,8 +242,8 @@ Inject custom CSS for fine-grained styling overrides.
242
242
  ```tsx
243
243
  const { open } = useExpressCSV({
244
244
  schema,
245
- getSessionToken: async () => fetchSessionToken(),
246
- importIdentifier: "user-import",
245
+ getAuthToken: async () => fetchAuthToken(),
246
+ importNamespace: "user-import",
247
247
  customCSS: `
248
248
  .ecsv [data-step="upload"] {
249
249
  border-radius: 1rem;
@@ -262,8 +262,8 @@ Load custom fonts via the `fonts` option:
262
262
  ```tsx
263
263
  const { open } = useExpressCSV({
264
264
  schema,
265
- getSessionToken: async () => fetchSessionToken(),
266
- importIdentifier: "user-import",
265
+ getAuthToken: async () => fetchAuthToken(),
266
+ importNamespace: "user-import",
267
267
  fonts: {
268
268
  title: { source: "google", name: "Space Grotesk", weights: [400, 600, 700] },
269
269
  body: { source: "custom", url: "https://example.com/font.woff2", format: "woff2" },
@@ -281,18 +281,19 @@ ExpressCSV delivers imported data through `onData`. Your app receives validated
281
281
 
282
282
  ```tsx
283
283
  open({
284
- chunkSize: 500,
284
+ chunkSize: { unit: "kb", value: 500 },
285
285
  onData: async (chunk, next) => {
286
- const response = await fetch("/api/import-users/chunks", {
286
+ const response = await fetch("/your-api/import-users/chunks", {
287
287
  method: "POST",
288
288
  headers: {
289
289
  "Content-Type": "application/json",
290
+ Authorization: `Bearer ${accessToken}`,
290
291
  },
291
292
  body: JSON.stringify({
292
293
  sessionId: chunk.sessionId,
293
- chunkIdempotencyKey: chunk.chunkIdempotencyKey,
294
+ deliveryId: chunk.deliveryId,
295
+ chunkIndex: chunk.chunkIndex,
294
296
  records: chunk.records,
295
- currentChunkIndex: chunk.currentChunkIndex,
296
297
  totalChunks: chunk.totalChunks,
297
298
  totalRecords: chunk.totalRecords,
298
299
  }),
@@ -304,8 +305,15 @@ open({
304
305
 
305
306
  next();
306
307
  },
307
- onComplete: ({ sessionId }) => {
308
- console.log("Import complete for", sessionId);
308
+ onComplete: async ({ sessionId, deliveryId }) => {
309
+ await fetch("/your-api/import-users/complete", {
310
+ method: "POST",
311
+ headers: {
312
+ "Content-Type": "application/json",
313
+ Authorization: `Bearer ${accessToken}`,
314
+ },
315
+ body: JSON.stringify({ sessionId, deliveryId }),
316
+ });
309
317
  },
310
318
  });
311
319
  ```
@@ -314,15 +322,18 @@ Each delivered chunk includes:
314
322
 
315
323
  - `records`
316
324
  - `sessionId`
317
- - `chunkIdempotencyKey`
318
- - `currentChunkIndex`
325
+ - `deliveryId`
326
+ - `chunkIndex`
319
327
  - `totalChunks`
320
328
  - `totalRecords`
321
329
 
330
+ 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.
331
+
332
+
322
333
  ## Advanced Example
323
334
 
324
335
  ```tsx
325
- import { useExpressCSV, x, type Infer } from "@expresscsv/react";
336
+ import { ImporterStatus, useExpressCSV, x, type Infer } from "@expresscsv/react";
326
337
  import { useState } from "react";
327
338
 
328
339
  const candidateSchema = x.row({
@@ -342,10 +353,10 @@ const candidateSchema = x.row({
342
353
  function CandidateImporter() {
343
354
  const [status, setStatus] = useState<string | null>(null);
344
355
 
345
- const { open, isOpen } = useExpressCSV({
356
+ const { open, status: importerStatus } = useExpressCSV({
346
357
  schema: candidateSchema,
347
- getSessionToken: async () => fetchSessionToken(),
348
- importIdentifier: "candidate-import",
358
+ getAuthToken: async () => fetchAuthToken(),
359
+ importNamespace: "candidate-import",
349
360
  title: "Import Candidates",
350
361
  });
351
362
 
@@ -355,12 +366,12 @@ function CandidateImporter() {
355
366
  open({
356
367
  onData: async (chunk, next) => {
357
368
  setStatus(
358
- `Processing chunk ${chunk.currentChunkIndex + 1}/${chunk.totalChunks}...`
369
+ `Processing chunk ${chunk.chunkIndex + 1}/${chunk.totalChunks}...`
359
370
  );
360
371
  await importCandidates(chunk.records);
361
372
  next();
362
373
  },
363
- onComplete: ({ sessionId }) => {
374
+ onComplete: ({ sessionId, deliveryId }) => {
364
375
  setStatus(`Import complete: ${sessionId}`);
365
376
  },
366
377
  onError: (error, { sessionId }) => {
@@ -375,8 +386,13 @@ function CandidateImporter() {
375
386
 
376
387
  return (
377
388
  <div>
378
- <button onClick={handleImport} disabled={isOpen}>
379
- {isOpen ? "Importing..." : "Import Candidates"}
389
+ <button
390
+ onClick={handleImport}
391
+ disabled={importerStatus === ImporterStatus.OPEN}
392
+ >
393
+ {importerStatus === ImporterStatus.OPEN
394
+ ? "Importing..."
395
+ : "Import Candidates"}
380
396
  </button>
381
397
  {status && <p>{status}</p>}
382
398
  </div>
@@ -393,9 +409,7 @@ function useExpressCSV<TSchema>(
393
409
  options: UseExpressCSVOptions<TSchema>
394
410
  ): {
395
411
  open: (options: OpenOptions<Infer<TSchema>>) => void;
396
- importerState: ImporterState;
397
- isInitialising: boolean;
398
- isOpen: boolean;
412
+ status: ImporterStatus;
399
413
  };
400
414
  ```
401
415
 
@@ -404,21 +418,21 @@ function useExpressCSV<TSchema>(
404
418
  | Option | Type | Required | Default | Description |
405
419
  |---|---|---|---|---|
406
420
  | `schema` | Schema | Yes | - | Schema definition created with `x.row()` |
407
- | `getSessionToken` | `() => Promise<string>` | Yes | - | Async callback that asks your backend for a short-lived importer session token |
408
- | `importIdentifier` | `string` | Yes | - | Unique identifier for this import type |
421
+ | `getAuthToken` | `() => Promise<string>` | Yes | - | Async callback that asks your backend for a short-lived importer auth token |
422
+ | `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. |
409
423
  | `title` | `string` | No | - | Title shown in the importer header |
410
424
  | `preload` | `boolean` | No | `true` | Preload the importer for instant display |
411
425
  | `debug` | `boolean` | No | `false` | Enable debug logging |
412
- | `theme` | `ECSVTheme` | No | - | Custom theme configuration |
426
+ | `theme` | `Theme` | No | - | Custom theme configuration |
413
427
  | `colorMode` | `ColorModePref` | No | - | Light/dark mode (`'light'`, `'dark'`, or `'system'`) |
414
428
  | `customCSS` | `string` | No | - | Custom CSS to inject into the importer |
415
- | `fonts` | `Record<string, ECSVFontSource>` | No | - | Custom font sources |
429
+ | `fonts` | `Record<string, FontSource>` | No | - | Custom font sources |
416
430
  | `stepDisplay` | `'progressBar' \| 'segmented' \| 'numbered'` | No | `'progressBar'` | Step indicator style |
417
431
  | `previewSchemaBeforeUpload` | `boolean` | No | `true` | Show schema preview before upload |
418
- | `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 |
419
- | `promptedEdits` | `{ type: "managed" } \| { type: "custom"; edit: (...) => Promise<...> }` | No | `undefined` | Enable managed prompted edits or provide a custom edit handler |
432
+ | `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 |
433
+ | `promptedEdits` | `{ type: "managed" } \| { type: "custom"; promptedEditHandler: (...) => Promise<...> }` | No | `undefined` | Enable managed prompted edits or provide a custom edit handler |
420
434
  | `templateDownload` | `TemplateDownloadOptions<TSchema>` | No | - | Template download configuration with optional schema-typed example rows |
421
- | `sessionRecovery` | `SessionRecoveryOptions` | No | - | Enable Recovered Sessions with the built-in local backend or a custom adapter implementing `get`, `set`, and `remove` |
435
+ | `sessionRecovery` | `SessionRecoveryOptions` | No | - | Enable Recovered sessions with the built-in local backend or a custom adapter implementing `get`, `set`, and `remove` |
422
436
  | `locale` | `DeepPartial<ExpressCSVLocaleInput>` | No | - | Localization overrides |
423
437
  | `disableStatusStep` | `boolean` | No | - | Skip the success/error status screen |
424
438
 
@@ -427,9 +441,7 @@ function useExpressCSV<TSchema>(
427
441
  | Property | Type | Description |
428
442
  |---|---|---|
429
443
  | `open` | `(options: OpenOptions) => void` | Opens the importer. Requires `onData` for delivery. |
430
- | `importerState` | `ImporterState` | Current importer lifecycle state (reactive) |
431
- | `isInitialising` | `boolean` | `true` while the importer is initializing or opening |
432
- | `isOpen` | `boolean` | `true` while the importer is open |
444
+ | `status` | `ImporterStatus` | Current importer lifecycle status (reactive) |
433
445
 
434
446
  ### `OpenOptions<T>`
435
447
 
@@ -438,13 +450,12 @@ Options passed to `open()`.
438
450
  | Option | Type | Required | Description |
439
451
  |---|---|---|---|
440
452
  | `onData` | `(chunk: RecordsChunk<T>, next: () => void) => void` | Yes | Callback for each delivered chunk. Call `next()` after your backend accepts the current chunk. |
441
- | `chunkSize` | `number` | No | Records per chunk (default: 1000) |
453
+ | `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. |
442
454
  | `onComplete` | `(context: { sessionId: string }) => void` | No | Called when all chunks have been processed |
443
455
  | `onCancel` | `(context: { sessionId: string }) => void` | No | Called when the user cancels the import |
444
456
  | `onError` | `(error: Error, context: { sessionId: string }) => void` | No | Called when an error occurs |
445
- | `onImporterOpen` | `() => void` | No | Called when the importer opens |
446
- | `onImporterClose` | `(reason: 'user_close' \| 'cancel' \| 'complete' \| 'error') => void` | No | Called when the importer closes |
447
- | `onStepChange` | `(stepId, previousStepId?) => void` | No | Called when the wizard step changes |
457
+ | `onOpen` | `(context: { sessionId: string }) => void` | No | Called when the importer opens |
458
+ | `onStepChange` | `(stepId, previousStepId?) => void` | No | Called when the importer step changes |
448
459
 
449
460
  ### `RecordsChunk<T>`
450
461
 
@@ -452,10 +463,10 @@ Options passed to `open()`.
452
463
  interface RecordsChunk<T> {
453
464
  records: T[]; // Automatically typed to your schema
454
465
  totalChunks: number;
455
- currentChunkIndex: number;
466
+ chunkIndex: number;
456
467
  totalRecords: number;
457
468
  sessionId: string;
458
- chunkIdempotencyKey: string;
469
+ deliveryId: string;
459
470
  }
460
471
  ```
461
472
 
@@ -570,7 +581,6 @@ All field types support:
570
581
  |---|---|
571
582
  | `.label(text)` | User-facing label shown in the importer |
572
583
  | `.description(text)` | Help text for the field |
573
- | `.example(text)` | Example value shown as placeholder |
574
584
  | `.optional()` | Makes the field optional (default is required) |
575
585
  | `.refine(fn, params?)` | Custom per-value validation — any sync or async JS function |
576
586
  | `.refineBatch(fn, params?)` | Custom whole-column validation — receives all values at once |
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>;
@@ -1913,12 +1929,12 @@ declare const CurrencyCodes: readonly [{
1913
1929
 
1914
1930
  declare type CustomColumnMatchingOptions<TSchema extends ExType<unknown, ExBaseDef, unknown> = ExRow<ExRowShape>> = {
1915
1931
  type: 'custom';
1916
- match: ColumnMatchingFn<SchemaFieldName<TSchema>>;
1932
+ columnMatchHandler: ColumnMatchHandler<TSchema>;
1917
1933
  };
1918
1934
 
1919
1935
  declare type CustomPromptedEditsOptions<TSchema extends ExType<unknown, ExBaseDef, unknown> = ExRow<ExRowShape>> = {
1920
1936
  type: 'custom';
1921
- edit: PromptedEditsFn<SchemaFieldName<TSchema>>;
1937
+ promptedEditHandler: PromptedEditHandler<TSchema>;
1922
1938
  };
1923
1939
 
1924
1940
  export declare type CustomSessionRecoveryOptions = {
@@ -1936,39 +1952,6 @@ export declare type DeepPartial<T> = {
1936
1952
  [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
1937
1953
  };
1938
1954
 
1939
- /**
1940
- * Font source configuration for custom fonts
1941
- */
1942
- export declare type ECSVFontSource = {
1943
- source: 'google';
1944
- name: string;
1945
- weights?: (number | string)[];
1946
- } | {
1947
- source: 'custom';
1948
- url: string;
1949
- format?: 'woff2' | 'woff';
1950
- };
1951
-
1952
- /**
1953
- * Theme - can be either dual-mode (light/dark) or single-mode (applies to both)
1954
- */
1955
- export declare type ECSVTheme = ECSVThemeWithModes | ECSVThemeSingle;
1956
-
1957
- /**
1958
- * Single theme that applies to both light and dark modes
1959
- */
1960
- declare type ECSVThemeSingle = TailwindThemeVars;
1961
-
1962
- /**
1963
- * Theme with light and dark mode support
1964
- */
1965
- declare interface ECSVThemeWithModes {
1966
- modes: {
1967
- light: TailwindThemeVars;
1968
- dark: TailwindThemeVars;
1969
- };
1970
- }
1971
-
1972
1955
  declare interface ExBaseDef {
1973
1956
  typeName: string;
1974
1957
  }
@@ -3044,11 +3027,6 @@ declare interface ExpressCSVLocale {
3044
3027
  /** User-facing locale type where every leaf is a plain `string`. */
3045
3028
  export declare type ExpressCSVLocaleInput = StripBrand<ExpressCSVLocale>;
3046
3029
 
3047
- /**
3048
- * Core step identifiers for the CSV import wizard
3049
- */
3050
- export declare type ExpressCSVStep = 'upload' | 'select-sheet' | 'select-header' | 'match-columns' | 'match-options' | 'review';
3051
-
3052
3030
  declare type ExPrimitiveType = ExString | ExNumber | ExCurrencyNumber | ExPercentageNumber | ExBoolean | ExDate | ExTime | ExDatetime | ExSelect<string | number> | ExMultiselect<string | number> | ExOptionalPrimitiveType;
3053
3031
 
3054
3032
  declare class ExRow<T extends ExRowShape> extends ExType<{
@@ -3504,6 +3482,19 @@ declare abstract class ExType<Output, Def extends ExBaseDef, Input = Output> {
3504
3482
  protected _addCheck(type: string, params?: Record<string, unknown>, message?: string): ValidatorCheck;
3505
3483
  }
3506
3484
 
3485
+ /**
3486
+ * Font source configuration for custom fonts
3487
+ */
3488
+ export declare type FontSource = {
3489
+ source: 'google';
3490
+ name: string;
3491
+ weights?: (number | string)[];
3492
+ } | {
3493
+ source: 'custom';
3494
+ url: string;
3495
+ format?: 'woff2' | 'woff';
3496
+ };
3497
+
3507
3498
  declare interface GTINOptions {
3508
3499
  message?: string;
3509
3500
  }
@@ -3520,6 +3511,11 @@ export declare class ImportCancelledError extends Error {
3520
3511
  constructor(message?: string);
3521
3512
  }
3522
3513
 
3514
+ export declare interface ImportDeliveryContext extends ImportSessionContext {
3515
+ /** Stable ID for the delivery attempt that completed or failed */
3516
+ deliveryId: string;
3517
+ }
3518
+
3523
3519
  /**
3524
3520
  * Importer preload mode
3525
3521
  */
@@ -3528,10 +3524,15 @@ export declare enum ImporterMode {
3528
3524
  PRELOAD = "preload"
3529
3525
  }
3530
3526
 
3527
+ export declare type ImportErrorContext = ImportSessionContext & {
3528
+ /** Present when an error occurs while delivering records */
3529
+ deliveryId?: string;
3530
+ };
3531
+
3531
3532
  /**
3532
- * Importer lifecycle state
3533
+ * Importer lifecycle status
3533
3534
  */
3534
- export declare enum ImporterState {
3535
+ export declare enum ImporterStatus {
3535
3536
  UNINITIALIZED = "uninitialized",
3536
3537
  INITIALIZING = "initializing",
3537
3538
  READY = "ready",
@@ -3543,8 +3544,13 @@ export declare enum ImporterState {
3543
3544
  DESTROYED = "destroyed"
3544
3545
  }
3545
3546
 
3547
+ /**
3548
+ * Core step identifiers for the CSV importer
3549
+ */
3550
+ export declare type ImporterStep = 'upload' | 'select-sheet' | 'select-header' | 'match-columns' | 'match-options' | 'review';
3551
+
3546
3552
  export declare interface ImportSessionContext {
3547
- /** Generated session ID for the current import run */
3553
+ /** Stable ID that groups one import run across chunks and lifecycle callbacks */
3548
3554
  sessionId: string;
3549
3555
  }
3550
3556
 
@@ -3580,20 +3586,18 @@ declare interface MultiselectOptions {
3580
3586
  export declare type OpenOptions<T> = {
3581
3587
  /** Callback for processing delivered chunks */
3582
3588
  onData: (chunk: RecordsChunk<T>, next: () => void) => void | Promise<void>;
3583
- /** Number of records per chunk (default: 1000) */
3584
- chunkSize?: number;
3589
+ /** Chunk size by KB quota or row count. Defaults to 500 KB. Values <= 0 send one chunk. */
3590
+ chunkSize?: ChunkSize;
3585
3591
  /** Called when all chunks have been processed */
3586
- onComplete?: (context: ImportSessionContext) => void;
3592
+ onComplete?: (context: ImportDeliveryContext) => void;
3587
3593
  /** Called when the user cancels the import */
3588
3594
  onCancel?: (context: ImportSessionContext) => void;
3589
3595
  /** Called when an error occurs */
3590
- onError?: (error: Error, context: ImportSessionContext) => void;
3596
+ onError?: (error: Error, context: ImportErrorContext) => void;
3591
3597
  /** Called when the importer opens */
3592
- onImporterOpen?: () => void;
3593
- /** Called when the importer closes */
3594
- onImporterClose?: (reason: 'user_close' | 'cancel' | 'complete' | 'error') => void;
3595
- /** Called when the step changes in the wizard */
3596
- onStepChange?: (stepId: ExpressCSVStep, previousStepId?: ExpressCSVStep) => void;
3598
+ onOpen?: (context: ImportSessionContext) => void;
3599
+ /** Called when the importer step changes */
3600
+ onStepChange?: (stepId: ImporterStep, previousStepId?: ImporterStep) => void;
3597
3601
  };
3598
3602
 
3599
3603
  declare interface PersistedImportSessionData {
@@ -3622,7 +3626,6 @@ declare interface PrimitiveExBaseDef extends ExBaseDef {
3622
3626
  columnNameAliases?: string[];
3623
3627
  description?: string;
3624
3628
  label?: string;
3625
- example?: string;
3626
3629
  message?: string;
3627
3630
  checks?: ValidatorCheck[];
3628
3631
  defaultValue?: unknown | (() => unknown);
@@ -3650,13 +3653,6 @@ declare abstract class PrimitiveExType<Output, Def extends PrimitiveExBaseDef, I
3650
3653
  * @returns The type instance for method chaining
3651
3654
  */
3652
3655
  label(text: string): this;
3653
- /**
3654
- * Sets an example value for this field
3655
- *
3656
- * @param text - Example text
3657
- * @returns The type instance for method chaining
3658
- */
3659
- example(text: string): this;
3660
3656
  /**
3661
3657
  * Adds a custom refinement validator to this field.
3662
3658
  *
@@ -3699,6 +3695,10 @@ declare abstract class PrimitiveExType<Output, Def extends PrimitiveExBaseDef, I
3699
3695
  protected _replaceOrAddCheck(check: ValidatorCheck, existingIndex: number): void;
3700
3696
  }
3701
3697
 
3698
+ export declare type PromptedEditHandler<TSchema extends ExType<unknown, ExBaseDef, unknown> = ExRow<ExRowShape>> = PromptedEditsFn<SchemaFieldName<TSchema>>;
3699
+
3700
+ export declare type PromptedEditResult<TSchema extends ExType<unknown, ExBaseDef, unknown> = ExRow<ExRowShape>> = PromptedEditsResult<SchemaFieldName<TSchema>>;
3701
+
3702
3702
  export declare type PromptedEditsChange<TField extends string = string> = {
3703
3703
  type: 'add';
3704
3704
  values: Partial<Record<TField, unknown>>;
@@ -3754,14 +3754,14 @@ export declare interface RecordsChunk<T> {
3754
3754
  records: T[];
3755
3755
  /** Total number of chunks */
3756
3756
  totalChunks: number;
3757
- /** Current chunk index (0-based) */
3758
- currentChunkIndex: number;
3757
+ /** Chunk index within this delivery (0-based) */
3758
+ chunkIndex: number;
3759
3759
  /** Total number of records across all chunks */
3760
3760
  totalRecords: number;
3761
- /** Generated session ID for the current import run */
3761
+ /** Stable ID that groups one import run across chunks and lifecycle callbacks */
3762
3762
  sessionId: string;
3763
- /** Stable per-chunk idempotency key */
3764
- chunkIdempotencyKey: string;
3763
+ /** Stable ID for this delivery attempt within the import session */
3764
+ deliveryId: string;
3765
3765
  }
3766
3766
 
3767
3767
  export declare type RecoveredSession = PersistedImportSessionData;
@@ -3797,19 +3797,20 @@ declare type RefineResultItem = {
3797
3797
  };
3798
3798
  };
3799
3799
 
3800
- declare type SchemaFieldName<TSchema extends ExType<unknown, ExBaseDef, unknown>> = Extract<keyof Infer<TSchema>, string>;
3800
+ export declare type SchemaFieldName<TSchema extends ExType<unknown, ExBaseDef, unknown>> = Extract<keyof Infer<TSchema>, string>;
3801
3801
 
3802
3802
  export declare interface SDKOptions<TSchema extends ExType<unknown, ExBaseDef, unknown>> {
3803
3803
  schema: TSchema;
3804
- getSessionToken: () => Promise<string>;
3805
- importIdentifier: string;
3804
+ getAuthToken: () => Promise<string>;
3805
+ /** Stable namespace string your app assigns to this importer configuration or workflow */
3806
+ importNamespace: string;
3806
3807
  title?: string;
3807
3808
  debug?: boolean;
3808
3809
  preload?: boolean;
3809
- theme?: ECSVTheme;
3810
+ theme?: Theme;
3810
3811
  colorMode?: ColorModePref;
3811
3812
  customCSS?: string;
3812
- fonts?: Record<string, ECSVFontSource>;
3813
+ fonts?: Record<string, FontSource>;
3813
3814
  stepDisplay?: 'progressBar' | 'segmented' | 'numbered';
3814
3815
  previewSchemaBeforeUpload?: boolean;
3815
3816
  columnMatching?: ColumnMatchingOptions<TSchema>;
@@ -3908,6 +3909,26 @@ declare type TemplateString<TVars extends string = string> = string & {
3908
3909
  readonly __vars: TVars;
3909
3910
  };
3910
3911
 
3912
+ /**
3913
+ * Theme - can be either dual-mode (light/dark) or single-mode (applies to both)
3914
+ */
3915
+ export declare type Theme = ThemeWithModes | ThemeSingle;
3916
+
3917
+ /**
3918
+ * Single theme that applies to both light and dark modes
3919
+ */
3920
+ declare type ThemeSingle = TailwindThemeVars;
3921
+
3922
+ /**
3923
+ * Theme with light and dark mode support
3924
+ */
3925
+ declare interface ThemeWithModes {
3926
+ modes: {
3927
+ light: TailwindThemeVars;
3928
+ dark: TailwindThemeVars;
3929
+ };
3930
+ }
3931
+
3911
3932
  /**
3912
3933
  * Time validation options
3913
3934
  */
@@ -3924,11 +3945,9 @@ declare interface URLOptions {
3924
3945
  message?: string;
3925
3946
  }
3926
3947
 
3927
- export declare function useExpressCSV<TSchema extends ExType<unknown, ExBaseDef, unknown>>({ schema, title, importIdentifier, getSessionToken, debug, preload, theme, colorMode, customCSS, fonts, stepDisplay, previewSchemaBeforeUpload, columnMatching, promptedEdits, templateDownload, sessionRecovery, locale, disableStatusStep, }: UseExpressCSVOptions<TSchema>): {
3948
+ export declare function useExpressCSV<TSchema extends ExType<unknown, ExBaseDef, unknown>>({ schema, title, importNamespace, getAuthToken, debug, preload, theme, colorMode, customCSS, fonts, stepDisplay, previewSchemaBeforeUpload, columnMatching, promptedEdits, templateDownload, sessionRecovery, locale, disableStatusStep, }: UseExpressCSVOptions<TSchema>): {
3928
3949
  open: (options: OpenOptions<Infer<TSchema>>) => void;
3929
- importerState: ImporterState;
3930
- isInitialising: boolean;
3931
- isOpen: boolean;
3950
+ status: ImporterStatus;
3932
3951
  };
3933
3952
 
3934
3953
  export declare type UseExpressCSVOptions<TSchema extends ExType<unknown, ExBaseDef, unknown>> = SDKOptions<TSchema>;