@unboundcx/sdk 4.13.18 → 4.13.19

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/services/portals.js +502 -7
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unboundcx/sdk",
3
- "version": "4.13.18",
3
+ "version": "4.13.19",
4
4
  "description": "Official JavaScript SDK for the Unbound API - A comprehensive toolkit for integrating with Unbound's communication, AI, and data management services",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -9,8 +9,11 @@ export class PortalsService {
9
9
  *
10
10
  * @param {object} params
11
11
  * @param {string} params.name - Display name of the portal.
12
- * @param {string} params.domain - Custom domain for the portal (e.g. `portal.example.com`).
12
+ * @param {string} [params.kind] - Portal kind (`marketing` | `support` | `partner`).
13
+ * @param {string} [params.domain] - Custom domain for the portal (e.g. `portal.example.com`).
13
14
  * A CNAME DNS record pointing to the platform's portal host is required.
15
+ * @param {string} [params.slug] - Per-account preview slug (not a custom domain).
16
+ * At least one of `domain` or `slug` is required by the API.
14
17
  * @param {object} [params.settings] - Optional portal configuration settings.
15
18
  * @param {boolean} [params.isPublic] - Whether the portal is publicly accessible without
16
19
  * authentication. Defaults to private if omitted.
@@ -28,7 +31,9 @@ export class PortalsService {
28
31
  */
29
32
  async create({
30
33
  name,
34
+ kind,
31
35
  domain,
36
+ slug,
32
37
  settings,
33
38
  isPublic,
34
39
  customCss,
@@ -37,10 +42,12 @@ export class PortalsService {
37
42
  logo,
38
43
  }) {
39
44
  this.sdk.validateParams(
40
- { name, domain },
45
+ { name, kind, domain, slug },
41
46
  {
42
47
  name: { type: 'string', required: true },
43
- domain: { type: 'string', required: true },
48
+ kind: { type: 'string', required: false },
49
+ domain: { type: 'string', required: false },
50
+ slug: { type: 'string', required: false },
44
51
  settings: { type: 'object', required: false },
45
52
  isPublic: { type: 'boolean', required: false },
46
53
  customCss: { type: 'string', required: false },
@@ -50,7 +57,10 @@ export class PortalsService {
50
57
  },
51
58
  );
52
59
 
53
- const portalData = { name, domain };
60
+ const portalData = { name };
61
+ if (kind) portalData.kind = kind;
62
+ if (domain) portalData.domain = domain;
63
+ if (slug) portalData.slug = slug;
54
64
  if (settings) portalData.settings = settings;
55
65
  if (isPublic !== undefined) portalData.isPublic = isPublic;
56
66
  if (customCss) portalData.customCss = customCss;
@@ -223,10 +233,495 @@ export class PortalsService {
223
233
  },
224
234
  );
225
235
 
226
- const result = await internalRequest(this.sdk,
227
- `/portals/${portalId}/verify-dns`,
236
+ const result = await internalRequest(this.sdk, '/portals/dns/verify', 'GET', {
237
+ query: { id: portalId },
238
+ });
239
+ return result;
240
+ }
241
+
242
+ /**
243
+ * Lists pages for a portal.
244
+ *
245
+ * @param {string} portalId
246
+ * @returns {Promise<{ pages: object[] }>}
247
+ */
248
+ async listPages(portalId) {
249
+ this.sdk.validateParams(
250
+ { portalId },
251
+ {
252
+ portalId: { type: 'string', required: true },
253
+ },
254
+ );
255
+
256
+ return internalRequest(this.sdk, `/portals/${portalId}/pages`, 'GET');
257
+ }
258
+
259
+ /**
260
+ * Creates a portal page.
261
+ *
262
+ * @param {string} portalId
263
+ * @param {object} params
264
+ * @param {string} params.path - `/` or a slash-prefixed path like `/spring-sale`.
265
+ * @param {string} params.title
266
+ * @param {string} params.type - landing|html|layout|kbHome|kbArticle|ticketList|ticketDetail|login|redirect
267
+ * @param {boolean} [params.requiresLogin] - Require a signed-in portal session to view this page.
268
+ * @returns {Promise<object>}
269
+ */
270
+ async createPage(portalId, { path, title, type, requiresLogin }) {
271
+ this.sdk.validateParams(
272
+ { portalId, path, title, type, requiresLogin },
273
+ {
274
+ portalId: { type: 'string', required: true },
275
+ path: { type: 'string', required: true },
276
+ title: { type: 'string', required: true },
277
+ type: { type: 'string', required: true },
278
+ requiresLogin: { type: 'boolean', required: false },
279
+ },
280
+ );
281
+
282
+ const body = { path, title, type };
283
+ if (requiresLogin !== undefined) body.requiresLogin = requiresLogin;
284
+
285
+ return internalRequest(this.sdk, `/portals/${portalId}/pages`, 'POST', {
286
+ body,
287
+ });
288
+ }
289
+
290
+ /**
291
+ * Retrieves a portal page by ID.
292
+ *
293
+ * @param {string} portalId
294
+ * @param {string} pageId
295
+ * @returns {Promise<object>}
296
+ */
297
+ async getPage(portalId, pageId) {
298
+ this.sdk.validateParams(
299
+ { portalId, pageId },
300
+ {
301
+ portalId: { type: 'string', required: true },
302
+ pageId: { type: 'string', required: true },
303
+ },
304
+ );
305
+
306
+ return internalRequest(
307
+ this.sdk,
308
+ `/portals/${portalId}/pages/${pageId}`,
309
+ 'GET',
310
+ );
311
+ }
312
+
313
+ /**
314
+ * Updates a portal page. Only provided fields are changed.
315
+ *
316
+ * @param {string} portalId
317
+ * @param {string} pageId
318
+ * @param {object} [updates]
319
+ * @returns {Promise<object>}
320
+ */
321
+ async updatePage(
322
+ portalId,
323
+ pageId,
324
+ {
325
+ path,
326
+ title,
327
+ type,
328
+ isPublished,
329
+ publishedVersionId,
330
+ draftVersionId,
331
+ requiresLogin,
332
+ } = {},
333
+ ) {
334
+ this.sdk.validateParams(
335
+ {
336
+ portalId,
337
+ pageId,
338
+ path,
339
+ title,
340
+ type,
341
+ isPublished,
342
+ publishedVersionId,
343
+ draftVersionId,
344
+ requiresLogin,
345
+ },
346
+ {
347
+ portalId: { type: 'string', required: true },
348
+ pageId: { type: 'string', required: true },
349
+ path: { type: 'string', required: false },
350
+ title: { type: 'string', required: false },
351
+ type: { type: 'string', required: false },
352
+ isPublished: { type: 'boolean', required: false },
353
+ publishedVersionId: { type: 'string', required: false },
354
+ draftVersionId: { type: 'string', required: false },
355
+ requiresLogin: { type: 'boolean', required: false },
356
+ },
357
+ );
358
+
359
+ const body = {};
360
+ if (path !== undefined) body.path = path;
361
+ if (title !== undefined) body.title = title;
362
+ if (type !== undefined) body.type = type;
363
+ if (isPublished !== undefined) body.isPublished = isPublished;
364
+ if (publishedVersionId !== undefined) {
365
+ body.publishedVersionId = publishedVersionId;
366
+ }
367
+ if (draftVersionId !== undefined) body.draftVersionId = draftVersionId;
368
+ if (requiresLogin !== undefined) body.requiresLogin = requiresLogin;
369
+
370
+ return internalRequest(
371
+ this.sdk,
372
+ `/portals/${portalId}/pages/${pageId}`,
373
+ 'PUT',
374
+ { body },
375
+ );
376
+ }
377
+
378
+ /**
379
+ * Soft-deletes a portal page.
380
+ *
381
+ * @param {string} portalId
382
+ * @param {string} pageId
383
+ * @returns {Promise<{ message: string }>}
384
+ */
385
+ async deletePage(portalId, pageId) {
386
+ this.sdk.validateParams(
387
+ { portalId, pageId },
388
+ {
389
+ portalId: { type: 'string', required: true },
390
+ pageId: { type: 'string', required: true },
391
+ },
392
+ );
393
+
394
+ return internalRequest(
395
+ this.sdk,
396
+ `/portals/${portalId}/pages/${pageId}`,
397
+ 'DELETE',
398
+ );
399
+ }
400
+
401
+ /**
402
+ * Lists versions for a portal page.
403
+ *
404
+ * @param {string} portalId
405
+ * @param {string} pageId
406
+ * @returns {Promise<{ versions: object[] }>}
407
+ */
408
+ async listPageVersions(portalId, pageId) {
409
+ this.sdk.validateParams(
410
+ { portalId, pageId },
411
+ {
412
+ portalId: { type: 'string', required: true },
413
+ pageId: { type: 'string', required: true },
414
+ },
415
+ );
416
+
417
+ return internalRequest(
418
+ this.sdk,
419
+ `/portals/${portalId}/pages/${pageId}/versions`,
420
+ 'GET',
421
+ );
422
+ }
423
+
424
+ /**
425
+ * Creates a page version (S3 pointers / layout / object only; no HTML compile).
426
+ *
427
+ * @param {string} portalId
428
+ * @param {string} pageId
429
+ * @param {object} [params]
430
+ * @returns {Promise<object>}
431
+ */
432
+ async createPageVersion(
433
+ portalId,
434
+ pageId,
435
+ { designStorageId, htmlStorageId, layoutId, objectName } = {},
436
+ ) {
437
+ this.sdk.validateParams(
438
+ {
439
+ portalId,
440
+ pageId,
441
+ designStorageId,
442
+ htmlStorageId,
443
+ layoutId,
444
+ objectName,
445
+ },
446
+ {
447
+ portalId: { type: 'string', required: true },
448
+ pageId: { type: 'string', required: true },
449
+ designStorageId: { type: 'string', required: false },
450
+ htmlStorageId: { type: 'string', required: false },
451
+ layoutId: { type: 'string', required: false },
452
+ objectName: { type: 'string', required: false },
453
+ },
454
+ );
455
+
456
+ const body = {};
457
+ if (designStorageId !== undefined) body.designStorageId = designStorageId;
458
+ if (htmlStorageId !== undefined) body.htmlStorageId = htmlStorageId;
459
+ if (layoutId !== undefined) body.layoutId = layoutId;
460
+ if (objectName !== undefined) body.objectName = objectName;
461
+
462
+ return internalRequest(
463
+ this.sdk,
464
+ `/portals/${portalId}/pages/${pageId}/versions`,
228
465
  'POST',
466
+ { body },
229
467
  );
230
- return result;
468
+ }
469
+
470
+ /**
471
+ * Autosave a page draft. Landing pages pass a block `tree`; `html`-type
472
+ * pages (marketing portals only, P7.1) pass the raw full-document `html`
473
+ * string instead.
474
+ *
475
+ * @param {string} portalId
476
+ * @param {string} pageId
477
+ * @param {object} params
478
+ * @param {object|Array} [params.tree] - Block tree JSON (landing pages).
479
+ * @param {string} [params.html] - Raw full-document HTML (html pages).
480
+ * @returns {Promise<object>}
481
+ */
482
+ async savePageDraft(portalId, pageId, { tree, html } = {}) {
483
+ this.sdk.validateParams(
484
+ { portalId, pageId, tree, html },
485
+ {
486
+ portalId: { type: 'string', required: true },
487
+ pageId: { type: 'string', required: true },
488
+ tree: { type: 'object', required: false },
489
+ html: { type: 'string', required: false },
490
+ },
491
+ );
492
+
493
+ const body = {};
494
+ if (tree !== undefined) body.tree = tree;
495
+ if (html !== undefined) body.html = html;
496
+
497
+ return internalRequest(
498
+ this.sdk,
499
+ `/portals/${portalId}/pages/${pageId}/draft`,
500
+ 'PUT',
501
+ { body },
502
+ );
503
+ }
504
+
505
+ /**
506
+ * Compile a landing-page draft (P1.4) and publish HTML, or (for `html`-type
507
+ * pages, P7.1) store the raw document string verbatim.
508
+ *
509
+ * @param {string} portalId
510
+ * @param {string} pageId
511
+ * @param {object} [params]
512
+ * @param {object|Array} [params.tree] - Optional tree; otherwise the draft design is loaded.
513
+ * @param {string} [params.html] - Raw full-document HTML (html pages); otherwise the draft is loaded.
514
+ * @returns {Promise<object>}
515
+ */
516
+ async publishPage(portalId, pageId, { tree, html } = {}) {
517
+ this.sdk.validateParams(
518
+ { portalId, pageId, tree, html },
519
+ {
520
+ portalId: { type: 'string', required: true },
521
+ pageId: { type: 'string', required: true },
522
+ tree: { type: 'object', required: false },
523
+ html: { type: 'string', required: false },
524
+ },
525
+ );
526
+
527
+ const body = {};
528
+ if (tree !== undefined) body.tree = tree;
529
+ if (html !== undefined) body.html = html;
530
+
531
+ return internalRequest(
532
+ this.sdk,
533
+ `/portals/${portalId}/pages/${pageId}/publish`,
534
+ 'POST',
535
+ { body },
536
+ );
537
+ }
538
+
539
+ /**
540
+ * Staff-only portal credential status for a person. Never includes hashes.
541
+ *
542
+ * @param {string} peopleId
543
+ * @returns {Promise<{
544
+ * hasPassword: boolean,
545
+ * ssoLinked: boolean,
546
+ * lastLoginAt: string|null,
547
+ * lastLoginMethod: string|null,
548
+ * mustReset: boolean
549
+ * }>}
550
+ */
551
+ async getPeopleAccess(peopleId) {
552
+ this.sdk.validateParams(
553
+ { peopleId },
554
+ {
555
+ peopleId: { type: 'string', required: true },
556
+ },
557
+ );
558
+
559
+ return internalRequest(
560
+ this.sdk,
561
+ `/portals/people/${encodeURIComponent(peopleId)}/access`,
562
+ 'GET',
563
+ );
564
+ }
565
+
566
+ /**
567
+ * Force the person to reset their portal password on next login (`mustReset=1`).
568
+ *
569
+ * @param {string} peopleId
570
+ * @returns {Promise<{
571
+ * hasPassword: boolean,
572
+ * ssoLinked: boolean,
573
+ * lastLoginAt: string|null,
574
+ * lastLoginMethod: string|null,
575
+ * mustReset: boolean
576
+ * }>}
577
+ */
578
+ async forceResetPeopleAccess(peopleId) {
579
+ this.sdk.validateParams(
580
+ { peopleId },
581
+ {
582
+ peopleId: { type: 'string', required: true },
583
+ },
584
+ );
585
+
586
+ return internalRequest(
587
+ this.sdk,
588
+ `/portals/people/${encodeURIComponent(peopleId)}/access/force-reset`,
589
+ 'POST',
590
+ );
591
+ }
592
+
593
+ /**
594
+ * Lists the customer-facing labels configured for each engagement status.
595
+ *
596
+ * One entry per valid `engagementSessions.status` value; `customerLabel`
597
+ * is `null` when unset (P4.2: the portal hides statuses with no label).
598
+ *
599
+ * @returns {Promise<{ statuses: Array<{ status: string, customerLabel: string|null }> }>}
600
+ */
601
+ async listTicketStatuses() {
602
+ return internalRequest(this.sdk, '/portals/ticket-statuses', 'GET');
603
+ }
604
+
605
+ /**
606
+ * Upserts customer-facing labels for engagement statuses.
607
+ *
608
+ * @param {object} params
609
+ * @param {Array<{ status: string, customerLabel: string|null }>} params.statuses
610
+ * @returns {Promise<{ statuses: Array<{ status: string, customerLabel: string|null }> }>}
611
+ */
612
+ async updateTicketStatuses({ statuses }) {
613
+ this.sdk.validateParams(
614
+ { statuses },
615
+ {
616
+ statuses: { type: 'array', required: true },
617
+ },
618
+ );
619
+
620
+ return internalRequest(this.sdk, '/portals/ticket-statuses', 'PUT', {
621
+ body: { statuses },
622
+ });
623
+ }
624
+
625
+ /**
626
+ * Retrieves the single-sign-on (OIDC) connection configured for a portal.
627
+ *
628
+ * Never includes the client secret; `hasClientSecret` indicates whether
629
+ * one is on file.
630
+ *
631
+ * @param {string} portalId
632
+ * @returns {Promise<{ connection: {
633
+ * id: string,
634
+ * provider: string,
635
+ * name: string,
636
+ * issuer: string,
637
+ * clientId: string,
638
+ * tenant: string|null,
639
+ * scopes: string,
640
+ * status: string,
641
+ * requireVerifiedEmail: boolean,
642
+ * hasClientSecret: boolean,
643
+ * redirectUri: string,
644
+ * updatedAt: string
645
+ * } | null }>}
646
+ */
647
+ async getSsoConnection(portalId) {
648
+ this.sdk.validateParams(
649
+ { portalId },
650
+ {
651
+ portalId: { type: 'string', required: true },
652
+ },
653
+ );
654
+
655
+ return internalRequest(this.sdk, `/portals/${portalId}/sso`, 'GET');
656
+ }
657
+
658
+ /**
659
+ * Creates or updates a portal's single-sign-on (OIDC) connection.
660
+ *
661
+ * Only `support`/`partner` portals may have a connection. `clientSecret`
662
+ * is required when creating a connection and optional on update (omit it
663
+ * to keep the existing secret).
664
+ *
665
+ * @param {string} portalId
666
+ * @param {object} params
667
+ * @param {string} [params.name] - Display name shown to visitors (e.g. "Single sign-on").
668
+ * @param {string} params.issuer - OIDC issuer URL (https, no query/fragment).
669
+ * @param {string} params.clientId
670
+ * @param {string} [params.clientSecret] - Required to create; omit on update to keep existing.
671
+ * @param {string} [params.tenant] - Provider tenant hint (e.g. an Azure tenant id).
672
+ * @param {string} [params.scopes] - Space-separated scopes; must include `openid` and `email`.
673
+ * @param {string} [params.status] - `active` | `disabled`.
674
+ * @param {boolean} [params.requireVerifiedEmail]
675
+ * @returns {Promise<{ connection: object }>}
676
+ */
677
+ async upsertSsoConnection(
678
+ portalId,
679
+ { name, issuer, clientId, clientSecret, tenant, scopes, status, requireVerifiedEmail } = {},
680
+ ) {
681
+ this.sdk.validateParams(
682
+ { portalId, issuer, clientId },
683
+ {
684
+ portalId: { type: 'string', required: true },
685
+ issuer: { type: 'string', required: true },
686
+ clientId: { type: 'string', required: true },
687
+ name: { type: 'string', required: false },
688
+ clientSecret: { type: 'string', required: false },
689
+ tenant: { type: 'string', required: false },
690
+ scopes: { type: 'string', required: false },
691
+ status: { type: 'string', required: false },
692
+ requireVerifiedEmail: { type: 'boolean', required: false },
693
+ },
694
+ );
695
+
696
+ const body = { issuer, clientId };
697
+ if (name !== undefined) body.name = name;
698
+ if (clientSecret !== undefined) body.clientSecret = clientSecret;
699
+ if (tenant !== undefined) body.tenant = tenant;
700
+ if (scopes !== undefined) body.scopes = scopes;
701
+ if (status !== undefined) body.status = status;
702
+ if (requireVerifiedEmail !== undefined) {
703
+ body.requireVerifiedEmail = requireVerifiedEmail;
704
+ }
705
+
706
+ return internalRequest(this.sdk, `/portals/${portalId}/sso`, 'PUT', {
707
+ body,
708
+ });
709
+ }
710
+
711
+ /**
712
+ * Soft-deletes a portal's single-sign-on (OIDC) connection.
713
+ *
714
+ * @param {string} portalId
715
+ * @returns {Promise<{ message: string }>}
716
+ */
717
+ async deleteSsoConnection(portalId) {
718
+ this.sdk.validateParams(
719
+ { portalId },
720
+ {
721
+ portalId: { type: 'string', required: true },
722
+ },
723
+ );
724
+
725
+ return internalRequest(this.sdk, `/portals/${portalId}/sso`, 'DELETE');
231
726
  }
232
727
  }