@chronary/sdk 0.1.3
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 +13 -0
- package/LICENSE +189 -0
- package/README.md +71 -0
- package/dist/index.cjs +1213 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1016 -0
- package/dist/index.d.ts +1016 -0
- package/dist/index.js +1171 -0
- package/dist/index.js.map +1 -0
- package/package.json +64 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1171 @@
|
|
|
1
|
+
// src/version.ts
|
|
2
|
+
var VERSION = "0.1.3";
|
|
3
|
+
|
|
4
|
+
// src/error.ts
|
|
5
|
+
var ChronaryError = class extends Error {
|
|
6
|
+
status;
|
|
7
|
+
requestId;
|
|
8
|
+
headers;
|
|
9
|
+
errorType;
|
|
10
|
+
constructor(message, status, requestId, headers, errorType) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.name = "ChronaryError";
|
|
13
|
+
this.status = status;
|
|
14
|
+
this.requestId = requestId;
|
|
15
|
+
this.headers = headers;
|
|
16
|
+
this.errorType = errorType;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
var AuthenticationError = class extends ChronaryError {
|
|
20
|
+
constructor(message, requestId, headers) {
|
|
21
|
+
super(message, 401, requestId, headers, "authentication_error");
|
|
22
|
+
this.name = "AuthenticationError";
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
var RateLimitError = class extends ChronaryError {
|
|
26
|
+
retryAfter;
|
|
27
|
+
constructor(message, requestId, headers) {
|
|
28
|
+
super(message, 429, requestId, headers, "rate_limit_error");
|
|
29
|
+
this.name = "RateLimitError";
|
|
30
|
+
if (headers) {
|
|
31
|
+
const ra = headers.get("retry-after");
|
|
32
|
+
if (ra) this.retryAfter = parseInt(ra, 10);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
var NotFoundError = class extends ChronaryError {
|
|
37
|
+
constructor(message, requestId, headers) {
|
|
38
|
+
super(message, 404, requestId, headers, "not_found");
|
|
39
|
+
this.name = "NotFoundError";
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
var ValidationError = class extends ChronaryError {
|
|
43
|
+
constructor(message, status, requestId, headers) {
|
|
44
|
+
super(message, status, requestId, headers, "validation_error");
|
|
45
|
+
this.name = "ValidationError";
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
var QuotaExceededError = class extends ChronaryError {
|
|
49
|
+
constructor(message, requestId, headers) {
|
|
50
|
+
super(message, 402, requestId, headers, "quota_exceeded");
|
|
51
|
+
this.name = "QuotaExceededError";
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
var TimeoutError = class extends ChronaryError {
|
|
55
|
+
constructor(message) {
|
|
56
|
+
super(message, 0);
|
|
57
|
+
this.name = "TimeoutError";
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
var ConnectionError = class extends ChronaryError {
|
|
61
|
+
constructor(message) {
|
|
62
|
+
super(message, 0);
|
|
63
|
+
this.name = "ConnectionError";
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
// src/api-promise.ts
|
|
68
|
+
var APIPromise = class {
|
|
69
|
+
innerPromise;
|
|
70
|
+
constructor(responsePromise) {
|
|
71
|
+
this.innerPromise = responsePromise;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Returns both the parsed data and the raw HTTP response.
|
|
75
|
+
*/
|
|
76
|
+
async withResponse() {
|
|
77
|
+
const { data, rawResponse } = await this.innerPromise;
|
|
78
|
+
return { data, response: rawResponse };
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Implements the thenable interface. When awaited, resolves to just the parsed data `T`.
|
|
82
|
+
*/
|
|
83
|
+
then(onfulfilled, onrejected) {
|
|
84
|
+
return this.innerPromise.then(
|
|
85
|
+
(result) => onfulfilled ? onfulfilled(result.data) : result.data,
|
|
86
|
+
onrejected
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Attaches a rejection handler.
|
|
91
|
+
*/
|
|
92
|
+
catch(onrejected) {
|
|
93
|
+
return this.then(void 0, onrejected);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Attaches a handler that runs on both fulfillment and rejection.
|
|
97
|
+
*/
|
|
98
|
+
finally(onfinally) {
|
|
99
|
+
return this.then(
|
|
100
|
+
(value) => {
|
|
101
|
+
onfinally?.();
|
|
102
|
+
return value;
|
|
103
|
+
},
|
|
104
|
+
(reason) => {
|
|
105
|
+
onfinally?.();
|
|
106
|
+
throw reason;
|
|
107
|
+
}
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
// src/client.ts
|
|
113
|
+
var DEFAULT_BASE_URL = "https://api.chronary.ai";
|
|
114
|
+
var DEFAULT_TIMEOUT = 3e4;
|
|
115
|
+
var DEFAULT_MAX_RETRIES = 2;
|
|
116
|
+
var RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([408, 429, 500, 502, 503, 504]);
|
|
117
|
+
var MUTATING_METHODS = /* @__PURE__ */ new Set(["POST", "PUT", "PATCH", "DELETE"]);
|
|
118
|
+
var MAX_RETRY_DELAY = 6e4;
|
|
119
|
+
function getEnvVar(name) {
|
|
120
|
+
try {
|
|
121
|
+
if (typeof process !== "undefined" && process.env) {
|
|
122
|
+
return process.env[name];
|
|
123
|
+
}
|
|
124
|
+
} catch {
|
|
125
|
+
}
|
|
126
|
+
return void 0;
|
|
127
|
+
}
|
|
128
|
+
function resolveLogLevel(config) {
|
|
129
|
+
if (config.logLevel) return config.logLevel;
|
|
130
|
+
const envLog = getEnvVar("CHRONARY_LOG");
|
|
131
|
+
if (envLog && ["debug", "info", "warn", "error", "off"].includes(envLog)) {
|
|
132
|
+
return envLog;
|
|
133
|
+
}
|
|
134
|
+
return "off";
|
|
135
|
+
}
|
|
136
|
+
var LOG_PRIORITY = {
|
|
137
|
+
debug: 0,
|
|
138
|
+
info: 1,
|
|
139
|
+
warn: 2,
|
|
140
|
+
error: 3,
|
|
141
|
+
off: 4
|
|
142
|
+
};
|
|
143
|
+
var CoreClient = class {
|
|
144
|
+
baseUrl;
|
|
145
|
+
apiKey;
|
|
146
|
+
timeout;
|
|
147
|
+
maxRetries;
|
|
148
|
+
logLevel;
|
|
149
|
+
fetchFn;
|
|
150
|
+
userAgent;
|
|
151
|
+
extraHeaders;
|
|
152
|
+
constructor(config = {}) {
|
|
153
|
+
this.apiKey = config.apiKey ?? getEnvVar("CHRONARY_API_KEY") ?? "";
|
|
154
|
+
this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
155
|
+
this.timeout = config.timeout ?? DEFAULT_TIMEOUT;
|
|
156
|
+
this.maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
157
|
+
this.logLevel = resolveLogLevel(config);
|
|
158
|
+
this.fetchFn = config.fetch ?? globalThis.fetch.bind(globalThis);
|
|
159
|
+
this.extraHeaders = config.extraHeaders ?? {};
|
|
160
|
+
let ua = `chronary-ts/${VERSION}`;
|
|
161
|
+
if (config.appInfo) {
|
|
162
|
+
ua += ` ${config.appInfo.name}`;
|
|
163
|
+
if (config.appInfo.version) ua += `/${config.appInfo.version}`;
|
|
164
|
+
}
|
|
165
|
+
try {
|
|
166
|
+
if (typeof process !== "undefined" && process.version) {
|
|
167
|
+
ua += ` node/${process.version.replace("v", "")}`;
|
|
168
|
+
}
|
|
169
|
+
} catch {
|
|
170
|
+
}
|
|
171
|
+
this.userAgent = ua;
|
|
172
|
+
}
|
|
173
|
+
log(level, message) {
|
|
174
|
+
if (level === "off" || LOG_PRIORITY[level] < LOG_PRIORITY[this.logLevel]) return;
|
|
175
|
+
const prefix = `[chronary:${level}]`;
|
|
176
|
+
switch (level) {
|
|
177
|
+
case "debug":
|
|
178
|
+
console.debug(prefix, message);
|
|
179
|
+
break;
|
|
180
|
+
case "info":
|
|
181
|
+
console.info(prefix, message);
|
|
182
|
+
break;
|
|
183
|
+
case "warn":
|
|
184
|
+
console.warn(prefix, message);
|
|
185
|
+
break;
|
|
186
|
+
case "error":
|
|
187
|
+
console.error(prefix, message);
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
request(method, path, body, query, options) {
|
|
192
|
+
return new APIPromise(this._request(method, path, body, query, options));
|
|
193
|
+
}
|
|
194
|
+
async _request(method, path, body, query, options) {
|
|
195
|
+
const url = this.buildUrl(path, query);
|
|
196
|
+
const headers = {
|
|
197
|
+
"User-Agent": this.userAgent,
|
|
198
|
+
"X-Chronary-SDK-Version": VERSION,
|
|
199
|
+
...this.extraHeaders
|
|
200
|
+
};
|
|
201
|
+
if (this.apiKey) {
|
|
202
|
+
headers["Authorization"] = `Bearer ${this.apiKey}`;
|
|
203
|
+
}
|
|
204
|
+
if (body !== void 0) {
|
|
205
|
+
headers["Content-Type"] = "application/json";
|
|
206
|
+
}
|
|
207
|
+
if (MUTATING_METHODS.has(method)) {
|
|
208
|
+
headers["Idempotency-Key"] = options?.idempotencyKey ?? crypto.randomUUID();
|
|
209
|
+
}
|
|
210
|
+
const requestTimeout = options?.timeout ?? this.timeout;
|
|
211
|
+
let lastError;
|
|
212
|
+
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
|
|
213
|
+
if (attempt > 0) {
|
|
214
|
+
const delay = this.retryDelay(attempt, lastError);
|
|
215
|
+
this.log("info", `Retry #${attempt} after ${delay}ms`);
|
|
216
|
+
await sleep(delay);
|
|
217
|
+
}
|
|
218
|
+
if (options?.signal?.aborted) throw new ChronaryError("Request aborted", 0);
|
|
219
|
+
const controller = new AbortController();
|
|
220
|
+
const abortFromCaller = () => controller.abort(options?.signal?.reason);
|
|
221
|
+
options?.signal?.addEventListener("abort", abortFromCaller, { once: true });
|
|
222
|
+
const timeoutId = setTimeout(() => controller.abort(), requestTimeout);
|
|
223
|
+
try {
|
|
224
|
+
this.log("debug", `${method} ${path}`);
|
|
225
|
+
const startTime = Date.now();
|
|
226
|
+
const response = await this.fetchFn(url, {
|
|
227
|
+
method,
|
|
228
|
+
headers,
|
|
229
|
+
body: body !== void 0 ? JSON.stringify(body) : void 0,
|
|
230
|
+
signal: controller.signal
|
|
231
|
+
});
|
|
232
|
+
clearTimeout(timeoutId);
|
|
233
|
+
options?.signal?.removeEventListener("abort", abortFromCaller);
|
|
234
|
+
const elapsed = Date.now() - startTime;
|
|
235
|
+
const requestId = response.headers.get("x-request-id") ?? void 0;
|
|
236
|
+
this.log("debug", `${method} ${path} \u2192 ${response.status} in ${elapsed}ms${requestId ? ` (${requestId})` : ""}`);
|
|
237
|
+
if (response.ok) {
|
|
238
|
+
const rawResponse = {
|
|
239
|
+
status: response.status,
|
|
240
|
+
headers: response.headers,
|
|
241
|
+
url: response.url,
|
|
242
|
+
quota: parseQuotaSnapshot(response.headers)
|
|
243
|
+
};
|
|
244
|
+
if (response.status === 204) {
|
|
245
|
+
return { data: void 0, rawResponse };
|
|
246
|
+
}
|
|
247
|
+
const data = await response.json();
|
|
248
|
+
return { data, rawResponse };
|
|
249
|
+
}
|
|
250
|
+
if (RETRYABLE_STATUS_CODES.has(response.status) && attempt < this.maxRetries) {
|
|
251
|
+
lastError = await this.buildError(response, requestId);
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
throw await this.buildError(response, requestId);
|
|
255
|
+
} catch (err) {
|
|
256
|
+
clearTimeout(timeoutId);
|
|
257
|
+
options?.signal?.removeEventListener("abort", abortFromCaller);
|
|
258
|
+
if (err instanceof ChronaryError) throw err;
|
|
259
|
+
if (err instanceof DOMException && err.name === "AbortError") {
|
|
260
|
+
if (options?.signal?.aborted) throw new ChronaryError("Request aborted", 0);
|
|
261
|
+
throw new TimeoutError(`Request timed out after ${requestTimeout}ms`);
|
|
262
|
+
}
|
|
263
|
+
if (attempt < this.maxRetries) {
|
|
264
|
+
lastError = err;
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
267
|
+
throw new ConnectionError(`Connection failed: ${err.message}`);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
throw lastError ?? new ConnectionError("Request failed after retries");
|
|
271
|
+
}
|
|
272
|
+
buildUrl(path, query) {
|
|
273
|
+
const base = `${this.baseUrl}${path}`;
|
|
274
|
+
if (!query) return base;
|
|
275
|
+
const params = new URLSearchParams();
|
|
276
|
+
for (const [key, value] of Object.entries(query)) {
|
|
277
|
+
if (value !== void 0) params.set(key, String(value));
|
|
278
|
+
}
|
|
279
|
+
const qs = params.toString();
|
|
280
|
+
return qs ? `${base}?${qs}` : base;
|
|
281
|
+
}
|
|
282
|
+
async buildError(response, requestId) {
|
|
283
|
+
let errorBody;
|
|
284
|
+
try {
|
|
285
|
+
errorBody = await response.json();
|
|
286
|
+
} catch {
|
|
287
|
+
}
|
|
288
|
+
const message = errorBody?.error?.message ?? `HTTP ${response.status}`;
|
|
289
|
+
const rid = requestId ?? errorBody?.error?.request_id;
|
|
290
|
+
const errorType = errorBody?.error?.type;
|
|
291
|
+
switch (response.status) {
|
|
292
|
+
case 400:
|
|
293
|
+
if (errorType === "validation_error") {
|
|
294
|
+
return new ValidationError(message, response.status, rid, response.headers);
|
|
295
|
+
}
|
|
296
|
+
return new ChronaryError(message, response.status, rid, response.headers, errorType);
|
|
297
|
+
case 401:
|
|
298
|
+
return new AuthenticationError(message, rid, response.headers);
|
|
299
|
+
case 402:
|
|
300
|
+
return new QuotaExceededError(message, rid, response.headers);
|
|
301
|
+
case 404:
|
|
302
|
+
return new NotFoundError(message, rid, response.headers);
|
|
303
|
+
case 422:
|
|
304
|
+
return new ValidationError(message, response.status, rid, response.headers);
|
|
305
|
+
case 429: {
|
|
306
|
+
if (errorType === "quota_exceeded") {
|
|
307
|
+
return new QuotaExceededError(message, rid, response.headers);
|
|
308
|
+
}
|
|
309
|
+
return new RateLimitError(message, rid, response.headers);
|
|
310
|
+
}
|
|
311
|
+
default:
|
|
312
|
+
return new ChronaryError(message, response.status, rid, response.headers, errorType);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
retryDelay(attempt, lastError) {
|
|
316
|
+
if (lastError instanceof RateLimitError && lastError.retryAfter) {
|
|
317
|
+
return Math.min(lastError.retryAfter * 1e3, MAX_RETRY_DELAY);
|
|
318
|
+
}
|
|
319
|
+
const base = 500;
|
|
320
|
+
const exponential = base * Math.pow(2, attempt - 1);
|
|
321
|
+
const jitter = Math.random() * base;
|
|
322
|
+
return Math.min(exponential + jitter, MAX_RETRY_DELAY);
|
|
323
|
+
}
|
|
324
|
+
};
|
|
325
|
+
function sleep(ms) {
|
|
326
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
327
|
+
}
|
|
328
|
+
function parseQuotaSnapshot(headers) {
|
|
329
|
+
const rateLimit = headers.get("ratelimit");
|
|
330
|
+
const policy = headers.get("ratelimit-policy");
|
|
331
|
+
if (!rateLimit || !policy) return void 0;
|
|
332
|
+
const remaining = parseStructuredParam(rateLimit, "r");
|
|
333
|
+
const resetSeconds = parseStructuredParam(rateLimit, "t");
|
|
334
|
+
const limit = parseStructuredParam(policy, "q");
|
|
335
|
+
if (remaining === void 0 || resetSeconds === void 0 || limit === void 0) {
|
|
336
|
+
return void 0;
|
|
337
|
+
}
|
|
338
|
+
return {
|
|
339
|
+
limit,
|
|
340
|
+
remaining,
|
|
341
|
+
resetAt: new Date(Date.now() + resetSeconds * 1e3)
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
function parseStructuredParam(header, key) {
|
|
345
|
+
const re = new RegExp(`(?:^|;)\\s*${key}=(-?\\d+)(?:;|$)`);
|
|
346
|
+
const match = re.exec(header);
|
|
347
|
+
if (!match) return void 0;
|
|
348
|
+
const n = Number(match[1]);
|
|
349
|
+
return Number.isFinite(n) ? n : void 0;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// src/pagination.ts
|
|
353
|
+
var PageIterator = class {
|
|
354
|
+
fetchPage;
|
|
355
|
+
defaultLimit;
|
|
356
|
+
initialOffset;
|
|
357
|
+
constructor(fetchPage, defaultLimit = 50, initialOffset = 0) {
|
|
358
|
+
this.fetchPage = fetchPage;
|
|
359
|
+
this.defaultLimit = defaultLimit;
|
|
360
|
+
this.initialOffset = initialOffset;
|
|
361
|
+
}
|
|
362
|
+
async getPage(offset = this.initialOffset, limit) {
|
|
363
|
+
const l = limit ?? this.defaultLimit;
|
|
364
|
+
const response = await this.fetchPage(offset, l);
|
|
365
|
+
return {
|
|
366
|
+
...response,
|
|
367
|
+
hasMore: offset + response.data.length < response.total
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
async *[Symbol.asyncIterator]() {
|
|
371
|
+
let offset = this.initialOffset;
|
|
372
|
+
const limit = this.defaultLimit;
|
|
373
|
+
while (true) {
|
|
374
|
+
const page = await this.fetchPage(offset, limit);
|
|
375
|
+
for (const item of page.data) {
|
|
376
|
+
yield item;
|
|
377
|
+
}
|
|
378
|
+
offset += page.data.length;
|
|
379
|
+
if (offset >= page.total || page.data.length === 0) break;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
// src/resources/agents.ts
|
|
385
|
+
var AgentsClient = class {
|
|
386
|
+
constructor(client) {
|
|
387
|
+
this.client = client;
|
|
388
|
+
}
|
|
389
|
+
client;
|
|
390
|
+
/**
|
|
391
|
+
* Register your agent with Chronary. Creates a Chronary identity for an agent
|
|
392
|
+
* that already exists in your system, so it can own calendars, events, and webhooks.
|
|
393
|
+
*/
|
|
394
|
+
async create(params, options) {
|
|
395
|
+
return this.client.request("POST", "/v1/agents", params, void 0, options);
|
|
396
|
+
}
|
|
397
|
+
async get(id, options) {
|
|
398
|
+
return this.client.request("GET", `/v1/agents/${id}`, void 0, void 0, options);
|
|
399
|
+
}
|
|
400
|
+
list(params = {}) {
|
|
401
|
+
const { limit = 50, offset = 0, ...filters } = params;
|
|
402
|
+
return new PageIterator(
|
|
403
|
+
(offset2, l) => this.client.request("GET", "/v1/agents", void 0, {
|
|
404
|
+
...filters,
|
|
405
|
+
limit: l,
|
|
406
|
+
offset: offset2
|
|
407
|
+
}),
|
|
408
|
+
limit,
|
|
409
|
+
offset
|
|
410
|
+
);
|
|
411
|
+
}
|
|
412
|
+
async update(id, params, options) {
|
|
413
|
+
return this.client.request("PATCH", `/v1/agents/${id}`, params, void 0, options);
|
|
414
|
+
}
|
|
415
|
+
async delete(id, options) {
|
|
416
|
+
await this.client.request("DELETE", `/v1/agents/${id}`, void 0, void 0, options);
|
|
417
|
+
}
|
|
418
|
+
};
|
|
419
|
+
|
|
420
|
+
// src/resources/calendars.ts
|
|
421
|
+
var CalendarsClient = class {
|
|
422
|
+
constructor(client) {
|
|
423
|
+
this.client = client;
|
|
424
|
+
}
|
|
425
|
+
client;
|
|
426
|
+
async create(params, options) {
|
|
427
|
+
const { agentId, ...body } = params;
|
|
428
|
+
const path = agentId ? `/v1/agents/${agentId}/calendars` : "/v1/calendars";
|
|
429
|
+
return this.client.request("POST", path, body, void 0, options);
|
|
430
|
+
}
|
|
431
|
+
async get(id, options) {
|
|
432
|
+
return this.client.request("GET", `/v1/calendars/${id}`, void 0, void 0, options);
|
|
433
|
+
}
|
|
434
|
+
list(params = {}) {
|
|
435
|
+
const { agentId, limit = 50, offset = 0, ...filters } = params;
|
|
436
|
+
const path = agentId ? `/v1/agents/${agentId}/calendars` : "/v1/calendars";
|
|
437
|
+
return new PageIterator(
|
|
438
|
+
(offset2, l) => this.client.request("GET", path, void 0, {
|
|
439
|
+
...filters,
|
|
440
|
+
limit: l,
|
|
441
|
+
offset: offset2
|
|
442
|
+
}),
|
|
443
|
+
limit,
|
|
444
|
+
offset
|
|
445
|
+
);
|
|
446
|
+
}
|
|
447
|
+
async update(id, params, options) {
|
|
448
|
+
return this.client.request("PATCH", `/v1/calendars/${id}`, params, void 0, options);
|
|
449
|
+
}
|
|
450
|
+
async delete(id, options) {
|
|
451
|
+
await this.client.request("DELETE", `/v1/calendars/${id}`, void 0, void 0, options);
|
|
452
|
+
}
|
|
453
|
+
async getContext(id, options) {
|
|
454
|
+
return this.client.request(
|
|
455
|
+
"GET",
|
|
456
|
+
`/v1/calendars/${id}/context`,
|
|
457
|
+
void 0,
|
|
458
|
+
void 0,
|
|
459
|
+
options
|
|
460
|
+
);
|
|
461
|
+
}
|
|
462
|
+
async setAvailabilityRules(id, params, options) {
|
|
463
|
+
return this.client.request(
|
|
464
|
+
"PUT",
|
|
465
|
+
`/v1/calendars/${id}/availability-rules`,
|
|
466
|
+
params,
|
|
467
|
+
void 0,
|
|
468
|
+
options
|
|
469
|
+
);
|
|
470
|
+
}
|
|
471
|
+
async getAvailabilityRules(id, options) {
|
|
472
|
+
return this.client.request(
|
|
473
|
+
"GET",
|
|
474
|
+
`/v1/calendars/${id}/availability-rules`,
|
|
475
|
+
void 0,
|
|
476
|
+
void 0,
|
|
477
|
+
options
|
|
478
|
+
);
|
|
479
|
+
}
|
|
480
|
+
async deleteAvailabilityRules(id, options) {
|
|
481
|
+
await this.client.request(
|
|
482
|
+
"DELETE",
|
|
483
|
+
`/v1/calendars/${id}/availability-rules`,
|
|
484
|
+
void 0,
|
|
485
|
+
void 0,
|
|
486
|
+
options
|
|
487
|
+
);
|
|
488
|
+
}
|
|
489
|
+
};
|
|
490
|
+
|
|
491
|
+
// src/resources/events.ts
|
|
492
|
+
var EventsClient = class {
|
|
493
|
+
constructor(client) {
|
|
494
|
+
this.client = client;
|
|
495
|
+
}
|
|
496
|
+
client;
|
|
497
|
+
async create(calendarId, params, options) {
|
|
498
|
+
return this.client.request(
|
|
499
|
+
"POST",
|
|
500
|
+
`/v1/calendars/${calendarId}/events`,
|
|
501
|
+
params,
|
|
502
|
+
void 0,
|
|
503
|
+
options
|
|
504
|
+
);
|
|
505
|
+
}
|
|
506
|
+
async get(calendarId, eventId, options) {
|
|
507
|
+
return this.client.request(
|
|
508
|
+
"GET",
|
|
509
|
+
`/v1/calendars/${calendarId}/events/${eventId}`,
|
|
510
|
+
void 0,
|
|
511
|
+
void 0,
|
|
512
|
+
options
|
|
513
|
+
);
|
|
514
|
+
}
|
|
515
|
+
list(params = {}) {
|
|
516
|
+
const { calendarId, agentId, limit = 50, offset = 0, ...filters } = params;
|
|
517
|
+
let path;
|
|
518
|
+
if (agentId) {
|
|
519
|
+
path = `/v1/agents/${agentId}/events`;
|
|
520
|
+
} else if (calendarId) {
|
|
521
|
+
path = `/v1/calendars/${calendarId}/events`;
|
|
522
|
+
} else {
|
|
523
|
+
throw new Error("Either calendarId or agentId is required for events.list()");
|
|
524
|
+
}
|
|
525
|
+
return new PageIterator(
|
|
526
|
+
(offset2, l) => this.client.request("GET", path, void 0, {
|
|
527
|
+
...filters,
|
|
528
|
+
limit: l,
|
|
529
|
+
offset: offset2
|
|
530
|
+
}),
|
|
531
|
+
limit,
|
|
532
|
+
offset
|
|
533
|
+
);
|
|
534
|
+
}
|
|
535
|
+
async update(calendarId, eventId, params, options) {
|
|
536
|
+
return this.client.request(
|
|
537
|
+
"PATCH",
|
|
538
|
+
`/v1/calendars/${calendarId}/events/${eventId}`,
|
|
539
|
+
params,
|
|
540
|
+
void 0,
|
|
541
|
+
options
|
|
542
|
+
);
|
|
543
|
+
}
|
|
544
|
+
async delete(calendarId, eventId, options) {
|
|
545
|
+
await this.client.request(
|
|
546
|
+
"DELETE",
|
|
547
|
+
`/v1/calendars/${calendarId}/events/${eventId}`,
|
|
548
|
+
void 0,
|
|
549
|
+
void 0,
|
|
550
|
+
options
|
|
551
|
+
);
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* Promote a held event (status='hold') to status='confirmed'. Fails with 409
|
|
555
|
+
* if the event is not a hold, or if the hold has already expired.
|
|
556
|
+
*/
|
|
557
|
+
async confirm(eventId, options) {
|
|
558
|
+
return this.client.request(
|
|
559
|
+
"PUT",
|
|
560
|
+
`/v1/events/${eventId}/confirm`,
|
|
561
|
+
void 0,
|
|
562
|
+
void 0,
|
|
563
|
+
options
|
|
564
|
+
);
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* Manually release a held event before its TTL, freeing the slot. Fails with
|
|
568
|
+
* 409 if the event is not a hold.
|
|
569
|
+
*/
|
|
570
|
+
async release(eventId, options) {
|
|
571
|
+
return this.client.request(
|
|
572
|
+
"PUT",
|
|
573
|
+
`/v1/events/${eventId}/release`,
|
|
574
|
+
void 0,
|
|
575
|
+
void 0,
|
|
576
|
+
options
|
|
577
|
+
);
|
|
578
|
+
}
|
|
579
|
+
};
|
|
580
|
+
|
|
581
|
+
// src/resources/availability.ts
|
|
582
|
+
var AvailabilityClient = class {
|
|
583
|
+
constructor(client) {
|
|
584
|
+
this.client = client;
|
|
585
|
+
}
|
|
586
|
+
client;
|
|
587
|
+
async forAgent(agentId, params, options) {
|
|
588
|
+
return this.client.request(
|
|
589
|
+
"GET",
|
|
590
|
+
`/v1/agents/${agentId}/availability`,
|
|
591
|
+
void 0,
|
|
592
|
+
{
|
|
593
|
+
start: params.start,
|
|
594
|
+
end: params.end,
|
|
595
|
+
slot_duration: params.slot_duration,
|
|
596
|
+
include_busy: params.include_busy
|
|
597
|
+
},
|
|
598
|
+
options
|
|
599
|
+
);
|
|
600
|
+
}
|
|
601
|
+
async forCalendar(calendarId, params, options) {
|
|
602
|
+
return this.client.request(
|
|
603
|
+
"GET",
|
|
604
|
+
`/v1/calendars/${calendarId}/availability`,
|
|
605
|
+
void 0,
|
|
606
|
+
{
|
|
607
|
+
start: params.start,
|
|
608
|
+
end: params.end,
|
|
609
|
+
slot_duration: params.slot_duration,
|
|
610
|
+
include_busy: params.include_busy
|
|
611
|
+
},
|
|
612
|
+
options
|
|
613
|
+
);
|
|
614
|
+
}
|
|
615
|
+
async check(params, options) {
|
|
616
|
+
return this.client.request(
|
|
617
|
+
"GET",
|
|
618
|
+
"/v1/availability",
|
|
619
|
+
void 0,
|
|
620
|
+
{
|
|
621
|
+
agents: params.agents.join(","),
|
|
622
|
+
start: params.start,
|
|
623
|
+
end: params.end,
|
|
624
|
+
slot_duration: params.slot_duration,
|
|
625
|
+
calendars: params.calendars?.join(","),
|
|
626
|
+
include_busy: params.include_busy
|
|
627
|
+
},
|
|
628
|
+
options
|
|
629
|
+
);
|
|
630
|
+
}
|
|
631
|
+
};
|
|
632
|
+
|
|
633
|
+
// src/resources/webhooks.ts
|
|
634
|
+
var WebhooksClient = class {
|
|
635
|
+
constructor(client) {
|
|
636
|
+
this.client = client;
|
|
637
|
+
}
|
|
638
|
+
client;
|
|
639
|
+
async create(params, options) {
|
|
640
|
+
return this.client.request("POST", "/v1/webhooks", params, void 0, options);
|
|
641
|
+
}
|
|
642
|
+
async get(id, options) {
|
|
643
|
+
return this.client.request("GET", `/v1/webhooks/${id}`, void 0, void 0, options);
|
|
644
|
+
}
|
|
645
|
+
list(params = {}) {
|
|
646
|
+
const { limit = 20, offset = 0, ...filters } = params;
|
|
647
|
+
return new PageIterator(
|
|
648
|
+
(offset2, l) => this.client.request("GET", "/v1/webhooks", void 0, {
|
|
649
|
+
...filters,
|
|
650
|
+
limit: l,
|
|
651
|
+
offset: offset2
|
|
652
|
+
}),
|
|
653
|
+
limit,
|
|
654
|
+
offset
|
|
655
|
+
);
|
|
656
|
+
}
|
|
657
|
+
async update(id, params, options) {
|
|
658
|
+
return this.client.request("PATCH", `/v1/webhooks/${id}`, params, void 0, options);
|
|
659
|
+
}
|
|
660
|
+
async delete(id, options) {
|
|
661
|
+
await this.client.request("DELETE", `/v1/webhooks/${id}`, void 0, void 0, options);
|
|
662
|
+
}
|
|
663
|
+
async listDeliveries(webhookId, params = {}, options) {
|
|
664
|
+
const { limit = 20, offset = 0, status, include_payload } = params;
|
|
665
|
+
return this.client.request(
|
|
666
|
+
"GET",
|
|
667
|
+
`/v1/webhooks/${webhookId}/deliveries`,
|
|
668
|
+
void 0,
|
|
669
|
+
{ limit, offset, ...status !== void 0 && { status }, ...include_payload !== void 0 && { include_payload } },
|
|
670
|
+
options
|
|
671
|
+
);
|
|
672
|
+
}
|
|
673
|
+
};
|
|
674
|
+
|
|
675
|
+
// src/resources/ical-subscriptions.ts
|
|
676
|
+
var ICalSubscriptionsClient = class {
|
|
677
|
+
constructor(client) {
|
|
678
|
+
this.client = client;
|
|
679
|
+
}
|
|
680
|
+
client;
|
|
681
|
+
async create(agentId, params, options) {
|
|
682
|
+
return this.client.request(
|
|
683
|
+
"POST",
|
|
684
|
+
`/v1/agents/${agentId}/ical-subscriptions`,
|
|
685
|
+
params,
|
|
686
|
+
void 0,
|
|
687
|
+
options
|
|
688
|
+
);
|
|
689
|
+
}
|
|
690
|
+
async get(id, options) {
|
|
691
|
+
return this.client.request(
|
|
692
|
+
"GET",
|
|
693
|
+
`/v1/ical-subscriptions/${id}`,
|
|
694
|
+
void 0,
|
|
695
|
+
void 0,
|
|
696
|
+
options
|
|
697
|
+
);
|
|
698
|
+
}
|
|
699
|
+
list(params) {
|
|
700
|
+
const { agentId, limit = 50, offset = 0, ...filters } = params;
|
|
701
|
+
return new PageIterator(
|
|
702
|
+
(offset2, l) => this.client.request(
|
|
703
|
+
"GET",
|
|
704
|
+
`/v1/agents/${agentId}/ical-subscriptions`,
|
|
705
|
+
void 0,
|
|
706
|
+
{ ...filters, limit: l, offset: offset2 }
|
|
707
|
+
),
|
|
708
|
+
limit,
|
|
709
|
+
offset
|
|
710
|
+
);
|
|
711
|
+
}
|
|
712
|
+
async update(id, params, options) {
|
|
713
|
+
return this.client.request(
|
|
714
|
+
"PATCH",
|
|
715
|
+
`/v1/ical-subscriptions/${id}`,
|
|
716
|
+
params,
|
|
717
|
+
void 0,
|
|
718
|
+
options
|
|
719
|
+
);
|
|
720
|
+
}
|
|
721
|
+
async delete(id, options) {
|
|
722
|
+
await this.client.request(
|
|
723
|
+
"DELETE",
|
|
724
|
+
`/v1/ical-subscriptions/${id}`,
|
|
725
|
+
void 0,
|
|
726
|
+
void 0,
|
|
727
|
+
options
|
|
728
|
+
);
|
|
729
|
+
}
|
|
730
|
+
async sync(id, options) {
|
|
731
|
+
return this.client.request(
|
|
732
|
+
"POST",
|
|
733
|
+
`/v1/ical-subscriptions/${id}/sync`,
|
|
734
|
+
void 0,
|
|
735
|
+
void 0,
|
|
736
|
+
options
|
|
737
|
+
);
|
|
738
|
+
}
|
|
739
|
+
};
|
|
740
|
+
|
|
741
|
+
// src/resources/scheduling.ts
|
|
742
|
+
var SchedulingClient = class {
|
|
743
|
+
constructor(client) {
|
|
744
|
+
this.client = client;
|
|
745
|
+
}
|
|
746
|
+
client;
|
|
747
|
+
async create(params, options) {
|
|
748
|
+
return this.client.request(
|
|
749
|
+
"POST",
|
|
750
|
+
"/v1/scheduling/proposals",
|
|
751
|
+
params,
|
|
752
|
+
void 0,
|
|
753
|
+
options
|
|
754
|
+
);
|
|
755
|
+
}
|
|
756
|
+
list(params = {}) {
|
|
757
|
+
const { limit = 50, offset = 0, ...filters } = params;
|
|
758
|
+
return new PageIterator(
|
|
759
|
+
(offset2, l) => this.client.request(
|
|
760
|
+
"GET",
|
|
761
|
+
"/v1/scheduling/proposals",
|
|
762
|
+
void 0,
|
|
763
|
+
{ ...filters, limit: l, offset: offset2 }
|
|
764
|
+
),
|
|
765
|
+
limit,
|
|
766
|
+
offset
|
|
767
|
+
);
|
|
768
|
+
}
|
|
769
|
+
async get(id, options) {
|
|
770
|
+
return this.client.request(
|
|
771
|
+
"GET",
|
|
772
|
+
`/v1/scheduling/proposals/${id}`,
|
|
773
|
+
void 0,
|
|
774
|
+
void 0,
|
|
775
|
+
options
|
|
776
|
+
);
|
|
777
|
+
}
|
|
778
|
+
async respond(id, params, options) {
|
|
779
|
+
return this.client.request(
|
|
780
|
+
"POST",
|
|
781
|
+
`/v1/scheduling/proposals/${id}/respond`,
|
|
782
|
+
params,
|
|
783
|
+
void 0,
|
|
784
|
+
options
|
|
785
|
+
);
|
|
786
|
+
}
|
|
787
|
+
async resolve(id, options) {
|
|
788
|
+
return this.client.request(
|
|
789
|
+
"POST",
|
|
790
|
+
`/v1/scheduling/proposals/${id}/resolve`,
|
|
791
|
+
void 0,
|
|
792
|
+
void 0,
|
|
793
|
+
options
|
|
794
|
+
);
|
|
795
|
+
}
|
|
796
|
+
async cancel(id, options) {
|
|
797
|
+
return this.client.request(
|
|
798
|
+
"POST",
|
|
799
|
+
`/v1/scheduling/proposals/${id}/cancel`,
|
|
800
|
+
void 0,
|
|
801
|
+
void 0,
|
|
802
|
+
options
|
|
803
|
+
);
|
|
804
|
+
}
|
|
805
|
+
};
|
|
806
|
+
|
|
807
|
+
// src/resources/usage.ts
|
|
808
|
+
var UsageClient = class {
|
|
809
|
+
constructor(client) {
|
|
810
|
+
this.client = client;
|
|
811
|
+
}
|
|
812
|
+
client;
|
|
813
|
+
async get(options) {
|
|
814
|
+
return this.client.request("GET", "/v1/usage", void 0, void 0, options);
|
|
815
|
+
}
|
|
816
|
+
};
|
|
817
|
+
|
|
818
|
+
// src/resources/audit-log.ts
|
|
819
|
+
var AuditLogClient = class {
|
|
820
|
+
constructor(client) {
|
|
821
|
+
this.client = client;
|
|
822
|
+
}
|
|
823
|
+
client;
|
|
824
|
+
async list(params, options) {
|
|
825
|
+
const query = {
|
|
826
|
+
from: params?.from,
|
|
827
|
+
to: params?.to,
|
|
828
|
+
action: params?.action,
|
|
829
|
+
actor_key_prefix: params?.actor_key_prefix,
|
|
830
|
+
cursor: params?.cursor,
|
|
831
|
+
limit: params?.limit
|
|
832
|
+
};
|
|
833
|
+
return this.client.request("GET", "/v1/audit-log", void 0, query, options);
|
|
834
|
+
}
|
|
835
|
+
};
|
|
836
|
+
|
|
837
|
+
// src/resources/keys.ts
|
|
838
|
+
var KeysClient = class {
|
|
839
|
+
constructor(client) {
|
|
840
|
+
this.client = client;
|
|
841
|
+
}
|
|
842
|
+
client;
|
|
843
|
+
async create(params, options) {
|
|
844
|
+
return this.client.request("POST", "/v1/keys", params, void 0, options);
|
|
845
|
+
}
|
|
846
|
+
async list(options) {
|
|
847
|
+
const response = await this.client.request(
|
|
848
|
+
"GET",
|
|
849
|
+
"/v1/keys",
|
|
850
|
+
void 0,
|
|
851
|
+
void 0,
|
|
852
|
+
options
|
|
853
|
+
);
|
|
854
|
+
return response.keys;
|
|
855
|
+
}
|
|
856
|
+
async delete(id, options) {
|
|
857
|
+
await this.client.request("DELETE", `/v1/keys/${id}`, void 0, void 0, options);
|
|
858
|
+
}
|
|
859
|
+
};
|
|
860
|
+
|
|
861
|
+
// src/resources/agent-auth.ts
|
|
862
|
+
var AgentAuthClient = class {
|
|
863
|
+
constructor(client) {
|
|
864
|
+
this.client = client;
|
|
865
|
+
}
|
|
866
|
+
client;
|
|
867
|
+
/**
|
|
868
|
+
* Register a new agent + org. Sends an OTP to the provided email.
|
|
869
|
+
*
|
|
870
|
+
* No authentication required — callers may construct a `Chronary` client
|
|
871
|
+
* with no `apiKey` to invoke this method.
|
|
872
|
+
*
|
|
873
|
+
* The response is a discriminated union:
|
|
874
|
+
* - **New org path** — returns `org_id`, `agent_id`, and `api_key`.
|
|
875
|
+
* The `api_key` is restricted to the verify endpoint until the OTP
|
|
876
|
+
* is submitted successfully; after verification it unlocks the full API.
|
|
877
|
+
* - **Existing-org dedup** — returns only `message`. No credentials are
|
|
878
|
+
* leaked when the email matches an existing org (enumeration defense).
|
|
879
|
+
*
|
|
880
|
+
* Use `isAgentSignUpNewOrg()` to narrow the union before accessing keys.
|
|
881
|
+
*
|
|
882
|
+
* @throws ChronaryError (409 `tos_version_stale`) if `tos_version` is not
|
|
883
|
+
* the currently-published version — retry with the value from the
|
|
884
|
+
* `current_version` field on the error body.
|
|
885
|
+
*/
|
|
886
|
+
async signUp(params, options) {
|
|
887
|
+
return this.client.request(
|
|
888
|
+
"POST",
|
|
889
|
+
"/v1/agent/sign-up",
|
|
890
|
+
params,
|
|
891
|
+
void 0,
|
|
892
|
+
options
|
|
893
|
+
);
|
|
894
|
+
}
|
|
895
|
+
/**
|
|
896
|
+
* Submit the OTP sent during `signUp()` to unlock the API key.
|
|
897
|
+
*
|
|
898
|
+
* Must be invoked on a `Chronary` client constructed with the restricted
|
|
899
|
+
* `api_key` returned by `signUp()` — NOT on the client that issued
|
|
900
|
+
* `signUp()` itself (which had no key).
|
|
901
|
+
*
|
|
902
|
+
* @throws ChronaryError (status 400) when the OTP is wrong or expired.
|
|
903
|
+
* The SDK's `ValidationError` class is reserved for HTTP 422; the
|
|
904
|
+
* API returns 400 for invalid/expired OTPs, which surfaces as a
|
|
905
|
+
* generic `ChronaryError` with the original message.
|
|
906
|
+
*/
|
|
907
|
+
async verify(params, options) {
|
|
908
|
+
return this.client.request(
|
|
909
|
+
"POST",
|
|
910
|
+
"/v1/agent/verify",
|
|
911
|
+
params,
|
|
912
|
+
void 0,
|
|
913
|
+
options
|
|
914
|
+
);
|
|
915
|
+
}
|
|
916
|
+
};
|
|
917
|
+
function isAgentSignUpNewOrg(response) {
|
|
918
|
+
return "api_key" in response;
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
// src/resources/waitlist.ts
|
|
922
|
+
var WaitlistClient = class {
|
|
923
|
+
constructor(client) {
|
|
924
|
+
this.client = client;
|
|
925
|
+
}
|
|
926
|
+
client;
|
|
927
|
+
/**
|
|
928
|
+
* Join the Chronary waitlist (#442). Used during private preview when open
|
|
929
|
+
* signup is gated. Creates a real organization row flagged as
|
|
930
|
+
* `is_waitlisted: true`; an admin flips the flag to activate the account.
|
|
931
|
+
*
|
|
932
|
+
* No authentication required — invoke on a `Chronary` client constructed
|
|
933
|
+
* with no `apiKey`.
|
|
934
|
+
*
|
|
935
|
+
* Idempotent on repeat hits: a second call with the same email returns
|
|
936
|
+
* the existing waitlisted org instead of erroring. An active (non-waitlisted)
|
|
937
|
+
* account at the same email returns 409 `email_taken`.
|
|
938
|
+
*
|
|
939
|
+
* @throws ChronaryError (409 `email_taken`) when an active account already
|
|
940
|
+
* exists for this email — direct the user to sign-in instead.
|
|
941
|
+
* @throws ChronaryError (409 `tos_version_stale`) when the supplied
|
|
942
|
+
* `tos_version` doesn't match the currently-published version.
|
|
943
|
+
* @throws ChronaryError (429 `rate_limit_error`) on the per-IP / per-email
|
|
944
|
+
* waitlist limiter.
|
|
945
|
+
*/
|
|
946
|
+
async join(params, options) {
|
|
947
|
+
return this.client.request(
|
|
948
|
+
"POST",
|
|
949
|
+
"/v1/waitlist",
|
|
950
|
+
params,
|
|
951
|
+
void 0,
|
|
952
|
+
options
|
|
953
|
+
);
|
|
954
|
+
}
|
|
955
|
+
};
|
|
956
|
+
|
|
957
|
+
// src/resources/feedback.ts
|
|
958
|
+
var FeedbackClient = class {
|
|
959
|
+
constructor(client) {
|
|
960
|
+
this.client = client;
|
|
961
|
+
}
|
|
962
|
+
client;
|
|
963
|
+
/**
|
|
964
|
+
* Submit structured feedback (bug, feature, or friction) to Chronary.
|
|
965
|
+
*
|
|
966
|
+
* Rate-limited to 25 submissions per day per organization (UTC day).
|
|
967
|
+
* Available on all plans, including free. The 26th submission returns
|
|
968
|
+
* HTTP 429 with a `Retry-After` header set to the seconds until the
|
|
969
|
+
* next UTC midnight.
|
|
970
|
+
*/
|
|
971
|
+
async submit(params, options) {
|
|
972
|
+
return this.client.request(
|
|
973
|
+
"POST",
|
|
974
|
+
"/v1/feedback",
|
|
975
|
+
params,
|
|
976
|
+
void 0,
|
|
977
|
+
options
|
|
978
|
+
);
|
|
979
|
+
}
|
|
980
|
+
};
|
|
981
|
+
|
|
982
|
+
// src/resources/plans.ts
|
|
983
|
+
var PlansClient = class {
|
|
984
|
+
constructor(client) {
|
|
985
|
+
this.client = client;
|
|
986
|
+
}
|
|
987
|
+
client;
|
|
988
|
+
/**
|
|
989
|
+
* Fetch the public plan catalog (`GET /v1/plans`).
|
|
990
|
+
*
|
|
991
|
+
* Returns all sellable tiers (free, pro, scale) plus the enterprise
|
|
992
|
+
* tier with `custom_pricing: true`. No authentication required.
|
|
993
|
+
* Responses are cacheable for 5 minutes at the edge.
|
|
994
|
+
*/
|
|
995
|
+
async list(options) {
|
|
996
|
+
return this.client.request("GET", "/v1/plans", void 0, void 0, options);
|
|
997
|
+
}
|
|
998
|
+
};
|
|
999
|
+
|
|
1000
|
+
// src/resources/account.ts
|
|
1001
|
+
var AccountClient = class {
|
|
1002
|
+
constructor(client) {
|
|
1003
|
+
this.client = client;
|
|
1004
|
+
}
|
|
1005
|
+
client;
|
|
1006
|
+
/**
|
|
1007
|
+
* Export every row this org owns as a single JSON payload (GDPR Art. 15 + 20
|
|
1008
|
+
* portability / CCPA right-to-know / EU Data Act interoperability).
|
|
1009
|
+
*
|
|
1010
|
+
* **Authentication:** This endpoint is JWT-only — it returns decrypted
|
|
1011
|
+
* webhook secrets and iCal subscription URLs that aren't normally accessible
|
|
1012
|
+
* via API-key endpoints. Configure the SDK with a console JWT (e.g. cookie
|
|
1013
|
+
* value or Bearer token from the console session) as the `apiKey` config to
|
|
1014
|
+
* call this. API keys (`chr_sk_*` / `chr_ak_*`) will return 401.
|
|
1015
|
+
*
|
|
1016
|
+
* In most cases, end users should download via the console UI at
|
|
1017
|
+
* `console.chronary.ai/settings`. The SDK method exists for programmatic
|
|
1018
|
+
* use cases (e.g. server-side compliance tooling holding a delegated JWT).
|
|
1019
|
+
*
|
|
1020
|
+
* **Rate limit:** 10 exports/hour/org.
|
|
1021
|
+
*/
|
|
1022
|
+
async export(options) {
|
|
1023
|
+
return this.client.request(
|
|
1024
|
+
"GET",
|
|
1025
|
+
"/v1/auth/export",
|
|
1026
|
+
void 0,
|
|
1027
|
+
void 0,
|
|
1028
|
+
options
|
|
1029
|
+
);
|
|
1030
|
+
}
|
|
1031
|
+
};
|
|
1032
|
+
|
|
1033
|
+
// src/webhook-verify.ts
|
|
1034
|
+
var DEFAULT_TOLERANCE = 5 * 60 * 1e3;
|
|
1035
|
+
function bufToHex(buf) {
|
|
1036
|
+
return Array.from(new Uint8Array(buf)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
1037
|
+
}
|
|
1038
|
+
async function computeSignature(secret, timestamp, payload) {
|
|
1039
|
+
const encoder = new TextEncoder();
|
|
1040
|
+
const key = await crypto.subtle.importKey(
|
|
1041
|
+
"raw",
|
|
1042
|
+
encoder.encode(secret),
|
|
1043
|
+
{ name: "HMAC", hash: "SHA-256" },
|
|
1044
|
+
false,
|
|
1045
|
+
["sign"]
|
|
1046
|
+
);
|
|
1047
|
+
const message = encoder.encode(`${timestamp}.${payload}`);
|
|
1048
|
+
const sig = await crypto.subtle.sign("HMAC", key, message);
|
|
1049
|
+
return `sha256=${bufToHex(sig)}`;
|
|
1050
|
+
}
|
|
1051
|
+
function constantTimeEqual(a, b) {
|
|
1052
|
+
const encoder = new TextEncoder();
|
|
1053
|
+
const aBuf = encoder.encode(a);
|
|
1054
|
+
const bBuf = encoder.encode(b);
|
|
1055
|
+
if (aBuf.length !== bBuf.length) return false;
|
|
1056
|
+
let diff = 0;
|
|
1057
|
+
for (let i = 0; i < aBuf.length; i++) diff |= aBuf[i] ^ bBuf[i];
|
|
1058
|
+
return diff === 0;
|
|
1059
|
+
}
|
|
1060
|
+
function getHeader(headers, name) {
|
|
1061
|
+
if (headers instanceof Headers) return headers.get(name);
|
|
1062
|
+
const record = headers;
|
|
1063
|
+
const direct = record[name] ?? record[name.toLowerCase()];
|
|
1064
|
+
if (direct !== void 0) return direct;
|
|
1065
|
+
const lowerName = name.toLowerCase();
|
|
1066
|
+
for (const [key, value] of Object.entries(record)) {
|
|
1067
|
+
if (key.toLowerCase() === lowerName) return value;
|
|
1068
|
+
}
|
|
1069
|
+
return null;
|
|
1070
|
+
}
|
|
1071
|
+
function extractHeaders(headers) {
|
|
1072
|
+
const get = (name) => {
|
|
1073
|
+
return getHeader(headers, name);
|
|
1074
|
+
};
|
|
1075
|
+
const signature = get("X-Signature") ?? get("x-signature");
|
|
1076
|
+
const timestamp = get("X-Timestamp") ?? get("x-timestamp");
|
|
1077
|
+
if (!signature) throw new ChronaryError("Missing X-Signature header", 0);
|
|
1078
|
+
if (!timestamp) throw new ChronaryError("Missing X-Timestamp header", 0);
|
|
1079
|
+
return { signature, timestamp };
|
|
1080
|
+
}
|
|
1081
|
+
async function verifySignature(rawBody, headers, secret, options) {
|
|
1082
|
+
if (typeof rawBody !== "string") {
|
|
1083
|
+
throw new ChronaryError(
|
|
1084
|
+
"rawBody must be a string. If you parsed the JSON body, pass the raw string instead.",
|
|
1085
|
+
0
|
|
1086
|
+
);
|
|
1087
|
+
}
|
|
1088
|
+
const { signature, timestamp } = extractHeaders(headers);
|
|
1089
|
+
const tolerance = options?.tolerance ?? DEFAULT_TOLERANCE;
|
|
1090
|
+
const tsMs = parseInt(timestamp, 10) * 1e3;
|
|
1091
|
+
const now = Date.now();
|
|
1092
|
+
if (Math.abs(now - tsMs) > tolerance) {
|
|
1093
|
+
throw new ChronaryError(
|
|
1094
|
+
`Webhook timestamp too old. Received ${timestamp}, current time ${Math.floor(now / 1e3)}. Tolerance: ${tolerance / 1e3}s`,
|
|
1095
|
+
0
|
|
1096
|
+
);
|
|
1097
|
+
}
|
|
1098
|
+
const expected = await computeSignature(secret, timestamp, rawBody);
|
|
1099
|
+
if (!constantTimeEqual(expected, signature)) {
|
|
1100
|
+
throw new ChronaryError("Webhook signature verification failed", 0);
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
async function constructEvent(rawBody, headers, secret, options) {
|
|
1104
|
+
await verifySignature(rawBody, headers, secret, options);
|
|
1105
|
+
const type = getHeader(headers, "X-Chronary-Event-Type");
|
|
1106
|
+
if (!type) throw new ChronaryError("Missing X-Chronary-Event-Type header", 0);
|
|
1107
|
+
const data = JSON.parse(rawBody);
|
|
1108
|
+
return { type, data };
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
// src/index.ts
|
|
1112
|
+
var Chronary = class {
|
|
1113
|
+
agents;
|
|
1114
|
+
calendars;
|
|
1115
|
+
events;
|
|
1116
|
+
availability;
|
|
1117
|
+
webhooks;
|
|
1118
|
+
icalSubscriptions;
|
|
1119
|
+
scheduling;
|
|
1120
|
+
usage;
|
|
1121
|
+
auditLog;
|
|
1122
|
+
keys;
|
|
1123
|
+
agentAuth;
|
|
1124
|
+
waitlist;
|
|
1125
|
+
feedback;
|
|
1126
|
+
plans;
|
|
1127
|
+
account;
|
|
1128
|
+
constructor(config) {
|
|
1129
|
+
const client = new CoreClient(config);
|
|
1130
|
+
this.agents = new AgentsClient(client);
|
|
1131
|
+
this.calendars = new CalendarsClient(client);
|
|
1132
|
+
this.events = new EventsClient(client);
|
|
1133
|
+
this.availability = new AvailabilityClient(client);
|
|
1134
|
+
this.webhooks = new WebhooksClient(client);
|
|
1135
|
+
this.icalSubscriptions = new ICalSubscriptionsClient(client);
|
|
1136
|
+
this.scheduling = new SchedulingClient(client);
|
|
1137
|
+
this.usage = new UsageClient(client);
|
|
1138
|
+
this.auditLog = new AuditLogClient(client);
|
|
1139
|
+
this.keys = new KeysClient(client);
|
|
1140
|
+
this.agentAuth = new AgentAuthClient(client);
|
|
1141
|
+
this.waitlist = new WaitlistClient(client);
|
|
1142
|
+
this.feedback = new FeedbackClient(client);
|
|
1143
|
+
this.plans = new PlansClient(client);
|
|
1144
|
+
this.account = new AccountClient(client);
|
|
1145
|
+
}
|
|
1146
|
+
static webhooks = {
|
|
1147
|
+
verifySignature,
|
|
1148
|
+
constructEvent
|
|
1149
|
+
};
|
|
1150
|
+
};
|
|
1151
|
+
var index_default = Chronary;
|
|
1152
|
+
export {
|
|
1153
|
+
APIPromise,
|
|
1154
|
+
AuthenticationError,
|
|
1155
|
+
Chronary,
|
|
1156
|
+
ChronaryError,
|
|
1157
|
+
ConnectionError,
|
|
1158
|
+
CoreClient,
|
|
1159
|
+
NotFoundError,
|
|
1160
|
+
PageIterator,
|
|
1161
|
+
QuotaExceededError,
|
|
1162
|
+
RateLimitError,
|
|
1163
|
+
TimeoutError,
|
|
1164
|
+
VERSION,
|
|
1165
|
+
ValidationError,
|
|
1166
|
+
constructEvent,
|
|
1167
|
+
index_default as default,
|
|
1168
|
+
isAgentSignUpNewOrg,
|
|
1169
|
+
verifySignature
|
|
1170
|
+
};
|
|
1171
|
+
//# sourceMappingURL=index.js.map
|