@expresscsv/sdk 0.1.14 → 0.1.16

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
@@ -83,6 +83,116 @@ importer.open({
83
83
  });
84
84
  ```
85
85
 
86
+ ### Webhook Payload Structure
87
+
88
+ Each chunk is delivered as a JSON `POST` (or whichever method you configured) to your endpoint. The request body has this shape:
89
+
90
+ ```typescript
91
+ interface WebhookPayload {
92
+ /** Imported records for this chunk, matching your schema */
93
+ records: Record<string, unknown>[];
94
+ /** 0-based index of the current chunk */
95
+ chunkIndex: number;
96
+ /** Total number of chunks in this delivery */
97
+ totalChunks: number;
98
+ /** Total number of records across all chunks */
99
+ totalRecords: number;
100
+ /** Present only if you passed `metadata` in `WebhookConfig` */
101
+ metadata?: Record<string, unknown>;
102
+ /** Delivery context added by ExpressCSV */
103
+ delivery: {
104
+ publishableKey: string;
105
+ environmentName: string;
106
+ environmentType: string;
107
+ teamSlug: string;
108
+ importIdentifier: string;
109
+ deliveryId: string;
110
+ timestamp: string; // ISO 8601
111
+ };
112
+ }
113
+ ```
114
+
115
+ Example payload:
116
+
117
+ ```json
118
+ {
119
+ "records": [
120
+ { "name": "Alice Johnson", "email": "alice@example.com", "age": 32 },
121
+ { "name": "Bob Smith", "email": "bob@example.com", "age": 45 }
122
+ ],
123
+ "chunkIndex": 0,
124
+ "totalChunks": 3,
125
+ "totalRecords": 2500,
126
+ "metadata": {
127
+ "source": "web-app",
128
+ "userId": "user-123"
129
+ },
130
+ "delivery": {
131
+ "publishableKey": "pk_live_abc123",
132
+ "environmentName": "Production",
133
+ "environmentType": "production",
134
+ "teamSlug": "my-team",
135
+ "importIdentifier": "user-import",
136
+ "deliveryId": "del_abc123",
137
+ "timestamp": "2026-03-02T14:30:00.000Z"
138
+ }
139
+ }
140
+ ```
141
+
142
+ The request includes a `Content-Type: application/json` header plus any custom `headers` you specified in `WebhookConfig`.
143
+
144
+ ### Handling Webhooks on Your Server
145
+
146
+ Your endpoint should return a **2xx** status code to acknowledge each chunk. Non-2xx responses trigger the following retry behaviour:
147
+
148
+ - **5xx** and **429** responses are retried automatically (up to 5 attempts per chunk).
149
+ - **4xx** responses (except 429) are treated as permanent failures and are **not** retried.
150
+
151
+ Chunks are delivered **serially** — the next chunk is only sent after the previous one succeeds.
152
+
153
+ Below is a minimal Express.js example:
154
+
155
+ ```typescript
156
+ import express from "express";
157
+
158
+ const app = express();
159
+ app.use(express.json());
160
+
161
+ app.post("/webhooks/csv-import", async (req, res) => {
162
+ const token = req.headers.authorization;
163
+ if (token !== "Bearer your-api-token") {
164
+ return res.status(401).json({ error: "Unauthorized" });
165
+ }
166
+
167
+ const { records, chunkIndex, totalChunks, totalRecords, metadata, delivery } =
168
+ req.body;
169
+
170
+ try {
171
+ // Process the records — e.g. insert into your database
172
+ await db.insertMany("users", records);
173
+
174
+ console.log(
175
+ `Chunk ${chunkIndex + 1}/${totalChunks} processed ` +
176
+ `(${records.length} records, delivery ${delivery.deliveryId})`
177
+ );
178
+
179
+ res.status(200).json({ success: true });
180
+ } catch (error) {
181
+ // Return 500 so ExpressCSV retries this chunk
182
+ console.error("Failed to process chunk:", error);
183
+ res.status(500).json({ error: "Internal server error" });
184
+ }
185
+ });
186
+
187
+ app.listen(3000);
188
+ ```
189
+
190
+ **Tips:**
191
+
192
+ - Use `delivery.deliveryId` and `chunkIndex` to **deduplicate** retried chunks (the same chunk may be delivered more than once on retry).
193
+ - Use `chunkIndex` and `totalChunks` to track progress and know when the full import is complete (`chunkIndex === totalChunks - 1` for the last chunk).
194
+ - Store `metadata` alongside imported records if you need to correlate the import with a specific user or action in your app.
195
+
86
196
  ### Combined Local Callback and Webhook
87
197
 
88
198
  You can use both `onData` and `webhook` simultaneously:
package/dist/index.d.cts CHANGED
@@ -1281,6 +1281,11 @@ export declare class CSVImporter<TSchema extends ExType<unknown, ExBaseDef, unkn
1281
1281
  * Chunks data using SDK-determined chunk size (independent of customer's chunkSize)
1282
1282
  */
1283
1283
  private deliverToWebhook;
1284
+ /**
1285
+ * Poll the delivery status endpoint until the delivery reaches a terminal state
1286
+ * ('success' or 'failed'), or until the timeout is exceeded.
1287
+ */
1288
+ private pollDeliveryStatus;
1284
1289
  /**
1285
1290
  * Send a single chunk to backend webhook API with retry logic
1286
1291
  */
@@ -2852,6 +2857,13 @@ declare interface ExpressCSVLocale {
2852
2857
  matched: string;
2853
2858
  unmatched: string;
2854
2859
  custom: string;
2860
+ nextDisabledUpload: string;
2861
+ nextDisabledSelectSheet: string;
2862
+ nextDisabledSelectHeader: string;
2863
+ nextDisabledMatchColumns: string;
2864
+ nextDisabledMatchOptions: string;
2865
+ nextDisabledReviewValidating: string;
2866
+ nextDisabledReviewInvalid: string;
2855
2867
  };
2856
2868
  widget: {
2857
2869
  title: string;
@@ -3878,6 +3890,13 @@ export declare interface WebhookConfig {
3878
3890
  retries?: number;
3879
3891
  /** Arbitrary developer-provided metadata */
3880
3892
  metadata?: Record<string, unknown>;
3893
+ /**
3894
+ * Whether to wait for the delivery service to confirm the webhook was
3895
+ * successfully received before considering the import complete.
3896
+ * When false, the import completes as soon as all chunks are queued.
3897
+ * Default: true
3898
+ */
3899
+ awaitWebhookArrival?: boolean;
3881
3900
  }
3882
3901
 
3883
3902
  /**
package/dist/index.d.mts CHANGED
@@ -1281,6 +1281,11 @@ export declare class CSVImporter<TSchema extends ExType<unknown, ExBaseDef, unkn
1281
1281
  * Chunks data using SDK-determined chunk size (independent of customer's chunkSize)
1282
1282
  */
1283
1283
  private deliverToWebhook;
1284
+ /**
1285
+ * Poll the delivery status endpoint until the delivery reaches a terminal state
1286
+ * ('success' or 'failed'), or until the timeout is exceeded.
1287
+ */
1288
+ private pollDeliveryStatus;
1284
1289
  /**
1285
1290
  * Send a single chunk to backend webhook API with retry logic
1286
1291
  */
@@ -2852,6 +2857,13 @@ declare interface ExpressCSVLocale {
2852
2857
  matched: string;
2853
2858
  unmatched: string;
2854
2859
  custom: string;
2860
+ nextDisabledUpload: string;
2861
+ nextDisabledSelectSheet: string;
2862
+ nextDisabledSelectHeader: string;
2863
+ nextDisabledMatchColumns: string;
2864
+ nextDisabledMatchOptions: string;
2865
+ nextDisabledReviewValidating: string;
2866
+ nextDisabledReviewInvalid: string;
2855
2867
  };
2856
2868
  widget: {
2857
2869
  title: string;
@@ -3878,6 +3890,13 @@ export declare interface WebhookConfig {
3878
3890
  retries?: number;
3879
3891
  /** Arbitrary developer-provided metadata */
3880
3892
  metadata?: Record<string, unknown>;
3893
+ /**
3894
+ * Whether to wait for the delivery service to confirm the webhook was
3895
+ * successfully received before considering the import complete.
3896
+ * When false, the import completes as soon as all chunks are queued.
3897
+ * Default: true
3898
+ */
3899
+ awaitWebhookArrival?: boolean;
3881
3900
  }
3882
3901
 
3883
3902
  /**
package/dist/index.d.ts CHANGED
@@ -1281,6 +1281,11 @@ export declare class CSVImporter<TSchema extends ExType<unknown, ExBaseDef, unkn
1281
1281
  * Chunks data using SDK-determined chunk size (independent of customer's chunkSize)
1282
1282
  */
1283
1283
  private deliverToWebhook;
1284
+ /**
1285
+ * Poll the delivery status endpoint until the delivery reaches a terminal state
1286
+ * ('success' or 'failed'), or until the timeout is exceeded.
1287
+ */
1288
+ private pollDeliveryStatus;
1284
1289
  /**
1285
1290
  * Send a single chunk to backend webhook API with retry logic
1286
1291
  */
@@ -2852,6 +2857,13 @@ declare interface ExpressCSVLocale {
2852
2857
  matched: string;
2853
2858
  unmatched: string;
2854
2859
  custom: string;
2860
+ nextDisabledUpload: string;
2861
+ nextDisabledSelectSheet: string;
2862
+ nextDisabledSelectHeader: string;
2863
+ nextDisabledMatchColumns: string;
2864
+ nextDisabledMatchOptions: string;
2865
+ nextDisabledReviewValidating: string;
2866
+ nextDisabledReviewInvalid: string;
2855
2867
  };
2856
2868
  widget: {
2857
2869
  title: string;
@@ -3878,6 +3890,13 @@ export declare interface WebhookConfig {
3878
3890
  retries?: number;
3879
3891
  /** Arbitrary developer-provided metadata */
3880
3892
  metadata?: Record<string, unknown>;
3893
+ /**
3894
+ * Whether to wait for the delivery service to confirm the webhook was
3895
+ * successfully received before considering the import complete.
3896
+ * When false, the import completes as soon as all chunks are queued.
3897
+ * Default: true
3898
+ */
3899
+ awaitWebhookArrival?: boolean;
3881
3900
  }
3882
3901
 
3883
3902
  /**