bul-email 0.1.1 → 0.1.2
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 +6 -0
- package/dist/index.d.ts +6 -4
- package/dist/index.js +4 -2
- package/dist/types.d.ts +5 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -41,6 +41,8 @@ const { id } = await bul.emails.send(
|
|
|
41
41
|
(`maxRetries`, ברירת מחדל 3). לכל שליחה `Idempotency-Key` אחד, שחוזר בכל ניסיון — ניסיון חוזר אף פעם לא שולח פעמיים.
|
|
42
42
|
- **שגיאות ברורות:** כל שגיאה מה-API היא `BulError` (או תת-מחלקה) עם `code` ו-`status`. 409 `route_paused` → `RoutePausedError`
|
|
43
43
|
(`reasonCode`, `returns[]`) — שום דבר לא התקבל; שולחים בדרך אחרת ומדווחים עם `recipients.proof`.
|
|
44
|
+
- **חסימות:** `suppressions.add` / `import` יוצרות רק חסימה ידנית (`reason: "manual"`, או בלי). החזרות, תלונות והסרות — בול מוסיפה
|
|
45
|
+
לבד, ואי אפשר למחוק אותן (`remove` מחזיר 409 `suppression_not_removable`).
|
|
44
46
|
- **Webhooks:** `verifyWebhookSignature` / `constructWebhookEvent` — HMAC-SHA256, סבילות של 5 דקות, השוואה בזמן קבוע.
|
|
45
47
|
`BulEvent` מוקלד לפי `event`.
|
|
46
48
|
|
|
@@ -89,6 +91,8 @@ const { id } = await bul.emails.send(
|
|
|
89
91
|
backoff (`maxRetries`, default 3). Each send gets one `Idempotency-Key`, reused on every retry — a retry never sends twice.
|
|
90
92
|
- **Clear errors**: every API error is a `BulError` (or a subclass) with `code` and `status`. 409 `route_paused` → `RoutePausedError` (`reasonCode`,
|
|
91
93
|
`returns[]`) — nothing was accepted; send another way and report it with `recipients.proof`.
|
|
94
|
+
- **Suppressions**: `suppressions.add` / `import` create manual suppressions only (`reason: "manual"`, or omit it). Bounces, complaints and
|
|
95
|
+
unsubscribes are added by Bul itself and cannot be removed (`remove` → 409 `suppression_not_removable`).
|
|
92
96
|
- **Webhooks**: `verifyWebhookSignature` / `constructWebhookEvent` — HMAC-SHA256, 5-minute tolerance, constant-time comparison.
|
|
93
97
|
`BulEvent` is typed by `event`.
|
|
94
98
|
|
|
@@ -98,6 +102,8 @@ Almost the same code: change the import and the key. Full guide: [Migrating from
|
|
|
98
102
|
|
|
99
103
|
### Changelog
|
|
100
104
|
|
|
105
|
+
- **0.1.2** — `suppressions.add` / `suppressions.import`: `reason` accepts only `"manual"` (new type `CreatableSuppressionReason`), matching the
|
|
106
|
+
API — creating any other reason now fails with 422 `reason_not_allowed`. `SuppressionReason` (all four) is unchanged for reading.
|
|
101
107
|
- **0.1.1** — documentation (this changelog) and the version string. No behavior changes. The first release published straight from the build pipeline, with a verified publisher.
|
|
102
108
|
- **0.1.0** — first release.
|
|
103
109
|
|
package/dist/index.d.ts
CHANGED
|
@@ -36,7 +36,7 @@ interface RequestSpec {
|
|
|
36
36
|
/** POST that is safe to repeat even without an Idempotency-Key (the API deduplicates). */
|
|
37
37
|
idempotent?: boolean;
|
|
38
38
|
}
|
|
39
|
-
export declare const SDK_VERSION = "0.1.
|
|
39
|
+
export declare const SDK_VERSION = "0.1.2";
|
|
40
40
|
export declare class Bul {
|
|
41
41
|
private readonly apiKey;
|
|
42
42
|
private readonly baseUrl;
|
|
@@ -124,22 +124,24 @@ export declare class Bul {
|
|
|
124
124
|
limit: number;
|
|
125
125
|
offset: number;
|
|
126
126
|
}>;
|
|
127
|
+
/** POST /v1/suppressions — always a manual suppression (`reason` may be omitted or "manual"). */
|
|
127
128
|
add: (input: {
|
|
128
129
|
recipient: string;
|
|
129
|
-
reason?: T.
|
|
130
|
+
reason?: T.CreatableSuppressionReason;
|
|
130
131
|
}) => Promise<T.Suppression | {
|
|
131
132
|
recipient: string;
|
|
132
133
|
already_suppressed: true;
|
|
133
134
|
}>;
|
|
135
|
+
/** POST /v1/suppressions/import — always manual, like `add`. */
|
|
134
136
|
import: (input: {
|
|
135
137
|
recipients: string[];
|
|
136
|
-
reason?: T.
|
|
138
|
+
reason?: T.CreatableSuppressionReason;
|
|
137
139
|
}) => Promise<{
|
|
138
140
|
added: number;
|
|
139
141
|
already_suppressed: number;
|
|
140
142
|
invalid: string[];
|
|
141
143
|
}>;
|
|
142
|
-
/** DELETE /v1/suppressions/{id or email} (full key). */
|
|
144
|
+
/** DELETE /v1/suppressions/{id or email} (full key). Only manual suppressions can be removed — others → 409 `suppression_not_removable`. */
|
|
143
145
|
remove: (idOrEmail: string) => Promise<void>;
|
|
144
146
|
};
|
|
145
147
|
readonly recipients: {
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ export * from "./errors";
|
|
|
3
3
|
export * from "./types";
|
|
4
4
|
export { constructWebhookEvent, verifyWebhookSignature } from "./webhooks";
|
|
5
5
|
const RETRY_STATUS = new Set([500, 502, 503, 504]);
|
|
6
|
-
export const SDK_VERSION = "0.1.
|
|
6
|
+
export const SDK_VERSION = "0.1.2";
|
|
7
7
|
function newKey() {
|
|
8
8
|
return typeof crypto !== "undefined" && "randomUUID" in crypto
|
|
9
9
|
? crypto.randomUUID()
|
|
@@ -158,9 +158,11 @@ export class Bul {
|
|
|
158
158
|
};
|
|
159
159
|
suppressions = {
|
|
160
160
|
list: (params = {}) => this.request({ method: "GET", path: "/v1/suppressions", query: params }),
|
|
161
|
+
/** POST /v1/suppressions — always a manual suppression (`reason` may be omitted or "manual"). */
|
|
161
162
|
add: (input) => this.request({ method: "POST", path: "/v1/suppressions", body: input, idempotent: true }),
|
|
163
|
+
/** POST /v1/suppressions/import — always manual, like `add`. */
|
|
162
164
|
import: (input) => this.request({ method: "POST", path: "/v1/suppressions/import", body: input, idempotent: true }),
|
|
163
|
-
/** DELETE /v1/suppressions/{id or email} (full key). */
|
|
165
|
+
/** DELETE /v1/suppressions/{id or email} (full key). Only manual suppressions can be removed — others → 409 `suppression_not_removable`. */
|
|
164
166
|
remove: (idOrEmail) => this.request({ method: "DELETE", path: `/v1/suppressions/${encodeURIComponent(idOrEmail)}` }),
|
|
165
167
|
};
|
|
166
168
|
recipients = {
|
package/dist/types.d.ts
CHANGED
|
@@ -158,6 +158,11 @@ export interface WebhookTestResult {
|
|
|
158
158
|
error: string | null;
|
|
159
159
|
}
|
|
160
160
|
export type SuppressionReason = "hard_bounce" | "complaint" | "manual" | "unsubscribe";
|
|
161
|
+
/**
|
|
162
|
+
* The only reason a customer can create (0.1.2). Bounces, complaints and unsubscribes are added by Bul itself, from the provider or the
|
|
163
|
+
* recipient, and cannot be removed; the API rejects any other reason with 422 `reason_not_allowed`.
|
|
164
|
+
*/
|
|
165
|
+
export type CreatableSuppressionReason = "manual";
|
|
161
166
|
export interface Suppression {
|
|
162
167
|
id: string;
|
|
163
168
|
recipient: string;
|