@expresscsv/sdk 0.1.17 → 0.1.19

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
@@ -5,6 +5,8 @@
5
5
 
6
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.
7
7
 
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
+
8
10
  ## Installation
9
11
 
10
12
  ```bash
@@ -55,6 +57,8 @@ importer.open({
55
57
  });
56
58
  ```
57
59
 
60
+ 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
+
58
62
  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.
59
63
 
60
64
  ## Webhook Delivery
@@ -112,6 +116,8 @@ interface WebhookPayload {
112
116
  }
113
117
  ```
114
118
 
119
+ When you already have a schema, prefer `InferWebhookPayload<typeof schema>` from `@expresscsv/schemas` instead of rewriting this object shape by hand.
120
+
115
121
  Example payload:
116
122
 
117
123
  ```json
@@ -150,6 +156,25 @@ Your endpoint should return a **2xx** status code to acknowledge each chunk. Non
150
156
 
151
157
  Chunks are delivered **serially** — the next chunk is only sent after the previous one succeeds.
152
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
+
153
178
  Below is a minimal Express.js example:
154
179
 
155
180
  ```typescript
@@ -241,6 +266,40 @@ const importer = new CSVImporter({
241
266
  });
242
267
  ```
243
268
 
269
+ ## Template Downloads
270
+
271
+ Generated templates can include example rows that match your schema.
272
+
273
+ ```typescript
274
+ import { CSVImporter, x, type Infer } from "@expresscsv/sdk";
275
+
276
+ const candidateSchema = x.row({
277
+ firstName: x.string().label("First Name"),
278
+ email: x.string().email().label("Email"),
279
+ role: x.select([
280
+ { label: "Admin", value: "admin" },
281
+ { label: "Editor", value: "editor" },
282
+ ]).label("Role"),
283
+ });
284
+
285
+ const importer = new CSVImporter({
286
+ schema: candidateSchema,
287
+ publishableKey: "your-publishable-key",
288
+ importIdentifier: "candidate-import",
289
+ templateDownload: {
290
+ source: "generate",
291
+ formats: ["csv", "xlsx"],
292
+ exampleRows: () => [
293
+ {
294
+ firstName: "Alice",
295
+ email: "alice@example.com",
296
+ role: "admin",
297
+ },
298
+ ],
299
+ },
300
+ });
301
+ ```
302
+
244
303
  ## Theming and Styling
245
304
 
246
305
  Customize the widget's appearance with the `theme`, `colorMode`, `customCSS`, and `fonts` options.
@@ -375,6 +434,8 @@ const importer = new CSVImporter({
375
434
 
376
435
  The `x` schema builder provides a type-safe, fluent API for defining your CSV structure.
377
436
 
437
+ For apps that share schema definitions with backend code or webhook handlers, prefer defining the schema in `@expresscsv/schemas` and importing it into your frontend. That keeps schema authoring free of widget/runtime dependencies.
438
+
378
439
  ### Field Types
379
440
 
380
441
  ```typescript
@@ -413,6 +474,65 @@ const schema = x.row({
413
474
  });
414
475
  ```
415
476
 
477
+ ### Runtime-Built Schemas
478
+
479
+ For a fixed schema, keep everything in a normal `x.row(...)` definition:
480
+
481
+ ```typescript
482
+ const schema = x.row({
483
+ email: x.string().email().label("Email"),
484
+ lifecycleStage: x
485
+ .select([
486
+ { label: "Lead", value: "lead" },
487
+ { label: "Customer", value: "customer" },
488
+ { label: "Churned", value: "churned" },
489
+ ])
490
+ .label("Lifecycle Stage"),
491
+ accountOwner: x.string().label("Account Owner").optional(),
492
+ contractValue: x.number().currency("USD").label("Contract Value").optional(),
493
+ });
494
+ ```
495
+
496
+ `x.row(...)` also works for runtime-built schemas, which is useful when the shape depends on account data, user preferences, or enabled custom fields.
497
+
498
+ ```typescript
499
+ import { x } from "@expresscsv/sdk";
500
+
501
+ function buildCustomerSchema(options: {
502
+ collectCrmId: boolean;
503
+ collectHealthScore: boolean;
504
+ collectSegment: boolean;
505
+ }) {
506
+ return x.row({
507
+ email: x.string().email().label("Email"),
508
+ companyName: x.string().label("Company Name"),
509
+ ...(options.collectCrmId ? { crmId: x.string().label("CRM ID") } : {}),
510
+ ...(options.collectHealthScore
511
+ ? { healthScore: x.number().label("Health Score") }
512
+ : {}),
513
+ ...(options.collectSegment
514
+ ? {
515
+ segment: x
516
+ .select([
517
+ { label: "SMB", value: "smb" },
518
+ { label: "Mid-Market", value: "mid-market" },
519
+ { label: "Enterprise", value: "enterprise" },
520
+ ])
521
+ .label("Segment"),
522
+ }
523
+ : {}),
524
+ });
525
+ }
526
+
527
+ const schema = buildCustomerSchema({
528
+ collectCrmId: true,
529
+ collectHealthScore: true,
530
+ collectSegment: false,
531
+ });
532
+ ```
533
+
534
+ Dynamic schema assembly preserves the same runtime parsing behavior, but it can widen `Infer<typeof schema>` because the exact keys are no longer fully known to TypeScript. Use it intentionally.
535
+
416
536
  ### Common Modifiers
417
537
 
418
538
  All field types support:
@@ -571,7 +691,7 @@ new CSVImporter(options: SDKOptions)
571
691
  | `fonts` | `Record<string, ECSVFontSource>` | No | - | Custom font sources |
572
692
  | `stepDisplay` | `'progressBar' \| 'segmented' \| 'numbered'` | No | `'progressBar'` | Step indicator style |
573
693
  | `previewSchemaBeforeUpload` | `boolean` | No | `true` | Show schema preview before upload |
574
- | `templateDownload` | `TemplateDownloadConfig` | No | - | Template download configuration |
694
+ | `templateDownload` | `TemplateDownloadOptions<TSchema>` | No | - | Template download configuration with optional schema-typed example rows |
575
695
  | `saveSession` | `boolean` | No | - | Persist session state |
576
696
  | `locale` | `DeepPartial<ExpressCSVLocaleInput>` | No | - | Localization overrides |
577
697
 
package/dist/index.d.cts CHANGED
@@ -1256,6 +1256,7 @@ export declare class CSVImporter<TSchema extends ExType<unknown, ExBaseDef, unkn
1256
1256
  private cachedSchemaJson;
1257
1257
  private initCompletePromise;
1258
1258
  private resolveInitComplete;
1259
+ private resolvedTemplateDownload;
1259
1260
  constructor(options: SDKOptions<TSchema>);
1260
1261
  /**
1261
1262
  * Enhanced state management
@@ -3126,6 +3127,11 @@ declare class ExRow<T extends ExRowShape> extends ExType<{
3126
3127
  * Factory method to create an ExRow validator for a row of data
3127
3128
  *
3128
3129
  * @param shape - Object defining the structure of fields in the row
3130
+ *
3131
+ * Object literals preserve exact key inference. If callers build the shape
3132
+ * through a widened variable or conditional assembly, TypeScript may widen
3133
+ * the resulting row type as well.
3134
+ *
3129
3135
  * @returns A new ExRow instance
3130
3136
  */
3131
3137
  static create<T extends ExRowShape>(shape: T): ExRow<T>;
@@ -3770,7 +3776,7 @@ export declare interface SDKOptions<TSchema extends ExType<unknown, ExBaseDef, u
3770
3776
  fonts?: Record<string, ECSVFontSource>;
3771
3777
  stepDisplay?: 'progressBar' | 'segmented' | 'numbered';
3772
3778
  previewSchemaBeforeUpload?: boolean;
3773
- templateDownload?: TemplateDownloadConfig;
3779
+ templateDownload?: TemplateDownloadOptions<TSchema>;
3774
3780
  saveSession?: boolean;
3775
3781
  locale?: DeepPartial<ExpressCSVLocaleInput>;
3776
3782
  disableStatusStep?: boolean;
@@ -3827,18 +3833,28 @@ export declare interface TailwindThemeVars {
3827
3833
 
3828
3834
  /**
3829
3835
  * Configuration for template download in the upload step.
3830
- * When `source` is `"generate"`, a header-only template file is created
3831
- * client-side from the schema column names.
3836
+ * When `source` is `"generate"`, a template file is created client-side
3837
+ * from the schema column names and optional example rows.
3832
3838
  */
3833
- declare interface TemplateDownloadConfig {
3839
+ export declare interface TemplateDownloadConfig {
3834
3840
  source: 'generate';
3835
3841
  formats?: TemplateDownloadFormat[];
3842
+ exampleRows?: TemplateDownloadExampleRow[];
3836
3843
  }
3837
3844
 
3845
+ /**
3846
+ * A serializable example row used to populate generated templates.
3847
+ */
3848
+ export declare type TemplateDownloadExampleRow = Record<string, unknown>;
3849
+
3838
3850
  /**
3839
3851
  * Template download format
3840
3852
  */
3841
- declare type TemplateDownloadFormat = 'csv' | 'xlsx';
3853
+ export declare type TemplateDownloadFormat = 'csv' | 'xlsx';
3854
+
3855
+ export declare type TemplateDownloadOptions<TSchema extends ExType<unknown, ExBaseDef, unknown>> = Omit<TemplateDownloadConfig, 'exampleRows'> & {
3856
+ exampleRows?: Infer<TSchema>[] | (() => Infer<TSchema>[]);
3857
+ };
3842
3858
 
3843
3859
  /**
3844
3860
  * A branded string type for locale entries that require interpolation via `{variable}` syntax.
package/dist/index.d.mts CHANGED
@@ -1256,6 +1256,7 @@ export declare class CSVImporter<TSchema extends ExType<unknown, ExBaseDef, unkn
1256
1256
  private cachedSchemaJson;
1257
1257
  private initCompletePromise;
1258
1258
  private resolveInitComplete;
1259
+ private resolvedTemplateDownload;
1259
1260
  constructor(options: SDKOptions<TSchema>);
1260
1261
  /**
1261
1262
  * Enhanced state management
@@ -3126,6 +3127,11 @@ declare class ExRow<T extends ExRowShape> extends ExType<{
3126
3127
  * Factory method to create an ExRow validator for a row of data
3127
3128
  *
3128
3129
  * @param shape - Object defining the structure of fields in the row
3130
+ *
3131
+ * Object literals preserve exact key inference. If callers build the shape
3132
+ * through a widened variable or conditional assembly, TypeScript may widen
3133
+ * the resulting row type as well.
3134
+ *
3129
3135
  * @returns A new ExRow instance
3130
3136
  */
3131
3137
  static create<T extends ExRowShape>(shape: T): ExRow<T>;
@@ -3770,7 +3776,7 @@ export declare interface SDKOptions<TSchema extends ExType<unknown, ExBaseDef, u
3770
3776
  fonts?: Record<string, ECSVFontSource>;
3771
3777
  stepDisplay?: 'progressBar' | 'segmented' | 'numbered';
3772
3778
  previewSchemaBeforeUpload?: boolean;
3773
- templateDownload?: TemplateDownloadConfig;
3779
+ templateDownload?: TemplateDownloadOptions<TSchema>;
3774
3780
  saveSession?: boolean;
3775
3781
  locale?: DeepPartial<ExpressCSVLocaleInput>;
3776
3782
  disableStatusStep?: boolean;
@@ -3827,18 +3833,28 @@ export declare interface TailwindThemeVars {
3827
3833
 
3828
3834
  /**
3829
3835
  * Configuration for template download in the upload step.
3830
- * When `source` is `"generate"`, a header-only template file is created
3831
- * client-side from the schema column names.
3836
+ * When `source` is `"generate"`, a template file is created client-side
3837
+ * from the schema column names and optional example rows.
3832
3838
  */
3833
- declare interface TemplateDownloadConfig {
3839
+ export declare interface TemplateDownloadConfig {
3834
3840
  source: 'generate';
3835
3841
  formats?: TemplateDownloadFormat[];
3842
+ exampleRows?: TemplateDownloadExampleRow[];
3836
3843
  }
3837
3844
 
3845
+ /**
3846
+ * A serializable example row used to populate generated templates.
3847
+ */
3848
+ export declare type TemplateDownloadExampleRow = Record<string, unknown>;
3849
+
3838
3850
  /**
3839
3851
  * Template download format
3840
3852
  */
3841
- declare type TemplateDownloadFormat = 'csv' | 'xlsx';
3853
+ export declare type TemplateDownloadFormat = 'csv' | 'xlsx';
3854
+
3855
+ export declare type TemplateDownloadOptions<TSchema extends ExType<unknown, ExBaseDef, unknown>> = Omit<TemplateDownloadConfig, 'exampleRows'> & {
3856
+ exampleRows?: Infer<TSchema>[] | (() => Infer<TSchema>[]);
3857
+ };
3842
3858
 
3843
3859
  /**
3844
3860
  * A branded string type for locale entries that require interpolation via `{variable}` syntax.
package/dist/index.d.ts CHANGED
@@ -1256,6 +1256,7 @@ export declare class CSVImporter<TSchema extends ExType<unknown, ExBaseDef, unkn
1256
1256
  private cachedSchemaJson;
1257
1257
  private initCompletePromise;
1258
1258
  private resolveInitComplete;
1259
+ private resolvedTemplateDownload;
1259
1260
  constructor(options: SDKOptions<TSchema>);
1260
1261
  /**
1261
1262
  * Enhanced state management
@@ -3126,6 +3127,11 @@ declare class ExRow<T extends ExRowShape> extends ExType<{
3126
3127
  * Factory method to create an ExRow validator for a row of data
3127
3128
  *
3128
3129
  * @param shape - Object defining the structure of fields in the row
3130
+ *
3131
+ * Object literals preserve exact key inference. If callers build the shape
3132
+ * through a widened variable or conditional assembly, TypeScript may widen
3133
+ * the resulting row type as well.
3134
+ *
3129
3135
  * @returns A new ExRow instance
3130
3136
  */
3131
3137
  static create<T extends ExRowShape>(shape: T): ExRow<T>;
@@ -3770,7 +3776,7 @@ export declare interface SDKOptions<TSchema extends ExType<unknown, ExBaseDef, u
3770
3776
  fonts?: Record<string, ECSVFontSource>;
3771
3777
  stepDisplay?: 'progressBar' | 'segmented' | 'numbered';
3772
3778
  previewSchemaBeforeUpload?: boolean;
3773
- templateDownload?: TemplateDownloadConfig;
3779
+ templateDownload?: TemplateDownloadOptions<TSchema>;
3774
3780
  saveSession?: boolean;
3775
3781
  locale?: DeepPartial<ExpressCSVLocaleInput>;
3776
3782
  disableStatusStep?: boolean;
@@ -3827,18 +3833,28 @@ export declare interface TailwindThemeVars {
3827
3833
 
3828
3834
  /**
3829
3835
  * Configuration for template download in the upload step.
3830
- * When `source` is `"generate"`, a header-only template file is created
3831
- * client-side from the schema column names.
3836
+ * When `source` is `"generate"`, a template file is created client-side
3837
+ * from the schema column names and optional example rows.
3832
3838
  */
3833
- declare interface TemplateDownloadConfig {
3839
+ export declare interface TemplateDownloadConfig {
3834
3840
  source: 'generate';
3835
3841
  formats?: TemplateDownloadFormat[];
3842
+ exampleRows?: TemplateDownloadExampleRow[];
3836
3843
  }
3837
3844
 
3845
+ /**
3846
+ * A serializable example row used to populate generated templates.
3847
+ */
3848
+ export declare type TemplateDownloadExampleRow = Record<string, unknown>;
3849
+
3838
3850
  /**
3839
3851
  * Template download format
3840
3852
  */
3841
- declare type TemplateDownloadFormat = 'csv' | 'xlsx';
3853
+ export declare type TemplateDownloadFormat = 'csv' | 'xlsx';
3854
+
3855
+ export declare type TemplateDownloadOptions<TSchema extends ExType<unknown, ExBaseDef, unknown>> = Omit<TemplateDownloadConfig, 'exampleRows'> & {
3856
+ exampleRows?: Infer<TSchema>[] | (() => Infer<TSchema>[]);
3857
+ };
3842
3858
 
3843
3859
  /**
3844
3860
  * A branded string type for locale entries that require interpolation via `{variable}` syntax.