@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 +110 -0
- package/dist/index.d.cts +19 -0
- package/dist/index.d.mts +19 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
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
|
/**
|