@myapihq/sdk 2.4.2 → 2.5.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/dist/client.d.ts +8 -0
- package/dist/client.js +31 -1
- package/dist/container.d.ts +3 -0
- package/dist/container.js +12 -0
- package/dist/email.d.ts +2 -1
- package/dist/email.js +4 -2
- package/dist/hq.d.ts +5 -1
- package/dist/hq.js +12 -2
- package/dist/payments.d.ts +2 -1
- package/dist/payments.js +4 -2
- package/dist/pixel.d.ts +4 -0
- package/dist/pixel.js +15 -0
- package/dist/storage.d.ts +2 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/webhook.d.ts +14 -0
- package/dist/webhook.js +27 -0
- package/package.json +1 -1
package/dist/client.d.ts
CHANGED
|
@@ -25,6 +25,14 @@ export interface RequestOptions {
|
|
|
25
25
|
retryUnsafe?: boolean;
|
|
26
26
|
/** Caller-supplied AbortSignal, composed with the timeout. */
|
|
27
27
|
signal?: AbortSignal;
|
|
28
|
+
/**
|
|
29
|
+
* Called when the backend answered from its idempotency cache instead of
|
|
30
|
+
* executing — i.e. a retry collapsed into the original request rather than
|
|
31
|
+
* running again. "Succeeded" and "already succeeded" are different facts to
|
|
32
|
+
* an agent deciding whether to count a charge, so this is surfaced rather
|
|
33
|
+
* than swallowed.
|
|
34
|
+
*/
|
|
35
|
+
onReplay?: () => void;
|
|
28
36
|
}
|
|
29
37
|
export declare function request<T>(method: string, url: string, apiKey?: string, body?: unknown, extraHeaders?: Record<string, string>, opts?: RequestOptions): Promise<T>;
|
|
30
38
|
export interface Page<T> {
|
package/dist/client.js
CHANGED
|
@@ -196,9 +196,39 @@ async function requestFull(method, url, apiKey, body, extraHeaders, opts) {
|
|
|
196
196
|
await sleep(after ?? backoffMs(attempt));
|
|
197
197
|
continue;
|
|
198
198
|
}
|
|
199
|
+
// Idempotency-Replayed: true means the backend served its cached response
|
|
200
|
+
// for this key and never ran the handler. Only meaningful on the billable
|
|
201
|
+
// endpoints that opt into retry, but the header is cheap to check.
|
|
202
|
+
if (opts?.onReplay && response.headers.get('idempotency-replayed') === 'true') {
|
|
203
|
+
opts.onReplay();
|
|
204
|
+
}
|
|
199
205
|
return await parseResponse(upper, url, response);
|
|
200
206
|
}
|
|
201
207
|
}
|
|
208
|
+
// A bare "invalid_json_response" reads as a platform fault. A user building on
|
|
209
|
+
// MyAPI hit it three times on an oversized container deploy and, in their
|
|
210
|
+
// words, "went looking for an outage" — the actual cause was a 198 MB upload
|
|
211
|
+
// context. The status code and the shape of the body usually say which side
|
|
212
|
+
// the problem is on, so say it rather than making the caller guess.
|
|
213
|
+
function diagnoseNonJson(status, raw) {
|
|
214
|
+
const looksHtml = /^\s*<(?:!doctype|html)/i.test(raw);
|
|
215
|
+
if (status === 413) {
|
|
216
|
+
return '→ The request body was too large. This is a client-side limit, not an outage — send less (for a deploy, exclude build artefacts and node_modules from the upload context).';
|
|
217
|
+
}
|
|
218
|
+
if (status === 0 || status === 502 || status === 503 || status === 504) {
|
|
219
|
+
return '→ The service did not answer. This one probably IS transient — retry shortly.';
|
|
220
|
+
}
|
|
221
|
+
if (looksHtml && status >= 500) {
|
|
222
|
+
return '→ An HTML error page in place of JSON means the edge replaced the origin\'s response, so the real reason is not in this body. Check the service logs for the underlying error.';
|
|
223
|
+
}
|
|
224
|
+
if (looksHtml) {
|
|
225
|
+
return '→ An HTML page came back instead of JSON, which usually means the request never reached the API (wrong URL, a proxy, or a captive network) rather than the API failing.';
|
|
226
|
+
}
|
|
227
|
+
if (status >= 400 && status < 500) {
|
|
228
|
+
return '→ A 4xx with a non-JSON body is usually the request being rejected before it reached the API — check the URL and the payload size.';
|
|
229
|
+
}
|
|
230
|
+
return '→ If the body above looks truncated or empty, the connection was probably cut mid-response.';
|
|
231
|
+
}
|
|
202
232
|
async function parseResponse(method, url, response) {
|
|
203
233
|
if (response.status === 204) {
|
|
204
234
|
return { success: true, data: null, error: null, meta: {} };
|
|
@@ -213,7 +243,7 @@ async function parseResponse(method, url, response) {
|
|
|
213
243
|
}
|
|
214
244
|
catch {
|
|
215
245
|
const snippet = raw.slice(0, 200).replace(/\s+/g, ' ').trim();
|
|
216
|
-
throw new MyApiError('invalid_json_response', response.status, `${method} ${url} returned non-JSON (status ${response.status}): ${snippet}`);
|
|
246
|
+
throw new MyApiError('invalid_json_response', response.status, `${method} ${url} returned non-JSON (status ${response.status}): ${snippet}\n${diagnoseNonJson(response.status, raw)}`);
|
|
217
247
|
}
|
|
218
248
|
if (!response.ok) {
|
|
219
249
|
throw toError(result?.error, response.status);
|
package/dist/container.d.ts
CHANGED
|
@@ -69,3 +69,6 @@ export interface DomainBinding {
|
|
|
69
69
|
}
|
|
70
70
|
export declare function bindDomain(apiKey: string, orgId: string, containerId: string, domain: string): Promise<DomainBinding>;
|
|
71
71
|
export declare function unbindDomain(apiKey: string, orgId: string, containerId: string): Promise<void>;
|
|
72
|
+
export declare function buildLogs(apiKey: string, orgId: string, id: string, tail?: number): Promise<{
|
|
73
|
+
logs: string[];
|
|
74
|
+
}>;
|
package/dist/container.js
CHANGED
|
@@ -10,6 +10,7 @@ exports.deployContainerSource = deployContainerSource;
|
|
|
10
10
|
exports.getContainerLogs = getContainerLogs;
|
|
11
11
|
exports.bindDomain = bindDomain;
|
|
12
12
|
exports.unbindDomain = unbindDomain;
|
|
13
|
+
exports.buildLogs = buildLogs;
|
|
13
14
|
const client_1 = require("./client");
|
|
14
15
|
const config_1 = require("./config");
|
|
15
16
|
// Backend: my-container-api per myapi-hq/internal/routes/container/. Phase 1
|
|
@@ -24,6 +25,7 @@ exports.EXPOSES = [
|
|
|
24
25
|
'GET /container/orgs/{org_id}/containers/{id}/logs',
|
|
25
26
|
'POST /container/orgs/{org_id}/containers/{id}/domain',
|
|
26
27
|
'DELETE /container/orgs/{org_id}/containers/{id}/domain',
|
|
28
|
+
'GET /container/orgs/{org_id}/containers/{id}/build-logs',
|
|
27
29
|
];
|
|
28
30
|
async function createContainer(apiKey, orgId, payload) {
|
|
29
31
|
return (0, client_1.request)('POST', `${config_1.CONTAINER_BASE}/container/orgs/${encodeURIComponent(orgId)}/containers`, apiKey, payload);
|
|
@@ -86,3 +88,13 @@ async function bindDomain(apiKey, orgId, containerId, domain) {
|
|
|
86
88
|
async function unbindDomain(apiKey, orgId, containerId) {
|
|
87
89
|
return (0, client_1.request)('DELETE', domainUrl(orgId, containerId), apiKey);
|
|
88
90
|
}
|
|
91
|
+
// Build logs for the most recent source build, oldest first.
|
|
92
|
+
//
|
|
93
|
+
// Distinct from `logs`, which is the running container's stream and — as a
|
|
94
|
+
// user reported — interleaves multi-kilobyte platform audit records with your
|
|
95
|
+
// own output. When a `deploy --source` fails, this is the endpoint that says
|
|
96
|
+
// why, without the noise.
|
|
97
|
+
async function buildLogs(apiKey, orgId, id, tail) {
|
|
98
|
+
const q = tail !== undefined ? `?tail=${encodeURIComponent(String(tail))}` : '';
|
|
99
|
+
return (0, client_1.request)('GET', `${config_1.CONTAINER_BASE}/container/orgs/${encodeURIComponent(orgId)}/containers/${encodeURIComponent(id)}/build-logs${q}`, apiKey);
|
|
100
|
+
}
|
package/dist/email.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type RequestOptions } from './client';
|
|
1
2
|
import type { Exposes } from './exposes';
|
|
2
3
|
export declare const EXPOSES: Exposes;
|
|
3
4
|
export interface EmailMessage {
|
|
@@ -96,7 +97,7 @@ export declare function sendEmail(apiKey: string, payload: {
|
|
|
96
97
|
text?: string;
|
|
97
98
|
template_id?: string;
|
|
98
99
|
template_vars?: Record<string, string>;
|
|
99
|
-
}): Promise<{
|
|
100
|
+
}, opts?: RequestOptions): Promise<{
|
|
100
101
|
message_id: string;
|
|
101
102
|
}>;
|
|
102
103
|
export declare function getEmailStatus(apiKey: string, messageId: string): Promise<{
|
package/dist/email.js
CHANGED
|
@@ -124,8 +124,10 @@ async function deleteForwarding(apiKey, address) {
|
|
|
124
124
|
return (0, client_1.request)('DELETE', `${config_1.EMAIL_BASE}/email/mailboxes/${encodeURIComponent(address)}/forwarding`, apiKey);
|
|
125
125
|
}
|
|
126
126
|
// ── Sending and reading (account-scoped) ─────────────────────────────────────
|
|
127
|
-
async function sendEmail(apiKey, payload) {
|
|
128
|
-
|
|
127
|
+
async function sendEmail(apiKey, payload, opts) {
|
|
128
|
+
// Retryable: deduplicated on Idempotency-Key, so a retry after a timeout
|
|
129
|
+
// replays rather than sending the recipient a second copy.
|
|
130
|
+
return (0, client_1.request)('POST', `${config_1.EMAIL_BASE}/email/send`, apiKey, payload, undefined, { retryUnsafe: true, ...opts });
|
|
129
131
|
}
|
|
130
132
|
async function getEmailStatus(apiKey, messageId) {
|
|
131
133
|
return (0, client_1.request)('GET', `${config_1.EMAIL_BASE}/email/status/${encodeURIComponent(messageId)}`, apiKey);
|
package/dist/hq.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type RequestOptions } from './client';
|
|
1
2
|
import type { Exposes } from './exposes';
|
|
2
3
|
export declare const EXPOSES: Exposes;
|
|
3
4
|
export interface Org {
|
|
@@ -58,6 +59,8 @@ export interface ApiKey {
|
|
|
58
59
|
spend_cap_period: string;
|
|
59
60
|
current_period_spend_cents?: number;
|
|
60
61
|
api_key?: string;
|
|
62
|
+
created_at?: string;
|
|
63
|
+
last_used_at?: string | null;
|
|
61
64
|
}
|
|
62
65
|
export declare function createAnonymousAccount(): Promise<AuthResult & {
|
|
63
66
|
subdomain_url: string;
|
|
@@ -135,7 +138,7 @@ export declare function getBillingUsage(apiKey: string, period?: 'month' | '30d'
|
|
|
135
138
|
export declare function setupPayment(apiKey: string): Promise<{
|
|
136
139
|
url: string;
|
|
137
140
|
}>;
|
|
138
|
-
export declare function topUp(apiKey: string, amountDollars: number): Promise<{
|
|
141
|
+
export declare function topUp(apiKey: string, amountDollars: number, opts?: RequestOptions): Promise<{
|
|
139
142
|
new_balance_display: string;
|
|
140
143
|
}>;
|
|
141
144
|
export type RechargeStatus = 'succeeded' | 'failed' | 'capped' | 'no_pm' | 'pending';
|
|
@@ -192,3 +195,4 @@ export interface DoctorReport {
|
|
|
192
195
|
};
|
|
193
196
|
}
|
|
194
197
|
export declare function getDoctor(apiKey: string, orgId: string): Promise<DoctorReport>;
|
|
198
|
+
export declare function setAccountDefaultOrg(apiKey: string, orgId: string | null): Promise<void>;
|
package/dist/hq.js
CHANGED
|
@@ -31,9 +31,11 @@ exports.getAutoRecharge = getAutoRecharge;
|
|
|
31
31
|
exports.setAutoRecharge = setAutoRecharge;
|
|
32
32
|
exports.disableAutoRecharge = disableAutoRecharge;
|
|
33
33
|
exports.getDoctor = getDoctor;
|
|
34
|
+
exports.setAccountDefaultOrg = setAccountDefaultOrg;
|
|
34
35
|
const client_1 = require("./client");
|
|
35
36
|
const config_1 = require("./config");
|
|
36
37
|
exports.EXPOSES = [
|
|
38
|
+
'PATCH /hq/account/default-org',
|
|
37
39
|
'POST /hq/account/anonymous',
|
|
38
40
|
'POST /hq/account/send-code',
|
|
39
41
|
'POST /hq/account/verify-code',
|
|
@@ -173,8 +175,10 @@ async function getBillingUsage(apiKey, period) {
|
|
|
173
175
|
async function setupPayment(apiKey) {
|
|
174
176
|
return (0, client_1.request)('POST', `${config_1.HQ_BASE}/hq/billing/setup-payment`, apiKey);
|
|
175
177
|
}
|
|
176
|
-
async function topUp(apiKey, amountDollars) {
|
|
177
|
-
|
|
178
|
+
async function topUp(apiKey, amountDollars, opts) {
|
|
179
|
+
// Retryable: the backend deduplicates on Idempotency-Key (24h), so a retry
|
|
180
|
+
// after a timeout replays the original rather than topping up twice.
|
|
181
|
+
return (0, client_1.request)('POST', `${config_1.HQ_BASE}/hq/billing/topup`, apiKey, { amount_dollars: amountDollars }, undefined, { retryUnsafe: true, ...opts });
|
|
178
182
|
}
|
|
179
183
|
async function getAutoRecharge(apiKey) {
|
|
180
184
|
return (0, client_1.request)('GET', `${config_1.HQ_BASE}/hq/billing/auto-recharge`, apiKey);
|
|
@@ -194,3 +198,9 @@ async function disableAutoRecharge(apiKey) {
|
|
|
194
198
|
async function getDoctor(apiKey, orgId) {
|
|
195
199
|
return (0, client_1.request)('GET', `${config_1.HQ_BASE}/hq/orgs/${encodeURIComponent(orgId)}/doctor`, apiKey);
|
|
196
200
|
}
|
|
201
|
+
// Pin the org that `login` hands back as default_org — sticky across sessions
|
|
202
|
+
// AND machines, unlike the local default in ~/.myapi/config.json. Pass null to
|
|
203
|
+
// clear it and revert to "most recently created".
|
|
204
|
+
async function setAccountDefaultOrg(apiKey, orgId) {
|
|
205
|
+
return (0, client_1.request)('PATCH', `${config_1.HQ_BASE}/hq/account/default-org`, apiKey, { org_id: orgId });
|
|
206
|
+
}
|
package/dist/payments.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type RequestOptions } from './client';
|
|
1
2
|
import type { Exposes } from './exposes';
|
|
2
3
|
export declare const EXPOSES: Exposes;
|
|
3
4
|
export interface ConnectStatus {
|
|
@@ -36,7 +37,7 @@ export interface CreateChargePayload {
|
|
|
36
37
|
}
|
|
37
38
|
export declare function connect(apiKey: string, orgId: string, stripeSecretKey: string, tier?: 't0' | 't1'): Promise<ConnectStatus>;
|
|
38
39
|
export declare function getConnect(apiKey: string, orgId: string): Promise<ConnectStatus>;
|
|
39
|
-
export declare function createCharge(apiKey: string, orgId: string, payload: CreateChargePayload): Promise<CreateChargeResponse>;
|
|
40
|
+
export declare function createCharge(apiKey: string, orgId: string, payload: CreateChargePayload, opts?: RequestOptions): Promise<CreateChargeResponse>;
|
|
40
41
|
export declare function listCharges(apiKey: string, orgId: string): Promise<Charge[]>;
|
|
41
42
|
export declare function getCharge(apiKey: string, orgId: string, chargeId: string): Promise<Charge>;
|
|
42
43
|
export declare function refundCharge(apiKey: string, orgId: string, chargeId: string): Promise<{
|
package/dist/payments.js
CHANGED
|
@@ -39,8 +39,10 @@ async function getConnect(apiKey, orgId) {
|
|
|
39
39
|
}
|
|
40
40
|
// createCharge opens a Stripe Checkout Session on the org's connected
|
|
41
41
|
// account. `every` makes it a subscription; otherwise a one-off payment.
|
|
42
|
-
async function createCharge(apiKey, orgId, payload) {
|
|
43
|
-
|
|
42
|
+
async function createCharge(apiKey, orgId, payload, opts) {
|
|
43
|
+
// Retryable: deduplicated on Idempotency-Key, so a retried charge cannot
|
|
44
|
+
// double-charge — it replays the original response.
|
|
45
|
+
return (0, client_1.request)('POST', `${config_1.PAYMENTS_BASE}/payments/orgs/${encodeURIComponent(orgId)}/charges`, apiKey, payload, undefined, { retryUnsafe: true, ...opts });
|
|
44
46
|
}
|
|
45
47
|
async function listCharges(apiKey, orgId) {
|
|
46
48
|
return (0, client_1.request)('GET', `${config_1.PAYMENTS_BASE}/payments/orgs/${encodeURIComponent(orgId)}/charges`, apiKey);
|
package/dist/pixel.d.ts
CHANGED
|
@@ -66,3 +66,7 @@ export declare function getIdentity(apiKey: string, orgId: string, pixelId: stri
|
|
|
66
66
|
latency_ms: number;
|
|
67
67
|
}>;
|
|
68
68
|
export declare function getGeoSample(apiKey: string, orgId: string): Promise<Record<string, unknown>>;
|
|
69
|
+
export declare function identify(apiKey: string, orgId: string, pixelId: string, who: {
|
|
70
|
+
email?: string;
|
|
71
|
+
externalId?: string;
|
|
72
|
+
}): Promise<Record<string, unknown>>;
|
package/dist/pixel.js
CHANGED
|
@@ -6,9 +6,11 @@ exports.getVisits = getVisits;
|
|
|
6
6
|
exports.getEvents = getEvents;
|
|
7
7
|
exports.getIdentity = getIdentity;
|
|
8
8
|
exports.getGeoSample = getGeoSample;
|
|
9
|
+
exports.identify = identify;
|
|
9
10
|
const client_1 = require("./client");
|
|
10
11
|
const config_1 = require("./config");
|
|
11
12
|
exports.EXPOSES = [
|
|
13
|
+
'POST /pixel/orgs/{org_id}/identify',
|
|
12
14
|
'GET /pixel/orgs/{org_id}/interactions',
|
|
13
15
|
'GET /pixel/orgs/{org_id}/visits',
|
|
14
16
|
'GET /pixel/orgs/{org_id}/events',
|
|
@@ -59,3 +61,16 @@ async function getIdentity(apiKey, orgId, pixelId, website) {
|
|
|
59
61
|
async function getGeoSample(apiKey, orgId) {
|
|
60
62
|
return (0, client_1.request)('GET', `${config_1.PIXEL_BASE}/pixel/orgs/${encodeURIComponent(orgId)}/audience/get_geo_sample`, apiKey);
|
|
61
63
|
}
|
|
64
|
+
// Link a known identity to an anonymous pixel visitor.
|
|
65
|
+
//
|
|
66
|
+
// The write half of identity resolution: call it on form submit or straight
|
|
67
|
+
// after sign-in and the visitor's whole prior anonymous graph resolves to that
|
|
68
|
+
// person. Without it, `pixel identity` can only ever report anonymous nodes.
|
|
69
|
+
async function identify(apiKey, orgId, pixelId, who) {
|
|
70
|
+
const body = { pixel_id: pixelId };
|
|
71
|
+
if (who.email)
|
|
72
|
+
body.email = who.email;
|
|
73
|
+
if (who.externalId)
|
|
74
|
+
body.external_id = who.externalId;
|
|
75
|
+
return (0, client_1.request)('POST', `${config_1.PIXEL_BASE}/pixel/orgs/${encodeURIComponent(orgId)}/identify`, apiKey, body);
|
|
76
|
+
}
|
package/dist/storage.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export interface Asset {
|
|
|
8
8
|
}
|
|
9
9
|
export declare function ingestAsset(apiKey: string, orgId: string, url: string, name?: string): Promise<Asset>;
|
|
10
10
|
export type UploadContentType = 'image/jpeg' | 'image/png' | 'image/gif' | 'image/webp' | 'image/svg+xml' | 'application/pdf' | 'video/mp4' | 'video/webm';
|
|
11
|
-
export
|
|
11
|
+
export type UploadContentTypeInput = UploadContentType | (string & {});
|
|
12
|
+
export declare function uploadAsset(apiKey: string, orgId: string, file: Blob | Buffer, contentType: UploadContentTypeInput, name?: string): Promise<Asset>;
|
|
12
13
|
export declare function listAssets(apiKey: string, orgId: string): Promise<Asset[]>;
|
|
13
14
|
export declare function deleteAsset(apiKey: string, orgId: string, assetId: string): Promise<void>;
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const SDK_VERSION = "2.
|
|
1
|
+
export declare const SDK_VERSION = "2.5.0";
|
package/dist/version.js
CHANGED
|
@@ -8,4 +8,4 @@ exports.SDK_VERSION = void 0;
|
|
|
8
8
|
// Why a constant and not a package.json read: the SDK runs inside edge
|
|
9
9
|
// functions (Cloudflare Workers), so it must not import node:fs. A literal
|
|
10
10
|
// is the only version source that works in every runtime we ship to.
|
|
11
|
-
exports.SDK_VERSION = '2.
|
|
11
|
+
exports.SDK_VERSION = '2.5.0';
|
package/dist/webhook.d.ts
CHANGED
|
@@ -20,6 +20,19 @@ export interface Delivery {
|
|
|
20
20
|
last_forward_at?: string;
|
|
21
21
|
last_forward_error?: string;
|
|
22
22
|
}
|
|
23
|
+
export interface ListDeliveriesOptions {
|
|
24
|
+
/** Restrict to one endpoint. An id the org doesn't own is a 404, not an empty page. */
|
|
25
|
+
endpointId?: string;
|
|
26
|
+
/** 1-200, default 50 server-side. */
|
|
27
|
+
limit?: number;
|
|
28
|
+
/** `next_cursor` from the previous page. An unknown cursor is a 400, never a silent restart. */
|
|
29
|
+
cursor?: string;
|
|
30
|
+
}
|
|
31
|
+
export interface DeliveriesPage {
|
|
32
|
+
deliveries: Delivery[];
|
|
33
|
+
next_cursor?: string;
|
|
34
|
+
has_more?: boolean;
|
|
35
|
+
}
|
|
23
36
|
export interface CreateEndpointOptions {
|
|
24
37
|
description?: string;
|
|
25
38
|
crm_email_path?: string;
|
|
@@ -36,3 +49,4 @@ export declare function updateEndpoint(apiKey: string, orgId: string, endpointId
|
|
|
36
49
|
export declare function listEndpoints(apiKey: string, orgId: string): Promise<WebhookEndpoint[]>;
|
|
37
50
|
export declare function deleteEndpoint(apiKey: string, orgId: string, endpointId: string): Promise<void>;
|
|
38
51
|
export declare function getDelivery(apiKey: string, orgId: string, deliveryId: string): Promise<Delivery>;
|
|
52
|
+
export declare function listDeliveries(apiKey: string, orgId: string, opts?: ListDeliveriesOptions): Promise<DeliveriesPage>;
|
package/dist/webhook.js
CHANGED
|
@@ -6,6 +6,7 @@ exports.updateEndpoint = updateEndpoint;
|
|
|
6
6
|
exports.listEndpoints = listEndpoints;
|
|
7
7
|
exports.deleteEndpoint = deleteEndpoint;
|
|
8
8
|
exports.getDelivery = getDelivery;
|
|
9
|
+
exports.listDeliveries = listDeliveries;
|
|
9
10
|
const client_1 = require("./client");
|
|
10
11
|
const config_1 = require("./config");
|
|
11
12
|
exports.EXPOSES = [
|
|
@@ -14,6 +15,7 @@ exports.EXPOSES = [
|
|
|
14
15
|
'PATCH /webhook/orgs/{org_id}/endpoints/{endpoint_id}',
|
|
15
16
|
'DELETE /webhook/orgs/{org_id}/endpoints/{endpoint_id}',
|
|
16
17
|
'GET /webhook/orgs/{org_id}/deliveries/{delivery_id}',
|
|
18
|
+
'GET /webhook/orgs/{org_id}/deliveries',
|
|
17
19
|
];
|
|
18
20
|
async function createEndpoint(apiKey, orgId, name, opts = {}) {
|
|
19
21
|
const body = { name };
|
|
@@ -37,3 +39,28 @@ async function deleteEndpoint(apiKey, orgId, endpointId) {
|
|
|
37
39
|
async function getDelivery(apiKey, orgId, deliveryId) {
|
|
38
40
|
return (0, client_1.request)('GET', `${config_1.WEBHOOK_BASE}/webhook/orgs/${encodeURIComponent(orgId)}/deliveries/${encodeURIComponent(deliveryId)}`, apiKey);
|
|
39
41
|
}
|
|
42
|
+
// listDeliveries — the deliveries an endpoint has received, newest first.
|
|
43
|
+
//
|
|
44
|
+
// This closes the gap that made webhooks unreadable to the agent that built
|
|
45
|
+
// them: `getDelivery` needs an id, and that id is only ever returned to
|
|
46
|
+
// whoever POSTed — for a funnel form, the visitor's browser. Without a list,
|
|
47
|
+
// an agent could not see the submissions its own form collected.
|
|
48
|
+
//
|
|
49
|
+
// Keyset-paginated (backend `envelope.WrapPage`), so use requestPage to keep
|
|
50
|
+
// the cursor. Two backend behaviours worth knowing: an endpoint_id the org
|
|
51
|
+
// doesn't own is a 404 rather than an empty page (an empty 200 would confirm
|
|
52
|
+
// the id exists to someone guessing), and an unknown cursor is a 400 rather
|
|
53
|
+
// than a silent restart from the top (a polling agent handed "start over"
|
|
54
|
+
// would reprocess every lead it had already handled).
|
|
55
|
+
async function listDeliveries(apiKey, orgId, opts = {}) {
|
|
56
|
+
const qs = new URLSearchParams();
|
|
57
|
+
if (opts.endpointId)
|
|
58
|
+
qs.set('endpoint_id', opts.endpointId);
|
|
59
|
+
if (opts.limit !== undefined)
|
|
60
|
+
qs.set('limit', String(opts.limit));
|
|
61
|
+
if (opts.cursor)
|
|
62
|
+
qs.set('cursor', opts.cursor);
|
|
63
|
+
const query = qs.toString() ? `?${qs.toString()}` : '';
|
|
64
|
+
const page = await (0, client_1.requestPage)('GET', `${config_1.WEBHOOK_BASE}/webhook/orgs/${encodeURIComponent(orgId)}/deliveries${query}`, apiKey);
|
|
65
|
+
return { deliveries: page.data, next_cursor: page.next_cursor, has_more: page.has_more };
|
|
66
|
+
}
|