@expresscsv/sdk 0.1.17 → 0.1.18

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, use `x.dynamicRow(...)` instead of `x.row(...)`. It keeps the same runtime parsing behavior while intentionally widening TypeScript inference for runtime-built shapes.
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
@@ -375,6 +400,8 @@ const importer = new CSVImporter({
375
400
 
376
401
  The `x` schema builder provides a type-safe, fluent API for defining your CSV structure.
377
402
 
403
+ 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.
404
+
378
405
  ### Field Types
379
406
 
380
407
  ```typescript
@@ -413,6 +440,63 @@ const schema = x.row({
413
440
  });
414
441
  ```
415
442
 
443
+ ### Runtime-Built Schemas
444
+
445
+ For a fixed schema, keep everything in a normal `x.row(...)` definition:
446
+
447
+ ```typescript
448
+ const schema = x.row({
449
+ email: x.string().email().label("Email"),
450
+ lifecycleStage: x
451
+ .select([
452
+ { label: "Lead", value: "lead" },
453
+ { label: "Customer", value: "customer" },
454
+ { label: "Churned", value: "churned" },
455
+ ])
456
+ .label("Lifecycle Stage"),
457
+ accountOwner: x.string().label("Account Owner").optional(),
458
+ contractValue: x.number().currency("USD").label("Contract Value").optional(),
459
+ });
460
+ ```
461
+
462
+ `x.dynamicRow(...)` lets you build the row at runtime, which is useful when the schema depends on account data, user preferences, or enabled custom fields.
463
+
464
+ ```typescript
465
+ import { x } from "@expresscsv/sdk";
466
+
467
+ function buildCustomerSchema(options: {
468
+ collectCrmId: boolean;
469
+ collectHealthScore: boolean;
470
+ collectSegment: boolean;
471
+ }) {
472
+ return x.dynamicRow({
473
+ email: x.string().email().label("Email"),
474
+ companyName: x.string().label("Company Name"),
475
+ ...(options.collectCrmId ? { crmId: x.string().label("CRM ID") } : {}),
476
+ ...(options.collectHealthScore
477
+ ? { healthScore: x.number().label("Health Score") }
478
+ : {}),
479
+ ...(options.collectSegment
480
+ ? {
481
+ segment: x
482
+ .select([
483
+ { label: "SMB", value: "smb" },
484
+ { label: "Mid-Market", value: "mid-market" },
485
+ { label: "Enterprise", value: "enterprise" },
486
+ ])
487
+ .label("Segment"),
488
+ }
489
+ : {}),
490
+ });
491
+ }
492
+
493
+ const schema = buildCustomerSchema({
494
+ collectCrmId: true,
495
+ collectHealthScore: true,
496
+ collectSegment: false,
497
+ });
498
+ ```
499
+
416
500
  ### Common Modifiers
417
501
 
418
502
  All field types support:
package/dist/index.d.cts CHANGED
@@ -3129,6 +3129,13 @@ declare class ExRow<T extends ExRowShape> extends ExType<{
3129
3129
  * @returns A new ExRow instance
3130
3130
  */
3131
3131
  static create<T extends ExRowShape>(shape: T): ExRow<T>;
3132
+ /**
3133
+ * Factory method for runtime-built row shapes.
3134
+ *
3135
+ * This intentionally widens the returned type to ExRow<ExRowShape> so callers
3136
+ * can assemble fields conditionally without relying on exact key inference.
3137
+ */
3138
+ static createDynamic(shape: ExRowShape): ExRow<ExRowShape>;
3132
3139
  /**
3133
3140
  * Specifies columns that can be null/optional with conditional logic
3134
3141
  *
@@ -3930,6 +3937,7 @@ export declare const x: {
3930
3937
  time: typeof ExTime.create;
3931
3938
  datetime: typeof ExDatetime.create;
3932
3939
  row: typeof ExRow.create;
3940
+ dynamicRow: typeof ExRow.createDynamic;
3933
3941
  select: typeof ExSelect.create;
3934
3942
  multiselect: typeof ExMultiselect.create;
3935
3943
  infer: <T extends ExType<unknown, ExBaseDef, unknown>>(_schema: T) => Infer<T>;
package/dist/index.d.mts CHANGED
@@ -3129,6 +3129,13 @@ declare class ExRow<T extends ExRowShape> extends ExType<{
3129
3129
  * @returns A new ExRow instance
3130
3130
  */
3131
3131
  static create<T extends ExRowShape>(shape: T): ExRow<T>;
3132
+ /**
3133
+ * Factory method for runtime-built row shapes.
3134
+ *
3135
+ * This intentionally widens the returned type to ExRow<ExRowShape> so callers
3136
+ * can assemble fields conditionally without relying on exact key inference.
3137
+ */
3138
+ static createDynamic(shape: ExRowShape): ExRow<ExRowShape>;
3132
3139
  /**
3133
3140
  * Specifies columns that can be null/optional with conditional logic
3134
3141
  *
@@ -3930,6 +3937,7 @@ export declare const x: {
3930
3937
  time: typeof ExTime.create;
3931
3938
  datetime: typeof ExDatetime.create;
3932
3939
  row: typeof ExRow.create;
3940
+ dynamicRow: typeof ExRow.createDynamic;
3933
3941
  select: typeof ExSelect.create;
3934
3942
  multiselect: typeof ExMultiselect.create;
3935
3943
  infer: <T extends ExType<unknown, ExBaseDef, unknown>>(_schema: T) => Infer<T>;
package/dist/index.d.ts CHANGED
@@ -3129,6 +3129,13 @@ declare class ExRow<T extends ExRowShape> extends ExType<{
3129
3129
  * @returns A new ExRow instance
3130
3130
  */
3131
3131
  static create<T extends ExRowShape>(shape: T): ExRow<T>;
3132
+ /**
3133
+ * Factory method for runtime-built row shapes.
3134
+ *
3135
+ * This intentionally widens the returned type to ExRow<ExRowShape> so callers
3136
+ * can assemble fields conditionally without relying on exact key inference.
3137
+ */
3138
+ static createDynamic(shape: ExRowShape): ExRow<ExRowShape>;
3132
3139
  /**
3133
3140
  * Specifies columns that can be null/optional with conditional logic
3134
3141
  *
@@ -3930,6 +3937,7 @@ export declare const x: {
3930
3937
  time: typeof ExTime.create;
3931
3938
  datetime: typeof ExDatetime.create;
3932
3939
  row: typeof ExRow.create;
3940
+ dynamicRow: typeof ExRow.createDynamic;
3933
3941
  select: typeof ExSelect.create;
3934
3942
  multiselect: typeof ExMultiselect.create;
3935
3943
  infer: <T extends ExType<unknown, ExBaseDef, unknown>>(_schema: T) => Infer<T>;