@hellopivot/sdk 0.0.1
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/LICENSE +21 -0
- package/README.md +73 -0
- package/dist/index.d.mts +1664 -0
- package/dist/index.mjs +829 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +45 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,829 @@
|
|
|
1
|
+
import { createHmac, timingSafeEqual } from 'crypto';
|
|
2
|
+
|
|
3
|
+
// libs/pivot-sdk/src/errors.ts
|
|
4
|
+
var PivotError = class extends Error {
|
|
5
|
+
constructor(message) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = "PivotError";
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
var PivotAPIError = class extends PivotError {
|
|
11
|
+
status;
|
|
12
|
+
statusText;
|
|
13
|
+
body;
|
|
14
|
+
headers;
|
|
15
|
+
constructor(status, statusText, body, headers) {
|
|
16
|
+
const message = typeof body === "object" && body !== null && "message" in body ? String(body.message) : `API error: ${status} ${statusText}`;
|
|
17
|
+
super(message);
|
|
18
|
+
this.name = "PivotAPIError";
|
|
19
|
+
this.status = status;
|
|
20
|
+
this.statusText = statusText;
|
|
21
|
+
this.body = body;
|
|
22
|
+
this.headers = headers;
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
var PivotTimeoutError = class extends PivotError {
|
|
26
|
+
constructor(timeoutMs) {
|
|
27
|
+
super(`Request timed out after ${timeoutMs}ms`);
|
|
28
|
+
this.name = "PivotTimeoutError";
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
var PivotRetryError = class extends PivotError {
|
|
32
|
+
lastError;
|
|
33
|
+
attempts;
|
|
34
|
+
constructor(lastError, attempts) {
|
|
35
|
+
super(
|
|
36
|
+
`All ${attempts} retry attempts failed. Last error: ${lastError.message}`
|
|
37
|
+
);
|
|
38
|
+
this.name = "PivotRetryError";
|
|
39
|
+
this.lastError = lastError;
|
|
40
|
+
this.attempts = attempts;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
var PivotAuthenticationError = class extends PivotError {
|
|
44
|
+
constructor() {
|
|
45
|
+
super(
|
|
46
|
+
"API key is required. Pass it via the `apiKey` option or set the PIVOT_API_KEY environment variable."
|
|
47
|
+
);
|
|
48
|
+
this.name = "PivotAuthenticationError";
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
// libs/pivot-sdk/src/retry.ts
|
|
53
|
+
var DEFAULT_RETRY_CONFIG = {
|
|
54
|
+
maxRetries: 3,
|
|
55
|
+
initialDelayMs: 500,
|
|
56
|
+
maxDelayMs: 3e4,
|
|
57
|
+
backoffMultiplier: 2,
|
|
58
|
+
jitterFactor: 0.25,
|
|
59
|
+
retryableStatusCodes: [408, 409, 429, 500, 502, 503, 504]
|
|
60
|
+
};
|
|
61
|
+
function calculateDelay(attempt, config) {
|
|
62
|
+
const baseDelay = config.initialDelayMs * Math.pow(config.backoffMultiplier, attempt);
|
|
63
|
+
const cappedDelay = Math.min(baseDelay, config.maxDelayMs);
|
|
64
|
+
const jitter = cappedDelay * config.jitterFactor * (2 * Math.random() - 1);
|
|
65
|
+
return Math.max(0, Math.round(cappedDelay + jitter));
|
|
66
|
+
}
|
|
67
|
+
function isRetryable(error, config) {
|
|
68
|
+
if (error instanceof TypeError) return true;
|
|
69
|
+
if (error instanceof PivotAPIError) {
|
|
70
|
+
return config.retryableStatusCodes.includes(error.status);
|
|
71
|
+
}
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
function sleep(ms) {
|
|
75
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
76
|
+
}
|
|
77
|
+
async function withRetry(fn, config) {
|
|
78
|
+
let lastError;
|
|
79
|
+
for (let attempt = 0; attempt <= config.maxRetries; attempt++) {
|
|
80
|
+
try {
|
|
81
|
+
return await fn();
|
|
82
|
+
} catch (error) {
|
|
83
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
84
|
+
const retryable = isRetryable(error, config);
|
|
85
|
+
if (attempt < config.maxRetries && retryable) {
|
|
86
|
+
let delayMs = calculateDelay(attempt, config);
|
|
87
|
+
if (error instanceof PivotAPIError) {
|
|
88
|
+
const retryAfter = error.headers["retry-after"];
|
|
89
|
+
if (retryAfter) {
|
|
90
|
+
const retryAfterMs = Number(retryAfter) * 1e3;
|
|
91
|
+
if (!isNaN(retryAfterMs) && retryAfterMs > 0) {
|
|
92
|
+
delayMs = Math.min(retryAfterMs, config.maxDelayMs);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
await sleep(delayMs);
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
if (!retryable) {
|
|
100
|
+
throw lastError;
|
|
101
|
+
}
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
throw new PivotRetryError(
|
|
106
|
+
lastError ?? new Error("Unknown error"),
|
|
107
|
+
config.maxRetries + 1
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// libs/pivot-sdk/src/client-core.ts
|
|
112
|
+
var PivotClientCore = class {
|
|
113
|
+
apiKey;
|
|
114
|
+
baseUrl;
|
|
115
|
+
timeoutMs;
|
|
116
|
+
retryConfig;
|
|
117
|
+
fetchFn;
|
|
118
|
+
defaultHeaders;
|
|
119
|
+
constructor(options = {}) {
|
|
120
|
+
this.apiKey = options.apiKey ?? (typeof process !== "undefined" ? process.env?.["PIVOT_API_KEY"] ?? "" : "");
|
|
121
|
+
if (!this.apiKey) {
|
|
122
|
+
throw new PivotAuthenticationError();
|
|
123
|
+
}
|
|
124
|
+
this.baseUrl = (options.baseUrl ?? "https://api.pivot.app").replace(
|
|
125
|
+
/\/$/,
|
|
126
|
+
""
|
|
127
|
+
);
|
|
128
|
+
this.timeoutMs = options.timeoutMs ?? 3e4;
|
|
129
|
+
this.fetchFn = options.fetch ?? globalThis.fetch;
|
|
130
|
+
this.defaultHeaders = {
|
|
131
|
+
"Content-Type": "application/json",
|
|
132
|
+
Accept: "application/json",
|
|
133
|
+
...options.defaultHeaders
|
|
134
|
+
};
|
|
135
|
+
if (options.retry === false) {
|
|
136
|
+
this.retryConfig = false;
|
|
137
|
+
} else {
|
|
138
|
+
this.retryConfig = {
|
|
139
|
+
...DEFAULT_RETRY_CONFIG,
|
|
140
|
+
...options.retry
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Make an authenticated HTTP request to the Pivot API.
|
|
146
|
+
*/
|
|
147
|
+
async request(method, path, options = {}) {
|
|
148
|
+
const doRequest = async () => {
|
|
149
|
+
const url = new URL(`${this.baseUrl}${path}`);
|
|
150
|
+
if (options.query) {
|
|
151
|
+
for (const [key, value] of Object.entries(options.query)) {
|
|
152
|
+
if (value !== void 0 && value !== null) {
|
|
153
|
+
if (Array.isArray(value)) {
|
|
154
|
+
for (const v of value) {
|
|
155
|
+
url.searchParams.append(key, String(v));
|
|
156
|
+
}
|
|
157
|
+
} else {
|
|
158
|
+
url.searchParams.set(key, String(value));
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
const headers = {
|
|
164
|
+
...this.defaultHeaders,
|
|
165
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
166
|
+
...options.headers
|
|
167
|
+
};
|
|
168
|
+
const init = {
|
|
169
|
+
method,
|
|
170
|
+
headers
|
|
171
|
+
};
|
|
172
|
+
if (options.body !== void 0 && method !== "GET") {
|
|
173
|
+
init.body = JSON.stringify(options.body);
|
|
174
|
+
}
|
|
175
|
+
const timeoutMs = options.timeoutMs ?? this.timeoutMs;
|
|
176
|
+
const controller = new AbortController();
|
|
177
|
+
let didTimeout = false;
|
|
178
|
+
const timeoutId = setTimeout(() => {
|
|
179
|
+
didTimeout = true;
|
|
180
|
+
controller.abort();
|
|
181
|
+
}, timeoutMs);
|
|
182
|
+
const onAbort = () => controller.abort();
|
|
183
|
+
if (options.signal) {
|
|
184
|
+
if (options.signal.aborted) {
|
|
185
|
+
controller.abort();
|
|
186
|
+
} else {
|
|
187
|
+
options.signal.addEventListener("abort", onAbort, { once: true });
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
init.signal = controller.signal;
|
|
191
|
+
let response;
|
|
192
|
+
try {
|
|
193
|
+
response = await this.fetchFn(url.toString(), init);
|
|
194
|
+
} catch (error) {
|
|
195
|
+
clearTimeout(timeoutId);
|
|
196
|
+
if (error?.name === "AbortError" && didTimeout) {
|
|
197
|
+
throw new PivotTimeoutError(timeoutMs);
|
|
198
|
+
}
|
|
199
|
+
throw error;
|
|
200
|
+
} finally {
|
|
201
|
+
clearTimeout(timeoutId);
|
|
202
|
+
if (options.signal) {
|
|
203
|
+
options.signal.removeEventListener("abort", onAbort);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
const responseHeaders = {};
|
|
207
|
+
response.headers.forEach((value, key) => {
|
|
208
|
+
responseHeaders[key] = value;
|
|
209
|
+
});
|
|
210
|
+
if (!response.ok) {
|
|
211
|
+
let body;
|
|
212
|
+
try {
|
|
213
|
+
body = await response.json();
|
|
214
|
+
} catch {
|
|
215
|
+
body = await response.text().catch(() => null);
|
|
216
|
+
}
|
|
217
|
+
throw new PivotAPIError(
|
|
218
|
+
response.status,
|
|
219
|
+
response.statusText,
|
|
220
|
+
body,
|
|
221
|
+
responseHeaders
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
const contentType = response.headers.get("content-type");
|
|
225
|
+
if (contentType?.includes("application/json")) {
|
|
226
|
+
return await response.json();
|
|
227
|
+
}
|
|
228
|
+
return await response.text();
|
|
229
|
+
};
|
|
230
|
+
if (this.retryConfig) {
|
|
231
|
+
return withRetry(doRequest, this.retryConfig);
|
|
232
|
+
}
|
|
233
|
+
return doRequest();
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
// libs/pivot-sdk/src/generated/resources.ts
|
|
238
|
+
var BlocksResource = class {
|
|
239
|
+
constructor(client) {
|
|
240
|
+
this.client = client;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Delete a block response attachment
|
|
244
|
+
*
|
|
245
|
+
* Deletes a file attached to a block response.
|
|
246
|
+
*/
|
|
247
|
+
async deleteBlockResponseAttachment(attachmentId) {
|
|
248
|
+
return this.client.request("DELETE", `/v1/blocks/responses/attachments/${attachmentId}`);
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Delete a block response
|
|
252
|
+
*
|
|
253
|
+
* Deletes a response from a block.
|
|
254
|
+
*/
|
|
255
|
+
async deleteResponseForBlock(responseId) {
|
|
256
|
+
return this.client.request("DELETE", `/v1/blocks/responses/${responseId}`);
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Update block response
|
|
260
|
+
*
|
|
261
|
+
* Updates an existing block response.
|
|
262
|
+
*/
|
|
263
|
+
async updateResponseForBlock(responseId, body) {
|
|
264
|
+
return this.client.request("PATCH", `/v1/blocks/responses/${responseId}`, { body });
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Create an attachment for a block response
|
|
268
|
+
*
|
|
269
|
+
* Adds a file to a block response.
|
|
270
|
+
*/
|
|
271
|
+
async createBlockResponseAttachment(responseId, body) {
|
|
272
|
+
return this.client.request("POST", `/v1/blocks/responses/${responseId}/attachments`, { body });
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Send block response
|
|
276
|
+
*
|
|
277
|
+
* Sends or marks the response as submitted.
|
|
278
|
+
*/
|
|
279
|
+
async sendResponseForBlock(responseId) {
|
|
280
|
+
return this.client.request("POST", `/v1/blocks/responses/${responseId}/send`);
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Get block
|
|
284
|
+
*
|
|
285
|
+
* Returns a block by ID.
|
|
286
|
+
*/
|
|
287
|
+
async getBlockById(blockId) {
|
|
288
|
+
return this.client.request("GET", `/v1/blocks/${blockId}`);
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* List block responses
|
|
292
|
+
*
|
|
293
|
+
* Returns responses for a block.
|
|
294
|
+
*/
|
|
295
|
+
async getBlockResponsesByBlockId(blockId) {
|
|
296
|
+
return this.client.request("GET", `/v1/blocks/${blockId}/responses`);
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Create block response
|
|
300
|
+
*
|
|
301
|
+
* Creates a new response for a block.
|
|
302
|
+
*/
|
|
303
|
+
async createResponseForBlock(blockId, body) {
|
|
304
|
+
return this.client.request("POST", `/v1/blocks/${blockId}/responses`, { body });
|
|
305
|
+
}
|
|
306
|
+
};
|
|
307
|
+
var GroupsResource = class {
|
|
308
|
+
constructor(client) {
|
|
309
|
+
this.client = client;
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* List groups
|
|
313
|
+
*
|
|
314
|
+
* Returns groups in the organization.
|
|
315
|
+
*/
|
|
316
|
+
async getGroupsByOrganizationId(organizationId, offset) {
|
|
317
|
+
return this.client.request("GET", `/v1/organizations/${organizationId}/groups/${offset}`);
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* List group members
|
|
321
|
+
*
|
|
322
|
+
* Returns users in the specified group.
|
|
323
|
+
*/
|
|
324
|
+
async getGroupMembersByGroupId(organizationId, groupId) {
|
|
325
|
+
return this.client.request("GET", `/v1/organizations/${organizationId}/${groupId}/members`);
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Add group members
|
|
329
|
+
*
|
|
330
|
+
* Adds users to the specified group.
|
|
331
|
+
*/
|
|
332
|
+
async createGroupMembersByGroupId(organizationId, groupId, body) {
|
|
333
|
+
return this.client.request("POST", `/v1/organizations/${organizationId}/${groupId}/members`, { body });
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Remove group members
|
|
337
|
+
*
|
|
338
|
+
* Removes users from a group.
|
|
339
|
+
*/
|
|
340
|
+
async deleteGroupMembersByGroupId(organizationId, groupId, query) {
|
|
341
|
+
return this.client.request("DELETE", `/v1/organizations/${organizationId}/${groupId}/members`, { query });
|
|
342
|
+
}
|
|
343
|
+
};
|
|
344
|
+
var InvitesResource = class {
|
|
345
|
+
constructor(client) {
|
|
346
|
+
this.client = client;
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Revoke invite by ID
|
|
350
|
+
*
|
|
351
|
+
* Revokes an invitation by its unique ID and email address.
|
|
352
|
+
*/
|
|
353
|
+
async revokeInviteById(organizationId, inviteId, email) {
|
|
354
|
+
return this.client.request("DELETE", `/v1/organizations/${organizationId}/invites/${inviteId}/${email}`);
|
|
355
|
+
}
|
|
356
|
+
};
|
|
357
|
+
var LabelsResource = class {
|
|
358
|
+
constructor(client) {
|
|
359
|
+
this.client = client;
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Delete label
|
|
363
|
+
*
|
|
364
|
+
* Deletes a label.
|
|
365
|
+
*/
|
|
366
|
+
async deleteLabel(labelId) {
|
|
367
|
+
return this.client.request("DELETE", `/v1/labels/${labelId}`);
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* Update label
|
|
371
|
+
*
|
|
372
|
+
* Updates an existing label.
|
|
373
|
+
*/
|
|
374
|
+
async updateLabel(labelId, body) {
|
|
375
|
+
return this.client.request("PATCH", `/v1/labels/${labelId}`, { body });
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* List organization labels
|
|
379
|
+
*
|
|
380
|
+
* Returns labels in the organization.
|
|
381
|
+
*/
|
|
382
|
+
async getLabelsByOrganizationId(organizationId) {
|
|
383
|
+
return this.client.request("GET", `/v1/organizations/${organizationId}/labels`);
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Create label
|
|
387
|
+
*
|
|
388
|
+
* Creates a new label in the organization.
|
|
389
|
+
*/
|
|
390
|
+
async createLabel(organizationId, body) {
|
|
391
|
+
return this.client.request("POST", `/v1/organizations/${organizationId}/labels`, { body });
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* Update space labels
|
|
395
|
+
*
|
|
396
|
+
* Adds labels to a space without removing existing labels. To remove labels, use the DELETE endpoint.
|
|
397
|
+
*/
|
|
398
|
+
async updateSpaceLabels(spaceId, body) {
|
|
399
|
+
return this.client.request("PATCH", `/v1/spaces/${spaceId}/labels`, { body });
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Remove label from space
|
|
403
|
+
*
|
|
404
|
+
* Removes a single label from a space.
|
|
405
|
+
*/
|
|
406
|
+
async removeLabelFromSpace(spaceId, labelId) {
|
|
407
|
+
return this.client.request("DELETE", `/v1/spaces/${spaceId}/labels/${labelId}`);
|
|
408
|
+
}
|
|
409
|
+
};
|
|
410
|
+
var RoomsResource = class {
|
|
411
|
+
constructor(client) {
|
|
412
|
+
this.client = client;
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* Get room
|
|
416
|
+
*
|
|
417
|
+
* Returns a room by ID.
|
|
418
|
+
*/
|
|
419
|
+
async getRoomById(roomId) {
|
|
420
|
+
return this.client.request("GET", `/v1/rooms/${roomId}`);
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* Invite to room
|
|
424
|
+
*
|
|
425
|
+
* Invites users to a room by email.
|
|
426
|
+
*/
|
|
427
|
+
async inviteToRoomByEmails(roomId, body) {
|
|
428
|
+
return this.client.request("POST", `/v1/rooms/${roomId}/invites`, { body });
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Revoke room invite
|
|
432
|
+
*
|
|
433
|
+
* Revokes an invitation to a room by email address.
|
|
434
|
+
*/
|
|
435
|
+
async revokeRoomInvite(roomId, email) {
|
|
436
|
+
return this.client.request("DELETE", `/v1/rooms/${roomId}/invites/${email}`);
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Add room members
|
|
440
|
+
*
|
|
441
|
+
* Adds users to a room with a role.
|
|
442
|
+
*/
|
|
443
|
+
async createRoomMembersByRoomId(roomId, body) {
|
|
444
|
+
return this.client.request("POST", `/v1/rooms/${roomId}/members`, { body });
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* List room messages (Deprecated)
|
|
448
|
+
*
|
|
449
|
+
* Deprecated: Use GET /v2/rooms/{room_id}/messages instead. Returns messages in a room by offset.
|
|
450
|
+
* @deprecated
|
|
451
|
+
*/
|
|
452
|
+
async getMessagesByRoomId(roomId, offset) {
|
|
453
|
+
return this.client.request("GET", `/v1/rooms/${roomId}/messages/${offset}`);
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* List message replies (Deprecated)
|
|
457
|
+
*
|
|
458
|
+
* Deprecated: Use GET /v2/rooms/{room_id}/threads/{parent_id}/messages instead. Returns replies under a parent message.
|
|
459
|
+
* @deprecated
|
|
460
|
+
*/
|
|
461
|
+
async getMessagesByParentId(roomId, parentId, query) {
|
|
462
|
+
return this.client.request("GET", `/v1/rooms/${roomId}/messages/${parentId}/children`, { query });
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* List room recordings
|
|
466
|
+
*
|
|
467
|
+
* Returns recordings for a room, including transcripts and other assets.
|
|
468
|
+
*/
|
|
469
|
+
async getRoomRecordingsByRoomId(roomId, query) {
|
|
470
|
+
return this.client.request("GET", `/v1/rooms/${roomId}/recordings`, { query });
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* Get room recording
|
|
474
|
+
*
|
|
475
|
+
* Returns a specific room recording by ID, including transcripts and other assets.
|
|
476
|
+
*/
|
|
477
|
+
async getRoomRecordingById(roomId, recordingId, query) {
|
|
478
|
+
return this.client.request("GET", `/v1/rooms/${roomId}/recordings/${recordingId}`, { query });
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* Get active participants in a room and their messages stats
|
|
482
|
+
*
|
|
483
|
+
* Returns active users in a room and their message stats.
|
|
484
|
+
*/
|
|
485
|
+
async getRoomActiveParticipants(roomId) {
|
|
486
|
+
return this.client.request("GET", `/v1/rooms/${roomId}/users`);
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
489
|
+
* List room messages
|
|
490
|
+
*
|
|
491
|
+
* Returns messages in a room using cursor-based pagination (newest first). For partition navigation, backfill strategy, and examples, see https://pivot.app/docs/developers/rest-api/message-retrieval.
|
|
492
|
+
*/
|
|
493
|
+
async getRoomMessages(roomId, query) {
|
|
494
|
+
return this.client.request("GET", `/v2/rooms/${roomId}/messages`, { query });
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* Get message by ID
|
|
498
|
+
*
|
|
499
|
+
* Retrieves a single message by ID.
|
|
500
|
+
|
|
501
|
+
The `sent_at` parameter is currently optional but will become required in a future release. For thread messages, `thread_parent_message_id` will also become required. Clients should start passing these parameters now to ensure continued functionality after the migration.
|
|
502
|
+
*/
|
|
503
|
+
async getMessageById(roomId, messageId, query) {
|
|
504
|
+
return this.client.request("GET", `/v2/rooms/${roomId}/messages/${messageId}`, { query });
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* List thread messages
|
|
508
|
+
*
|
|
509
|
+
* Returns messages in a thread using cursor-based pagination (oldest first). For guidance and examples, see https://pivot.app/docs/developers/rest-api/message-retrieval.
|
|
510
|
+
*/
|
|
511
|
+
async getThreadMessages(roomId, parentId, query) {
|
|
512
|
+
return this.client.request("GET", `/v2/rooms/${roomId}/threads/${parentId}/messages`, { query });
|
|
513
|
+
}
|
|
514
|
+
};
|
|
515
|
+
var SpacesResource = class {
|
|
516
|
+
constructor(client) {
|
|
517
|
+
this.client = client;
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* Create space
|
|
521
|
+
*
|
|
522
|
+
* Creates a new space in the organization.
|
|
523
|
+
*/
|
|
524
|
+
async createSpace(organizationId, body) {
|
|
525
|
+
return this.client.request("POST", `/v1/organizations/${organizationId}/spaces`, { body });
|
|
526
|
+
}
|
|
527
|
+
/**
|
|
528
|
+
* List spaces
|
|
529
|
+
*
|
|
530
|
+
* Returns spaces in the organization. Filter by status using 'active', 'archived', 'hidden', or 'deleted'. If no status is provided, defaults to returning only active spaces. Sort results using sort_by: 'created_at_asc' (default), 'created_at_desc', 'last_activity_asc', or 'last_activity_desc'.
|
|
531
|
+
*/
|
|
532
|
+
async getSpacesByOrganizationId(organizationId, offset, query) {
|
|
533
|
+
return this.client.request("GET", `/v1/organizations/${organizationId}/spaces/${offset}`, { query });
|
|
534
|
+
}
|
|
535
|
+
/**
|
|
536
|
+
* Update space
|
|
537
|
+
*
|
|
538
|
+
* Updates space settings or metadata.
|
|
539
|
+
*/
|
|
540
|
+
async updateSpace(organizationId, spaceId, body) {
|
|
541
|
+
return this.client.request("PATCH", `/v1/organizations/${organizationId}/spaces/${spaceId}`, { body });
|
|
542
|
+
}
|
|
543
|
+
/**
|
|
544
|
+
* List assignment blocks
|
|
545
|
+
*
|
|
546
|
+
* Returns all assignment blocks in the space.
|
|
547
|
+
*/
|
|
548
|
+
async getAssignmentBlocksBySpaceId(organizationId, spaceId) {
|
|
549
|
+
return this.client.request("GET", `/v1/organizations/${organizationId}/spaces/${spaceId}/assignments`);
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* Copy space
|
|
553
|
+
*
|
|
554
|
+
* Creates a copy of an existing space with a new name.
|
|
555
|
+
*/
|
|
556
|
+
async copySpace(organizationId, spaceId, body) {
|
|
557
|
+
return this.client.request("POST", `/v1/organizations/${organizationId}/spaces/${spaceId}/copy`, { body });
|
|
558
|
+
}
|
|
559
|
+
/**
|
|
560
|
+
* Add group to space
|
|
561
|
+
*
|
|
562
|
+
* Grants a group access to a space.
|
|
563
|
+
*/
|
|
564
|
+
async addGroupToSpace(organizationId, spaceId, body) {
|
|
565
|
+
return this.client.request("POST", `/v1/organizations/${organizationId}/spaces/${spaceId}/groups`, { body });
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
568
|
+
* Hide space
|
|
569
|
+
*
|
|
570
|
+
* Hides a space from view.
|
|
571
|
+
*/
|
|
572
|
+
async hideSpace(organizationId, spaceId) {
|
|
573
|
+
return this.client.request("PATCH", `/v1/organizations/${organizationId}/spaces/${spaceId}/hide`);
|
|
574
|
+
}
|
|
575
|
+
/**
|
|
576
|
+
* Invite to space
|
|
577
|
+
*
|
|
578
|
+
* Invite users by email. Existing users are added directly.
|
|
579
|
+
*/
|
|
580
|
+
async inviteToSpaceByEmails(organizationId, spaceId, body) {
|
|
581
|
+
return this.client.request("POST", `/v1/organizations/${organizationId}/spaces/${spaceId}/invites`, { body });
|
|
582
|
+
}
|
|
583
|
+
/**
|
|
584
|
+
* Revoke space invite
|
|
585
|
+
*
|
|
586
|
+
* Revokes an invitation to a space by email address.
|
|
587
|
+
*/
|
|
588
|
+
async revokeSpaceInvite(organizationId, spaceId, email) {
|
|
589
|
+
return this.client.request("DELETE", `/v1/organizations/${organizationId}/spaces/${spaceId}/invites/${email}`);
|
|
590
|
+
}
|
|
591
|
+
/**
|
|
592
|
+
* Add space members
|
|
593
|
+
*
|
|
594
|
+
* Adds users to a space.
|
|
595
|
+
*/
|
|
596
|
+
async createSpaceMembersBySpaceId(organizationId, spaceId, body) {
|
|
597
|
+
return this.client.request("POST", `/v1/organizations/${organizationId}/spaces/${spaceId}/members`, { body });
|
|
598
|
+
}
|
|
599
|
+
/**
|
|
600
|
+
* Remove space member
|
|
601
|
+
*
|
|
602
|
+
* Removes a user from a space.
|
|
603
|
+
*/
|
|
604
|
+
async deleteSpaceMember(organizationId, spaceId, memberId) {
|
|
605
|
+
return this.client.request("DELETE", `/v1/organizations/${organizationId}/spaces/${spaceId}/members/${memberId}`);
|
|
606
|
+
}
|
|
607
|
+
/**
|
|
608
|
+
* Update space member
|
|
609
|
+
*
|
|
610
|
+
* Updates a member’s role or title in a space.
|
|
611
|
+
*/
|
|
612
|
+
async updateSpaceMember(organizationId, spaceId, memberId, body) {
|
|
613
|
+
return this.client.request("PATCH", `/v1/organizations/${organizationId}/spaces/${spaceId}/members/${memberId}`, { body });
|
|
614
|
+
}
|
|
615
|
+
/**
|
|
616
|
+
* List space members
|
|
617
|
+
*
|
|
618
|
+
* Returns members of a space.
|
|
619
|
+
*/
|
|
620
|
+
async getSpaceMembers(organizationId, spaceId, offset) {
|
|
621
|
+
return this.client.request("GET", `/v1/organizations/${organizationId}/spaces/${spaceId}/members/${offset}`);
|
|
622
|
+
}
|
|
623
|
+
/**
|
|
624
|
+
* List space roles
|
|
625
|
+
*
|
|
626
|
+
* Returns roles available in a space.
|
|
627
|
+
*/
|
|
628
|
+
async getSpaceRoles(organizationId, spaceId) {
|
|
629
|
+
return this.client.request("GET", `/v1/organizations/${organizationId}/spaces/${spaceId}/roles`);
|
|
630
|
+
}
|
|
631
|
+
/**
|
|
632
|
+
* Create space role
|
|
633
|
+
*
|
|
634
|
+
* Creates a custom role in a space.
|
|
635
|
+
*/
|
|
636
|
+
async createSpaceRole(organizationId, spaceId, body) {
|
|
637
|
+
return this.client.request("POST", `/v1/organizations/${organizationId}/spaces/${spaceId}/roles`, { body });
|
|
638
|
+
}
|
|
639
|
+
/**
|
|
640
|
+
* List room blocks
|
|
641
|
+
*
|
|
642
|
+
* Returns all room blocks in the space.
|
|
643
|
+
*/
|
|
644
|
+
async getRoomBlocksBySpaceId(organizationId, spaceId) {
|
|
645
|
+
return this.client.request("GET", `/v1/organizations/${organizationId}/spaces/${spaceId}/rooms`);
|
|
646
|
+
}
|
|
647
|
+
};
|
|
648
|
+
var UsersResource = class {
|
|
649
|
+
constructor(client) {
|
|
650
|
+
this.client = client;
|
|
651
|
+
}
|
|
652
|
+
/**
|
|
653
|
+
* Get user context
|
|
654
|
+
*
|
|
655
|
+
* Returns user info, memberships, and groups.
|
|
656
|
+
*/
|
|
657
|
+
async getUserContextByOrganizationId(organizationId, identifier) {
|
|
658
|
+
return this.client.request("GET", `/v1/organizations/${organizationId}/users/${identifier}`);
|
|
659
|
+
}
|
|
660
|
+
/**
|
|
661
|
+
* Delete user
|
|
662
|
+
*
|
|
663
|
+
* Deletes a user if their email is verified by the org and not verified by any others. This is permanent and affects all orgs.
|
|
664
|
+
*/
|
|
665
|
+
async deleteUser(organizationId, identifier) {
|
|
666
|
+
return this.client.request("DELETE", `/v1/organizations/${organizationId}/users/${identifier}`);
|
|
667
|
+
}
|
|
668
|
+
/**
|
|
669
|
+
* Delete or remove user
|
|
670
|
+
*
|
|
671
|
+
* Deletes the user if verified by the org; otherwise removes org memberships.
|
|
672
|
+
*/
|
|
673
|
+
async deleteVerifiedUserOrRemoveFromOrg(organizationId, userId) {
|
|
674
|
+
return this.client.request("DELETE", `/v1/organizations/${organizationId}/users/${userId}/membership`);
|
|
675
|
+
}
|
|
676
|
+
};
|
|
677
|
+
var WebhooksResource = class {
|
|
678
|
+
constructor(client) {
|
|
679
|
+
this.client = client;
|
|
680
|
+
}
|
|
681
|
+
/**
|
|
682
|
+
* List webhooks
|
|
683
|
+
*
|
|
684
|
+
* Returns all webhooks for the organization.
|
|
685
|
+
*/
|
|
686
|
+
async getWebhooksByOrganizationId(organizationId) {
|
|
687
|
+
return this.client.request("GET", `/v1/organizations/${organizationId}/webhooks`);
|
|
688
|
+
}
|
|
689
|
+
/**
|
|
690
|
+
* Create webhook
|
|
691
|
+
*
|
|
692
|
+
* Creates a new webhook for the organization. Returns the webhook secret which must be stored securely.
|
|
693
|
+
*/
|
|
694
|
+
async createWebhook(organizationId, body) {
|
|
695
|
+
return this.client.request("POST", `/v1/organizations/${organizationId}/webhooks`, { body });
|
|
696
|
+
}
|
|
697
|
+
/**
|
|
698
|
+
* Delete webhook
|
|
699
|
+
*
|
|
700
|
+
* Deletes a webhook.
|
|
701
|
+
*/
|
|
702
|
+
async deleteWebhook(organizationId, webhookId) {
|
|
703
|
+
return this.client.request("DELETE", `/v1/organizations/${organizationId}/webhooks/${webhookId}`);
|
|
704
|
+
}
|
|
705
|
+
/**
|
|
706
|
+
* Update webhook
|
|
707
|
+
*
|
|
708
|
+
* Updates an existing webhook. If subscriptions are provided, they replace all existing subscriptions.
|
|
709
|
+
*/
|
|
710
|
+
async updateWebhook(organizationId, webhookId, body) {
|
|
711
|
+
return this.client.request("PATCH", `/v1/organizations/${organizationId}/webhooks/${webhookId}`, { body });
|
|
712
|
+
}
|
|
713
|
+
/**
|
|
714
|
+
* Get webhook logs
|
|
715
|
+
*
|
|
716
|
+
* Returns delivery logs for a webhook. Logs are retained for 30 days.
|
|
717
|
+
*/
|
|
718
|
+
async getWebhookLogs(organizationId, webhookId, query) {
|
|
719
|
+
return this.client.request("GET", `/v1/organizations/${organizationId}/webhooks/${webhookId}/logs`, { query });
|
|
720
|
+
}
|
|
721
|
+
};
|
|
722
|
+
|
|
723
|
+
// libs/pivot-sdk/src/client.ts
|
|
724
|
+
var Pivot = class {
|
|
725
|
+
core;
|
|
726
|
+
/** Block operations (pages, assignments, forms, etc.) */
|
|
727
|
+
blocks;
|
|
728
|
+
/** Group operations */
|
|
729
|
+
groups;
|
|
730
|
+
/** Invite operations */
|
|
731
|
+
invites;
|
|
732
|
+
/** Label operations */
|
|
733
|
+
labels;
|
|
734
|
+
/** Room operations (chat, messages, recordings) */
|
|
735
|
+
rooms;
|
|
736
|
+
/** Space operations */
|
|
737
|
+
spaces;
|
|
738
|
+
/** User operations */
|
|
739
|
+
users;
|
|
740
|
+
/** Webhook operations */
|
|
741
|
+
webhooks;
|
|
742
|
+
constructor(options) {
|
|
743
|
+
this.core = new PivotClientCore(options);
|
|
744
|
+
this.blocks = new BlocksResource(this.core);
|
|
745
|
+
this.groups = new GroupsResource(this.core);
|
|
746
|
+
this.invites = new InvitesResource(this.core);
|
|
747
|
+
this.labels = new LabelsResource(this.core);
|
|
748
|
+
this.rooms = new RoomsResource(this.core);
|
|
749
|
+
this.spaces = new SpacesResource(this.core);
|
|
750
|
+
this.users = new UsersResource(this.core);
|
|
751
|
+
this.webhooks = new WebhooksResource(this.core);
|
|
752
|
+
}
|
|
753
|
+
};
|
|
754
|
+
|
|
755
|
+
// libs/pivot-sdk/src/pagination.ts
|
|
756
|
+
async function autoPageOffset(fetchPage, extractPage, options = {}) {
|
|
757
|
+
const { startOffset = 0, maxItems = Infinity } = options;
|
|
758
|
+
const allItems = [];
|
|
759
|
+
let currentOffset = startOffset;
|
|
760
|
+
while (allItems.length < maxItems) {
|
|
761
|
+
const response = await fetchPage(currentOffset);
|
|
762
|
+
const page = extractPage(response);
|
|
763
|
+
allItems.push(...page.items);
|
|
764
|
+
const nextOffset = page.nextOffset;
|
|
765
|
+
if (page.items.length === 0 || nextOffset == null) {
|
|
766
|
+
break;
|
|
767
|
+
}
|
|
768
|
+
if (nextOffset <= currentOffset) {
|
|
769
|
+
throw new Error(
|
|
770
|
+
`Offset pagination did not advance (current=${currentOffset}, next=${nextOffset}).`
|
|
771
|
+
);
|
|
772
|
+
}
|
|
773
|
+
currentOffset = nextOffset;
|
|
774
|
+
}
|
|
775
|
+
return allItems.slice(0, maxItems);
|
|
776
|
+
}
|
|
777
|
+
async function autoPageCursor(fetchPage, extractPage, options = {}) {
|
|
778
|
+
const { maxItems = Infinity, maxPages = Infinity } = options;
|
|
779
|
+
const allItems = [];
|
|
780
|
+
let cursor;
|
|
781
|
+
let pageCount = 0;
|
|
782
|
+
while (allItems.length < maxItems && pageCount < maxPages) {
|
|
783
|
+
const response = await fetchPage(cursor);
|
|
784
|
+
const page = extractPage(response);
|
|
785
|
+
allItems.push(...page.items);
|
|
786
|
+
pageCount++;
|
|
787
|
+
if (!page.hasMore || page.items.length === 0) {
|
|
788
|
+
break;
|
|
789
|
+
}
|
|
790
|
+
if (!page.nextCursor) {
|
|
791
|
+
throw new Error(
|
|
792
|
+
"Cursor pagination indicated more pages but no nextCursor was returned."
|
|
793
|
+
);
|
|
794
|
+
}
|
|
795
|
+
cursor = page.nextCursor;
|
|
796
|
+
}
|
|
797
|
+
return allItems.slice(0, maxItems);
|
|
798
|
+
}
|
|
799
|
+
function verifyWebhookSignature(payload, signature, secret) {
|
|
800
|
+
if (!payload || !signature || !secret) {
|
|
801
|
+
return false;
|
|
802
|
+
}
|
|
803
|
+
const expectedSignature = "sha256=" + createHmac("sha256", secret).update(payload).digest("hex");
|
|
804
|
+
const sigBuffer = Buffer.from(signature);
|
|
805
|
+
const expectedBuffer = Buffer.from(expectedSignature);
|
|
806
|
+
if (sigBuffer.length !== expectedBuffer.length) {
|
|
807
|
+
return false;
|
|
808
|
+
}
|
|
809
|
+
return timingSafeEqual(sigBuffer, expectedBuffer);
|
|
810
|
+
}
|
|
811
|
+
function constructWebhookSignature(payload, secret) {
|
|
812
|
+
return "sha256=" + createHmac("sha256", secret).update(payload).digest("hex");
|
|
813
|
+
}
|
|
814
|
+
function parseWebhookEvent(payload, signature, secret) {
|
|
815
|
+
if (!verifyWebhookSignature(payload, signature, secret)) {
|
|
816
|
+
throw new Error(
|
|
817
|
+
"Invalid webhook signature. Ensure you are using the correct secret."
|
|
818
|
+
);
|
|
819
|
+
}
|
|
820
|
+
const event = JSON.parse(payload);
|
|
821
|
+
if (!event.eventType || !event.organizationId || !event.subject) {
|
|
822
|
+
throw new Error("Invalid webhook payload: missing required fields.");
|
|
823
|
+
}
|
|
824
|
+
return event;
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
export { BlocksResource, DEFAULT_RETRY_CONFIG, GroupsResource, InvitesResource, LabelsResource, Pivot, PivotAPIError, PivotAuthenticationError, PivotError, PivotRetryError, PivotTimeoutError, RoomsResource, SpacesResource, UsersResource, WebhooksResource, autoPageCursor, autoPageOffset, constructWebhookSignature, Pivot as default, parseWebhookEvent, verifyWebhookSignature };
|
|
828
|
+
//# sourceMappingURL=index.mjs.map
|
|
829
|
+
//# sourceMappingURL=index.mjs.map
|