@primitivedotdev/sdk 0.8.0 → 0.10.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/README.md +22 -0
- package/dist/{address-parser-CfPHs3mE.js → address-parser-BYn8oW5r.js} +1 -3
- package/dist/api/generated/index.js +1 -1
- package/dist/api/generated/sdk.gen.js +26 -0
- package/dist/api/index.d.ts +2 -4
- package/dist/api/index.js +72 -33
- package/dist/{api-BH8PnmHs.js → api-CLLpjjWy.js} +142 -113
- package/dist/chunk-pbuEa-1d.js +13 -0
- package/dist/contract/index.d.ts +6 -9
- package/dist/contract/index.js +28 -17
- package/dist/{index-CuuP1JkG.d.ts → index-CbEivn3S.d.ts} +7 -31
- package/dist/{index-D9lanVFt.d.ts → index-K4KbjppU.d.ts} +266 -56
- package/dist/index.d.ts +7 -7
- package/dist/index.js +4 -8
- package/dist/oclif/api-command.js +89 -1
- package/dist/openapi/index.d.ts +8 -3
- package/dist/openapi/openapi.generated.js +191 -5
- package/dist/openapi/operations.generated.js +288 -0
- package/dist/parser/index.d.ts +4 -19
- package/dist/parser/index.js +7 -18
- package/dist/{received-email-Q6Cha3wc.js → received-email-D6tKtWwW.js} +2 -4
- package/dist/{received-email-C67Z7Dha.d.ts → received-email-DNjpq_Wt.d.ts} +4 -3
- package/dist/{types-CIOzt1FY.d.ts → types-9vXGZjPd.d.ts} +3 -19
- package/dist/webhook/index.d.ts +3 -3
- package/dist/webhook/index.js +3 -5
- package/dist/{webhook-2TALcBQz.js → webhook-zkN4wUTs.js} +107 -84
- package/oclif.manifest.json +63 -9
- package/package.json +2 -2
- package/dist/chunk-Cl8Af3a2.js +0 -11
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { formatAddress } from "./received-email-
|
|
3
|
-
|
|
1
|
+
import { t as __exportAll } from "./chunk-pbuEa-1d.js";
|
|
2
|
+
import { r as formatAddress } from "./received-email-D6tKtWwW.js";
|
|
4
3
|
//#region src/api/generated/core/bodySerializer.gen.ts
|
|
5
4
|
const jsonBodySerializer = { bodySerializer: (body) => JSON.stringify(body, (_key, value) => typeof value === "bigint" ? value.toString() : value) };
|
|
6
|
-
|
|
7
5
|
//#endregion
|
|
8
6
|
//#region src/api/generated/core/serverSentEvents.gen.ts
|
|
9
|
-
function createSseClient({ onRequest, onSseError, onSseEvent, responseTransformer, responseValidator, sseDefaultRetryDelay, sseMaxRetryAttempts, sseMaxRetryDelay, sseSleepFn, url
|
|
7
|
+
function createSseClient({ onRequest, onSseError, onSseEvent, responseTransformer, responseValidator, sseDefaultRetryDelay, sseMaxRetryAttempts, sseMaxRetryDelay, sseSleepFn, url, ...options }) {
|
|
10
8
|
let lastEventId;
|
|
11
9
|
const sleep = sseSleepFn ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
|
|
12
10
|
const createStream = async function* () {
|
|
@@ -28,8 +26,7 @@ function createSseClient({ onRequest, onSseError, onSseEvent, responseTransforme
|
|
|
28
26
|
};
|
|
29
27
|
let request = new Request(url, requestInit);
|
|
30
28
|
if (onRequest) request = await onRequest(url, requestInit);
|
|
31
|
-
const
|
|
32
|
-
const response = await _fetch(request);
|
|
29
|
+
const response = await (options.fetch ?? globalThis.fetch)(request);
|
|
33
30
|
if (!response.ok) throw new Error(`SSE failed: ${response.status} ${response.statusText}`);
|
|
34
31
|
if (!response.body) throw new Error("No body in SSE response");
|
|
35
32
|
const reader = response.body.pipeThrough(new TextDecoderStream()).getReader();
|
|
@@ -91,15 +88,12 @@ function createSseClient({ onRequest, onSseError, onSseEvent, responseTransforme
|
|
|
91
88
|
} catch (error) {
|
|
92
89
|
onSseError?.(error);
|
|
93
90
|
if (sseMaxRetryAttempts !== void 0 && attempt >= sseMaxRetryAttempts) break;
|
|
94
|
-
|
|
95
|
-
await sleep(backoff);
|
|
91
|
+
await sleep(Math.min(retryDelay * 2 ** (attempt - 1), sseMaxRetryDelay ?? 3e4));
|
|
96
92
|
}
|
|
97
93
|
}
|
|
98
94
|
};
|
|
99
|
-
|
|
100
|
-
return { stream };
|
|
95
|
+
return { stream: createStream() };
|
|
101
96
|
}
|
|
102
|
-
|
|
103
97
|
//#endregion
|
|
104
98
|
//#region src/api/generated/core/pathSerializer.gen.ts
|
|
105
99
|
const separatorArrayExplode = (style) => {
|
|
@@ -128,12 +122,12 @@ const separatorObjectExplode = (style) => {
|
|
|
128
122
|
};
|
|
129
123
|
const serializeArrayParam = ({ allowReserved, explode, name, style, value }) => {
|
|
130
124
|
if (!explode) {
|
|
131
|
-
const joinedValues
|
|
125
|
+
const joinedValues = (allowReserved ? value : value.map((v) => encodeURIComponent(v))).join(separatorArrayNoExplode(style));
|
|
132
126
|
switch (style) {
|
|
133
|
-
case "label": return `.${joinedValues
|
|
134
|
-
case "matrix": return `;${name}=${joinedValues
|
|
135
|
-
case "simple": return joinedValues
|
|
136
|
-
default: return `${name}=${joinedValues
|
|
127
|
+
case "label": return `.${joinedValues}`;
|
|
128
|
+
case "matrix": return `;${name}=${joinedValues}`;
|
|
129
|
+
case "simple": return joinedValues;
|
|
130
|
+
default: return `${name}=${joinedValues}`;
|
|
137
131
|
}
|
|
138
132
|
}
|
|
139
133
|
const separator = separatorArrayExplode(style);
|
|
@@ -163,12 +157,12 @@ const serializeObjectParam = ({ allowReserved, explode, name, style, value, valu
|
|
|
163
157
|
allowReserved ? v : encodeURIComponent(v)
|
|
164
158
|
];
|
|
165
159
|
});
|
|
166
|
-
const joinedValues
|
|
160
|
+
const joinedValues = values.join(",");
|
|
167
161
|
switch (style) {
|
|
168
|
-
case "form": return `${name}=${joinedValues
|
|
169
|
-
case "label": return `.${joinedValues
|
|
170
|
-
case "matrix": return `;${name}=${joinedValues
|
|
171
|
-
default: return joinedValues
|
|
162
|
+
case "form": return `${name}=${joinedValues}`;
|
|
163
|
+
case "label": return `.${joinedValues}`;
|
|
164
|
+
case "matrix": return `;${name}=${joinedValues}`;
|
|
165
|
+
default: return joinedValues;
|
|
172
166
|
}
|
|
173
167
|
}
|
|
174
168
|
const separator = separatorObjectExplode(style);
|
|
@@ -179,7 +173,6 @@ const serializeObjectParam = ({ allowReserved, explode, name, style, value, valu
|
|
|
179
173
|
})).join(separator);
|
|
180
174
|
return style === "label" || style === "matrix" ? separator + joinedValues : joinedValues;
|
|
181
175
|
};
|
|
182
|
-
|
|
183
176
|
//#endregion
|
|
184
177
|
//#region src/api/generated/core/utils.gen.ts
|
|
185
178
|
const PATH_PARAM_RE = /\{[^{}]+\}/g;
|
|
@@ -248,18 +241,12 @@ const getUrl = ({ baseUrl, path, query, querySerializer, url: _url }) => {
|
|
|
248
241
|
};
|
|
249
242
|
function getValidRequestBody(options) {
|
|
250
243
|
const hasBody = options.body !== void 0;
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
if ("serializedBody" in options) {
|
|
254
|
-
const hasSerializedBody = options.serializedBody !== void 0 && options.serializedBody !== "";
|
|
255
|
-
return hasSerializedBody ? options.serializedBody : null;
|
|
256
|
-
}
|
|
244
|
+
if (hasBody && options.bodySerializer) {
|
|
245
|
+
if ("serializedBody" in options) return options.serializedBody !== void 0 && options.serializedBody !== "" ? options.serializedBody : null;
|
|
257
246
|
return options.body !== "" ? options.body : null;
|
|
258
247
|
}
|
|
259
248
|
if (hasBody) return options.body;
|
|
260
|
-
return void 0;
|
|
261
249
|
}
|
|
262
|
-
|
|
263
250
|
//#endregion
|
|
264
251
|
//#region src/api/generated/core/auth.gen.ts
|
|
265
252
|
const getAuthToken = async (auth, callback) => {
|
|
@@ -269,10 +256,9 @@ const getAuthToken = async (auth, callback) => {
|
|
|
269
256
|
if (auth.scheme === "basic") return `Basic ${btoa(token)}`;
|
|
270
257
|
return token;
|
|
271
258
|
};
|
|
272
|
-
|
|
273
259
|
//#endregion
|
|
274
260
|
//#region src/api/generated/client/utils.gen.ts
|
|
275
|
-
const createQuerySerializer = ({ parameters = {}
|
|
261
|
+
const createQuerySerializer = ({ parameters = {}, ...args } = {}) => {
|
|
276
262
|
const querySerializer = (queryParams) => {
|
|
277
263
|
const search = [];
|
|
278
264
|
if (queryParams && typeof queryParams === "object") for (const name in queryParams) {
|
|
@@ -328,14 +314,13 @@ const getParseAs = (contentType) => {
|
|
|
328
314
|
"video/"
|
|
329
315
|
].some((type) => cleanContent.startsWith(type))) return "blob";
|
|
330
316
|
if (cleanContent.startsWith("text/")) return "text";
|
|
331
|
-
return;
|
|
332
317
|
};
|
|
333
318
|
const checkForExistence = (options, name) => {
|
|
334
319
|
if (!name) return false;
|
|
335
320
|
if (options.headers.has(name) || options.query?.[name] || options.headers.get("Cookie")?.includes(`${name}=`)) return true;
|
|
336
321
|
return false;
|
|
337
322
|
};
|
|
338
|
-
const setAuthParams = async ({ security
|
|
323
|
+
const setAuthParams = async ({ security, ...options }) => {
|
|
339
324
|
for (const auth of security) {
|
|
340
325
|
if (checkForExistence(options, auth.name)) continue;
|
|
341
326
|
const token = await getAuthToken(auth, options.auth);
|
|
@@ -349,7 +334,6 @@ const setAuthParams = async ({ security,...options }) => {
|
|
|
349
334
|
case "cookie":
|
|
350
335
|
options.headers.append("Cookie", `${name}=${token}`);
|
|
351
336
|
break;
|
|
352
|
-
case "header":
|
|
353
337
|
default:
|
|
354
338
|
options.headers.set(name, token);
|
|
355
339
|
break;
|
|
@@ -444,14 +428,13 @@ const createConfig = (override = {}) => ({
|
|
|
444
428
|
querySerializer: defaultQuerySerializer,
|
|
445
429
|
...override
|
|
446
430
|
});
|
|
447
|
-
|
|
448
431
|
//#endregion
|
|
449
432
|
//#region src/api/generated/client/client.gen.ts
|
|
450
433
|
const createClient = (config = {}) => {
|
|
451
434
|
let _config = mergeConfigs(createConfig(), config);
|
|
452
435
|
const getConfig = () => ({ ..._config });
|
|
453
|
-
const setConfig = (config
|
|
454
|
-
_config = mergeConfigs(_config, config
|
|
436
|
+
const setConfig = (config) => {
|
|
437
|
+
_config = mergeConfigs(_config, config);
|
|
455
438
|
return getConfig();
|
|
456
439
|
};
|
|
457
440
|
const interceptors = createInterceptors();
|
|
@@ -471,10 +454,9 @@ const createClient = (config = {}) => {
|
|
|
471
454
|
if (opts.body !== void 0 && opts.bodySerializer) opts.serializedBody = opts.bodySerializer(opts.body);
|
|
472
455
|
if (opts.body === void 0 || opts.serializedBody === "") opts.headers.delete("Content-Type");
|
|
473
456
|
const resolvedOpts = opts;
|
|
474
|
-
const url = buildUrl(resolvedOpts);
|
|
475
457
|
return {
|
|
476
458
|
opts: resolvedOpts,
|
|
477
|
-
url
|
|
459
|
+
url: buildUrl(resolvedOpts)
|
|
478
460
|
};
|
|
479
461
|
};
|
|
480
462
|
const request = async (options) => {
|
|
@@ -484,26 +466,26 @@ const createClient = (config = {}) => {
|
|
|
484
466
|
...opts,
|
|
485
467
|
body: getValidRequestBody(opts)
|
|
486
468
|
};
|
|
487
|
-
let request
|
|
488
|
-
for (const fn of interceptors.request.fns) if (fn) request
|
|
469
|
+
let request = new Request(url, requestInit);
|
|
470
|
+
for (const fn of interceptors.request.fns) if (fn) request = await fn(request, opts);
|
|
489
471
|
const _fetch = opts.fetch;
|
|
490
472
|
let response;
|
|
491
473
|
try {
|
|
492
|
-
response = await _fetch(request
|
|
493
|
-
} catch (error
|
|
494
|
-
let finalError
|
|
495
|
-
for (const fn of interceptors.error.fns) if (fn) finalError
|
|
496
|
-
finalError
|
|
497
|
-
if (opts.throwOnError) throw finalError
|
|
474
|
+
response = await _fetch(request);
|
|
475
|
+
} catch (error) {
|
|
476
|
+
let finalError = error;
|
|
477
|
+
for (const fn of interceptors.error.fns) if (fn) finalError = await fn(error, void 0, request, opts);
|
|
478
|
+
finalError = finalError || {};
|
|
479
|
+
if (opts.throwOnError) throw finalError;
|
|
498
480
|
return opts.responseStyle === "data" ? void 0 : {
|
|
499
|
-
error: finalError
|
|
500
|
-
request
|
|
481
|
+
error: finalError,
|
|
482
|
+
request,
|
|
501
483
|
response: void 0
|
|
502
484
|
};
|
|
503
485
|
}
|
|
504
|
-
for (const fn of interceptors.response.fns) if (fn) response = await fn(response, request
|
|
486
|
+
for (const fn of interceptors.response.fns) if (fn) response = await fn(response, request, opts);
|
|
505
487
|
const result = {
|
|
506
|
-
request
|
|
488
|
+
request,
|
|
507
489
|
response
|
|
508
490
|
};
|
|
509
491
|
if (response.ok) {
|
|
@@ -522,7 +504,6 @@ const createClient = (config = {}) => {
|
|
|
522
504
|
case "stream":
|
|
523
505
|
emptyData = response.body;
|
|
524
506
|
break;
|
|
525
|
-
case "json":
|
|
526
507
|
default:
|
|
527
508
|
emptyData = {};
|
|
528
509
|
break;
|
|
@@ -566,7 +547,7 @@ const createClient = (config = {}) => {
|
|
|
566
547
|
} catch {}
|
|
567
548
|
const error = jsonError ?? textError;
|
|
568
549
|
let finalError = error;
|
|
569
|
-
for (const fn of interceptors.error.fns) if (fn) finalError = await fn(error, response, request
|
|
550
|
+
for (const fn of interceptors.error.fns) if (fn) finalError = await fn(error, response, request, opts);
|
|
570
551
|
finalError = finalError || {};
|
|
571
552
|
if (opts.throwOnError) throw finalError;
|
|
572
553
|
return opts.responseStyle === "data" ? void 0 : {
|
|
@@ -585,10 +566,10 @@ const createClient = (config = {}) => {
|
|
|
585
566
|
body: opts.body,
|
|
586
567
|
headers: opts.headers,
|
|
587
568
|
method,
|
|
588
|
-
onRequest: async (url
|
|
589
|
-
let request
|
|
590
|
-
for (const fn of interceptors.request.fns) if (fn) request
|
|
591
|
-
return request
|
|
569
|
+
onRequest: async (url, init) => {
|
|
570
|
+
let request = new Request(url, init);
|
|
571
|
+
for (const fn of interceptors.request.fns) if (fn) request = await fn(request, opts);
|
|
572
|
+
return request;
|
|
592
573
|
},
|
|
593
574
|
serializedBody: getValidRequestBody(opts),
|
|
594
575
|
url
|
|
@@ -626,15 +607,12 @@ const createClient = (config = {}) => {
|
|
|
626
607
|
trace: makeMethodFn("TRACE")
|
|
627
608
|
};
|
|
628
609
|
};
|
|
629
|
-
|
|
630
610
|
//#endregion
|
|
631
611
|
//#region src/api/generated/client.gen.ts
|
|
632
612
|
const client$1 = createClient(createConfig({ baseUrl: "https://www.primitive.dev/api/v1" }));
|
|
633
|
-
|
|
634
613
|
//#endregion
|
|
635
614
|
//#region src/api/generated/sdk.gen.ts
|
|
636
|
-
var sdk_gen_exports = {
|
|
637
|
-
__export(sdk_gen_exports, {
|
|
615
|
+
var sdk_gen_exports = /* @__PURE__ */ __exportAll({
|
|
638
616
|
addDomain: () => addDomain,
|
|
639
617
|
createEndpoint: () => createEndpoint,
|
|
640
618
|
createFilter: () => createFilter,
|
|
@@ -655,6 +633,7 @@ __export(sdk_gen_exports, {
|
|
|
655
633
|
listFilters: () => listFilters,
|
|
656
634
|
replayDelivery: () => replayDelivery,
|
|
657
635
|
replayEmailWebhooks: () => replayEmailWebhooks,
|
|
636
|
+
replyToEmail: () => replyToEmail,
|
|
658
637
|
rotateWebhookSecret: () => rotateWebhookSecret,
|
|
659
638
|
sendEmail: () => sendEmail,
|
|
660
639
|
testEndpoint: () => testEndpoint,
|
|
@@ -894,6 +873,35 @@ const downloadAttachments = (options) => (options.client ?? client$1).get({
|
|
|
894
873
|
...options
|
|
895
874
|
});
|
|
896
875
|
/**
|
|
876
|
+
* Reply to an inbound email
|
|
877
|
+
*
|
|
878
|
+
* Sends an outbound reply to the inbound email identified by `id`.
|
|
879
|
+
* Threading headers (`In-Reply-To`, `References`), recipient
|
|
880
|
+
* derivation (Reply-To, then From, then bare sender), and the
|
|
881
|
+
* `Re:` subject prefix are all derived server-side from the
|
|
882
|
+
* stored inbound row. The request body carries only the message
|
|
883
|
+
* body and optional `wait` flag; passing any header or recipient
|
|
884
|
+
* override is rejected by the schema (`additionalProperties:
|
|
885
|
+
* false`).
|
|
886
|
+
*
|
|
887
|
+
* Forwards through the same gates as `/send-mail`: the response
|
|
888
|
+
* status, error envelope, and `idempotent_replay` flag mirror
|
|
889
|
+
* the send-mail contract verbatim.
|
|
890
|
+
*
|
|
891
|
+
*/
|
|
892
|
+
const replyToEmail = (options) => (options.client ?? client$1).post({
|
|
893
|
+
security: [{
|
|
894
|
+
scheme: "bearer",
|
|
895
|
+
type: "http"
|
|
896
|
+
}],
|
|
897
|
+
url: "/emails/{id}/reply",
|
|
898
|
+
...options,
|
|
899
|
+
headers: {
|
|
900
|
+
"Content-Type": "application/json",
|
|
901
|
+
...options.headers
|
|
902
|
+
}
|
|
903
|
+
});
|
|
904
|
+
/**
|
|
897
905
|
* Replay email webhooks
|
|
898
906
|
*
|
|
899
907
|
* Re-delivers the webhook payload for this email to all active
|
|
@@ -1110,7 +1118,6 @@ const sendEmail = (options) => (options.client ?? client$1).post({
|
|
|
1110
1118
|
...options.headers
|
|
1111
1119
|
}
|
|
1112
1120
|
});
|
|
1113
|
-
|
|
1114
1121
|
//#endregion
|
|
1115
1122
|
//#region src/api/index.ts
|
|
1116
1123
|
const DEFAULT_BASE_URL = "https://www.primitive.dev/api/v1";
|
|
@@ -1122,7 +1129,6 @@ const MAX_TO_HEADER_LENGTH = 320;
|
|
|
1122
1129
|
function createDefaultAuth(apiKey) {
|
|
1123
1130
|
return (security) => {
|
|
1124
1131
|
if (security.type === "http" && security.scheme === "bearer") return apiKey;
|
|
1125
|
-
return void 0;
|
|
1126
1132
|
};
|
|
1127
1133
|
}
|
|
1128
1134
|
function validateAddressHeader(field, value) {
|
|
@@ -1218,7 +1224,7 @@ function parseRetryAfterHeader(response) {
|
|
|
1218
1224
|
var PrimitiveApiClient = class {
|
|
1219
1225
|
client;
|
|
1220
1226
|
constructor(options = {}) {
|
|
1221
|
-
const { apiKey, auth, baseUrl = DEFAULT_BASE_URL
|
|
1227
|
+
const { apiKey, auth, baseUrl = DEFAULT_BASE_URL, ...config } = options;
|
|
1222
1228
|
this.client = createClient(createConfig({
|
|
1223
1229
|
...config,
|
|
1224
1230
|
auth: auth ?? createDefaultAuth(apiKey),
|
|
@@ -1235,54 +1241,52 @@ var PrimitiveApiClient = class {
|
|
|
1235
1241
|
var PrimitiveClient = class extends PrimitiveApiClient {
|
|
1236
1242
|
async send(input) {
|
|
1237
1243
|
validateSendInput(input);
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
body,
|
|
1244
|
+
return unwrapSendResult(await sendEmail({
|
|
1245
|
+
body: {
|
|
1246
|
+
from: input.from,
|
|
1247
|
+
to: input.to,
|
|
1248
|
+
subject: input.subject,
|
|
1249
|
+
...input.bodyText !== void 0 ? { body_text: input.bodyText } : {},
|
|
1250
|
+
...input.bodyHtml !== void 0 ? { body_html: input.bodyHtml } : {},
|
|
1251
|
+
...input.thread?.inReplyTo ? { in_reply_to: input.thread.inReplyTo } : {},
|
|
1252
|
+
...input.thread?.references?.length ? { references: input.thread.references } : {},
|
|
1253
|
+
...input.wait !== void 0 ? { wait: input.wait } : {},
|
|
1254
|
+
...input.waitTimeoutMs !== void 0 ? { wait_timeout_ms: input.waitTimeoutMs } : {}
|
|
1255
|
+
},
|
|
1251
1256
|
...input.idempotencyKey ? { headers: { "Idempotency-Key": input.idempotencyKey } } : {},
|
|
1252
1257
|
client: this.client,
|
|
1253
1258
|
responseStyle: "fields"
|
|
1254
|
-
});
|
|
1255
|
-
const response = result.response;
|
|
1256
|
-
if (result.error) {
|
|
1257
|
-
const parsed = parseApiErrorPayload(result.error);
|
|
1258
|
-
throw new PrimitiveApiError(parsed.message, {
|
|
1259
|
-
payload: result.error,
|
|
1260
|
-
status: response?.status,
|
|
1261
|
-
code: parsed.code,
|
|
1262
|
-
gates: parsed.gates,
|
|
1263
|
-
requestId: parsed.requestId,
|
|
1264
|
-
retryAfter: parseRetryAfterHeader(response),
|
|
1265
|
-
details: parsed.details
|
|
1266
|
-
});
|
|
1267
|
-
}
|
|
1268
|
-
if (!result.data?.data) throw new PrimitiveApiError("Primitive API returned no send result", {
|
|
1269
|
-
payload: result,
|
|
1270
|
-
status: response?.status
|
|
1271
|
-
});
|
|
1272
|
-
return mapSendResult(result.data.data);
|
|
1259
|
+
}));
|
|
1273
1260
|
}
|
|
1261
|
+
/**
|
|
1262
|
+
* Reply to an inbound email.
|
|
1263
|
+
*
|
|
1264
|
+
* Calls `POST /emails/{id}/reply`. The server derives recipients
|
|
1265
|
+
* (Reply-To, then From, then sender), subject (`Re: <parent>` with
|
|
1266
|
+
* idempotent prefix), and threading headers (`In-Reply-To`,
|
|
1267
|
+
* `References`) from the stored inbound row. The customer controls
|
|
1268
|
+
* only the body, an optional `from` override, and the `wait` flag.
|
|
1269
|
+
*
|
|
1270
|
+
* Subject overrides are intentionally not supported: Gmail's
|
|
1271
|
+
* Conversation View needs both a References match and a normalized-
|
|
1272
|
+
* subject match to thread, so a custom subject silently breaks the
|
|
1273
|
+
* thread for half the recipient population.
|
|
1274
|
+
*/
|
|
1274
1275
|
async reply(email, input) {
|
|
1275
1276
|
const resolved = typeof input === "string" ? { text: input } : input;
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
...
|
|
1283
|
-
|
|
1284
|
-
}
|
|
1285
|
-
|
|
1277
|
+
if ("subject" in resolved) throw new TypeError("reply does not support a subject override; the server prepends 'Re:' to the parent's subject for thread continuity");
|
|
1278
|
+
if (!resolved.text && !resolved.html) throw new TypeError("reply requires text or html");
|
|
1279
|
+
return unwrapSendResult(await replyToEmail({
|
|
1280
|
+
body: {
|
|
1281
|
+
...resolved.text !== void 0 ? { body_text: resolved.text } : {},
|
|
1282
|
+
...resolved.html !== void 0 ? { body_html: resolved.html } : {},
|
|
1283
|
+
...resolved.from !== void 0 ? { from: resolved.from } : {},
|
|
1284
|
+
...resolved.wait !== void 0 ? { wait: resolved.wait } : {}
|
|
1285
|
+
},
|
|
1286
|
+
path: { id: email.id },
|
|
1287
|
+
client: this.client,
|
|
1288
|
+
responseStyle: "fields"
|
|
1289
|
+
}));
|
|
1286
1290
|
}
|
|
1287
1291
|
async forward(email, input) {
|
|
1288
1292
|
validateForwardInput(input);
|
|
@@ -1295,7 +1299,7 @@ var PrimitiveClient = class extends PrimitiveApiClient {
|
|
|
1295
1299
|
}
|
|
1296
1300
|
};
|
|
1297
1301
|
function buildForwardText(email, intro) {
|
|
1298
|
-
|
|
1302
|
+
return [
|
|
1299
1303
|
...intro ? [intro.trim(), ""] : [],
|
|
1300
1304
|
"---------- Forwarded message ----------",
|
|
1301
1305
|
`From: ${formatAddress(email.sender)}`,
|
|
@@ -1305,8 +1309,33 @@ function buildForwardText(email, intro) {
|
|
|
1305
1309
|
...email.thread.messageId ? [`Message-ID: ${email.thread.messageId}`] : [],
|
|
1306
1310
|
"",
|
|
1307
1311
|
email.text ?? ""
|
|
1308
|
-
];
|
|
1309
|
-
|
|
1312
|
+
].join("\n").trimEnd();
|
|
1313
|
+
}
|
|
1314
|
+
/**
|
|
1315
|
+
* Shared response handler for `send`, `reply`, and any future
|
|
1316
|
+
* operation that returns a SendMailResult envelope. Unifies the
|
|
1317
|
+
* error-mapping path so the network call sites only have to invoke
|
|
1318
|
+
* the generated operation.
|
|
1319
|
+
*/
|
|
1320
|
+
function unwrapSendResult(result) {
|
|
1321
|
+
const response = result.response;
|
|
1322
|
+
if (result.error) {
|
|
1323
|
+
const parsed = parseApiErrorPayload(result.error);
|
|
1324
|
+
throw new PrimitiveApiError(parsed.message, {
|
|
1325
|
+
payload: result.error,
|
|
1326
|
+
status: response?.status,
|
|
1327
|
+
code: parsed.code,
|
|
1328
|
+
gates: parsed.gates,
|
|
1329
|
+
requestId: parsed.requestId,
|
|
1330
|
+
retryAfter: parseRetryAfterHeader(response),
|
|
1331
|
+
details: parsed.details
|
|
1332
|
+
});
|
|
1333
|
+
}
|
|
1334
|
+
if (!result.data?.data) throw new PrimitiveApiError("Primitive API returned no send result", {
|
|
1335
|
+
payload: result,
|
|
1336
|
+
status: response?.status
|
|
1337
|
+
});
|
|
1338
|
+
return mapSendResult(result.data.data);
|
|
1310
1339
|
}
|
|
1311
1340
|
function mapSendResult(result) {
|
|
1312
1341
|
return {
|
|
@@ -1318,6 +1347,7 @@ function mapSendResult(result) {
|
|
|
1318
1347
|
clientIdempotencyKey: result.client_idempotency_key,
|
|
1319
1348
|
requestId: result.request_id,
|
|
1320
1349
|
contentHash: result.content_hash,
|
|
1350
|
+
idempotentReplay: result.idempotent_replay ?? false,
|
|
1321
1351
|
...result.delivery_status !== void 0 ? { deliveryStatus: result.delivery_status } : {},
|
|
1322
1352
|
...result.smtp_response_code !== void 0 ? { smtpResponseCode: result.smtp_response_code } : {},
|
|
1323
1353
|
...result.smtp_response_text !== void 0 ? { smtpResponseText: result.smtp_response_text } : {}
|
|
@@ -1333,6 +1363,5 @@ function client(options = {}) {
|
|
|
1333
1363
|
return new PrimitiveClient(options);
|
|
1334
1364
|
}
|
|
1335
1365
|
const operations = sdk_gen_exports;
|
|
1336
|
-
|
|
1337
1366
|
//#endregion
|
|
1338
|
-
export {
|
|
1367
|
+
export { rotateWebhookSecret as A, listDomains as C, replayDelivery as D, listFilters as E, updateEndpoint as F, updateFilter as I, verifyDomain as L, testEndpoint as M, updateAccount as N, replayEmailWebhooks as O, updateDomain as P, listDeliveries as S, listEndpoints as T, downloadRawEmail as _, client as a, getStorageStats as b, operations as c, createFilter as d, deleteDomain as f, downloadAttachments as g, deleteFilter as h, PrimitiveClient as i, sendEmail as j, replyToEmail as k, addDomain as l, deleteEndpoint as m, PrimitiveApiClient as n, createPrimitiveApiClient as o, deleteEmail as p, PrimitiveApiError as r, createPrimitiveClient as s, DEFAULT_BASE_URL as t, createEndpoint as u, getAccount as v, listEmails as w, getWebhookSecret as x, getEmail as y };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
//#region \0rolldown/runtime.js
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __exportAll = (all, no_symbols) => {
|
|
4
|
+
let target = {};
|
|
5
|
+
for (var name in all) __defProp(target, name, {
|
|
6
|
+
get: all[name],
|
|
7
|
+
enumerable: true
|
|
8
|
+
});
|
|
9
|
+
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
10
|
+
return target;
|
|
11
|
+
};
|
|
12
|
+
//#endregion
|
|
13
|
+
export { __exportAll as t };
|
package/dist/contract/index.d.ts
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import "../
|
|
3
|
-
import { SignResult, StandardWebhooksSignResult, WEBHOOK_VERSION$1 as WEBHOOK_VERSION, signStandardWebhooksPayload$1 as signStandardWebhooksPayload, signWebhookPayload$1 as signWebhookPayload } from "../index-CuuP1JkG.js";
|
|
1
|
+
import { C as ParsedDataFailed, D as RawContentDownloadOnly, M as WebhookAttachment, O as RawContentInline, S as ParsedDataComplete, c as EmailAnalysis, l as EmailAuth, s as EmailAddress, u as EmailReceivedEvent, w as ParsedError } from "../types-9vXGZjPd.js";
|
|
2
|
+
import { C as signStandardWebhooksPayload, h as WEBHOOK_VERSION, j as signWebhookPayload, k as SignResult, x as StandardWebhooksSignResult } from "../index-CbEivn3S.js";
|
|
4
3
|
|
|
5
4
|
//#region src/contract/contract.d.ts
|
|
6
|
-
/** Maximum raw email size for inline inclusion (256 KB). */
|
|
7
|
-
|
|
8
5
|
/** Maximum raw email size for inline inclusion (256 KB). */
|
|
9
6
|
declare const RAW_EMAIL_INLINE_THRESHOLD = 262144;
|
|
10
7
|
/** Parsed content input when parsing succeeded. */
|
|
@@ -143,8 +140,7 @@ declare function generateEventId(endpoint_id: string, email_id: string): string;
|
|
|
143
140
|
* ```
|
|
144
141
|
*/
|
|
145
142
|
declare function buildEmailReceivedEvent(input: EmailReceivedEventInput, options?: {
|
|
146
|
-
/** Override the attempted-at timestamp, typically for tests. */
|
|
147
|
-
attempted_at?: string;
|
|
143
|
+
/** Override the attempted-at timestamp, typically for tests. */attempted_at?: string;
|
|
148
144
|
}): EmailReceivedEvent;
|
|
149
145
|
/**
|
|
150
146
|
* Input for building an `EmailReceivedEvent` directly from parser output.
|
|
@@ -222,5 +218,6 @@ interface BuildEventFromParsedDataOptions {
|
|
|
222
218
|
* @throws Error if `smtpRcptTo` is empty.
|
|
223
219
|
* @throws WebhookValidationError if the assembled event fails schema validation.
|
|
224
220
|
*/
|
|
225
|
-
declare function buildEventFromParsedData(params: BuildEventFromParsedDataOptions): EmailReceivedEvent;
|
|
226
|
-
|
|
221
|
+
declare function buildEventFromParsedData(params: BuildEventFromParsedDataOptions): EmailReceivedEvent;
|
|
222
|
+
//#endregion
|
|
223
|
+
export { BuildEventFromParsedDataOptions, type EmailAddress, type EmailAnalysis, type EmailAuth, type EmailReceivedEvent, EmailReceivedEventInput, type ParsedDataComplete, type ParsedDataFailed, type ParsedError, ParsedInput, ParsedInputComplete, ParsedInputFailed, RAW_EMAIL_INLINE_THRESHOLD, type RawContentDownloadOnly, type RawContentInline, type SignResult, type StandardWebhooksSignResult, WEBHOOK_VERSION, type WebhookAttachment, buildEmailReceivedEvent, buildEventFromParsedData, generateEventId, signStandardWebhooksPayload, signWebhookPayload };
|
package/dist/contract/index.js
CHANGED
|
@@ -1,9 +1,25 @@
|
|
|
1
|
-
import "../
|
|
2
|
-
import "../received-email-Q6Cha3wc.js";
|
|
3
|
-
import { WEBHOOK_VERSION, signStandardWebhooksPayload, signWebhookPayload, validateEmailReceivedEvent } from "../webhook-2TALcBQz.js";
|
|
1
|
+
import { E as signStandardWebhooksPayload, L as validateEmailReceivedEvent, M as signWebhookPayload, d as WEBHOOK_VERSION } from "../webhook-zkN4wUTs.js";
|
|
4
2
|
import { createHash } from "node:crypto";
|
|
5
|
-
|
|
6
3
|
//#region src/contract/contract.ts
|
|
4
|
+
/**
|
|
5
|
+
* Primitive Contract
|
|
6
|
+
*
|
|
7
|
+
* This module exposes the exact functions used by Primitive servers to construct
|
|
8
|
+
* webhook payloads. It serves two purposes:
|
|
9
|
+
*
|
|
10
|
+
* 1. **Build-time type safety**: Primitive producer code can import these types
|
|
11
|
+
* and functions so schema changes surface as TypeScript errors instead of
|
|
12
|
+
* runtime contract drift.
|
|
13
|
+
*
|
|
14
|
+
* 2. **Debugging transparency**: If you receive a malformed payload, you can
|
|
15
|
+
* compare it against these exact types and builder functions to identify
|
|
16
|
+
* which side broke the contract.
|
|
17
|
+
*
|
|
18
|
+
* This package is also useful for building test fixtures that match real
|
|
19
|
+
* payloads exactly.
|
|
20
|
+
*
|
|
21
|
+
* @module @primitivedotdev/sdk/contract
|
|
22
|
+
*/
|
|
7
23
|
/** Maximum raw email size for inline inclusion (256 KB). */
|
|
8
24
|
const RAW_EMAIL_INLINE_THRESHOLD = 262144;
|
|
9
25
|
/**
|
|
@@ -42,8 +58,7 @@ function validateTimestamp(timestamp, fieldName) {
|
|
|
42
58
|
*/
|
|
43
59
|
function generateEventId(endpoint_id, email_id) {
|
|
44
60
|
const hashInput = `email.received:${WEBHOOK_VERSION}:${endpoint_id}:${email_id}`;
|
|
45
|
-
|
|
46
|
-
return `evt_${hash}`;
|
|
61
|
+
return `evt_${createHash("sha256").update(hashInput).digest("hex")}`;
|
|
47
62
|
}
|
|
48
63
|
/**
|
|
49
64
|
* Build an `EmailReceivedEvent` from producer-side input.
|
|
@@ -94,13 +109,12 @@ function generateEventId(endpoint_id, email_id) {
|
|
|
94
109
|
*/
|
|
95
110
|
function buildEmailReceivedEvent(input, options) {
|
|
96
111
|
const event_id = generateEventId(input.endpoint_id, input.email_id);
|
|
97
|
-
const attempted_at = options?.attempted_at ? validateTimestamp(options.attempted_at, "attempted_at") : new Date().toISOString();
|
|
112
|
+
const attempted_at = options?.attempted_at ? validateTimestamp(options.attempted_at, "attempted_at") : (/* @__PURE__ */ new Date()).toISOString();
|
|
98
113
|
const raw_size_bytes = input.raw_bytes.length;
|
|
99
114
|
if (input.raw_size_bytes !== raw_size_bytes) throw new Error(`[@primitivedotdev/sdk/contract] Invalid raw_size_bytes: ${input.raw_size_bytes}. Expected ${raw_size_bytes} based on raw_bytes length`);
|
|
100
115
|
const raw_sha256 = createHash("sha256").update(input.raw_bytes).digest("hex");
|
|
101
116
|
if (input.raw_sha256 !== raw_sha256) throw new Error(`[@primitivedotdev/sdk/contract] Invalid raw_sha256: "${input.raw_sha256}". Expected ${raw_sha256} based on raw_bytes`);
|
|
102
|
-
const
|
|
103
|
-
const rawContent = shouldInline ? {
|
|
117
|
+
const rawContent = raw_size_bytes <= 262144 ? {
|
|
104
118
|
included: true,
|
|
105
119
|
encoding: "base64",
|
|
106
120
|
max_inline_bytes: RAW_EMAIL_INLINE_THRESHOLD,
|
|
@@ -158,7 +172,7 @@ function buildEmailReceivedEvent(input, options) {
|
|
|
158
172
|
attachments: [],
|
|
159
173
|
attachments_download_url: null
|
|
160
174
|
};
|
|
161
|
-
|
|
175
|
+
return validateEmailReceivedEvent({
|
|
162
176
|
id: event_id,
|
|
163
177
|
event: "email.received",
|
|
164
178
|
version: WEBHOOK_VERSION,
|
|
@@ -193,8 +207,7 @@ function buildEmailReceivedEvent(input, options) {
|
|
|
193
207
|
analysis: input.analysis,
|
|
194
208
|
auth: input.auth
|
|
195
209
|
}
|
|
196
|
-
};
|
|
197
|
-
return validateEmailReceivedEvent(event);
|
|
210
|
+
});
|
|
198
211
|
}
|
|
199
212
|
/**
|
|
200
213
|
* Build an `EmailReceivedEvent` from parsed email data plus delivery metadata.
|
|
@@ -241,7 +254,7 @@ function buildEventFromParsedData(params) {
|
|
|
241
254
|
references: parsed.references,
|
|
242
255
|
attachments: parsed.attachments
|
|
243
256
|
};
|
|
244
|
-
|
|
257
|
+
return buildEmailReceivedEvent({
|
|
245
258
|
email_id: params.emailId,
|
|
246
259
|
endpoint_id: params.endpointId,
|
|
247
260
|
message_id: params.messageId,
|
|
@@ -263,9 +276,7 @@ function buildEventFromParsedData(params) {
|
|
|
263
276
|
parsed: parsedInput,
|
|
264
277
|
auth: params.auth,
|
|
265
278
|
analysis: params.analysis
|
|
266
|
-
};
|
|
267
|
-
return buildEmailReceivedEvent(input, params.buildOptions);
|
|
279
|
+
}, params.buildOptions);
|
|
268
280
|
}
|
|
269
|
-
|
|
270
281
|
//#endregion
|
|
271
|
-
export { RAW_EMAIL_INLINE_THRESHOLD, WEBHOOK_VERSION, buildEmailReceivedEvent, buildEventFromParsedData, generateEventId, signStandardWebhooksPayload, signWebhookPayload };
|
|
282
|
+
export { RAW_EMAIL_INLINE_THRESHOLD, WEBHOOK_VERSION, buildEmailReceivedEvent, buildEventFromParsedData, generateEventId, signStandardWebhooksPayload, signWebhookPayload };
|