@cynco/sdk 0.1.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/CHANGELOG.md +20 -0
- package/LICENSE +21 -0
- package/README.md +410 -0
- package/dist/index.cjs +1222 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1169 -0
- package/dist/index.d.ts +1169 -0
- package/dist/index.js +1193 -0
- package/dist/index.js.map +1 -0
- package/package.json +65 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1193 @@
|
|
|
1
|
+
import { randomUUID, createHmac, timingSafeEqual } from 'crypto';
|
|
2
|
+
|
|
3
|
+
// src/client.ts
|
|
4
|
+
|
|
5
|
+
// src/errors.ts
|
|
6
|
+
var CyncoError = class extends Error {
|
|
7
|
+
/** Machine-readable error code from the API (e.g. "validation_error"). */
|
|
8
|
+
code;
|
|
9
|
+
/** HTTP status code returned by the API. */
|
|
10
|
+
status;
|
|
11
|
+
/** Unique request identifier for support troubleshooting. */
|
|
12
|
+
requestId;
|
|
13
|
+
/** Field-level validation details, present on 422 responses. */
|
|
14
|
+
details;
|
|
15
|
+
/** Raw response metadata from the API. */
|
|
16
|
+
meta;
|
|
17
|
+
constructor(message, options) {
|
|
18
|
+
super(message);
|
|
19
|
+
this.name = "CyncoError";
|
|
20
|
+
this.code = options.code;
|
|
21
|
+
this.status = options.status;
|
|
22
|
+
this.requestId = options.requestId;
|
|
23
|
+
this.details = options.details;
|
|
24
|
+
this.meta = options.meta;
|
|
25
|
+
if (Error.captureStackTrace) {
|
|
26
|
+
Error.captureStackTrace(this, this.constructor);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
var AuthenticationError = class extends CyncoError {
|
|
31
|
+
constructor(message, options) {
|
|
32
|
+
super(message, options);
|
|
33
|
+
this.name = "AuthenticationError";
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
var PermissionError = class extends CyncoError {
|
|
37
|
+
constructor(message, options) {
|
|
38
|
+
super(message, options);
|
|
39
|
+
this.name = "PermissionError";
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
var NotFoundError = class extends CyncoError {
|
|
43
|
+
constructor(message, options) {
|
|
44
|
+
super(message, options);
|
|
45
|
+
this.name = "NotFoundError";
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
var ConflictError = class extends CyncoError {
|
|
49
|
+
constructor(message, options) {
|
|
50
|
+
super(message, options);
|
|
51
|
+
this.name = "ConflictError";
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
var ValidationError = class extends CyncoError {
|
|
55
|
+
constructor(message, options) {
|
|
56
|
+
super(message, options);
|
|
57
|
+
this.name = "ValidationError";
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
var RateLimitError = class extends CyncoError {
|
|
61
|
+
/** Unix timestamp (seconds) when the rate limit resets. */
|
|
62
|
+
retryAfter;
|
|
63
|
+
constructor(message, options) {
|
|
64
|
+
super(message, options);
|
|
65
|
+
this.name = "RateLimitError";
|
|
66
|
+
this.retryAfter = options.retryAfter;
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
var InternalError = class extends CyncoError {
|
|
70
|
+
constructor(message, options) {
|
|
71
|
+
super(message, options);
|
|
72
|
+
this.name = "InternalError";
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
var TimeoutError = class extends CyncoError {
|
|
76
|
+
constructor(requestId, timeoutMs) {
|
|
77
|
+
super(`Request timed out after ${timeoutMs}ms`, {
|
|
78
|
+
code: "timeout",
|
|
79
|
+
status: 0,
|
|
80
|
+
requestId
|
|
81
|
+
});
|
|
82
|
+
this.name = "TimeoutError";
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
var ConnectionError = class extends CyncoError {
|
|
86
|
+
constructor(requestId, cause) {
|
|
87
|
+
super(`Connection failed: ${cause.message}`, {
|
|
88
|
+
code: "connection_error",
|
|
89
|
+
status: 0,
|
|
90
|
+
requestId
|
|
91
|
+
});
|
|
92
|
+
this.name = "ConnectionError";
|
|
93
|
+
this.cause = cause;
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
// src/client.ts
|
|
98
|
+
var DEFAULT_BASE_URL = "https://app.cynco.io/api/v1";
|
|
99
|
+
var DEFAULT_TIMEOUT = 3e4;
|
|
100
|
+
var DEFAULT_MAX_RETRIES = 3;
|
|
101
|
+
var SDK_VERSION = "0.1.0";
|
|
102
|
+
var USER_AGENT = `cynco-node/${SDK_VERSION}`;
|
|
103
|
+
var RETRYABLE_METHODS = /* @__PURE__ */ new Set(["GET", "HEAD", "OPTIONS", "DELETE"]);
|
|
104
|
+
var RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([408, 429, 500, 502, 503, 504]);
|
|
105
|
+
var CyncoClient = class {
|
|
106
|
+
_apiKey;
|
|
107
|
+
baseUrl;
|
|
108
|
+
_timeout;
|
|
109
|
+
_maxRetries;
|
|
110
|
+
_fetch;
|
|
111
|
+
constructor(apiKey, options = {}) {
|
|
112
|
+
if (!apiKey) {
|
|
113
|
+
throw new Error(
|
|
114
|
+
'An API key is required. Pass it as the first argument: new Cynco("cak_...")'
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
if (!apiKey.startsWith("cak_")) {
|
|
118
|
+
throw new Error(
|
|
119
|
+
'Invalid API key format. Cynco API keys start with "cak_".'
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
this._apiKey = apiKey;
|
|
123
|
+
this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
124
|
+
this._timeout = options.timeout ?? DEFAULT_TIMEOUT;
|
|
125
|
+
this._maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
126
|
+
this._fetch = options.fetch ?? globalThis.fetch;
|
|
127
|
+
}
|
|
128
|
+
// ---------------------------------------------------------------------------
|
|
129
|
+
// Public request methods
|
|
130
|
+
// ---------------------------------------------------------------------------
|
|
131
|
+
async get(path, params, options) {
|
|
132
|
+
const url = this._buildUrl(path, params);
|
|
133
|
+
return this._request("GET", url, void 0, options);
|
|
134
|
+
}
|
|
135
|
+
async getList(path, params, options) {
|
|
136
|
+
const url = this._buildUrl(path, params);
|
|
137
|
+
return this._request("GET", url, void 0, options);
|
|
138
|
+
}
|
|
139
|
+
async post(path, body, options) {
|
|
140
|
+
const url = this._buildUrl(path);
|
|
141
|
+
return this._request("POST", url, body, options);
|
|
142
|
+
}
|
|
143
|
+
async patch(path, body, options) {
|
|
144
|
+
const url = this._buildUrl(path);
|
|
145
|
+
return this._request("PATCH", url, body, options);
|
|
146
|
+
}
|
|
147
|
+
async put(path, body, options) {
|
|
148
|
+
const url = this._buildUrl(path);
|
|
149
|
+
return this._request("PUT", url, body, options);
|
|
150
|
+
}
|
|
151
|
+
async delete(path, options) {
|
|
152
|
+
const url = this._buildUrl(path);
|
|
153
|
+
return this._request("DELETE", url, void 0, options);
|
|
154
|
+
}
|
|
155
|
+
// ---------------------------------------------------------------------------
|
|
156
|
+
// Internal
|
|
157
|
+
// ---------------------------------------------------------------------------
|
|
158
|
+
_buildUrl(path, params) {
|
|
159
|
+
const url = new URL(`${this.baseUrl}${path}`);
|
|
160
|
+
if (params) {
|
|
161
|
+
for (const [key, value] of Object.entries(params)) {
|
|
162
|
+
if (value !== void 0 && value !== null) {
|
|
163
|
+
url.searchParams.set(key, String(value));
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return url.toString();
|
|
168
|
+
}
|
|
169
|
+
async _request(method, url, body, options, attempt = 0) {
|
|
170
|
+
const requestId = randomUUID();
|
|
171
|
+
const headers = {
|
|
172
|
+
"Authorization": `Bearer ${this._apiKey}`,
|
|
173
|
+
"User-Agent": USER_AGENT,
|
|
174
|
+
"Accept": "application/json",
|
|
175
|
+
"X-Request-ID": requestId,
|
|
176
|
+
...options?.headers
|
|
177
|
+
};
|
|
178
|
+
if (body !== void 0) {
|
|
179
|
+
headers["Content-Type"] = "application/json";
|
|
180
|
+
}
|
|
181
|
+
if (options?.idempotencyKey) {
|
|
182
|
+
headers["Idempotency-Key"] = options.idempotencyKey;
|
|
183
|
+
}
|
|
184
|
+
const controller = new AbortController();
|
|
185
|
+
const timeoutId = setTimeout(() => controller.abort(), this._timeout);
|
|
186
|
+
const signal = options?.signal ? anySignal([options.signal, controller.signal]) : controller.signal;
|
|
187
|
+
try {
|
|
188
|
+
const response = await this._fetch(url, {
|
|
189
|
+
method,
|
|
190
|
+
headers,
|
|
191
|
+
body: body !== void 0 ? JSON.stringify(body) : void 0,
|
|
192
|
+
signal
|
|
193
|
+
});
|
|
194
|
+
clearTimeout(timeoutId);
|
|
195
|
+
const rateLimitInfo = this._parseRateLimitHeaders(response.headers);
|
|
196
|
+
if (response.ok) {
|
|
197
|
+
if (response.status === 204) {
|
|
198
|
+
return { success: true, data: void 0 };
|
|
199
|
+
}
|
|
200
|
+
const json = await response.json();
|
|
201
|
+
if (rateLimitInfo && typeof json === "object" && json !== null) {
|
|
202
|
+
const withMeta = json;
|
|
203
|
+
withMeta["meta"] = {
|
|
204
|
+
...withMeta["meta"],
|
|
205
|
+
requestId,
|
|
206
|
+
rateLimit: rateLimitInfo
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
return json;
|
|
210
|
+
}
|
|
211
|
+
if (this._shouldRetry(method, response.status, attempt, options)) {
|
|
212
|
+
const retryDelay = this._getRetryDelay(
|
|
213
|
+
attempt,
|
|
214
|
+
response.status,
|
|
215
|
+
response.headers
|
|
216
|
+
);
|
|
217
|
+
await sleep(retryDelay);
|
|
218
|
+
return this._request(method, url, body, options, attempt + 1);
|
|
219
|
+
}
|
|
220
|
+
const errorBody = await this._safeParseJson(response);
|
|
221
|
+
throw this._buildError(response.status, errorBody, requestId, rateLimitInfo);
|
|
222
|
+
} catch (error) {
|
|
223
|
+
clearTimeout(timeoutId);
|
|
224
|
+
if (error instanceof CyncoError) {
|
|
225
|
+
throw error;
|
|
226
|
+
}
|
|
227
|
+
if (error instanceof DOMException && error.name === "AbortError") {
|
|
228
|
+
if (options?.signal?.aborted) {
|
|
229
|
+
throw new CyncoError("Request was cancelled", {
|
|
230
|
+
code: "cancelled",
|
|
231
|
+
status: 0,
|
|
232
|
+
requestId
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
throw new TimeoutError(requestId, this._timeout);
|
|
236
|
+
}
|
|
237
|
+
if (this._shouldRetryOnNetworkError(method, attempt, options)) {
|
|
238
|
+
const retryDelay = this._getRetryDelay(attempt, 0, void 0);
|
|
239
|
+
await sleep(retryDelay);
|
|
240
|
+
return this._request(method, url, body, options, attempt + 1);
|
|
241
|
+
}
|
|
242
|
+
throw new ConnectionError(
|
|
243
|
+
requestId,
|
|
244
|
+
error instanceof Error ? error : new Error(String(error))
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
_shouldRetry(method, status, attempt, options) {
|
|
249
|
+
if (attempt >= this._maxRetries) return false;
|
|
250
|
+
if (!RETRYABLE_STATUS_CODES.has(status)) return false;
|
|
251
|
+
if (!RETRYABLE_METHODS.has(method) && !options?.idempotencyKey) {
|
|
252
|
+
return status === 429;
|
|
253
|
+
}
|
|
254
|
+
return true;
|
|
255
|
+
}
|
|
256
|
+
_shouldRetryOnNetworkError(method, attempt, options) {
|
|
257
|
+
if (attempt >= this._maxRetries) return false;
|
|
258
|
+
return RETRYABLE_METHODS.has(method) || !!options?.idempotencyKey;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Calculate retry delay with exponential backoff and jitter.
|
|
262
|
+
* For 429 responses, uses Retry-After header if present.
|
|
263
|
+
*/
|
|
264
|
+
_getRetryDelay(attempt, status, headers) {
|
|
265
|
+
if (status === 429 && headers) {
|
|
266
|
+
const retryAfter = headers.get("Retry-After");
|
|
267
|
+
if (retryAfter) {
|
|
268
|
+
const seconds = parseInt(retryAfter, 10);
|
|
269
|
+
if (!Number.isNaN(seconds)) {
|
|
270
|
+
return seconds * 1e3;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
const baseDelay = 500;
|
|
275
|
+
const exponentialDelay = baseDelay * Math.pow(2, attempt);
|
|
276
|
+
const jitter = Math.random() * baseDelay;
|
|
277
|
+
return Math.min(exponentialDelay + jitter, 3e4);
|
|
278
|
+
}
|
|
279
|
+
_parseRateLimitHeaders(headers) {
|
|
280
|
+
const limit = headers.get("X-RateLimit-Limit");
|
|
281
|
+
const remaining = headers.get("X-RateLimit-Remaining");
|
|
282
|
+
const reset = headers.get("X-RateLimit-Reset");
|
|
283
|
+
if (!limit || !remaining || !reset) return void 0;
|
|
284
|
+
return {
|
|
285
|
+
limit: parseInt(limit, 10),
|
|
286
|
+
remaining: parseInt(remaining, 10),
|
|
287
|
+
reset: parseInt(reset, 10)
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
async _safeParseJson(response) {
|
|
291
|
+
try {
|
|
292
|
+
return await response.json();
|
|
293
|
+
} catch {
|
|
294
|
+
return null;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
_buildError(status, body, requestId, rateLimitInfo) {
|
|
298
|
+
const code = body?.error?.code ?? "unknown_error";
|
|
299
|
+
const message = body?.error?.message ?? `Request failed with status ${status}`;
|
|
300
|
+
const details = body?.error?.details;
|
|
301
|
+
const meta = { ...body?.meta, requestId, rateLimit: rateLimitInfo };
|
|
302
|
+
switch (status) {
|
|
303
|
+
case 401:
|
|
304
|
+
return new AuthenticationError(message, {
|
|
305
|
+
code,
|
|
306
|
+
status,
|
|
307
|
+
requestId,
|
|
308
|
+
meta
|
|
309
|
+
});
|
|
310
|
+
case 403:
|
|
311
|
+
return new PermissionError(message, {
|
|
312
|
+
code,
|
|
313
|
+
status,
|
|
314
|
+
requestId,
|
|
315
|
+
meta
|
|
316
|
+
});
|
|
317
|
+
case 404:
|
|
318
|
+
return new NotFoundError(message, {
|
|
319
|
+
code,
|
|
320
|
+
status,
|
|
321
|
+
requestId,
|
|
322
|
+
meta
|
|
323
|
+
});
|
|
324
|
+
case 409:
|
|
325
|
+
return new ConflictError(message, {
|
|
326
|
+
code,
|
|
327
|
+
status,
|
|
328
|
+
requestId,
|
|
329
|
+
meta
|
|
330
|
+
});
|
|
331
|
+
case 422:
|
|
332
|
+
return new ValidationError(message, {
|
|
333
|
+
code,
|
|
334
|
+
status,
|
|
335
|
+
requestId,
|
|
336
|
+
details,
|
|
337
|
+
meta
|
|
338
|
+
});
|
|
339
|
+
case 429:
|
|
340
|
+
return new RateLimitError(message, {
|
|
341
|
+
code,
|
|
342
|
+
status,
|
|
343
|
+
requestId,
|
|
344
|
+
retryAfter: rateLimitInfo?.reset ?? 0,
|
|
345
|
+
meta
|
|
346
|
+
});
|
|
347
|
+
default:
|
|
348
|
+
if (status >= 500) {
|
|
349
|
+
return new InternalError(message, {
|
|
350
|
+
code,
|
|
351
|
+
status,
|
|
352
|
+
requestId,
|
|
353
|
+
meta
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
return new CyncoError(message, {
|
|
357
|
+
code,
|
|
358
|
+
status,
|
|
359
|
+
requestId,
|
|
360
|
+
details,
|
|
361
|
+
meta
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
};
|
|
366
|
+
function sleep(ms) {
|
|
367
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
368
|
+
}
|
|
369
|
+
function anySignal(signals) {
|
|
370
|
+
const controller = new AbortController();
|
|
371
|
+
for (const signal of signals) {
|
|
372
|
+
if (signal.aborted) {
|
|
373
|
+
controller.abort(signal.reason);
|
|
374
|
+
return controller.signal;
|
|
375
|
+
}
|
|
376
|
+
signal.addEventListener(
|
|
377
|
+
"abort",
|
|
378
|
+
() => controller.abort(signal.reason),
|
|
379
|
+
{ once: true }
|
|
380
|
+
);
|
|
381
|
+
}
|
|
382
|
+
return controller.signal;
|
|
383
|
+
}
|
|
384
|
+
var TIMESTAMP_TOLERANCE_SECONDS = 300;
|
|
385
|
+
var webhookVerifier = {
|
|
386
|
+
/**
|
|
387
|
+
* Verify a webhook signature.
|
|
388
|
+
*
|
|
389
|
+
* @param payload - The raw request body as a string.
|
|
390
|
+
* @param signature - The value of the `X-Webhook-Signature` header.
|
|
391
|
+
* @param timestamp - The value of the `X-Webhook-Timestamp` header.
|
|
392
|
+
* @param secret - Your webhook signing secret.
|
|
393
|
+
* @param options - Optional configuration.
|
|
394
|
+
* @returns `true` if the signature is valid and the timestamp is within tolerance.
|
|
395
|
+
*/
|
|
396
|
+
verify(payload, signature, timestamp, secret, options) {
|
|
397
|
+
const tolerance = options?.tolerance ?? TIMESTAMP_TOLERANCE_SECONDS;
|
|
398
|
+
const ts = parseInt(timestamp, 10);
|
|
399
|
+
if (Number.isNaN(ts)) {
|
|
400
|
+
return false;
|
|
401
|
+
}
|
|
402
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
403
|
+
if (Math.abs(now - ts) > tolerance) {
|
|
404
|
+
return false;
|
|
405
|
+
}
|
|
406
|
+
const signedContent = `${timestamp}.${payload}`;
|
|
407
|
+
const expectedSignature = createHmac("sha256", secret).update(signedContent).digest("hex");
|
|
408
|
+
const sigBuffer = Buffer.from(signature, "utf8");
|
|
409
|
+
const expectedBuffer = Buffer.from(expectedSignature, "utf8");
|
|
410
|
+
if (sigBuffer.length !== expectedBuffer.length) {
|
|
411
|
+
return false;
|
|
412
|
+
}
|
|
413
|
+
return timingSafeEqual(sigBuffer, expectedBuffer);
|
|
414
|
+
},
|
|
415
|
+
/**
|
|
416
|
+
* Verify a webhook signature, throwing an error if invalid.
|
|
417
|
+
*
|
|
418
|
+
* @throws {Error} If the signature is invalid or the timestamp is stale.
|
|
419
|
+
*/
|
|
420
|
+
verifyOrThrow(payload, signature, timestamp, secret, options) {
|
|
421
|
+
const tolerance = options?.tolerance ?? TIMESTAMP_TOLERANCE_SECONDS;
|
|
422
|
+
const ts = parseInt(timestamp, 10);
|
|
423
|
+
if (Number.isNaN(ts)) {
|
|
424
|
+
throw new Error("Invalid webhook timestamp");
|
|
425
|
+
}
|
|
426
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
427
|
+
if (Math.abs(now - ts) > tolerance) {
|
|
428
|
+
throw new Error(
|
|
429
|
+
`Webhook timestamp is too old (${Math.abs(now - ts)}s > ${tolerance}s tolerance)`
|
|
430
|
+
);
|
|
431
|
+
}
|
|
432
|
+
const signedContent = `${timestamp}.${payload}`;
|
|
433
|
+
const expectedSignature = createHmac("sha256", secret).update(signedContent).digest("hex");
|
|
434
|
+
const sigBuffer = Buffer.from(signature, "utf8");
|
|
435
|
+
const expectedBuffer = Buffer.from(expectedSignature, "utf8");
|
|
436
|
+
if (sigBuffer.length !== expectedBuffer.length || !timingSafeEqual(sigBuffer, expectedBuffer)) {
|
|
437
|
+
throw new Error("Invalid webhook signature");
|
|
438
|
+
}
|
|
439
|
+
},
|
|
440
|
+
/**
|
|
441
|
+
* Generate a signature for testing purposes.
|
|
442
|
+
*
|
|
443
|
+
* @param payload - The request body.
|
|
444
|
+
* @param secret - The webhook secret.
|
|
445
|
+
* @param timestamp - Unix timestamp in seconds (defaults to now).
|
|
446
|
+
* @returns An object with the signature and timestamp strings.
|
|
447
|
+
*/
|
|
448
|
+
sign(payload, secret, timestamp) {
|
|
449
|
+
const ts = timestamp ?? Math.floor(Date.now() / 1e3);
|
|
450
|
+
const signedContent = `${ts}.${payload}`;
|
|
451
|
+
const signature = createHmac("sha256", secret).update(signedContent).digest("hex");
|
|
452
|
+
return { signature, timestamp: String(ts) };
|
|
453
|
+
}
|
|
454
|
+
};
|
|
455
|
+
|
|
456
|
+
// src/pagination.ts
|
|
457
|
+
var Page = class _Page {
|
|
458
|
+
data;
|
|
459
|
+
pagination;
|
|
460
|
+
links;
|
|
461
|
+
meta;
|
|
462
|
+
_fetchPage;
|
|
463
|
+
_params;
|
|
464
|
+
constructor(response, fetchPage, params) {
|
|
465
|
+
this.data = response.data;
|
|
466
|
+
this.pagination = response.pagination;
|
|
467
|
+
this.links = response.links;
|
|
468
|
+
this.meta = response.meta;
|
|
469
|
+
this._fetchPage = fetchPage;
|
|
470
|
+
this._params = params;
|
|
471
|
+
}
|
|
472
|
+
/** Whether there are more pages after this one. */
|
|
473
|
+
get hasMore() {
|
|
474
|
+
return this.pagination.hasMore;
|
|
475
|
+
}
|
|
476
|
+
/** Fetch the next page. Returns null if there are no more pages. */
|
|
477
|
+
async nextPage() {
|
|
478
|
+
if (!this.hasMore) {
|
|
479
|
+
return null;
|
|
480
|
+
}
|
|
481
|
+
const nextOffset = this.pagination.offset + this.pagination.limit;
|
|
482
|
+
const nextParams = {
|
|
483
|
+
...this._params,
|
|
484
|
+
offset: nextOffset
|
|
485
|
+
};
|
|
486
|
+
const response = await this._fetchPage(nextParams);
|
|
487
|
+
return new _Page(response, this._fetchPage, nextParams);
|
|
488
|
+
}
|
|
489
|
+
/** Iterate over all items across all pages. */
|
|
490
|
+
async *[Symbol.asyncIterator]() {
|
|
491
|
+
let page = this;
|
|
492
|
+
while (page) {
|
|
493
|
+
for (const item of page.data) {
|
|
494
|
+
yield item;
|
|
495
|
+
}
|
|
496
|
+
page = await page.nextPage();
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
};
|
|
500
|
+
var CursorPage = class _CursorPage {
|
|
501
|
+
data;
|
|
502
|
+
pagination;
|
|
503
|
+
links;
|
|
504
|
+
meta;
|
|
505
|
+
_fetchPage;
|
|
506
|
+
_params;
|
|
507
|
+
constructor(response, fetchPage, params) {
|
|
508
|
+
this.data = response.data;
|
|
509
|
+
this.pagination = response.pagination;
|
|
510
|
+
this.links = response.links;
|
|
511
|
+
this.meta = response.meta;
|
|
512
|
+
this._fetchPage = fetchPage;
|
|
513
|
+
this._params = params;
|
|
514
|
+
}
|
|
515
|
+
get hasMore() {
|
|
516
|
+
return this.pagination.hasMore;
|
|
517
|
+
}
|
|
518
|
+
async nextPage() {
|
|
519
|
+
if (!this.hasMore || !this.pagination.nextCursor) {
|
|
520
|
+
return null;
|
|
521
|
+
}
|
|
522
|
+
const nextParams = {
|
|
523
|
+
...this._params,
|
|
524
|
+
cursor: this.pagination.nextCursor
|
|
525
|
+
};
|
|
526
|
+
const response = await this._fetchPage(nextParams);
|
|
527
|
+
return new _CursorPage(response, this._fetchPage, nextParams);
|
|
528
|
+
}
|
|
529
|
+
async *[Symbol.asyncIterator]() {
|
|
530
|
+
let page = this;
|
|
531
|
+
while (page) {
|
|
532
|
+
for (const item of page.data) {
|
|
533
|
+
yield item;
|
|
534
|
+
}
|
|
535
|
+
page = await page.nextPage();
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
};
|
|
539
|
+
|
|
540
|
+
// src/resources/invoices.ts
|
|
541
|
+
var Invoices = class {
|
|
542
|
+
constructor(_client) {
|
|
543
|
+
this._client = _client;
|
|
544
|
+
}
|
|
545
|
+
/**
|
|
546
|
+
* List invoices with pagination.
|
|
547
|
+
*
|
|
548
|
+
* Returns a `Page` that can be used as an async iterator for auto-pagination:
|
|
549
|
+
* ```ts
|
|
550
|
+
* for await (const invoice of cynco.invoices.list({ limit: 50 })) {
|
|
551
|
+
* console.log(invoice.id);
|
|
552
|
+
* }
|
|
553
|
+
* ```
|
|
554
|
+
*/
|
|
555
|
+
async list(params) {
|
|
556
|
+
const fetchPage = async (p) => {
|
|
557
|
+
return this._client.getList("/invoices", p);
|
|
558
|
+
};
|
|
559
|
+
const response = await fetchPage(params ?? {});
|
|
560
|
+
return new Page(response, fetchPage, params ?? {});
|
|
561
|
+
}
|
|
562
|
+
/** Retrieve a single invoice by ID. */
|
|
563
|
+
async retrieve(id) {
|
|
564
|
+
const response = await this._client.get(`/invoices/${id}`);
|
|
565
|
+
return response.data;
|
|
566
|
+
}
|
|
567
|
+
/** Create a new invoice. */
|
|
568
|
+
async create(data, options) {
|
|
569
|
+
const response = await this._client.post(
|
|
570
|
+
"/invoices",
|
|
571
|
+
data,
|
|
572
|
+
options
|
|
573
|
+
);
|
|
574
|
+
return response.data;
|
|
575
|
+
}
|
|
576
|
+
/** Update an existing invoice. */
|
|
577
|
+
async update(id, data, options) {
|
|
578
|
+
const response = await this._client.patch(
|
|
579
|
+
`/invoices/${id}`,
|
|
580
|
+
data,
|
|
581
|
+
options
|
|
582
|
+
);
|
|
583
|
+
return response.data;
|
|
584
|
+
}
|
|
585
|
+
/** Delete an invoice. Only draft invoices can be deleted. */
|
|
586
|
+
async delete(id, options) {
|
|
587
|
+
await this._client.delete(`/invoices/${id}`, options);
|
|
588
|
+
}
|
|
589
|
+
/** Send an invoice to the customer via email. */
|
|
590
|
+
async send(id, options) {
|
|
591
|
+
const response = await this._client.post(
|
|
592
|
+
`/invoices/${id}/send`,
|
|
593
|
+
void 0,
|
|
594
|
+
options
|
|
595
|
+
);
|
|
596
|
+
return response.data;
|
|
597
|
+
}
|
|
598
|
+
/** Mark an invoice as paid. */
|
|
599
|
+
async markPaid(id, data, options) {
|
|
600
|
+
const response = await this._client.post(
|
|
601
|
+
`/invoices/${id}/mark-paid`,
|
|
602
|
+
data,
|
|
603
|
+
options
|
|
604
|
+
);
|
|
605
|
+
return response.data;
|
|
606
|
+
}
|
|
607
|
+
/** Void an invoice. */
|
|
608
|
+
async void(id, options) {
|
|
609
|
+
const response = await this._client.post(
|
|
610
|
+
`/invoices/${id}/void`,
|
|
611
|
+
void 0,
|
|
612
|
+
options
|
|
613
|
+
);
|
|
614
|
+
return response.data;
|
|
615
|
+
}
|
|
616
|
+
/** Get the PDF download URL for an invoice. */
|
|
617
|
+
async getPdf(id) {
|
|
618
|
+
const response = await this._client.get(
|
|
619
|
+
`/invoices/${id}/pdf`
|
|
620
|
+
);
|
|
621
|
+
return response.data;
|
|
622
|
+
}
|
|
623
|
+
};
|
|
624
|
+
|
|
625
|
+
// src/resources/customers.ts
|
|
626
|
+
var Customers = class {
|
|
627
|
+
constructor(_client) {
|
|
628
|
+
this._client = _client;
|
|
629
|
+
}
|
|
630
|
+
/**
|
|
631
|
+
* List customers with pagination.
|
|
632
|
+
*
|
|
633
|
+
* ```ts
|
|
634
|
+
* for await (const customer of cynco.customers.list({ limit: 50 })) {
|
|
635
|
+
* console.log(customer.name);
|
|
636
|
+
* }
|
|
637
|
+
* ```
|
|
638
|
+
*/
|
|
639
|
+
async list(params) {
|
|
640
|
+
const fetchPage = async (p) => {
|
|
641
|
+
return this._client.getList(
|
|
642
|
+
"/customers",
|
|
643
|
+
p
|
|
644
|
+
);
|
|
645
|
+
};
|
|
646
|
+
const response = await fetchPage(params ?? {});
|
|
647
|
+
return new Page(response, fetchPage, params ?? {});
|
|
648
|
+
}
|
|
649
|
+
/** Retrieve a single customer by ID. */
|
|
650
|
+
async retrieve(id) {
|
|
651
|
+
const response = await this._client.get(`/customers/${id}`);
|
|
652
|
+
return response.data;
|
|
653
|
+
}
|
|
654
|
+
/** Create a new customer. */
|
|
655
|
+
async create(data, options) {
|
|
656
|
+
const response = await this._client.post(
|
|
657
|
+
"/customers",
|
|
658
|
+
data,
|
|
659
|
+
options
|
|
660
|
+
);
|
|
661
|
+
return response.data;
|
|
662
|
+
}
|
|
663
|
+
/** Update an existing customer. */
|
|
664
|
+
async update(id, data, options) {
|
|
665
|
+
const response = await this._client.patch(
|
|
666
|
+
`/customers/${id}`,
|
|
667
|
+
data,
|
|
668
|
+
options
|
|
669
|
+
);
|
|
670
|
+
return response.data;
|
|
671
|
+
}
|
|
672
|
+
/** Delete a customer. Only customers with no associated records can be deleted. */
|
|
673
|
+
async delete(id, options) {
|
|
674
|
+
await this._client.delete(`/customers/${id}`, options);
|
|
675
|
+
}
|
|
676
|
+
};
|
|
677
|
+
|
|
678
|
+
// src/resources/vendors.ts
|
|
679
|
+
var Vendors = class {
|
|
680
|
+
constructor(_client) {
|
|
681
|
+
this._client = _client;
|
|
682
|
+
}
|
|
683
|
+
/**
|
|
684
|
+
* List vendors with pagination.
|
|
685
|
+
*
|
|
686
|
+
* ```ts
|
|
687
|
+
* for await (const vendor of cynco.vendors.list({ limit: 50 })) {
|
|
688
|
+
* console.log(vendor.name);
|
|
689
|
+
* }
|
|
690
|
+
* ```
|
|
691
|
+
*/
|
|
692
|
+
async list(params) {
|
|
693
|
+
const fetchPage = async (p) => {
|
|
694
|
+
return this._client.getList(
|
|
695
|
+
"/vendors",
|
|
696
|
+
p
|
|
697
|
+
);
|
|
698
|
+
};
|
|
699
|
+
const response = await fetchPage(params ?? {});
|
|
700
|
+
return new Page(response, fetchPage, params ?? {});
|
|
701
|
+
}
|
|
702
|
+
/** Retrieve a single vendor by ID. */
|
|
703
|
+
async retrieve(id) {
|
|
704
|
+
const response = await this._client.get(`/vendors/${id}`);
|
|
705
|
+
return response.data;
|
|
706
|
+
}
|
|
707
|
+
/** Create a new vendor. */
|
|
708
|
+
async create(data, options) {
|
|
709
|
+
const response = await this._client.post(
|
|
710
|
+
"/vendors",
|
|
711
|
+
data,
|
|
712
|
+
options
|
|
713
|
+
);
|
|
714
|
+
return response.data;
|
|
715
|
+
}
|
|
716
|
+
/** Update an existing vendor. */
|
|
717
|
+
async update(id, data, options) {
|
|
718
|
+
const response = await this._client.patch(
|
|
719
|
+
`/vendors/${id}`,
|
|
720
|
+
data,
|
|
721
|
+
options
|
|
722
|
+
);
|
|
723
|
+
return response.data;
|
|
724
|
+
}
|
|
725
|
+
/** Delete a vendor. Only vendors with no associated records can be deleted. */
|
|
726
|
+
async delete(id, options) {
|
|
727
|
+
await this._client.delete(`/vendors/${id}`, options);
|
|
728
|
+
}
|
|
729
|
+
};
|
|
730
|
+
|
|
731
|
+
// src/resources/bills.ts
|
|
732
|
+
var Bills = class {
|
|
733
|
+
constructor(_client) {
|
|
734
|
+
this._client = _client;
|
|
735
|
+
}
|
|
736
|
+
/**
|
|
737
|
+
* List bills with pagination.
|
|
738
|
+
*
|
|
739
|
+
* ```ts
|
|
740
|
+
* for await (const bill of cynco.bills.list({ limit: 50 })) {
|
|
741
|
+
* console.log(bill.billNumber);
|
|
742
|
+
* }
|
|
743
|
+
* ```
|
|
744
|
+
*/
|
|
745
|
+
async list(params) {
|
|
746
|
+
const fetchPage = async (p) => {
|
|
747
|
+
return this._client.getList(
|
|
748
|
+
"/bills",
|
|
749
|
+
p
|
|
750
|
+
);
|
|
751
|
+
};
|
|
752
|
+
const response = await fetchPage(params ?? {});
|
|
753
|
+
return new Page(response, fetchPage, params ?? {});
|
|
754
|
+
}
|
|
755
|
+
/** Retrieve a single bill by ID. */
|
|
756
|
+
async retrieve(id) {
|
|
757
|
+
const response = await this._client.get(`/bills/${id}`);
|
|
758
|
+
return response.data;
|
|
759
|
+
}
|
|
760
|
+
/** Create a new bill. */
|
|
761
|
+
async create(data, options) {
|
|
762
|
+
const response = await this._client.post("/bills", data, options);
|
|
763
|
+
return response.data;
|
|
764
|
+
}
|
|
765
|
+
/** Update an existing bill. */
|
|
766
|
+
async update(id, data, options) {
|
|
767
|
+
const response = await this._client.patch(
|
|
768
|
+
`/bills/${id}`,
|
|
769
|
+
data,
|
|
770
|
+
options
|
|
771
|
+
);
|
|
772
|
+
return response.data;
|
|
773
|
+
}
|
|
774
|
+
/** Delete a bill. Only draft bills can be deleted. */
|
|
775
|
+
async delete(id, options) {
|
|
776
|
+
await this._client.delete(`/bills/${id}`, options);
|
|
777
|
+
}
|
|
778
|
+
/** Mark a bill as paid. */
|
|
779
|
+
async markPaid(id, data, options) {
|
|
780
|
+
const response = await this._client.post(
|
|
781
|
+
`/bills/${id}/mark-paid`,
|
|
782
|
+
data,
|
|
783
|
+
options
|
|
784
|
+
);
|
|
785
|
+
return response.data;
|
|
786
|
+
}
|
|
787
|
+
/** Void a bill. */
|
|
788
|
+
async void(id, options) {
|
|
789
|
+
const response = await this._client.post(
|
|
790
|
+
`/bills/${id}/void`,
|
|
791
|
+
void 0,
|
|
792
|
+
options
|
|
793
|
+
);
|
|
794
|
+
return response.data;
|
|
795
|
+
}
|
|
796
|
+
};
|
|
797
|
+
|
|
798
|
+
// src/resources/items.ts
|
|
799
|
+
var Items = class {
|
|
800
|
+
constructor(_client) {
|
|
801
|
+
this._client = _client;
|
|
802
|
+
}
|
|
803
|
+
/**
|
|
804
|
+
* List items (products and services) with pagination.
|
|
805
|
+
*
|
|
806
|
+
* ```ts
|
|
807
|
+
* for await (const item of cynco.items.list({ type: 'service' })) {
|
|
808
|
+
* console.log(item.name);
|
|
809
|
+
* }
|
|
810
|
+
* ```
|
|
811
|
+
*/
|
|
812
|
+
async list(params) {
|
|
813
|
+
const fetchPage = async (p) => {
|
|
814
|
+
return this._client.getList(
|
|
815
|
+
"/items",
|
|
816
|
+
p
|
|
817
|
+
);
|
|
818
|
+
};
|
|
819
|
+
const response = await fetchPage(params ?? {});
|
|
820
|
+
return new Page(response, fetchPage, params ?? {});
|
|
821
|
+
}
|
|
822
|
+
/** Retrieve a single item by ID. */
|
|
823
|
+
async retrieve(id) {
|
|
824
|
+
const response = await this._client.get(`/items/${id}`);
|
|
825
|
+
return response.data;
|
|
826
|
+
}
|
|
827
|
+
/** Create a new item. */
|
|
828
|
+
async create(data, options) {
|
|
829
|
+
const response = await this._client.post("/items", data, options);
|
|
830
|
+
return response.data;
|
|
831
|
+
}
|
|
832
|
+
/** Update an existing item. */
|
|
833
|
+
async update(id, data, options) {
|
|
834
|
+
const response = await this._client.patch(
|
|
835
|
+
`/items/${id}`,
|
|
836
|
+
data,
|
|
837
|
+
options
|
|
838
|
+
);
|
|
839
|
+
return response.data;
|
|
840
|
+
}
|
|
841
|
+
/** Delete an item. Items referenced by invoices or bills cannot be deleted. */
|
|
842
|
+
async delete(id, options) {
|
|
843
|
+
await this._client.delete(`/items/${id}`, options);
|
|
844
|
+
}
|
|
845
|
+
};
|
|
846
|
+
|
|
847
|
+
// src/resources/accounts.ts
|
|
848
|
+
var Accounts = class {
|
|
849
|
+
constructor(_client) {
|
|
850
|
+
this._client = _client;
|
|
851
|
+
}
|
|
852
|
+
/**
|
|
853
|
+
* List chart of accounts with pagination.
|
|
854
|
+
*
|
|
855
|
+
* ```ts
|
|
856
|
+
* for await (const account of cynco.accounts.list({ type: 'revenue' })) {
|
|
857
|
+
* console.log(`${account.code} — ${account.name}`);
|
|
858
|
+
* }
|
|
859
|
+
* ```
|
|
860
|
+
*/
|
|
861
|
+
async list(params) {
|
|
862
|
+
const fetchPage = async (p) => {
|
|
863
|
+
return this._client.getList(
|
|
864
|
+
"/accounts",
|
|
865
|
+
p
|
|
866
|
+
);
|
|
867
|
+
};
|
|
868
|
+
const response = await fetchPage(params ?? {});
|
|
869
|
+
return new Page(response, fetchPage, params ?? {});
|
|
870
|
+
}
|
|
871
|
+
/** Retrieve a single account by ID. */
|
|
872
|
+
async retrieve(id) {
|
|
873
|
+
const response = await this._client.get(`/accounts/${id}`);
|
|
874
|
+
return response.data;
|
|
875
|
+
}
|
|
876
|
+
/** Create a new account. */
|
|
877
|
+
async create(data, options) {
|
|
878
|
+
const response = await this._client.post(
|
|
879
|
+
"/accounts",
|
|
880
|
+
data,
|
|
881
|
+
options
|
|
882
|
+
);
|
|
883
|
+
return response.data;
|
|
884
|
+
}
|
|
885
|
+
/** Update an existing account. */
|
|
886
|
+
async update(id, data, options) {
|
|
887
|
+
const response = await this._client.patch(
|
|
888
|
+
`/accounts/${id}`,
|
|
889
|
+
data,
|
|
890
|
+
options
|
|
891
|
+
);
|
|
892
|
+
return response.data;
|
|
893
|
+
}
|
|
894
|
+
/** Delete an account. Only unused accounts can be deleted. */
|
|
895
|
+
async delete(id, options) {
|
|
896
|
+
await this._client.delete(`/accounts/${id}`, options);
|
|
897
|
+
}
|
|
898
|
+
};
|
|
899
|
+
|
|
900
|
+
// src/resources/journal-entries.ts
|
|
901
|
+
var JournalEntries = class {
|
|
902
|
+
constructor(_client) {
|
|
903
|
+
this._client = _client;
|
|
904
|
+
}
|
|
905
|
+
/**
|
|
906
|
+
* List journal entries with pagination.
|
|
907
|
+
*
|
|
908
|
+
* ```ts
|
|
909
|
+
* for await (const entry of cynco.journalEntries.list({ status: 'posted' })) {
|
|
910
|
+
* console.log(entry.entryNumber);
|
|
911
|
+
* }
|
|
912
|
+
* ```
|
|
913
|
+
*/
|
|
914
|
+
async list(params) {
|
|
915
|
+
const fetchPage = async (p) => {
|
|
916
|
+
return this._client.getList(
|
|
917
|
+
"/journal-entries",
|
|
918
|
+
p
|
|
919
|
+
);
|
|
920
|
+
};
|
|
921
|
+
const response = await fetchPage(params ?? {});
|
|
922
|
+
return new Page(response, fetchPage, params ?? {});
|
|
923
|
+
}
|
|
924
|
+
/** Retrieve a single journal entry by ID. */
|
|
925
|
+
async retrieve(id) {
|
|
926
|
+
const response = await this._client.get(
|
|
927
|
+
`/journal-entries/${id}`
|
|
928
|
+
);
|
|
929
|
+
return response.data;
|
|
930
|
+
}
|
|
931
|
+
/** Create a new journal entry. */
|
|
932
|
+
async create(data, options) {
|
|
933
|
+
const response = await this._client.post(
|
|
934
|
+
"/journal-entries",
|
|
935
|
+
data,
|
|
936
|
+
options
|
|
937
|
+
);
|
|
938
|
+
return response.data;
|
|
939
|
+
}
|
|
940
|
+
/** Update a draft journal entry. */
|
|
941
|
+
async update(id, data, options) {
|
|
942
|
+
const response = await this._client.patch(
|
|
943
|
+
`/journal-entries/${id}`,
|
|
944
|
+
data,
|
|
945
|
+
options
|
|
946
|
+
);
|
|
947
|
+
return response.data;
|
|
948
|
+
}
|
|
949
|
+
/** Delete a draft journal entry. */
|
|
950
|
+
async delete(id, options) {
|
|
951
|
+
await this._client.delete(`/journal-entries/${id}`, options);
|
|
952
|
+
}
|
|
953
|
+
/** Post a draft journal entry to the ledger. */
|
|
954
|
+
async post(id, options) {
|
|
955
|
+
const response = await this._client.post(
|
|
956
|
+
`/journal-entries/${id}/post`,
|
|
957
|
+
void 0,
|
|
958
|
+
options
|
|
959
|
+
);
|
|
960
|
+
return response.data;
|
|
961
|
+
}
|
|
962
|
+
/** Void a posted journal entry. */
|
|
963
|
+
async void(id, options) {
|
|
964
|
+
const response = await this._client.post(
|
|
965
|
+
`/journal-entries/${id}/void`,
|
|
966
|
+
void 0,
|
|
967
|
+
options
|
|
968
|
+
);
|
|
969
|
+
return response.data;
|
|
970
|
+
}
|
|
971
|
+
};
|
|
972
|
+
|
|
973
|
+
// src/resources/bank-accounts.ts
|
|
974
|
+
var BankAccounts = class {
|
|
975
|
+
constructor(_client) {
|
|
976
|
+
this._client = _client;
|
|
977
|
+
}
|
|
978
|
+
/**
|
|
979
|
+
* List bank accounts with pagination.
|
|
980
|
+
*
|
|
981
|
+
* ```ts
|
|
982
|
+
* for await (const account of cynco.bankAccounts.list()) {
|
|
983
|
+
* console.log(`${account.bankName} — ${account.name}`);
|
|
984
|
+
* }
|
|
985
|
+
* ```
|
|
986
|
+
*/
|
|
987
|
+
async list(params) {
|
|
988
|
+
const fetchPage = async (p) => {
|
|
989
|
+
return this._client.getList(
|
|
990
|
+
"/bank-accounts",
|
|
991
|
+
p
|
|
992
|
+
);
|
|
993
|
+
};
|
|
994
|
+
const response = await fetchPage(params ?? {});
|
|
995
|
+
return new Page(response, fetchPage, params ?? {});
|
|
996
|
+
}
|
|
997
|
+
/** Retrieve a single bank account by ID. */
|
|
998
|
+
async retrieve(id) {
|
|
999
|
+
const response = await this._client.get(
|
|
1000
|
+
`/bank-accounts/${id}`
|
|
1001
|
+
);
|
|
1002
|
+
return response.data;
|
|
1003
|
+
}
|
|
1004
|
+
/** Create a new bank account. */
|
|
1005
|
+
async create(data, options) {
|
|
1006
|
+
const response = await this._client.post(
|
|
1007
|
+
"/bank-accounts",
|
|
1008
|
+
data,
|
|
1009
|
+
options
|
|
1010
|
+
);
|
|
1011
|
+
return response.data;
|
|
1012
|
+
}
|
|
1013
|
+
/** Update an existing bank account. */
|
|
1014
|
+
async update(id, data, options) {
|
|
1015
|
+
const response = await this._client.patch(
|
|
1016
|
+
`/bank-accounts/${id}`,
|
|
1017
|
+
data,
|
|
1018
|
+
options
|
|
1019
|
+
);
|
|
1020
|
+
return response.data;
|
|
1021
|
+
}
|
|
1022
|
+
/** Delete a bank account. */
|
|
1023
|
+
async delete(id, options) {
|
|
1024
|
+
await this._client.delete(`/bank-accounts/${id}`, options);
|
|
1025
|
+
}
|
|
1026
|
+
/**
|
|
1027
|
+
* List transactions for a specific bank account.
|
|
1028
|
+
*
|
|
1029
|
+
* ```ts
|
|
1030
|
+
* for await (const txn of cynco.bankAccounts.listTransactions('ba_123', { status: 'cleared' })) {
|
|
1031
|
+
* console.log(`${txn.date} ${txn.description} ${txn.amount}`);
|
|
1032
|
+
* }
|
|
1033
|
+
* ```
|
|
1034
|
+
*/
|
|
1035
|
+
async listTransactions(bankAccountId, params) {
|
|
1036
|
+
const fetchPage = async (p) => {
|
|
1037
|
+
return this._client.getList(
|
|
1038
|
+
`/bank-accounts/${bankAccountId}/transactions`,
|
|
1039
|
+
p
|
|
1040
|
+
);
|
|
1041
|
+
};
|
|
1042
|
+
const response = await fetchPage(params ?? {});
|
|
1043
|
+
return new Page(response, fetchPage, params ?? {});
|
|
1044
|
+
}
|
|
1045
|
+
};
|
|
1046
|
+
|
|
1047
|
+
// src/resources/reports.ts
|
|
1048
|
+
var Reports = class {
|
|
1049
|
+
constructor(_client) {
|
|
1050
|
+
this._client = _client;
|
|
1051
|
+
}
|
|
1052
|
+
/** Generate a balance sheet report. */
|
|
1053
|
+
async balanceSheet(params) {
|
|
1054
|
+
const response = await this._client.get(
|
|
1055
|
+
"/reports/balance-sheet",
|
|
1056
|
+
{ ...params }
|
|
1057
|
+
);
|
|
1058
|
+
return response.data;
|
|
1059
|
+
}
|
|
1060
|
+
/** Generate a profit and loss (income statement) report. */
|
|
1061
|
+
async profitAndLoss(params) {
|
|
1062
|
+
const response = await this._client.get(
|
|
1063
|
+
"/reports/profit-and-loss",
|
|
1064
|
+
{ ...params }
|
|
1065
|
+
);
|
|
1066
|
+
return response.data;
|
|
1067
|
+
}
|
|
1068
|
+
/** Generate a trial balance report. */
|
|
1069
|
+
async trialBalance(params) {
|
|
1070
|
+
const response = await this._client.get(
|
|
1071
|
+
"/reports/trial-balance",
|
|
1072
|
+
{ ...params }
|
|
1073
|
+
);
|
|
1074
|
+
return response.data;
|
|
1075
|
+
}
|
|
1076
|
+
};
|
|
1077
|
+
|
|
1078
|
+
// src/resources/webhooks.ts
|
|
1079
|
+
var Webhooks = class {
|
|
1080
|
+
constructor(_client) {
|
|
1081
|
+
this._client = _client;
|
|
1082
|
+
}
|
|
1083
|
+
/**
|
|
1084
|
+
* List webhook endpoints with pagination.
|
|
1085
|
+
*
|
|
1086
|
+
* ```ts
|
|
1087
|
+
* for await (const webhook of cynco.webhooks.list()) {
|
|
1088
|
+
* console.log(`${webhook.url} — ${webhook.events.join(', ')}`);
|
|
1089
|
+
* }
|
|
1090
|
+
* ```
|
|
1091
|
+
*/
|
|
1092
|
+
async list(params) {
|
|
1093
|
+
const fetchPage = async (p) => {
|
|
1094
|
+
return this._client.getList(
|
|
1095
|
+
"/webhooks",
|
|
1096
|
+
p
|
|
1097
|
+
);
|
|
1098
|
+
};
|
|
1099
|
+
const response = await fetchPage(params ?? {});
|
|
1100
|
+
return new Page(response, fetchPage, params ?? {});
|
|
1101
|
+
}
|
|
1102
|
+
/** Retrieve a single webhook endpoint by ID. */
|
|
1103
|
+
async retrieve(id) {
|
|
1104
|
+
const response = await this._client.get(`/webhooks/${id}`);
|
|
1105
|
+
return response.data;
|
|
1106
|
+
}
|
|
1107
|
+
/** Create a new webhook endpoint. */
|
|
1108
|
+
async create(data, options) {
|
|
1109
|
+
const response = await this._client.post(
|
|
1110
|
+
"/webhooks",
|
|
1111
|
+
data,
|
|
1112
|
+
options
|
|
1113
|
+
);
|
|
1114
|
+
return response.data;
|
|
1115
|
+
}
|
|
1116
|
+
/** Update an existing webhook endpoint. */
|
|
1117
|
+
async update(id, data, options) {
|
|
1118
|
+
const response = await this._client.patch(
|
|
1119
|
+
`/webhooks/${id}`,
|
|
1120
|
+
data,
|
|
1121
|
+
options
|
|
1122
|
+
);
|
|
1123
|
+
return response.data;
|
|
1124
|
+
}
|
|
1125
|
+
/** Delete a webhook endpoint. */
|
|
1126
|
+
async delete(id, options) {
|
|
1127
|
+
await this._client.delete(`/webhooks/${id}`, options);
|
|
1128
|
+
}
|
|
1129
|
+
/** Rotate the signing secret for a webhook endpoint. Returns the new secret. */
|
|
1130
|
+
async rotateSecret(id) {
|
|
1131
|
+
const response = await this._client.post(
|
|
1132
|
+
`/webhooks/${id}/rotate-secret`
|
|
1133
|
+
);
|
|
1134
|
+
return response.data;
|
|
1135
|
+
}
|
|
1136
|
+
};
|
|
1137
|
+
|
|
1138
|
+
// src/index.ts
|
|
1139
|
+
var Cynco = class {
|
|
1140
|
+
/** Invoices resource. */
|
|
1141
|
+
invoices;
|
|
1142
|
+
/** Customers resource. */
|
|
1143
|
+
customers;
|
|
1144
|
+
/** Vendors resource. */
|
|
1145
|
+
vendors;
|
|
1146
|
+
/** Bills resource. */
|
|
1147
|
+
bills;
|
|
1148
|
+
/** Items (products & services) resource. */
|
|
1149
|
+
items;
|
|
1150
|
+
/** Chart of accounts resource. */
|
|
1151
|
+
accounts;
|
|
1152
|
+
/** Journal entries resource. */
|
|
1153
|
+
journalEntries;
|
|
1154
|
+
/** Bank accounts resource. */
|
|
1155
|
+
bankAccounts;
|
|
1156
|
+
/** Financial reports resource. */
|
|
1157
|
+
reports;
|
|
1158
|
+
/** Webhook endpoints resource. */
|
|
1159
|
+
webhooks;
|
|
1160
|
+
/**
|
|
1161
|
+
* Static webhook signature verification utilities.
|
|
1162
|
+
*
|
|
1163
|
+
* ```ts
|
|
1164
|
+
* const valid = Cynco.webhooks.verify(payload, signature, timestamp, secret);
|
|
1165
|
+
* ```
|
|
1166
|
+
*/
|
|
1167
|
+
static webhooks = webhookVerifier;
|
|
1168
|
+
_client;
|
|
1169
|
+
/**
|
|
1170
|
+
* Create a new Cynco client instance.
|
|
1171
|
+
*
|
|
1172
|
+
* @param apiKey - Your Cynco API key (starts with `cak_`).
|
|
1173
|
+
* @param options - Optional client configuration.
|
|
1174
|
+
*/
|
|
1175
|
+
constructor(apiKey, options) {
|
|
1176
|
+
this._client = new CyncoClient(apiKey, options);
|
|
1177
|
+
this.invoices = new Invoices(this._client);
|
|
1178
|
+
this.customers = new Customers(this._client);
|
|
1179
|
+
this.vendors = new Vendors(this._client);
|
|
1180
|
+
this.bills = new Bills(this._client);
|
|
1181
|
+
this.items = new Items(this._client);
|
|
1182
|
+
this.accounts = new Accounts(this._client);
|
|
1183
|
+
this.journalEntries = new JournalEntries(this._client);
|
|
1184
|
+
this.bankAccounts = new BankAccounts(this._client);
|
|
1185
|
+
this.reports = new Reports(this._client);
|
|
1186
|
+
this.webhooks = new Webhooks(this._client);
|
|
1187
|
+
}
|
|
1188
|
+
};
|
|
1189
|
+
var index_default = Cynco;
|
|
1190
|
+
|
|
1191
|
+
export { Accounts, AuthenticationError, BankAccounts, Bills, ConflictError, ConnectionError, CursorPage, Customers, Cynco, CyncoClient, CyncoError, InternalError, Invoices, Items, JournalEntries, NotFoundError, Page, PermissionError, RateLimitError, Reports, TimeoutError, ValidationError, Vendors, Webhooks, index_default as default, webhookVerifier };
|
|
1192
|
+
//# sourceMappingURL=index.js.map
|
|
1193
|
+
//# sourceMappingURL=index.js.map
|