@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/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