samva 0.17.0 → 0.18.0
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/AGENTS.md +5 -0
- package/README.md +16 -3
- package/dist/{rolldown-runtime-D7D4PA-g.js → _virtual/_rolldown/runtime.js} +1 -1
- package/dist/client/client/client.gen.js +174 -0
- package/dist/client/client/utils.gen.js +177 -0
- package/dist/client/client.gen.js +8 -0
- package/dist/client/core/auth.gen.js +12 -0
- package/dist/client/core/bodySerializer.gen.js +6 -0
- package/dist/client/core/params.gen.js +77 -0
- package/dist/client/core/pathSerializer.gen.js +82 -0
- package/dist/client/core/serverSentEvents.gen.js +96 -0
- package/dist/client/core/utils.gen.js +78 -0
- package/dist/{promises---Kbh-7z.js → client/sdk.gen.js} +4 -2293
- package/dist/client-attribution.js +9 -0
- package/dist/effect/analytics.d.ts +6 -6
- package/dist/effect/analytics.js +23 -2
- package/dist/effect/api-keys.d.ts +12 -12
- package/dist/effect/api-keys.js +29 -2
- package/dist/effect/attachments.d.ts +4 -4
- package/dist/effect/attachments.js +19 -2
- package/dist/effect/brands.d.ts +6 -6
- package/dist/effect/brands.js +26 -3
- package/dist/effect/campaigns.d.ts +18 -18
- package/dist/effect/campaigns.js +35 -2
- package/dist/effect/categories.d.ts +2 -2
- package/dist/effect/categories.js +95 -1
- package/dist/effect/client.js +3 -3
- package/dist/effect/contact-groups.d.ts +14 -14
- package/dist/effect/contact-groups.js +31 -2
- package/dist/effect/contacts.d.ts +28 -28
- package/dist/effect/contacts.js +52 -2
- package/dist/effect/conversations.d.ts +17 -17
- package/dist/effect/conversations.js +37 -2
- package/dist/effect/custom-fields.d.ts +4 -4
- package/dist/effect/custom-fields.js +19 -2
- package/dist/effect/email.d.ts +75 -75
- package/dist/effect/email.js +140 -2
- package/dist/effect/errors.d.ts +2 -0
- package/dist/effect/errors.js +3 -0
- package/dist/effect/events.d.ts +2 -2
- package/dist/effect/events.js +17 -3
- package/dist/effect/extension-installations.d.ts +11 -11
- package/dist/effect/extension-installations.js +29 -2
- package/dist/effect/extensions.d.ts +9 -9
- package/dist/effect/extensions.js +21 -2
- package/dist/effect/feedback.d.ts +1 -1
- package/dist/effect/feedback.js +14 -3
- package/dist/{analytics-CaqPRsry.js → effect/generated/analytics.js} +4 -23
- package/dist/{api-keys-Ce1Y4_Ip.js → effect/generated/api-keys.js} +4 -29
- package/dist/{attachments-DYqVIraC.js → effect/generated/attachments.js} +3 -18
- package/dist/{brands-ZwuOGIWO.js → effect/generated/brands.js} +5 -25
- package/dist/{campaigns-DZlz1E9E.js → effect/generated/campaigns.js} +4 -35
- package/dist/effect/generated/contact-events.js +37 -0
- package/dist/{contact-groups-BLbFXnjq.js → effect/generated/contact-groups.js} +3 -30
- package/dist/{contacts-BbsoXXB4.js → effect/generated/contacts.js} +3 -81
- package/dist/{conversations-_sRHueML.js → effect/generated/conversations.js} +3 -36
- package/dist/{custom-fields-BHWbwlKn.js → effect/generated/custom-fields.js} +5 -19
- package/dist/{email-R0NAA9PW.js → effect/generated/email.js} +995 -1146
- package/dist/{events-CxbTUHYT.js → effect/generated/events.js} +3 -15
- package/dist/{extension-installations-CD94LPmk.js → effect/generated/extension-installations.js} +4 -29
- package/dist/{extensions-BKyNQLvu.js → effect/generated/extensions.js} +3 -20
- package/dist/{feedback-Bpa09JOS.js → effect/generated/feedback.js} +3 -12
- package/dist/{journeys-CARo_BJT.js → effect/generated/journeys.js} +3 -38
- package/dist/{mailboxes-BRDn7BIK.js → effect/generated/mailboxes.js} +793 -951
- package/dist/{media-VrrtNnft.js → effect/generated/media.js} +3 -3
- package/dist/effect/generated/messages.js +671 -0
- package/dist/{namespaces-CcvEbG-y.js → effect/generated/namespaces.js} +3 -20
- package/dist/{operations-CmB3FHwf.js → effect/generated/operations.js} +3 -16
- package/dist/{organizations-A-plufWc.js → effect/generated/organizations.js} +3 -24
- package/dist/{scheduled-messages-DkKZRRaN.js → effect/generated/scheduled-messages.js} +4 -21
- package/dist/effect/generated/shared.js +1053 -0
- package/dist/{subscriptions-DEXYtMXg.js → effect/generated/subscriptions.js} +3 -9
- package/dist/{templates-DZomxsG7.js → effect/generated/templates.js} +3 -78
- package/dist/{unsubscribe-groups-Iqk4Isf9.js → effect/generated/unsubscribe-groups.js} +5 -29
- package/dist/{webhooks-CPXuu8Xf.js → effect/generated/webhooks.js} +4 -34
- package/dist/{whoami-Ccz0jwlt.js → effect/generated/whoami.js} +5 -10
- package/dist/{categories-CA4XIQAb.js → effect/generated-metadata.js} +2 -94
- package/dist/effect/index.d.ts +1 -2
- package/dist/effect/index.js +32 -32
- package/dist/effect/internal/client.js +69 -0
- package/dist/effect/internal/email-sender.js +21 -0
- package/dist/effect/internal/mailbox-events.js +33 -0
- package/dist/effect/internal/operation.js +116 -0
- package/dist/effect/internal/send.js +56 -0
- package/dist/effect/journeys.d.ts +18 -18
- package/dist/effect/journeys.js +39 -2
- package/dist/effect/mailboxes.d.ts +191 -191
- package/dist/effect/mailboxes.js +135 -3
- package/dist/effect/media.d.ts +5 -5
- package/dist/effect/media.js +10 -10
- package/dist/effect/messages.d.ts +14 -14
- package/dist/effect/messages.js +15 -14
- package/dist/effect/namespaces.d.ts +7 -7
- package/dist/effect/namespaces.js +21 -2
- package/dist/effect/operations.d.ts +5 -5
- package/dist/effect/operations.js +17 -2
- package/dist/effect/organizations.d.ts +7 -7
- package/dist/effect/organizations.js +25 -2
- package/dist/effect/pagination.js +39 -0
- package/dist/effect/retry.js +3 -3
- package/dist/{runtime-P0l1_2-C.js → effect/runtime.js} +2 -2
- package/dist/effect/scheduled-messages.d.ts +7 -7
- package/dist/effect/scheduled-messages.js +21 -2
- package/dist/effect/subscriptions.d.ts +1 -1
- package/dist/effect/subscriptions.js +10 -2
- package/dist/effect/templates.d.ts +39 -39
- package/dist/effect/templates.js +80 -3
- package/dist/effect/unsubscribe-groups.d.ts +11 -11
- package/dist/effect/unsubscribe-groups.js +29 -2
- package/dist/effect/webhooks.d.ts +14 -14
- package/dist/effect/webhooks.js +35 -3
- package/dist/effect/whoami.d.ts +9 -9
- package/dist/effect/whoami.js +10 -2
- package/dist/index.js +4 -3
- package/dist/{inline-attachments-Bi1hDltp.js → inline-attachments.js} +13 -7
- package/dist/{mailbox-events-VKR4f3qq.js → mailbox-events.js} +2 -2
- package/dist/{normalize-B79uJIeb.js → normalize.js} +2 -2
- package/dist/package.js +6 -0
- package/dist/promises/errors.gen.js +1340 -0
- package/dist/promises/index.js +288 -3
- package/dist/{operation-n_IYgNVK.js → service-map.js} +2 -148
- package/package.json +6 -2
- package/dist/client-DOzUrdTE.js +0 -1115
- package/dist/send-Bxc0XfGE.js +0 -722
package/dist/promises/index.js
CHANGED
|
@@ -1,4 +1,289 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { CLIENT_ATTRIBUTION_HEADER, clientAttribution } from "../client-attribution.js";
|
|
2
|
+
import { mergeHeaders } from "../client/client/utils.gen.js";
|
|
3
|
+
import { createClient as createClient$1 } from "../client/client/client.gen.js";
|
|
4
|
+
import { Analytics, ApiKeys, Attachments, Brands, Campaigns, ContactEvents, ContactGroups, Contacts, Conversations, CustomFields, Email, Events, ExtensionInstallations, Extensions, Feedback, Journeys, Mailboxes, Media, Messages, Namespaces, Operations, Organizations, ScheduledMessages, Subscriptions, Templates, Unsubscribe, Webhooks, Whoami } from "../client/sdk.gen.js";
|
|
5
|
+
import { MediaUploadError, mediaCreateBody, planInlineUploads, withUploadedAttachments } from "../inline-attachments.js";
|
|
6
|
+
import { MailboxEventStream, MailboxEventStreamError } from "../mailbox-events.js";
|
|
7
|
+
import { buildEmailSendPayload, buildMessagesSendPayload, replyToEmailsPayload } from "../normalize.js";
|
|
8
|
+
import { AnalyticsQueryError, BillingProviderError, BrandAddressRequiredError, CampaignFooterRequiredError, ConflictError, DeliveryUnavailableError, EmailChannelError, ExternalServiceError, FlagDisabledError, ForbiddenError, GatewayTimeoutError, InternalError, MailboxChannelUnsupportedError, MailboxSendConflictError, MailboxSendRefusedError, OnboardingReviewRequiredError, PaymentRequiredError, RateLimitedError, ResourceNotFoundError, SamvaApiError, SamvaTransportError, SenderNotReadyError, UnauthorizedError, ValidationError, fromApiError } from "./errors.gen.js";
|
|
9
|
+
//#region src/promises/index.ts
|
|
10
|
+
/**
|
|
11
|
+
* Samva SDK - TypeScript client for the Samva API.
|
|
12
|
+
*
|
|
13
|
+
* Ergonomic methods resolve with decoded success values and throw generated
|
|
14
|
+
* plain-JavaScript error classes. The bound Hey API result surface remains
|
|
15
|
+
* available under `client.raw` for transport-level access.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* import { createClient, RateLimitedError } from "samva";
|
|
20
|
+
*
|
|
21
|
+
* const samva = createClient({ apiKey: "<samva-api-key>" });
|
|
22
|
+
*
|
|
23
|
+
* try {
|
|
24
|
+
* const { contact } = await samva.contacts.findOrCreate({
|
|
25
|
+
* create: { name: "Ada Lovelace" },
|
|
26
|
+
* lookup: { type: "email", value: "ada@example.com" },
|
|
27
|
+
* });
|
|
28
|
+
* await samva.email.send({
|
|
29
|
+
* to: contact,
|
|
30
|
+
* subject: "Hello",
|
|
31
|
+
* html: "<p>Hi there!</p>",
|
|
32
|
+
* });
|
|
33
|
+
* } catch (error) {
|
|
34
|
+
* if (error instanceof RateLimitedError) console.log(error.retryAfterSeconds);
|
|
35
|
+
* }
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
const isObject = (value) => typeof value === "object" && value !== null;
|
|
39
|
+
/**
|
|
40
|
+
* The key a retry-safe call sends as `idempotency-key`: the `idempotencyKey`
|
|
41
|
+
* option, else one the caller set in `headers`, else a fresh UUID. The
|
|
42
|
+
* generated header parameter is applied after request headers, so it must carry
|
|
43
|
+
* a caller-set header value rather than overwrite it.
|
|
44
|
+
*/
|
|
45
|
+
function resolveIdempotencyKey(options) {
|
|
46
|
+
const { idempotencyKey, ...requestOptions } = options ?? {};
|
|
47
|
+
return {
|
|
48
|
+
idempotencyKey: idempotencyKey ?? mergeHeaders(requestOptions.headers).get("idempotency-key") ?? crypto.randomUUID(),
|
|
49
|
+
requestOptions
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Inline attachment content over the API's request cap travels as media instead: the largest
|
|
54
|
+
* attachments are uploaded (create, put to the presigned URL, complete) and replaced by their
|
|
55
|
+
* `mediaId`. The returned payload is the one request every send attempt reuses, so nothing is
|
|
56
|
+
* uploaded twice.
|
|
57
|
+
*/
|
|
58
|
+
async function uploadOversizedAttachments(clientInstance, payload, requestOptions) {
|
|
59
|
+
const plan = planInlineUploads(payload);
|
|
60
|
+
if (plan.length === 0) return payload;
|
|
61
|
+
const uploaded = /* @__PURE__ */ new Map();
|
|
62
|
+
const directMedia = createDirectService(createBoundService(Media, clientInstance));
|
|
63
|
+
for (const upload of plan) {
|
|
64
|
+
const created = await directMedia.create(mediaCreateBody(upload), requestOptions);
|
|
65
|
+
await putUpload(clientInstance, upload, created, requestOptions.signal ?? void 0);
|
|
66
|
+
await directMedia.complete({ id: created.id }, requestOptions);
|
|
67
|
+
uploaded.set(upload.index, {
|
|
68
|
+
mediaId: created.id,
|
|
69
|
+
upload
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
return withUploadedAttachments(payload, uploaded);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Send with oversized inline attachments uploaded first. Within the cap this is the send call
|
|
76
|
+
* itself, one request and no extra await, so its result is returned unchanged.
|
|
77
|
+
*/
|
|
78
|
+
function sendWithUploads(clientInstance, payload, requestOptions, send) {
|
|
79
|
+
if (planInlineUploads(payload).length === 0) return send(payload);
|
|
80
|
+
return uploadOversizedAttachments(clientInstance, payload, requestOptions).then(send);
|
|
81
|
+
}
|
|
82
|
+
async function putUpload(clientInstance, upload, created, signal) {
|
|
83
|
+
const fail = (status, cause) => new MediaUploadError({
|
|
84
|
+
filename: upload.filename,
|
|
85
|
+
mediaId: created.id,
|
|
86
|
+
status,
|
|
87
|
+
cause
|
|
88
|
+
});
|
|
89
|
+
let response;
|
|
90
|
+
try {
|
|
91
|
+
response = await (clientInstance.getConfig().fetch ?? globalThis.fetch)(new Request(created.upload.url, {
|
|
92
|
+
method: created.upload.method,
|
|
93
|
+
headers: created.upload.headers,
|
|
94
|
+
body: upload.bytes,
|
|
95
|
+
signal: signal ?? null
|
|
96
|
+
}));
|
|
97
|
+
} catch (error) {
|
|
98
|
+
throw fail(void 0, error);
|
|
99
|
+
}
|
|
100
|
+
if (!response.ok) throw fail(response.status);
|
|
101
|
+
}
|
|
102
|
+
function createPromiseMessagesTransport(clientInstance) {
|
|
103
|
+
const boundMessages = createBoundService(Messages, clientInstance);
|
|
104
|
+
return {
|
|
105
|
+
list: boundMessages.list,
|
|
106
|
+
remove: boundMessages.remove,
|
|
107
|
+
get: boundMessages.get,
|
|
108
|
+
getEmail: boundMessages.getEmail,
|
|
109
|
+
getStatus: boundMessages.getStatus,
|
|
110
|
+
getEvents: boundMessages.getEvents,
|
|
111
|
+
listDeliveries: boundMessages.listDeliveries,
|
|
112
|
+
getContent: boundMessages.getContent,
|
|
113
|
+
validateEmail: boundMessages.validateEmail,
|
|
114
|
+
send: (input, options) => {
|
|
115
|
+
const { idempotencyKey, requestOptions } = resolveIdempotencyKey(options);
|
|
116
|
+
return sendWithUploads(clientInstance, buildMessagesSendPayload(input), requestOptions, (payload) => Messages.send({
|
|
117
|
+
"idempotency-key": idempotencyKey,
|
|
118
|
+
...payload
|
|
119
|
+
}, {
|
|
120
|
+
...requestOptions,
|
|
121
|
+
client: clientInstance
|
|
122
|
+
}));
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
function createPromiseEmailTransport(clientInstance) {
|
|
127
|
+
const boundEmail = createBoundService(Email, clientInstance);
|
|
128
|
+
return Object.assign(boundEmail, {
|
|
129
|
+
addSender: (input, options) => {
|
|
130
|
+
const { replyToEmails, ...sender } = input;
|
|
131
|
+
const { idempotencyKey, requestOptions } = resolveIdempotencyKey(options);
|
|
132
|
+
return Email.addSender({
|
|
133
|
+
"idempotency-key": idempotencyKey,
|
|
134
|
+
...sender,
|
|
135
|
+
...replyToEmailsPayload(replyToEmails)
|
|
136
|
+
}, {
|
|
137
|
+
...requestOptions,
|
|
138
|
+
client: clientInstance
|
|
139
|
+
});
|
|
140
|
+
},
|
|
141
|
+
send: (input, options) => {
|
|
142
|
+
const { idempotencyKey, requestOptions } = resolveIdempotencyKey(options);
|
|
143
|
+
return sendWithUploads(clientInstance, buildEmailSendPayload(input), requestOptions, (payload) => Messages.send({
|
|
144
|
+
"idempotency-key": idempotencyKey,
|
|
145
|
+
...payload
|
|
146
|
+
}, {
|
|
147
|
+
...requestOptions,
|
|
148
|
+
client: clientInstance
|
|
149
|
+
}));
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
function createPromiseTemplatesTransport(clientInstance) {
|
|
154
|
+
return createBoundService(Templates, clientInstance);
|
|
155
|
+
}
|
|
156
|
+
function createBoundService(service, clientInstance) {
|
|
157
|
+
const bound = {};
|
|
158
|
+
for (const key of Object.getOwnPropertyNames(service)) {
|
|
159
|
+
if (key === "length" || key === "name" || key === "prototype") continue;
|
|
160
|
+
const value = service[key];
|
|
161
|
+
if (typeof value === "function") bound[key] = value.length >= 2 ? (parameters, options) => value(parameters ?? {}, {
|
|
162
|
+
...options,
|
|
163
|
+
client: clientInstance
|
|
164
|
+
}) : (options) => value({
|
|
165
|
+
...options,
|
|
166
|
+
client: clientInstance
|
|
167
|
+
});
|
|
168
|
+
else if (isObject(value)) bound[key] = createBoundService(value, clientInstance);
|
|
169
|
+
else bound[key] = value;
|
|
170
|
+
}
|
|
171
|
+
return bound;
|
|
172
|
+
}
|
|
173
|
+
const directOptions = (options) => ({
|
|
174
|
+
...isObject(options) ? options : {},
|
|
175
|
+
responseStyle: "fields",
|
|
176
|
+
throwOnError: false
|
|
177
|
+
});
|
|
178
|
+
async function unwrap(method, arguments_) {
|
|
179
|
+
let result;
|
|
180
|
+
try {
|
|
181
|
+
result = await method(...arguments_);
|
|
182
|
+
} catch (error) {
|
|
183
|
+
if (error instanceof MediaUploadError) throw error;
|
|
184
|
+
throw fromApiError(error);
|
|
185
|
+
}
|
|
186
|
+
if (!isObject(result)) throw new SamvaTransportError(result);
|
|
187
|
+
const raw = result;
|
|
188
|
+
const context = {
|
|
189
|
+
request: raw.request,
|
|
190
|
+
response: raw.response
|
|
191
|
+
};
|
|
192
|
+
if (raw.error !== void 0) throw fromApiError(raw.error, context);
|
|
193
|
+
if ("data" in raw) return raw.data;
|
|
194
|
+
throw new SamvaTransportError(result, context);
|
|
195
|
+
}
|
|
196
|
+
function createDirectService(service) {
|
|
197
|
+
const direct = {};
|
|
198
|
+
for (const [key, value] of Object.entries(service)) if (typeof value === "function") direct[key] = value.length >= 2 ? (parameters = {}, options = {}) => unwrap(value, [parameters, directOptions(options)]) : (options = {}) => unwrap(value, [directOptions(options)]);
|
|
199
|
+
else if (isObject(value)) direct[key] = createDirectService(value);
|
|
200
|
+
else direct[key] = value;
|
|
201
|
+
return direct;
|
|
202
|
+
}
|
|
203
|
+
/** Create a configured Promise client. */
|
|
204
|
+
function createClient(config) {
|
|
205
|
+
const authHeaders = config.authToken !== void 0 ? { Authorization: `Bearer ${config.authToken}` } : { "X-API-Key": config.apiKey };
|
|
206
|
+
const clientInstance = createClient$1({
|
|
207
|
+
...config,
|
|
208
|
+
baseUrl: config.baseUrl ?? "https://api.samva.dev",
|
|
209
|
+
headers: mergeHeaders({ [CLIENT_ATTRIBUTION_HEADER]: clientAttribution("typescript-promise") }, config.headers, authHeaders),
|
|
210
|
+
responseStyle: "fields",
|
|
211
|
+
throwOnError: false
|
|
212
|
+
});
|
|
213
|
+
clientInstance.interceptors.request.use((request) => {
|
|
214
|
+
const headers = new Headers(request.headers);
|
|
215
|
+
for (const [name, value] of Object.entries(authHeaders)) headers.set(name, value);
|
|
216
|
+
return new Request(request, { headers });
|
|
217
|
+
});
|
|
218
|
+
const raw = {
|
|
219
|
+
client: clientInstance,
|
|
220
|
+
messages: createBoundService(Messages, clientInstance),
|
|
221
|
+
scheduledMessages: createBoundService(ScheduledMessages, clientInstance),
|
|
222
|
+
brands: createBoundService(Brands, clientInstance),
|
|
223
|
+
campaigns: createBoundService(Campaigns, clientInstance),
|
|
224
|
+
email: createBoundService(Email, clientInstance),
|
|
225
|
+
media: createBoundService(Media, clientInstance),
|
|
226
|
+
templates: createPromiseTemplatesTransport(clientInstance),
|
|
227
|
+
contacts: Object.assign(createBoundService(Contacts, clientInstance), createBoundService(ContactEvents, clientInstance)),
|
|
228
|
+
events: createBoundService(Events, clientInstance),
|
|
229
|
+
conversations: createBoundService(Conversations, clientInstance),
|
|
230
|
+
webhooks: createBoundService(Webhooks, clientInstance),
|
|
231
|
+
operations: createBoundService(Operations, clientInstance),
|
|
232
|
+
apiKeys: createBoundService(ApiKeys, clientInstance),
|
|
233
|
+
organizations: createBoundService(Organizations, clientInstance),
|
|
234
|
+
attachments: createBoundService(Attachments, clientInstance),
|
|
235
|
+
contactGroups: createBoundService(ContactGroups, clientInstance),
|
|
236
|
+
customFields: createBoundService(CustomFields, clientInstance),
|
|
237
|
+
subscriptions: createBoundService(Subscriptions, clientInstance),
|
|
238
|
+
unsubscribeGroups: createBoundService(Unsubscribe, clientInstance),
|
|
239
|
+
analytics: createBoundService(Analytics, clientInstance),
|
|
240
|
+
feedback: createBoundService(Feedback, clientInstance),
|
|
241
|
+
whoami: createBoundService(Whoami, clientInstance),
|
|
242
|
+
journeys: createBoundService(Journeys, clientInstance),
|
|
243
|
+
mailboxes: createBoundService(Mailboxes, clientInstance),
|
|
244
|
+
namespaces: createBoundService(Namespaces, clientInstance),
|
|
245
|
+
extensions: createBoundService(Extensions, clientInstance),
|
|
246
|
+
extensionInstallations: createBoundService(ExtensionInstallations, clientInstance)
|
|
247
|
+
};
|
|
248
|
+
const streamConnection = {
|
|
249
|
+
baseUrl: config.baseUrl ?? "https://api.samva.dev",
|
|
250
|
+
headers: async () => Object.fromEntries(mergeHeaders({ [CLIENT_ATTRIBUTION_HEADER]: clientAttribution("typescript-promise") }, config.headers, authHeaders).entries()),
|
|
251
|
+
fetch: config.fetch
|
|
252
|
+
};
|
|
253
|
+
const promiseMessages = createPromiseMessagesTransport(clientInstance);
|
|
254
|
+
const promiseEmail = createPromiseEmailTransport(clientInstance);
|
|
255
|
+
return {
|
|
256
|
+
raw,
|
|
257
|
+
messages: createDirectService(promiseMessages),
|
|
258
|
+
scheduledMessages: createDirectService(raw.scheduledMessages),
|
|
259
|
+
brands: createDirectService(raw.brands),
|
|
260
|
+
campaigns: createDirectService(raw.campaigns),
|
|
261
|
+
email: createDirectService(promiseEmail),
|
|
262
|
+
media: createDirectService(raw.media),
|
|
263
|
+
templates: createDirectService(raw.templates),
|
|
264
|
+
contacts: createDirectService(raw.contacts),
|
|
265
|
+
events: createDirectService(raw.events),
|
|
266
|
+
conversations: createDirectService(raw.conversations),
|
|
267
|
+
webhooks: createDirectService(raw.webhooks),
|
|
268
|
+
operations: createDirectService(raw.operations),
|
|
269
|
+
apiKeys: createDirectService(raw.apiKeys),
|
|
270
|
+
organizations: createDirectService(raw.organizations),
|
|
271
|
+
attachments: createDirectService(raw.attachments),
|
|
272
|
+
contactGroups: createDirectService(raw.contactGroups),
|
|
273
|
+
customFields: createDirectService(raw.customFields),
|
|
274
|
+
subscriptions: createDirectService(raw.subscriptions),
|
|
275
|
+
unsubscribeGroups: createDirectService(raw.unsubscribeGroups),
|
|
276
|
+
analytics: createDirectService(raw.analytics),
|
|
277
|
+
feedback: createDirectService(raw.feedback),
|
|
278
|
+
whoami: createDirectService(raw.whoami),
|
|
279
|
+
journeys: createDirectService(raw.journeys),
|
|
280
|
+
mailboxes: Object.assign(createDirectService(raw.mailboxes), { events: (options) => new MailboxEventStream(streamConnection, options) }),
|
|
281
|
+
namespaces: createDirectService(raw.namespaces),
|
|
282
|
+
extensions: createDirectService(raw.extensions),
|
|
283
|
+
extensionInstallations: createDirectService(raw.extensionInstallations)
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
//#endregion
|
|
4
287
|
export { AnalyticsQueryError, BillingProviderError, BrandAddressRequiredError, CampaignFooterRequiredError, ConflictError, DeliveryUnavailableError, EmailChannelError, ExternalServiceError, FlagDisabledError, ForbiddenError, GatewayTimeoutError, InternalError, MailboxChannelUnsupportedError, MailboxEventStream, MailboxEventStreamError, MailboxSendConflictError, MailboxSendRefusedError, MediaUploadError, OnboardingReviewRequiredError, PaymentRequiredError, RateLimitedError, ResourceNotFoundError, SamvaApiError, SamvaTransportError, SenderNotReadyError, UnauthorizedError, ValidationError, createClient, fromApiError };
|
|
288
|
+
|
|
289
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
import { t as Service } from "./client-DOzUrdTE.js";
|
|
2
|
-
import { y as SamvaOperations } from "./categories-CA4XIQAb.js";
|
|
3
|
-
import { withRetry } from "./effect/retry.js";
|
|
4
|
-
import { Effect, Option, Predicate, Stream } from "effect";
|
|
5
1
|
//#region src/service-map.ts
|
|
6
2
|
/** How each generated Effect operation is adapted to the Promise facade's direct input shape. */
|
|
7
3
|
const SDK_OPERATION_CALLS = {
|
|
@@ -1050,148 +1046,6 @@ const SDK_OPERATION_CALLS = {
|
|
|
1050
1046
|
}
|
|
1051
1047
|
};
|
|
1052
1048
|
//#endregion
|
|
1053
|
-
|
|
1054
|
-
/**
|
|
1055
|
-
* Stream pagination for the Effect SDK.
|
|
1056
|
-
*
|
|
1057
|
-
* Every list operation whose success value is a page envelope gains `.pages()`
|
|
1058
|
-
* and `.items()` companions on its domain operation. `.pages()` streams the raw
|
|
1059
|
-
* envelopes; `.items()` flattens them into a stream of items. Every list pages
|
|
1060
|
-
* by cursor, `{ items, nextCursor }`: each step passes the previous page's
|
|
1061
|
-
* `nextCursor` as `cursor`, and the walk stops at a null `nextCursor`.
|
|
1062
|
-
*
|
|
1063
|
-
* The traversal is **lazy**: built on `Stream.paginate` (a pull-based source),
|
|
1064
|
-
* so each page is fetched only as the stream is consumed — `Stream.take(n)`
|
|
1065
|
-
* stops requesting further pages. Caller params (the start `cursor`,
|
|
1066
|
-
* `limit`, filters) are respected; only the position is advanced per step.
|
|
1067
|
-
*
|
|
1068
|
-
* Retry is **not** re-applied here: the underlying domain operation is already
|
|
1069
|
-
* wrapped in the ambient {@link import("./retry").Service} policy (reads are
|
|
1070
|
-
* retry-safe), so each page fetch retries on its own and pagination composes
|
|
1071
|
-
* with retry instead of nesting retries.
|
|
1072
|
-
*/
|
|
1073
|
-
/** Honor a caller-supplied start `cursor`; default to the first page otherwise. */
|
|
1074
|
-
const startCursorOf = (input) => {
|
|
1075
|
-
const cursor = input?.cursor;
|
|
1076
|
-
return typeof cursor === "string" ? cursor : void 0;
|
|
1077
|
-
};
|
|
1078
|
-
/** Fetch the page at `cursor`, preserving all other caller params. */
|
|
1079
|
-
const fetchCursorPage = (operation, input, cursor) => operation({
|
|
1080
|
-
...input,
|
|
1081
|
-
cursor
|
|
1082
|
-
});
|
|
1083
|
-
/** Stream the raw cursor page envelopes, one per request, from the caller's start cursor. */
|
|
1084
|
-
const streamCursorPages = (operation, input) => Stream.paginate(startCursorOf(input), (cursor) => fetchCursorPage(operation, input, cursor).pipe(Effect.map((result) => [[result], Option.fromNullishOr(result.nextCursor)])));
|
|
1085
|
-
/** Stream individual items across cursor pages, fetching the next page only when pulled. */
|
|
1086
|
-
const streamCursorItems = (operation, input) => Stream.paginate(startCursorOf(input), (cursor) => fetchCursorPage(operation, input, cursor).pipe(Effect.map((result) => [result.items, Option.fromNullishOr(result.nextCursor)])));
|
|
1087
|
-
//#endregion
|
|
1088
|
-
//#region src/effect/internal/operation.ts
|
|
1089
|
-
const READ_METHODS = /* @__PURE__ */ new Set(["GET", "HEAD"]);
|
|
1090
|
-
const MODULE_NAMES = {
|
|
1091
|
-
analytics: "Analytics",
|
|
1092
|
-
apiKeys: "ApiKeys",
|
|
1093
|
-
attachments: "Attachments",
|
|
1094
|
-
brands: "Brands",
|
|
1095
|
-
campaigns: "Campaigns",
|
|
1096
|
-
contactGroups: "ContactGroups",
|
|
1097
|
-
contacts: "Contacts",
|
|
1098
|
-
conversations: "Conversations",
|
|
1099
|
-
customFields: "CustomFields",
|
|
1100
|
-
email: "Email",
|
|
1101
|
-
extensions: "Extensions",
|
|
1102
|
-
feedback: "Feedback",
|
|
1103
|
-
mailboxes: "Mailboxes",
|
|
1104
|
-
media: "Media",
|
|
1105
|
-
messages: "Messages",
|
|
1106
|
-
namespaces: "Namespaces",
|
|
1107
|
-
operations: "Operations",
|
|
1108
|
-
organizations: "Organizations",
|
|
1109
|
-
scheduledMessages: "ScheduledMessages",
|
|
1110
|
-
templates: "Templates",
|
|
1111
|
-
unsubscribe: "UnsubscribeGroups",
|
|
1112
|
-
webhooks: "Webhooks",
|
|
1113
|
-
whoami: "Whoami"
|
|
1114
|
-
};
|
|
1115
|
-
const traceName = (operationName) => {
|
|
1116
|
-
for (const [prefix, moduleName] of Object.entries(MODULE_NAMES)) {
|
|
1117
|
-
if (!operationName.startsWith(prefix)) continue;
|
|
1118
|
-
const method = operationName.slice(prefix.length);
|
|
1119
|
-
return `${moduleName}.${method[0].toLowerCase()}${method.slice(1)}`;
|
|
1120
|
-
}
|
|
1121
|
-
return `Samva.${operationName}`;
|
|
1122
|
-
};
|
|
1123
|
-
const stripUndefined = (input) => {
|
|
1124
|
-
if (!Predicate.isObject(input)) return input;
|
|
1125
|
-
if (Array.isArray(input)) return input.map(stripUndefined);
|
|
1126
|
-
if (Object.getPrototypeOf(input) !== Object.prototype) return input;
|
|
1127
|
-
return Object.fromEntries(Object.entries(input).filter(([, value]) => value !== void 0).map(([key, value]) => [key, stripUndefined(value)]));
|
|
1128
|
-
};
|
|
1129
|
-
const adapt = (operationName, rawCall, input) => {
|
|
1130
|
-
const descriptor = SDK_OPERATION_CALLS[operationName];
|
|
1131
|
-
const call = READ_METHODS.has(SamvaOperations[operationName].method) ? (request) => withRetry(rawCall(request)) : rawCall;
|
|
1132
|
-
if (descriptor.kind === "none") return call();
|
|
1133
|
-
if (descriptor.kind === "params") return call({ query: stripUndefined(input) });
|
|
1134
|
-
if (descriptor.kind === "payload") return call({ payload: stripUndefined(input) });
|
|
1135
|
-
if (descriptor.kind === "idempotentPayload") {
|
|
1136
|
-
const { idempotencyKey, ...payload } = input;
|
|
1137
|
-
return call({
|
|
1138
|
-
headers: { "idempotency-key": idempotencyKey },
|
|
1139
|
-
payload: stripUndefined(payload)
|
|
1140
|
-
});
|
|
1141
|
-
}
|
|
1142
|
-
const pathDescriptor = descriptor;
|
|
1143
|
-
const inputRecord = input ?? {};
|
|
1144
|
-
const params = {};
|
|
1145
|
-
for (const path of pathDescriptor.paths) {
|
|
1146
|
-
if (inputRecord[path] === void 0) return Effect.die(/* @__PURE__ */ new Error(`${operationName} requires path field ${path}`));
|
|
1147
|
-
params[path] = inputRecord[path];
|
|
1148
|
-
}
|
|
1149
|
-
if (pathDescriptor.kind === "path") return call({ params });
|
|
1150
|
-
if (pathDescriptor.kind === "idempotentPath") return call({
|
|
1151
|
-
params,
|
|
1152
|
-
headers: { "idempotency-key": inputRecord.idempotencyKey }
|
|
1153
|
-
});
|
|
1154
|
-
const optionalKeyHeaders = { headers: inputRecord.idempotencyKey === void 0 ? {} : { "idempotency-key": inputRecord.idempotencyKey } };
|
|
1155
|
-
if (pathDescriptor.kind === "optionalIdempotentPath") return call({
|
|
1156
|
-
params,
|
|
1157
|
-
...optionalKeyHeaders
|
|
1158
|
-
});
|
|
1159
|
-
const headerKey = pathDescriptor.kind === "optionalIdempotentPathPayload";
|
|
1160
|
-
const remainingInput = stripUndefined(Object.fromEntries(Object.entries(inputRecord).filter(([key]) => !pathDescriptor.paths.includes(key) && !(headerKey && key === "idempotencyKey"))));
|
|
1161
|
-
if (pathDescriptor.kind === "optionalIdempotentPathPayload") return call({
|
|
1162
|
-
params,
|
|
1163
|
-
payload: remainingInput,
|
|
1164
|
-
...optionalKeyHeaders
|
|
1165
|
-
});
|
|
1166
|
-
return call({
|
|
1167
|
-
params,
|
|
1168
|
-
[pathDescriptor.kind === "pathParams" ? "query" : "payload"]: remainingInput
|
|
1169
|
-
});
|
|
1170
|
-
};
|
|
1171
|
-
const isCursorPageEnvelope = (value) => Predicate.isObject(value) && Array.isArray(value.items) && (value.nextCursor === null || typeof value.nextCursor === "string");
|
|
1172
|
-
/**
|
|
1173
|
-
* Operation factory for one API group. Each domain module binds its own group, so importing it
|
|
1174
|
-
* loads that group's schemas and nothing else.
|
|
1175
|
-
*/
|
|
1176
|
-
const forGroup = (group) => (operationName) => {
|
|
1177
|
-
if (SamvaOperations[operationName].group !== group.identifier) throw new Error(`${operationName} is not an endpoint of ${group.identifier}`);
|
|
1178
|
-
return make(group, operationName);
|
|
1179
|
-
};
|
|
1180
|
-
/** Call one endpoint with an already-shaped request, outside the direct-operation adapter. */
|
|
1181
|
-
const callEndpoint = (group, name, request) => Effect.flatMap(Service, (client) => Effect.flatMap(client.endpoint(group, name), (call) => call(request)));
|
|
1182
|
-
const make = (group, operationName) => {
|
|
1183
|
-
const call = Effect.fn(traceName(operationName))((input) => Effect.flatMap(Service, (client) => Effect.flatMap(client.endpoint(group, operationName), (rawCall) => adapt(operationName, rawCall, input))));
|
|
1184
|
-
const operation = call;
|
|
1185
|
-
if (SamvaOperations[operationName].paginated) {
|
|
1186
|
-
const list = (input) => Effect.filterOrElse(call(input), isCursorPageEnvelope, () => Effect.die(/* @__PURE__ */ new Error(`${operationName} did not return a cursor page envelope`)));
|
|
1187
|
-
Object.assign(operation, {
|
|
1188
|
-
pages: (input) => streamCursorPages(list, input ?? {}),
|
|
1189
|
-
items: (input) => streamCursorItems(list, input ?? {})
|
|
1190
|
-
});
|
|
1191
|
-
}
|
|
1192
|
-
return operation;
|
|
1193
|
-
};
|
|
1194
|
-
//#endregion
|
|
1195
|
-
export { forGroup as n, stripUndefined as r, callEndpoint as t };
|
|
1049
|
+
export { SDK_OPERATION_CALLS };
|
|
1196
1050
|
|
|
1197
|
-
//# sourceMappingURL=
|
|
1051
|
+
//# sourceMappingURL=service-map.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "samva",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"description": "TypeScript SDK for the Samva email API",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"api-client",
|
|
@@ -47,6 +47,10 @@
|
|
|
47
47
|
"types": "./dist/effect/index.d.ts",
|
|
48
48
|
"import": "./dist/effect/index.js"
|
|
49
49
|
},
|
|
50
|
+
"./effect/errors": {
|
|
51
|
+
"types": "./dist/effect/errors.d.ts",
|
|
52
|
+
"import": "./dist/effect/errors.js"
|
|
53
|
+
},
|
|
50
54
|
"./effect/categories": {
|
|
51
55
|
"types": "./dist/effect/categories.d.ts",
|
|
52
56
|
"import": "./dist/effect/categories.js"
|
|
@@ -196,7 +200,7 @@
|
|
|
196
200
|
"typecheck": "tsc --noEmit && tsc --noEmit -p codegen/tsconfig.json && tsc --noEmit -p tests/tsconfig.json"
|
|
197
201
|
},
|
|
198
202
|
"dependencies": {
|
|
199
|
-
"@samva/webhooks": "0.
|
|
203
|
+
"@samva/webhooks": "0.18.0"
|
|
200
204
|
},
|
|
201
205
|
"devDependencies": {
|
|
202
206
|
"@effect/openapi-generator": "4.0.0",
|