@verdocs/js-sdk 4.0.4 → 4.0.6

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 CHANGED
@@ -441,2168 +441,2177 @@ class VerdocsEndpoint {
441
441
  }
442
442
 
443
443
  /**
444
- * Create an envelope
445
- *
446
- * ```typescript
447
- * import {Envelopes, ICreateEnvelopeRole, ICreateEnvelopeRequest} from '@verdocs/js-sdk/Envelopes';
448
- *
449
- * const role1: ICreateEnvelopeRole = {
450
- * type: 'signer',
451
- * name: 'Seller',
452
- * full_name: 'Paige Turner',
453
- * email: 'paige.turner@nomail.com',
454
- * phone: '',
455
- * sequence: 1,
456
- * delegator: false,
457
- * message: '',
458
- * };
459
- *
460
- * const role2: ICreateEnvelopeRole = {
461
- * type: 'signer',
462
- * name: 'Buyer',
463
- * full_name: 'Will Power',
464
- * email: 'will.power@nomail.com',
465
- * phone: '',
466
- * sequence: 2,
467
- * delegator: false,
468
- * message: '',
469
- * };
470
- *
471
- * const request: ICreateEnvelopeRequest = {template_id: 'd2338742-f3a1-465b-8592-806587413cc1', name: 'Bill of Sale', roles: [role1, role2]};
472
- * const {id, recipients} = await Envelopes.createEnvelope(VerdocsEndpoint.getDefault(), request);
473
- * ```
474
- */
475
- const createEnvelope = async (endpoint, request) => endpoint.api //
476
- .post('/envelopes', request)
477
- .then((r) => r.data);
478
- /**
479
- * Get a summary of currently active envelopes.
480
- *
481
- * ```typescript
482
- * import {Envelopes} from '@verdocs/js-sdk/Envelopes';
483
- *
484
- * const {action_required, completed, waiting_on_others} = await Envelopes.getSummary(VerdocsEndpoint.getDefault());
485
- * ```
486
- */
487
- const getEnvelopesSummary = async (endpoint, page) => endpoint.api //
488
- .post('/envelopes/summary', { page })
489
- .then((r) => r.data);
490
- /**
491
- * Search for envelopes matching various criteria.
492
- *
493
- * ```typescript
494
- * import {Envelopes} from '@verdocs/js-sdk/Envelopes';
495
- *
496
- * const {result, page, total} = await Envelopes.search(VerdocsEndpoint.getDefault(), { ... });
497
- * ```
498
- */
499
- const searchEnvelopes = async (endpoint, params) => endpoint.api //
500
- .post('/envelopes/search', params)
501
- .then((r) => r.data);
502
- /**
503
- * Get a signing session for an Envelope.
504
- */
505
- const getSigningSession = async (endpoint, params) => {
506
- window.console.log('[JS_SDK] getSigningSession', params, endpoint.api);
507
- return endpoint.api //
508
- .get(`/envelopes/${params.envelopeId}/recipients/${encodeURIComponent(params.roleId)}/invitation/${params.inviteCode}`)
509
- .then((r) => {
510
- // Avoiding a jsonwebtoken dependency here - we don't actually need the whole library
511
- const signerToken = r.headers?.signer_token || '';
512
- const session = decodeAccessTokenBody(signerToken);
513
- endpoint.setToken(signerToken);
514
- return { recipient: r.data, session, signerToken };
515
- });
516
- };
517
- /**
518
- * Get the list of recipients for an Envelope.
519
- */
520
- const getEnvelopeRecipients = async (endpoint, envelopeId) => endpoint.api //
521
- .get(`/envelopes/${envelopeId}/recipients`)
522
- .then((r) => r.data);
523
- /**
524
- * Get all metadata for an Envelope.
525
- */
526
- const getEnvelope = async (endpoint, envelopeId) => endpoint.api //
527
- .get(`/envelopes/${envelopeId}`)
528
- .then((r) => r.data);
529
- /**
530
- * Get an Envelope Document
531
- */
532
- const getEnvelopeDocument = async (endpoint, envelopeId, documentId) => endpoint.api //
533
- .get(`/envelopes/${envelopeId}/envelope_documents/${documentId}`)
534
- .then((r) => r.data);
535
- /**
536
- * Get a pre-signed download link for an Envelope Document. This link expires quickly, so it should
537
- * be accessed immediately and never shared. Content-Disposition will be set to "download".
538
- */
539
- const getDocumentDownloadLink = async (endpoint, envelopeId, documentId) => endpoint.api //
540
- .get(`/envelopes/${envelopeId}/envelope_documents/${documentId}?download=true`)
541
- .then((r) => r.data);
542
- /**
543
- * Get a pre-signed preview link for an Envelope Document. This link expires quickly, so it should
544
- * be accessed immediately and never shared. Content-Disposition will be set to "inline".
545
- */
546
- const getDocumentPreviewLink = async (endpoint, envelopeId, documentId) => endpoint.api //
547
- .get(`/envelopes/${envelopeId}/envelope_documents/${documentId}?preview=true`)
548
- .then((r) => r.data);
549
- /**
550
- * Cancel an Envelope.
551
- */
552
- const cancelEnvelope = async (endpoint, envelopeId) => endpoint.api //
553
- .put(`/envelopes/${envelopeId}`, { action: 'cancel' })
554
- .then((r) => r.data);
555
- /**
556
- * Get (binary download) a file attached to an Envelope. It is important to use this method
557
- * rather than a direct A HREF or similar link to set the authorization headers for the
558
- * request.
559
- */
560
- const getEnvelopeFile = async (endpoint, envelopeId, documentId) => endpoint.api //
561
- .get(`/envelopes/${envelopeId}/envelope_documents/${documentId}?file=true`, { responseType: 'blob' })
562
- .then((r) => r.data);
563
- /**
564
- * Update a Document field. Typically called during the signing process as a Recipient fills in fields.
565
- */
566
- const updateEnvelopeField = async (endpoint, envelopeId, fieldName, value) => endpoint.api //
567
- .put(`/envelopes/${envelopeId}/fields/${fieldName}`, value)
568
- .then((r) => r.data);
569
- /**
570
- * Update a Document signature field. Signature fields are ID-driven. Call `Document.createSignature()` first to create a
571
- * signature for a Recipient, then call `Documents.updateDocumentFieldSignature()` to attach it to a field.
572
- */
573
- const updateEnvelopeFieldSignature = async (endpoint, envelopeId, fieldName, signatureId) => endpoint.api //
574
- .put(`/envelopes/${envelopeId}/fields/${fieldName}/signature/${signatureId}`)
575
- .then((r) => r.data);
576
- /**
577
- * Update a Document signature field. Signature fields are ID-driven. Call `Document.createSignature()` first to create a
578
- * signature for a Recipient, then call `Documents.updateDocumentFieldSignature()` to attach it to a field.
444
+ * Given a `rgba(r,g,b,a)` string value, returns the hex equivalent, dropping the alpha channel.
579
445
  */
580
- const updateEnvelopeFieldInitials = async (endpoint, envelopeId, fieldName, initialId) => endpoint.api //
581
- .put(`/envelopes/${envelopeId}/fields/${fieldName}/initial/${initialId}`)
582
- .then((r) => r.data);
446
+ function getRGB(rgba) {
447
+ const rgbNumbers = rgba.replace('rgba(', '').replace(')', '').split(',');
448
+ const rgbObject = {
449
+ red: +rgbNumbers[0],
450
+ green: +rgbNumbers[1],
451
+ blue: +rgbNumbers[2],
452
+ alpha: +rgbNumbers[3],
453
+ };
454
+ const alpha = 1 - rgbObject.alpha;
455
+ const red = Math.round((rgbObject.alpha * (rgbObject.red / 255) + alpha) * 255);
456
+ const green = Math.round((rgbObject.alpha * (rgbObject.green / 255) + alpha) * 255);
457
+ const blue = Math.round((rgbObject.alpha * (rgbObject.blue / 255) + alpha) * 255);
458
+ return '#' + rgbToHex(red) + rgbToHex(green) + rgbToHex(blue);
459
+ }
583
460
  /**
584
- * Upload an attachment.
461
+ * Given an RGB string value, returns the hex equivalent.
585
462
  */
586
- const uploadEnvelopeFieldAttachment = async (endpoint, envelopeId, fieldName, file, onUploadProgress) => {
587
- const formData = new FormData();
588
- formData.append('document', file, file.name);
589
- return endpoint.api //
590
- .put(`/envelopes/${envelopeId}/fields/${fieldName}`, formData, {
591
- timeout: 120000,
592
- onUploadProgress: (event) => {
593
- const total = event.total || 1;
594
- const loaded = event.loaded || 0;
595
- onUploadProgress?.(Math.floor((loaded * 100) / (total || 1)), loaded, total || 1);
596
- },
597
- })
598
- .then((r) => r.data);
599
- };
463
+ function rgbToHex(rgb) {
464
+ const hex = rgb.toString(16);
465
+ if (hex.length < 2) {
466
+ return '0' + hex;
467
+ }
468
+ return hex;
469
+ }
600
470
  /**
601
- * Delete an attachment.
471
+ * Given a signer role index, return the color code for that signer.
602
472
  */
603
- const deleteEnvelopeFieldAttachment = async (endpoint, envelopeId, fieldName, file, onUploadProgress) => {
604
- const formData = new FormData();
605
- // Omitting file is the trigger here
606
- return endpoint.api //
607
- .put(`/envelopes/${envelopeId}/fields/${fieldName}`, formData, {
608
- timeout: 120000,
609
- onUploadProgress: (event) => {
610
- const total = event.total || 1;
611
- const loaded = event.loaded || 0;
612
- onUploadProgress?.(Math.floor((loaded * 100) / (total || 1)), loaded, total || 1);
613
- },
614
- })
615
- .then((r) => r.data);
616
- };
473
+ function getRGBA(roleIndex) {
474
+ switch (roleIndex % 10) {
475
+ case 0:
476
+ return roleIndex === 0 ? 'rgba(255, 193, 7, 0.4)' : 'rgba(134, 134, 134, 0.3)'; // #FFE69C
477
+ case 1:
478
+ return 'rgba(156, 39, 176, .4)'; // '#E3C3E9'
479
+ case 2:
480
+ return 'rgba(33, 150, 243, .4)'; // '#C1E1FB'
481
+ case 3:
482
+ return 'rgba(220, 231, 117, 0.3)';
483
+ case 4:
484
+ return 'rgba(121, 134, 203, 0.3)';
485
+ case 5:
486
+ return 'rgba(77, 182, 172, 0.3)';
487
+ case 6:
488
+ return 'rgba(255, 202, 165, 0.3)';
489
+ case 7:
490
+ return 'rgba(2, 247, 190, 0.3)';
491
+ case 8:
492
+ return 'rgba(255, 138, 101, 0.3)';
493
+ case 9:
494
+ return 'rgba(82, 255, 79, 0.3)';
495
+ default:
496
+ return 'rgba(229, 115, 155, 0.3)';
497
+ }
498
+ }
617
499
  /**
618
- * Get the attached file for an attachment field (if any)
500
+ * Given a role name, return a color code for it. This works by computing a hash code so the specific color returned
501
+ * is not specified explicitly, but will be the same for every call with the same input value.
619
502
  */
620
- const getFieldAttachment = async (endpoint, envelopeId, fieldName) => endpoint.api //
621
- .get(`/envelopes/${envelopeId}/fields/${fieldName}/document`, { responseType: 'blob' })
622
- .then((r) => r.data);
503
+ function nameToRGBA(str) {
504
+ if (!!str) {
505
+ const validNum = parseInt(str.slice(-1), 10);
506
+ if (!isNaN(validNum)) {
507
+ str += (validNum * 99).toString();
508
+ }
509
+ let hash = 0;
510
+ for (let i = 0; i < str.length; i++) {
511
+ // tslint:disable-next-line:no-bitwise
512
+ hash = str.charCodeAt(i) + ((hash << 5) - hash);
513
+ }
514
+ hash = Math.round(hash / 1.3);
515
+ // tslint:disable-next-line:no-bitwise
516
+ const c = (hash & 0x00ffff08).toString(16).toUpperCase();
517
+ const hex = '#' + '00000'.substring(0, 6 - c.length) + c;
518
+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
519
+ const color = {
520
+ r: parseInt(result[1], 16),
521
+ g: parseInt(result[2], 16),
522
+ b: parseInt(result[3], 16),
523
+ };
524
+ return `rgba(${color.r}, ${color.g}, ${color.b}, 0.2)`;
525
+ }
526
+ }
623
527
  /**
624
- * Get a display URI for a given page in a file attached to an envelope document. These pages are rendered server-side
625
- * into PNG resources suitable for display in IMG tags although they may be used elsewhere. Note that these are intended
626
- * for DISPLAY ONLY, are not legally binding documents, and do not contain any encoded metadata from participants.
528
+ * Helper function to obtain a color code given a role name given various possible inputs.
627
529
  */
628
- const getEnvelopeDocumentPageDisplayUri = async (endpoint, envelopeId, documentId, page, type = 'original') => endpoint.api
629
- .get(`/envelopes/${envelopeId}/envelope_documents/${documentId}/pages/${page}/image?type=${type}`, { timeout: 20000 })
630
- .then((r) => r.data);
631
- const cachedEnvelopes = {};
632
- /**
633
- * Wrapper for `getEnvelope()` that limits queries to one every 2 seconds per template ID.
634
- * This is intended for use in component hierarchies that all rely on the same template
635
- * to avoid unnecessary repeat server calls.
636
- */
637
- const throttledGetEnvelope = (endpoint, envelopeId) => {
638
- if (cachedEnvelopes[envelopeId] && cachedEnvelopes[envelopeId].loaded + 2000 < new Date().getTime()) {
639
- return cachedEnvelopes[envelopeId].envelope;
530
+ function getRoleColor(name, roles, index) {
531
+ if (index) {
532
+ return getRGBA(index);
640
533
  }
641
- return getEnvelope(endpoint, envelopeId).then((envelope) => {
642
- cachedEnvelopes[envelopeId] = { loaded: new Date().getTime(), envelope };
643
- return envelope;
644
- });
645
- };
646
- /**a
647
- * Lists all envelopes accessible by the caller, with optional filters.
648
- *
649
- * ```typescript
650
- * import {Envelopes} from '@verdocs/js-sdk/Envelopes';
651
- *
652
- * const {totals, envelopes} = await Envelopes.listEnvelopes((VerdocsEndpoint.getDefault(), { q: 'test', sort: 'created_at' });
653
- * ```
654
- */
655
- const listEnvelopes = (endpoint, params) => endpoint.api //
656
- .post('/envelopes/list', params)
657
- .then((r) => r.data);
534
+ else if (roles && roles.length > 0) {
535
+ const roleIndex = roles.findIndex((role) => role === name);
536
+ if (roleIndex > -1) {
537
+ return getRGBA(roleIndex);
538
+ }
539
+ else {
540
+ return nameToRGBA(name);
541
+ }
542
+ }
543
+ else {
544
+ return nameToRGBA(name);
545
+ }
546
+ }
658
547
 
659
- /**
660
- * Create an initials block. In a typical signing workflow, the user is asked at the beginning of the process to "adopt"
661
- * an initials block to be used for all initials fields in the document. Thus, this is typically called one time to
662
- * create and store an initials block. Thereafter, the ID of the initials block may be re-used for each initials field
663
- * to be "stamped" by the user.
664
- */
665
- const createInitials = (endpoint, name, initials) => {
666
- const data = new FormData();
667
- data.append('initial', initials, name);
668
- return endpoint.api //
669
- .post(`/initials`, data)
670
- .then((r) => r.data);
548
+ const YEAR = 365 * 24 * 60 * 60;
549
+ // const MONTH = 30 * 24 * 60 * 60;
550
+ const WEEK = 7 * 24 * 60 * 60;
551
+ const DAY = 24 * 60 * 60;
552
+ const HOUR = 60 * 60;
553
+ const MINUTE = 60;
554
+ const formatShortTimeAgo = (val) => {
555
+ if (val === undefined || val === null) {
556
+ return '';
557
+ }
558
+ let dateInput;
559
+ if (typeof val === 'string' || typeof val === 'number') {
560
+ dateInput = new Date(val);
561
+ }
562
+ else if (typeof val === 'object') {
563
+ dateInput = val;
564
+ }
565
+ else {
566
+ return '';
567
+ }
568
+ const timeDiff = Math.floor((new Date().getTime() - dateInput.getTime()) / 1000);
569
+ if (timeDiff >= YEAR) {
570
+ return Math.floor(timeDiff / YEAR) + 'Y';
571
+ }
572
+ // if (timeDiff >= MONTH) {
573
+ // return Math.floor(timeDiff / MONTH) + 'M';
574
+ // }
575
+ if (timeDiff >= WEEK) {
576
+ return Math.floor(timeDiff / WEEK) + 'W';
577
+ }
578
+ if (timeDiff >= DAY) {
579
+ return Math.floor(timeDiff / DAY) + 'D';
580
+ }
581
+ if (timeDiff >= HOUR) {
582
+ return Math.floor(timeDiff / HOUR) + 'H';
583
+ }
584
+ if (timeDiff >= MINUTE) {
585
+ return Math.floor(timeDiff / MINUTE) + 'M';
586
+ }
587
+ return `${timeDiff}S`;
671
588
  };
589
+ function timePeriod(type) {
590
+ let endDate = new Date().getTime();
591
+ const today = new Date();
592
+ const month = today.getMonth();
593
+ const year = today.getFullYear();
594
+ let startDate = null;
595
+ switch (type) {
596
+ case '30d':
597
+ startDate = endDate - 60 * 60 * 24 * 30 * 1000;
598
+ break;
599
+ case '60d':
600
+ startDate = endDate - 60 * 60 * 24 * 60 * 1000;
601
+ break;
602
+ case '6m':
603
+ startDate = endDate - 60 * 60 * 24 * 30 * 6 * 1000;
604
+ break;
605
+ case 'this_month':
606
+ startDate = new Date(year, month, 1).getTime();
607
+ break;
608
+ case 'last_month':
609
+ startDate = new Date(year, month - 1, 1).getTime();
610
+ endDate = new Date(year, month, 0).getTime();
611
+ break;
612
+ case 'this_year':
613
+ startDate = new Date(year, 0, 1);
614
+ break;
615
+ case 'all_time':
616
+ default:
617
+ return null;
618
+ }
619
+ if (startDate === null && endDate === null) {
620
+ return null;
621
+ }
622
+ return {
623
+ start_time: new Date(startDate).toISOString(),
624
+ end_time: new Date(endDate).toISOString(),
625
+ };
626
+ }
672
627
 
673
- /**
674
- * Update a recipient's status block
675
- */
676
- const updateRecipient = async (endpoint, envelopeId, roleName, params) => endpoint.api //
677
- .put(`/envelopes/${envelopeId}/recipients/${roleName}`, params)
678
- .then((r) => r.data);
679
- /**
680
- * Submit an envelope (signing is finished). Note that all fields must be valid/completed for this to succeed.
681
- */
682
- const envelopeRecipientSubmit = (endpoint, envelopeId, roleName) => updateRecipient(endpoint, envelopeId, roleName, { action: 'submit' });
683
- /**
684
- * Decline to complete an envelope (signing will not terminated).
685
- */
686
- const envelopeRecipientDecline = (endpoint, envelopeId, roleName) => updateRecipient(endpoint, envelopeId, roleName, { action: 'decline' });
687
- /**
688
- * Claim / change ownership of an envelope. This is a special-case operation only available in certain workflows.
689
- */
690
- const envelopeRecipientChangeOwner = (endpoint, envelopeId, roleName, email, fullName) => updateRecipient(endpoint, envelopeId, roleName, { action: 'owner_update', email, full_name: fullName });
691
- /**
692
- * Agree to electronic signing.
693
- */
694
- const envelopeRecipientAgree = (endpoint, envelopeId, roleName, agreed) => updateRecipient(endpoint, envelopeId, roleName, { action: 'update', agreed });
695
- /**
696
- * Change a recipient's name.
697
- */
698
- const envelopeRecipientUpdateName = (endpoint, envelopeId, roleName, fullName) => updateRecipient(endpoint, envelopeId, roleName, { action: 'update', new_full_name: fullName });
699
- /**
700
- * Change a recipient's name.
701
- */
702
- const envelopeRecipientPrepare = (endpoint, envelopeId, roleName, recipients) => updateRecipient(endpoint, envelopeId, roleName, { action: 'prepare', recipients });
703
- /**
704
- * Get a signing token.
705
- */
706
- const getSignerToken = (endpoint, envelopeId, roleName) => endpoint.api //
707
- .get(`/envelopes/${envelopeId}/recipients/${encodeURIComponent(roleName)}/signer-token`)
708
- .then((r) => r.data);
709
- /**
710
- * Get an in-person signing link.
711
- */
712
- const getInPersonLink = (endpoint, envelopeId, roleName) => endpoint.api //
713
- .get(`/envelopes/${envelopeId}/recipients/${encodeURIComponent(roleName)}?in_person_link=true`)
714
- .then((r) => r.data);
715
- /**
716
- * Send a delegation request.
717
- */
718
- const sendDelegate = (endpoint, envelopeId, roleName) => endpoint.api //
719
- .post(`/envelopes/${envelopeId}/recipients/${encodeURIComponent(roleName)}/delegate`)
720
- .then((r) => r.data);
721
- /**
722
- * Resend a recipient's invitation.
723
- */
724
- const resendInvitation = (endpoint, envelopeId, roleName) => endpoint.api //
725
- .post(`/envelopes/${envelopeId}/recipients/${encodeURIComponent(roleName)}/resend_invitation`)
726
- .then((r) => r.data);
628
+ function getRTop(y, fieldHeight, iTextHeight, yRatio) {
629
+ return iTextHeight - (y + fieldHeight) * yRatio;
630
+ }
631
+ function getRLeft(x, ratio) {
632
+ return x * ratio;
633
+ }
634
+ function getRValue(y, ratio) {
635
+ return y * ratio;
636
+ }
637
+ function blobToBase64(image) {
638
+ const fileReader = new FileReader();
639
+ return new Promise((resolve, reject) => {
640
+ fileReader.onerror = () => {
641
+ reject(new DOMException('Problem reading blob.'));
642
+ };
643
+ fileReader.onload = () => {
644
+ resolve(fileReader.result);
645
+ };
646
+ fileReader.readAsDataURL(image);
647
+ });
648
+ }
649
+ function rescale(r, n) {
650
+ return r * n;
651
+ }
727
652
 
728
653
  /**
729
- * Enable automatic reminders. setup_time is the number of days after the envelope is sent that the first reminder
730
- * should be sent. interval_time is the number of days between reminders.
731
- */
732
- const createEnvelopeReminder = (endpoint, envelopeId, params) => endpoint.api //
733
- .post(`/envelopes/${envelopeId}/reminder/`, params)
734
- .then((r) => r.data);
735
- /**
736
- * Get the reminder configuration for an envelope.
737
- */
738
- const getEnvelopeReminder = (endpoint, envelopeId, reminderId) => endpoint.api //
739
- .get(`/envelopes/${envelopeId}/reminder/${reminderId}`)
740
- .then((r) => r.data);
741
- /**
742
- * Update the reminder configuration for an envelope.
743
- */
744
- const updateEnvelopeReminder = (endpoint, envelopeId, reminderId, params) => endpoint.api //
745
- .put(`/envelopes/${envelopeId}/reminder/${reminderId}`, params)
746
- .then((r) => r.data);
747
- /**
748
- * Delete the reminder configuration for an envelope.
654
+ * Given a File, extract the file's content as a base64 encoded data URL. The response will have a prefix that
655
+ * includes the MIME type of the file, e.g. "data:image/jpeg;base64,iVBORw0K......"
749
656
  */
750
- const deleteEnvelopeReminder = (endpoint, envelopeId, reminderId) => endpoint.api //
751
- .delete(`/envelopes/${envelopeId}/reminder/${reminderId}`)
752
- .then((r) => r.data);
753
-
657
+ const fileToDataUrl = (file) => new Promise((resolve, reject) => {
658
+ const reader = new FileReader();
659
+ reader.onload = () => resolve({
660
+ lastModified: file.lastModified,
661
+ size: file.size,
662
+ type: file.type,
663
+ name: file.name,
664
+ data: reader.result,
665
+ });
666
+ reader.onerror = reject;
667
+ if (file) {
668
+ reader.readAsDataURL(file);
669
+ }
670
+ else {
671
+ reject(new Error('Invalid file'));
672
+ }
673
+ });
754
674
  /**
755
- * Various helpers to identify available operations for an envelope by a user.
756
- *
757
- * @module
675
+ * Trigger a download dialog to save a blob as a file on disk.
758
676
  */
759
- /**
760
- * Check to see if the user owns the envelope.
761
- */
762
- const userIsEnvelopeOwner = (session, envelope) => envelope.profile_id === session?.profile_id;
763
- /**
764
- * Check to see if the user owns the envelope.
765
- */
766
- const userIsEnvelopeRecipient = (session, envelope) => envelope.profile_id === session?.profile_id;
767
- /**
768
- * Check to see if the envelope has pending actions.
769
- */
770
- const envelopeIsActive = (envelope) => envelope.status !== 'complete' && envelope.status !== 'declined' && envelope.status !== 'canceled';
771
- /**
772
- * Check to see if the envelope has been completed.
773
- */
774
- const envelopeIsComplete = (envelope) => envelope.status !== 'complete';
775
- /**
776
- * Check to see if the user owns the envelope.
777
- */
778
- const userCanCancelEnvelope = (session, envelope) => userIsEnvelopeOwner(session, envelope) &&
779
- envelope.status !== 'complete' &&
780
- envelope.status !== 'declined' &&
781
- envelope.status !== 'canceled';
782
- /**
783
- * Check to see if the user owns the envelope.
784
- */
785
- const userCanFinishEnvelope = (session, envelope) => userIsEnvelopeOwner(session, envelope) &&
786
- envelope.status !== 'complete' &&
787
- envelope.status !== 'declined' &&
788
- envelope.status !== 'canceled';
789
- /**
790
- * Returns true if the recipient has a pending action. Note that this does not necessarily mean the recipient can act (yet).
791
- */
792
- const recipientHasAction = (recipient) => !['submitted', 'canceled', 'declined'].includes(recipient.status);
793
- /**
794
- * Returns the recipients who still have a pending action. Note that not all of these recipients may be able to act (yet).
795
- */
796
- const getRecipientsWithActions = (envelope) => (envelope?.recipients || []).filter(recipientHasAction);
797
- /**
798
- * Returns true if the recipient can act.
799
- */
800
- const recipientCanAct = (recipient, recipientsWithActions) => recipient.sequence === recipientsWithActions?.[0]?.sequence;
801
- /**
802
- * Returns true if the user can act.
803
- */
804
- const userCanAct = (email, recipientsWithActions) => {
805
- const recipient = recipientsWithActions.find((r) => r.email === email);
806
- return recipient && recipient.sequence === recipientsWithActions?.[0]?.sequence;
807
- };
808
- /**
809
- * Returns true if the user can act.
810
- */
811
- const userCanSignNow = (session, envelope) => {
812
- if (!session) {
813
- return false;
814
- }
815
- const recipientsWithActions = getRecipientsWithActions(envelope);
816
- const myRecipient = recipientsWithActions.find((r) => r.profile_id === session?.profile_id || r.email === session?.email);
817
- return (myRecipient &&
818
- envelopeIsActive(envelope) &&
819
- userIsEnvelopeRecipient(session, envelope) &&
820
- recipientCanAct(myRecipient, recipientsWithActions));
821
- };
822
- const getNextRecipient = (envelope) => {
823
- const recipientsWithActions = getRecipientsWithActions(envelope);
824
- return recipientsWithActions?.[0];
825
- };
826
-
827
- /**
828
- * Create a signature block. In a typical signing workflow, the user is asked at the beginning of the process to "adopt"
829
- * a signature block to be used for all signature fields in the document. Thus, this is typically called one time to
830
- * create and store a signature block. Thereafter, the ID of the signature block may be re-used for each signature field
831
- * to be "stamped" by the user.
832
- */
833
- const createSignature = (endpoint, name, signature) => {
834
- const data = new FormData();
835
- data.append('signature', signature, name);
836
- return endpoint.api //
837
- .post(`/signatures`, data)
838
- .then((r) => r.data);
677
+ const downloadBlob = (blob, name = 'file.pdf') => {
678
+ const blobUrl = URL.createObjectURL(blob);
679
+ const link = document.createElement('a');
680
+ link.href = blobUrl;
681
+ link.download = name;
682
+ document.body.appendChild(link);
683
+ link.dispatchEvent(new MouseEvent('click', {
684
+ bubbles: true,
685
+ cancelable: true,
686
+ view: window,
687
+ }));
688
+ document.body.removeChild(link);
839
689
  };
840
- /**
841
- * Get the availbable signatures for a user.
842
- */
843
- const getSignatures = (endpoint) => endpoint.api //
844
- .get('/signatures')
845
- .then((r) => r.data);
846
- /**
847
- * Get a user's signature by ID.
848
- */
849
- const getSignature = (endpoint, signatureId) => endpoint.api //
850
- .get(`/signatures/${signatureId}`)
851
- .then((r) => r.data);
852
- /**
853
- * Delete a user's signature.
854
- */
855
- const deleteSignature = (endpoint, signatureId) => endpoint.api //
856
- .delete(`/signatures/${signatureId}`)
857
- .then((r) => r.data);
858
-
859
- /**
860
- * API keys are used to authenticate server-to-server calls. (API keys should **never** be used for client-to-server operations!)
861
- * To generate a key, either use the Verdocs admin interface and make note of the client_id and client_secret generated, or call
862
- * createKey as shown below. Then call {@link Users.Auth.authenticateApp} to obtain an access token using the provided ID and
863
- * secret. Note that server-to-server authentication requests return shorter-lived tokens, so it is important to check the `exp`
864
- * field and re-authenticate as needed for subsequent calls.
865
- *
866
- * API keys may be updated or rotated at any time. Regular rotation is recommended. Rotation will not expire or invalidate
867
- * existing server-to-server sessions, so it may be done at any time without disrupting your application.
868
- *
869
- * @module
870
- */
871
- /**
872
- * Get a list of keys for a given organization. The caller must have admin access to the organization.
873
- *
874
- * ```typescript
875
- * import {ApiKeys} from '@verdocs/js-sdk/Organizations';
876
- *
877
- * const keys = await ApiKeys.getKeys(ORGID);
878
- * ```
879
- */
880
- const getApiKeys = (endpoint, organizationId) => endpoint.api //
881
- .get(`/organizations/${organizationId}/api_key`)
882
- .then((r) => r.data);
883
- /**
884
- * Create an API key.
885
- *
886
- * ```typescript
887
- * import {ApiKeys} from '@verdocs/js-sdk/Organizations';
888
- *
889
- * await ApiKeys.createKey(ORGID, {name: NEWNAME});
890
- * ```
891
- */
892
- const createApiKey = (endpoint, organizationId, params) => endpoint.api //
893
- .post(`/organizations/${organizationId}/api_key`, params)
894
- .then((r) => r.data);
895
- /**
896
- * Rotate the secret for an API key. The caller must have admin access to the organization.
897
- *
898
- * ```typescript
899
- * import {ApiKeys} from '@verdocs/js-sdk/Organizations';
900
- *
901
- * const {client_secret: newSecret} = await ApiKeys.rotateKey(ORGID, CLIENTID);
902
- * ```
903
- */
904
- const rotateApiKey = (endpoint, organizationId, clientId) => endpoint.api //
905
- .put(`/organizations/${organizationId}/api_key/${clientId}/rotate`)
906
- .then((r) => r.data);
907
- /**
908
- * Update an API key to change its assigned Profile ID or Name.
909
- *
910
- * ```typescript
911
- * import {ApiKeys} from '@verdocs/js-sdk/Organizations';
912
- *
913
- * await ApiKeys.updateKey(ORGID, CLIENTID, {name: NEWNAME});
914
- * ```
915
- */
916
- const updateApiKey = (endpoint, organizationId, clientId, params) => endpoint.api //
917
- .patch(`/organizations/${organizationId}/api_key/${clientId}`, params)
918
- .then((r) => r.data);
919
- /**
920
- * Delete an API key.
921
- *
922
- * ```typescript
923
- * import {ApiKeys} from '@verdocs/js-sdk/Organizations';
924
- *
925
- * await ApiKeys.deleteKey(ORGID, CLIENTID);
926
- * ```
927
- */
928
- const deleteApiKey = (endpoint, organizationId, clientId) => endpoint.api //
929
- .delete(`/organizations/${organizationId}/api_key/${clientId}`)
930
- .then((r) => r.data);
931
-
932
- /**
933
- * Organizations may contain "Groups" of user profiles, called Members. Groups may have permissions assigned that
934
- * apply to all Members, making it easy to configure role-based access control (RBAC) within an Organization. Note
935
- * that permissions are **additive**. A user may be a member of more than one group, and may also have permissions
936
- * assigned directly. In that case, the user will have the combined set of all permissions inherited from all
937
- * sources.
938
- *
939
- * @module
940
- */
941
- /**
942
- * Get a list of groups for a given organization. The caller must have admin access to the organization.
943
- *
944
- * ```typescript
945
- * import {Groups} from '@verdocs/js-sdk/Organizations';
946
- *
947
- * const groups = await Groups.getGroups(ORGID);
948
- * ```
949
- */
950
- const getGroups = (endpoint, organizationId) => endpoint.api //
951
- .get(`/organizations/${organizationId}/groups`)
952
- .then((r) => r.data);
953
- /**
954
- * Get a single group by name. Returns a detail record.
955
- *
956
- * ```typescript
957
- * import {Groups} from '@verdocs/js-sdk/Organizations';
958
- *
959
- * const groups = await Groups.getGroups(ORGID);
960
- * ```
961
- */
962
- const getGroupByName = (endpoint, organizationId, name) => endpoint.api //
963
- .get(`/organizations/${organizationId}/groups`, { params: { name } })
964
- .then((r) => r.data);
965
- /**
966
- * Get the details for a group.
967
- *
968
- * ```typescript
969
- * import {Groups} from '@verdocs/js-sdk/Organizations';
970
- *
971
- * const groups = await Groups.getGroups(ORGID);
972
- * ```
973
- */
974
- const getGroup = (endpoint, organizationId, groupId) => endpoint.api //
975
- .get(`/organizations/${organizationId}/groups/${groupId}`)
976
- .then((r) => r.data);
977
- const getGroupMembers = (endpoint, organizationId, groupId) => endpoint.api //
978
- .get(`/organizations/${organizationId}/groups/${groupId}/members`)
979
- .then((r) => r.data);
980
- const addGroupMembers = (endpoint, organizationId, groupId, params) => endpoint.api //
981
- .post(`/organizations/${organizationId}/groups/${groupId}/members`, params)
982
- .then((r) => r.data);
983
- const deleteGroupMembers = (endpoint, organizationId, groupId, params) => endpoint.api //
984
- .put(`/organizations/${organizationId}/groups/${groupId}/delete_members`, params)
985
- .then((r) => r.data);
986
- const addGroupPermission = (endpoint, organizationId, groupId, permission) => endpoint.api //
987
- .post(`/organizations/${organizationId}/groups/${groupId}/permissions/${permission}`, {})
988
- .then((r) => r.data);
989
- const deleteGroupPermission = (endpoint, organizationId, groupId, permission) => endpoint.api //
990
- .delete(`/organizations/${organizationId}/groups/${groupId}/permissions/${permission}`)
991
- .then((r) => r.data);
992
690
 
993
- /**
994
- * An invitation represents an opportunity for a Member to join an Organization.
995
- *
996
- * @module
997
- */
998
- const getOrganizationInvitations = (endpoint, organizationId) => endpoint.api //
999
- .get(`/organizations/${organizationId}/invitation`)
1000
- .then((r) => r.data);
1001
- const createOrganizationInvitation = (endpoint, organizationId, params) => endpoint.api //
1002
- .post(`/organizations/${organizationId}/invitation`, params)
1003
- .then((r) => r.data);
1004
- const deleteOrganizationInvitation = (endpoint, organizationId, email) => endpoint.api //
1005
- .delete(`/organizations/${organizationId}/invitation/${email}`)
1006
- .then((r) => r.data);
1007
- const updateOrganizationInvitation = (endpoint, organizationId, email, params) => endpoint.api //
1008
- .patch(`/organizations/${organizationId}/invitation/${email}`, params)
1009
- .then((r) => r.data);
1010
- const resendOrganizationInvitation = (endpoint, organizationId, email) => endpoint.api //
1011
- .post(`/organizations/${organizationId}/invitation/${email}/resend`)
1012
- .then((r) => r.data);
1013
- const getOrganizationInvitation = (endpoint, organizationId, email, token) => endpoint.api //
1014
- .get(`/organizations/${organizationId}/invitation/${email}/accept/${token}`)
1015
- .then((r) => r.data);
1016
- const acceptOrganizationInvitation = (endpoint, organizationId, email, token) => endpoint.api //
1017
- .post(`/organizations/${organizationId}/invitation/${email}/accept/${token}`)
1018
- .then((r) => r.data);
1019
- const declineOrganizationInvitation = (endpoint, organizationId, email, token) => endpoint.api //
1020
- .post(`/organizations/${organizationId}/invitation/${email}/decline/${token}`)
1021
- .then((r) => r.data);
1022
- const claimNewUser = (endpoint, organizationId, email, token) => endpoint.api //
1023
- .put(`/organizations/${organizationId}/invitation/${email}/token/${token}/new_user`)
1024
- .then((r) => r.data);
1025
-
1026
- /**
1027
- * An Organization Member (aka Profile) is an individual user with access to an organization.
1028
- *
1029
- * @module
1030
- */
1031
- const getOrganizationMembers = (endpoint, organizationId) => endpoint.api //
1032
- .get(`/organizations/${organizationId}/profiles`)
1033
- .then((r) => r.data);
1034
- const deleteOrganizationMember = (endpoint, organizationId, profileId) => endpoint.api //
1035
- .delete(`/organizations/${organizationId}/profiles/${profileId}`)
1036
- .then((r) => r.data);
1037
- const addOrganizationMemberRole = (endpoint, organizationId, profileId, roleId) => endpoint.api //
1038
- .post(`/organizations/${organizationId}/profiles/${profileId}/role/${roleId}`)
1039
- .then((r) => r.data);
1040
- const deleteOrganizationMemberRole = (endpoint, organizationId, profileId, roleId) => endpoint.api //
1041
- .delete(`/organizations/${organizationId}/profiles/${profileId}/role/${roleId}`)
1042
- .then((r) => r.data);
1043
- const getOrganizationMemberPlans = (endpoint, organizationId, profileId) => endpoint.api //
1044
- .get(`/organizations/${organizationId}/profiles/${profileId}/plans`)
1045
- .then((r) => r.data);
1046
-
1047
- /**
1048
- * An Organization is the top level object for ownership for Members, Documents, and Templates.
1049
- *
1050
- * @module
1051
- */
1052
- /**
1053
- * Get a list of organizations the user has access to.
1054
- */
1055
- const getOrganizations = (endpoint) => endpoint.api //
1056
- .get('/organizations')
1057
- .then((r) => r.data);
1058
- /**
1059
- * Create an organization.
1060
- */
1061
- const createOrganization = (endpoint) => endpoint.api //
1062
- .post('/organizations')
1063
- .then((r) => r.data);
1064
- /**
1065
- * Delete an organization.
1066
- */
1067
- const deleteOrganization = (endpoint, organizationId) => endpoint.api //
1068
- .delete(`/organizations/${organizationId}`)
1069
- .then((r) => r.data);
1070
- /**
1071
- * Get an organization by ID.
1072
- */
1073
- const getOrganization = (endpoint, organizationId) => endpoint.api //
1074
- .get(`/organizations/${organizationId}`)
1075
- .then((r) => r.data);
1076
- /**
1077
- * Update an organization.
1078
- */
1079
- const updateOrganization = (endpoint, organizationId, params) => endpoint.api //
1080
- .patch(`/organizations/${organizationId}`, params)
1081
- .then((r) => r.data);
1082
-
1083
- const getWebhooks = (endpoint) => endpoint.api //
1084
- .get(`/v2/webhooks/organization`)
1085
- .then((r) => r.data);
1086
- const setWebhooks = (endpoint, params) => endpoint.api //
1087
- .post(`/v2/webhooks/organization`, params)
1088
- .then((r) => r.data);
1089
-
1090
- /**
1091
- * Confirm whether the user has all of the specified permissions.
1092
- */
1093
- const userHasPermissions = (session, permissions) => permissions.every((perm) => (session?.permissions || []).includes(perm));
1094
-
1095
- const canPerformTemplateAction = (session, action, template) => {
1096
- if (!template && !action.includes('create')) {
1097
- return { canPerform: false, message: 'Missing required template object' };
691
+ const Countries = [
692
+ { code: '+7 840', name: 'Abkhazia', value: '+7' },
693
+ { code: '+93', name: 'Afghanistan', value: '+93' },
694
+ { code: '+355', name: 'Albania', value: '+355' },
695
+ { code: '+213', name: 'Algeria', value: '+213' },
696
+ { code: '+1', name: 'American Samoa', value: '+1' },
697
+ { code: '+376', name: 'Andorra', value: '+376' },
698
+ { code: '+244', name: 'Angola', value: '+244' },
699
+ { code: '+1', name: 'Anguilla', value: '+1' },
700
+ { code: '+1', name: 'Antigua and Barbuda', value: '+1' },
701
+ { code: '+54', name: 'Argentina', value: '+54' },
702
+ { code: '+374', name: 'Armenia', value: '+374' },
703
+ { code: '+297', name: 'Aruba', value: '+297' },
704
+ { code: '+247', name: 'Ascension', value: '+247' },
705
+ { code: '+61', name: 'Australia', value: '+61' },
706
+ { code: '+672', name: 'Australian External Territories', value: '+672' },
707
+ { code: '+43', name: 'Austria', value: '+43' },
708
+ { code: '+994', name: 'Azerbaijan', value: '+994' },
709
+ { code: '+1', name: 'Bahamas', value: '+1' },
710
+ { code: '+973', name: 'Bahrain', value: '+973' },
711
+ { code: '+880', name: 'Bangladesh', value: '+880' },
712
+ { code: '+1', name: 'Barbados', value: '+1' },
713
+ { code: '+1', name: 'Barbuda', value: '+1' },
714
+ { code: '+375', name: 'Belarus', value: '+375' },
715
+ { code: '+32', name: 'Belgium', value: '+32' },
716
+ { code: '+501', name: 'Belize', value: '+501' },
717
+ { code: '+229', name: 'Benin', value: '+229' },
718
+ { code: '+1', name: 'Bermuda', value: '+1' },
719
+ { code: '+975', name: 'Bhutan', value: '+975' },
720
+ { code: '+591', name: 'Bolivia', value: '+591' },
721
+ { code: '+387', name: 'Bosnia and Herzegovina', value: '+387' },
722
+ { code: '+267', name: 'Botswana', value: '+267' },
723
+ { code: '+55', name: 'Brazil', value: '+55' },
724
+ { code: '+246', name: 'British Indian Ocean Territory', value: '+246' },
725
+ { code: '+1', name: 'British Virgin Islands', value: '+1' },
726
+ { code: '+673', name: 'Brunei', value: '+673' },
727
+ { code: '+359', name: 'Bulgaria', value: '+359' },
728
+ { code: '+226', name: 'Burkina Faso', value: '+226' },
729
+ { code: '+257', name: 'Burundi', value: '+257' },
730
+ { code: '+855', name: 'Cambodia', value: '+855' },
731
+ { code: '+237', name: 'Cameroon', value: '+237' },
732
+ { code: '+1', name: 'Canada', value: '+1' },
733
+ { code: '+238', name: 'Cape Verde', value: '+238' },
734
+ { code: '+1', name: 'Cayman Islands', value: '+1' },
735
+ { code: '+236', name: 'Central African Republic', value: '+236' },
736
+ { code: '+235', name: 'Chad', value: '+235' },
737
+ { code: '+56', name: 'Chile', value: '+56' },
738
+ { code: '+86', name: 'China', value: '+86' },
739
+ { code: '+61', name: 'Christmas Island', value: '+61' },
740
+ { code: '+61', name: 'Cocos-Keeling Islands', value: '+61' },
741
+ { code: '+57', name: 'Colombia', value: '+57' },
742
+ { code: '+269', name: 'Comoros', value: '+269' },
743
+ { code: '+242', name: 'Congo', value: '+242' },
744
+ { code: '+243', name: 'Congo, Dem. Rep. of (Zaire)', value: '+243' },
745
+ { code: '+682', name: 'Cook Islands', value: '+682' },
746
+ { code: '+506', name: 'Costa Rica', value: '+506' },
747
+ { code: '+385', name: 'Croatia', value: '+385' },
748
+ { code: '+53', name: 'Cuba', value: '+53' },
749
+ { code: '+599', name: 'Curacao', value: '+599' },
750
+ { code: '+537', name: 'Cyprus', value: '+537' },
751
+ { code: '+420', name: 'Czech Republic', value: '+420' },
752
+ { code: '+45', name: 'Denmark', value: '+45' },
753
+ { code: '+246', name: 'Diego Garcia', value: '+246' },
754
+ { code: '+253', name: 'Djibouti', value: '+253' },
755
+ { code: '+1', name: 'Dominica', value: '+1' },
756
+ { code: '+1', name: 'Dominican Republic', value: '+1' },
757
+ { code: '+670', name: 'East Timor', value: '+670' },
758
+ { code: '+56', name: 'Easter Island', value: '+56' },
759
+ { code: '+593', name: 'Ecuador', value: '+593' },
760
+ { code: '+20', name: 'Egypt', value: '+20' },
761
+ { code: '+503', name: 'El Salvador', value: '+503' },
762
+ { code: '+240', name: 'Equatorial Guinea', value: '+240' },
763
+ { code: '+291', name: 'Eritrea', value: '+291' },
764
+ { code: '+372', name: 'Estonia', value: '+372' },
765
+ { code: '+251', name: 'Ethiopia', value: '+251' },
766
+ { code: '+500', name: 'Falkland Islands', value: '+500' },
767
+ { code: '+298', name: 'Faroe Islands', value: '+298' },
768
+ { code: '+679', name: 'Fiji', value: '+679' },
769
+ { code: '+358', name: 'Finland', value: '+358' },
770
+ { code: '+33', name: 'France', value: '+33' },
771
+ { code: '+596', name: 'Martinique', value: '+596' },
772
+ { code: '+594', name: 'French Guiana', value: '+594' },
773
+ { code: '+689', name: 'French Polynesia', value: '+689' },
774
+ { code: '+241', name: 'Gabon', value: '+241' },
775
+ { code: '+220', name: 'Gambia', value: '+220' },
776
+ { code: '+995', name: 'Georgia', value: '+995' },
777
+ { code: '+49', name: 'Germany', value: '+49' },
778
+ { code: '+233', name: 'Ghana', value: '+233' },
779
+ { code: '+350', name: 'Gibraltar', value: '+350' },
780
+ { code: '+30', name: 'Greece', value: '+30' },
781
+ { code: '+299', name: 'Greenland', value: '+299' },
782
+ { code: '+1', name: 'Grenada', value: '+1' },
783
+ { code: '+590', name: 'Guadeloupe', value: '+590' },
784
+ { code: '+1', name: 'Guam', value: '+1' },
785
+ { code: '+502', name: 'Guatemala', value: '+502' },
786
+ { code: '+224', name: 'Guinea', value: '+224' },
787
+ { code: '+245', name: 'Guinea-Bissau', value: '+245' },
788
+ { code: '+595', name: 'Guyana', value: '+595' },
789
+ { code: '+509', name: 'Haiti', value: '+509' },
790
+ { code: '+504', name: 'Honduras', value: '+504' },
791
+ { code: '+852', name: 'Hong Kong SAR China', value: '+852' },
792
+ { code: '+36', name: 'Hungary', value: '+36' },
793
+ { code: '+354', name: 'Iceland', value: '+354' },
794
+ { code: '+91', name: 'India', value: '+91' },
795
+ { code: '+62', name: 'Indonesia', value: '+62' },
796
+ { code: '+98', name: 'Iran', value: '+98' },
797
+ { code: '+964', name: 'Iraq', value: '+964' },
798
+ { code: '+353', name: 'Ireland', value: '+353' },
799
+ { code: '+972', name: 'Israel', value: '+972' },
800
+ { code: '+39', name: 'Italy', value: '+39' },
801
+ { code: '+225', name: 'Ivory Coast', value: '+225' },
802
+ { code: '+1', name: 'Jamaica', value: '+1' },
803
+ { code: '+81', name: 'Japan', value: '+81' },
804
+ { code: '+962', name: 'Jordan', value: '+962' },
805
+ { code: '+77', name: 'Kazakhstan', value: '+7' },
806
+ { code: '+254', name: 'Kenya', value: '+254' },
807
+ { code: '+686', name: 'Kiribati', value: '+686' },
808
+ { code: '+965', name: 'Kuwait', value: '+965' },
809
+ { code: '+996', name: 'Kyrgyzstan', value: '+996' },
810
+ { code: '+856', name: 'Laos', value: '+856' },
811
+ { code: '+371', name: 'Latvia', value: '+371' },
812
+ { code: '+961', name: 'Lebanon', value: '+961' },
813
+ { code: '+266', name: 'Lesotho', value: '+266' },
814
+ { code: '+231', name: 'Liberia', value: '+231' },
815
+ { code: '+218', name: 'Libya', value: '+218' },
816
+ { code: '+423', name: 'Liechtenstein', value: '+423' },
817
+ { code: '+370', name: 'Lithuania', value: '+370' },
818
+ { code: '+352', name: 'Luxembourg', value: '+352' },
819
+ { code: '+853', name: 'Macau SAR China', value: '+853' },
820
+ { code: '+389', name: 'Macedonia', value: '+389' },
821
+ { code: '+261', name: 'Madagascar', value: '+261' },
822
+ { code: '+265', name: 'Malawi', value: '+265' },
823
+ { code: '+60', name: 'Malaysia', value: '+60' },
824
+ { code: '+960', name: 'Maldives', value: '+960' },
825
+ { code: '+223', name: 'Mali', value: '+223' },
826
+ { code: '+356', name: 'Malta', value: '+356' },
827
+ { code: '+692', name: 'Marshall Islands', value: '+692' },
828
+ { code: '+596', name: 'Martinique', value: '+596' },
829
+ { code: '+222', name: 'Mauritania', value: '+222' },
830
+ { code: '+230', name: 'Mauritius', value: '+230' },
831
+ { code: '+262', name: 'Mayotte or Réunion', value: '+262' },
832
+ { code: '+52', name: 'Mexico', value: '+52' },
833
+ { code: '+691', name: 'Micronesia', value: '+691' },
834
+ { code: '+1', name: 'Midway Island', value: '+1' },
835
+ { code: '+373', name: 'Moldova', value: '+373' },
836
+ { code: '+377', name: 'Monaco', value: '+377' },
837
+ { code: '+976', name: 'Mongolia', value: '+976' },
838
+ { code: '+382', name: 'Montenegro', value: '+382' },
839
+ { code: '+1', name: 'Montserrat', value: '+1' },
840
+ { code: '+212', name: 'Morocco', value: '+212' },
841
+ { code: '+95', name: 'Myanmar', value: '+95' },
842
+ { code: '+264', name: 'Namibia', value: '+264' },
843
+ { code: '+674', name: 'Nauru', value: '+674' },
844
+ { code: '+977', name: 'Nepal', value: '+977' },
845
+ { code: '+31', name: 'Netherlands', value: '+31' },
846
+ { code: '+599', name: 'Netherlands Antilles', value: '+599' },
847
+ { code: '+1', name: 'Nevis', value: '+1' },
848
+ { code: '+687', name: 'New Caledonia', value: '+687' },
849
+ { code: '+64', name: 'New Zealand', value: '+64' },
850
+ { code: '+505', name: 'Nicaragua', value: '+505' },
851
+ { code: '+227', name: 'Niger', value: '+227' },
852
+ { code: '+234', name: 'Nigeria', value: '+234' },
853
+ { code: '+683', name: 'Niue', value: '+683' },
854
+ { code: '+672', name: 'Norfolk Island', value: '+672' },
855
+ { code: '+850', name: 'North Korea', value: '+850' },
856
+ { code: '+1', name: 'Northern Mariana Islands', value: '+1' },
857
+ { code: '+47', name: 'Norway', value: '+47' },
858
+ { code: '+968', name: 'Oman', value: '+968' },
859
+ { code: '+92', name: 'Pakistan', value: '+92' },
860
+ { code: '+680', name: 'Palau', value: '+680' },
861
+ { code: '+970', name: 'Palestinian Territory', value: '+970' },
862
+ { code: '+507', name: 'Panama', value: '+507' },
863
+ { code: '+675', name: 'Papua New Guinea', value: '+675' },
864
+ { code: '+595', name: 'Paraguay', value: '+595' },
865
+ { code: '+51', name: 'Peru', value: '+51' },
866
+ { code: '+63', name: 'Philippines', value: '+63' },
867
+ { code: '+48', name: 'Poland', value: '+48' },
868
+ { code: '+351', name: 'Portugal', value: '+351' },
869
+ { code: '+1', name: 'Puerto Rico', value: '+1' },
870
+ { code: '+974', name: 'Qatar', value: '+974' },
871
+ { code: '+40', name: 'Romania', value: '+40' },
872
+ { code: '+7', name: 'Russia', value: '+7' },
873
+ { code: '+250', name: 'Rwanda', value: '+250' },
874
+ { code: '508', name: 'Saint Pierre and Miquelon', value: '508' },
875
+ { code: '+685', name: 'Samoa', value: '+685' },
876
+ { code: '+378', name: 'San Marino', value: '+378' },
877
+ { code: '+966', name: 'Saudi Arabia', value: '+966' },
878
+ { code: '+221', name: 'Senegal', value: '+221' },
879
+ { code: '+381', name: 'Serbia', value: '+381' },
880
+ { code: '+248', name: 'Seychelles', value: '+248' },
881
+ { code: '+232', name: 'Sierra Leone', value: '+232' },
882
+ { code: '+65', name: 'Singapore', value: '+65' },
883
+ { code: '+421', name: 'Slovakia', value: '+421' },
884
+ { code: '+386', name: 'Slovenia', value: '+386' },
885
+ { code: '+677', name: 'Solomon Islands', value: '+677' },
886
+ { code: '+27', name: 'South Africa', value: '+27' },
887
+ { code: '+500', name: 'South Georgia and the South Sandwich Islands', value: '+500' },
888
+ { code: '+82', name: 'South Korea', value: '+82' },
889
+ { code: '+34', name: 'Spain', value: '+34' },
890
+ { code: '+94', name: 'Sri Lanka', value: '+94' },
891
+ { code: '+249', name: 'Sudan', value: '+249' },
892
+ { code: '+597', name: 'Suriname', value: '+597' },
893
+ { code: '+268', name: 'Swaziland', value: '+268' },
894
+ { code: '+46', name: 'Sweden', value: '+46' },
895
+ { code: '+41', name: 'Switzerland', value: '+41' },
896
+ { code: '+963', name: 'Syria', value: '+963' },
897
+ { code: '+886', name: 'Taiwan', value: '+886' },
898
+ { code: '+992', name: 'Tajikistan', value: '+992' },
899
+ { code: '+255', name: 'Tanzania', value: '+255' },
900
+ { code: '+66', name: 'Thailand', value: '+66' },
901
+ { code: '+670', name: 'Timor Leste', value: '+670' },
902
+ { code: '+228', name: 'Togo', value: '+228' },
903
+ { code: '+690', name: 'Tokelau', value: '+690' },
904
+ { code: '+676', name: 'Tonga', value: '+676' },
905
+ { code: '+1', name: 'Trinidad and Tobago', value: '+1' },
906
+ { code: '+216', name: 'Tunisia', value: '+216' },
907
+ { code: '+90', name: 'Turkey', value: '+90' },
908
+ { code: '+993', name: 'Turkmenistan', value: '+993' },
909
+ { code: '+1', name: 'Turks and Caicos Islands', value: '+1' },
910
+ { code: '+688', name: 'Tuvalu', value: '+688' },
911
+ { code: '+1', name: 'U.S. Virgin Islands', value: '+1' },
912
+ { code: '+256', name: 'Uganda', value: '+256' },
913
+ { code: '+380', name: 'Ukraine', value: '+380' },
914
+ { code: '+971', name: 'United Arab Emirates', value: '+971' },
915
+ { code: '+44', name: 'United Kingdom', value: '+44' },
916
+ { code: '+1', name: 'United States', value: '+1' },
917
+ { code: '+598', name: 'Uruguay', value: '+598' },
918
+ { code: '+998', name: 'Uzbekistan', value: '+998' },
919
+ { code: '+678', name: 'Vanuatu', value: '+678' },
920
+ { code: '+58', name: 'Venezuela', value: '+58' },
921
+ { code: '+84', name: 'Vietnam', value: '+84' },
922
+ { code: '+1', name: 'Wake Island', value: '+1' },
923
+ { code: '+681', name: 'Wallis and Futuna', value: '+681' },
924
+ { code: '+967', name: 'Yemen', value: '+967' },
925
+ { code: '+260', name: 'Zambia', value: '+260' },
926
+ { code: '+255', name: 'Zanzibar', value: '+255' },
927
+ { code: '+263', name: 'Zimbabwe', value: '+263' },
928
+ ];
929
+ function getCountryByCode(code) {
930
+ const found = Countries.find((country) => country.code === code);
931
+ if (found)
932
+ return found;
933
+ if (isFrenchGuiana(code)) {
934
+ return { code: '+594', name: 'French Guiana', value: '+594' };
1098
935
  }
1099
- // We use BOGUS here to force the option-chain in things like template?.profile_id to NOT match profile?.profile_id because if both
1100
- // were undefined, they would actually match.
1101
- const profile_id = session?.profile_id || 'BOGUS';
1102
- const organization_id = session?.organization_id || 'BOGUS';
1103
- if (!profile_id) {
1104
- return { canPerform: false, message: 'Active session required' };
936
+ else if (isGuadeloupe(code)) {
937
+ return { code: '+590', name: 'Guadeloupe', value: '+590' };
1105
938
  }
1106
- const isCreator = template?.profile_id === profile_id;
1107
- const isSameOrg = template?.organization_id === organization_id;
1108
- const isPersonal = template?.is_personal ?? false;
1109
- const isPublic = template?.is_public ?? false;
1110
- const permissionsRequired = [];
1111
- switch (action) {
1112
- case 'create_personal':
1113
- permissionsRequired.push('template:creator:create:personal');
1114
- break;
1115
- case 'create_org':
1116
- permissionsRequired.push('template:creator:create:org');
939
+ else if (isMartinique(code)) {
940
+ return { code: '+596', name: 'Martinique', value: '+596' };
941
+ }
942
+ else if (isMayotte(code)) {
943
+ return { code: '+262', name: 'Mayotte or Réunion', value: '+262' };
944
+ }
945
+ return null;
946
+ }
947
+ function isFrenchGuiana(code) {
948
+ return '+594' === code.substring(0, 4);
949
+ }
950
+ function isGuadeloupe(code) {
951
+ return '+590' === code.substring(0, 4);
952
+ }
953
+ function isMartinique(code) {
954
+ return '+596' === code.substring(0, 4);
955
+ }
956
+ function isMayotte(code) {
957
+ return '+262' === code.substring(0, 4);
958
+ }
959
+ function getPlusOneCountry(code) {
960
+ let info = null;
961
+ switch (code.substring(0, 5)) {
962
+ case '+1684':
963
+ info = { code: '+1', name: 'American Samoa', value: '+1' };
1117
964
  break;
1118
- case 'create_public':
1119
- permissionsRequired.push('template:creator:create:public');
965
+ case '+1264':
966
+ info = { code: '+1', name: 'Anguilla', value: '+1' };
1120
967
  break;
1121
- case 'read':
1122
- if (!isCreator) {
1123
- if ((!isPersonal && isSameOrg) || !isPublic) {
1124
- permissionsRequired.push('template:member:read');
1125
- }
1126
- }
968
+ case '+1268':
969
+ info = { code: '+1', name: 'Antigua and Barbuda', value: '+1' };
1127
970
  break;
1128
- case 'write':
1129
- if (!isCreator) {
1130
- permissionsRequired.push('template:member:read');
1131
- permissionsRequired.push('template:member:write');
1132
- }
971
+ case '+1242':
972
+ info = { code: '+1', name: 'Bahamas', value: '+1' };
1133
973
  break;
1134
- case 'change_visibility_personal':
1135
- if (isCreator) {
1136
- permissionsRequired.push('template:creator:create:personal');
1137
- }
1138
- else {
1139
- permissionsRequired.push('template:member:visibility');
1140
- }
974
+ case '+1246':
975
+ info = { code: '+1', name: 'Barbados', value: '+1' };
1141
976
  break;
1142
- case 'change_visibility_org':
1143
- if (isCreator) {
1144
- permissionsRequired.push('template:creator:create:org');
1145
- }
1146
- else {
1147
- permissionsRequired.push('template:member:visibility');
1148
- }
977
+ case '+1441':
978
+ info = { code: '+1', name: 'Bermuda', value: '+1' };
1149
979
  break;
1150
- case 'change_visibility_public':
1151
- if (isCreator) {
1152
- permissionsRequired.push('template:creator:create:public');
1153
- permissionsRequired.push('template:creator:visibility');
1154
- }
1155
- else {
1156
- permissionsRequired.push('template:member:visibility');
1157
- }
980
+ case '+1284':
981
+ info = { code: '+1', name: 'British Virgin Islands', value: '+1' };
1158
982
  break;
1159
- case 'delete':
1160
- if (isCreator) {
1161
- permissionsRequired.push('template:creator:delete');
1162
- }
1163
- else {
1164
- permissionsRequired.push('template:member:delete');
1165
- }
983
+ case '+1':
984
+ info = { code: '+1', name: '', value: '+1' };
1166
985
  break;
1167
- default:
1168
- return { canPerform: false, message: 'Action is not defined' };
1169
- }
1170
- if (hasRequiredPermissions(session, permissionsRequired)) {
1171
- return { canPerform: true, message: '' };
1172
986
  }
1173
- return { canPerform: false, message: `Insufficient access to perform '${action}'. Needed permissions: ${permissionsRequired.toString()}` };
1174
- };
1175
- const hasRequiredPermissions = (session, permissions) => permissions.every((perm) => (session?.permissions || []).includes(perm));
987
+ return info;
988
+ }
989
+ function isCanada(code) {
990
+ const canadianAreaCodes = [
991
+ '403',
992
+ '587',
993
+ '780',
994
+ '825',
995
+ '604',
996
+ '250',
997
+ '778',
998
+ '236',
999
+ '204',
1000
+ '431',
1001
+ '506',
1002
+ '709',
1003
+ '867',
1004
+ '782',
1005
+ '902',
1006
+ '867',
1007
+ '548',
1008
+ '705',
1009
+ '365',
1010
+ '613',
1011
+ '807',
1012
+ '226',
1013
+ '289',
1014
+ '437',
1015
+ '519',
1016
+ '647',
1017
+ '905',
1018
+ '249',
1019
+ '343',
1020
+ '416',
1021
+ '902',
1022
+ '782',
1023
+ '450',
1024
+ '418',
1025
+ '579',
1026
+ '873',
1027
+ '367',
1028
+ '514',
1029
+ '581',
1030
+ '819',
1031
+ '438',
1032
+ '639',
1033
+ '306',
1034
+ '867',
1035
+ ];
1036
+ const areaCode = code.substring(0, 5);
1037
+ return canadianAreaCodes.findIndex((x) => '+1' + x === areaCode) > -1;
1038
+ }
1039
+ function isAmericanSamoa(code) {
1040
+ return code.substring(0, 5) === '+1684';
1041
+ }
1042
+ function isDominicanRepublic(code) {
1043
+ return '+1809' === code.substring(0, 5) || '+1829' === code.substring(0, 5) || '+1849' === code.substring(0, 5);
1044
+ }
1045
+ function isPuertoRico(code) {
1046
+ return code.substring(0, 5) === '+' || code.substring(0, 5) === '+';
1047
+ }
1048
+ // need to finish
1049
+ function getMatchingCountry(code, substrings) {
1050
+ const toMatch = code.substring(0, substrings);
1051
+ return Countries.filter((c) => c.code === toMatch).length;
1052
+ }
1053
+ // const e164Regex = new RegExp(/\+[1-9]\d{6,14}/g);
1054
+ // export function simpleE164Validator(code: string) {
1055
+ // return (code !== null && code.length < 16 && code.length > 6 && e164Regex.test(code)) || code === '' || code === null;
1056
+ // }
1176
1057
 
1177
1058
  /**
1178
- * Add a field to a template.
1179
- */
1180
- const createField = (endpoint, templateId, params) => endpoint.api //
1181
- .post(`/templates/${templateId}/fields`, params)
1182
- .then((r) => r.data);
1183
- /**
1184
- * Update a template field.
1059
+ * Capitalize the first letter of a string.
1185
1060
  */
1186
- const updateField = (endpoint, templateId, fieldName, params) => endpoint.api //
1187
- .put(`/templates/${templateId}/fields/${fieldName}`, params)
1188
- .then((r) => r.data);
1061
+ const capitalize = (str) => str.charAt(0).toUpperCase() + str.slice(1);
1189
1062
  /**
1190
- * REmove a field from a template.
1063
+ * Convert a phone-number-like string to E164 format.
1064
+ * @see https://46elks.com/kb/e164
1191
1065
  */
1192
- const deleteField = (endpoint, templateId, fieldName) => endpoint.api //
1193
- .delete(`/templates/${templateId}/fields/${fieldName}`)
1194
- .then((r) => r.data);
1066
+ const convertToE164 = (input) => {
1067
+ // "(212) 555-1212" => +12125551212
1068
+ // "+46766861004" => "+46766861004"
1069
+ // "212-555-1212" => +12125551212
1070
+ // "212.555.1212" => +12125551212
1071
+ // "212 555 1212" => +12125551212
1072
+ let temp = (input || '').trim();
1073
+ // If we are already prefixed, assume the user did it deliberately and attempt to use what they entered. We also short-circuit blanks.
1074
+ if (!temp || temp.startsWith('+')) {
1075
+ return temp;
1076
+ }
1077
+ // Remove any spaces, parenthesis or other punctuation.
1078
+ temp = temp.replace(/[^0-9]/g, '');
1079
+ // If the number begins with a zero, remove the leading zero. Do not combine this with the previous step because it needs to be removed
1080
+ // whether it's the actual first character e.g. `0(5)` or just the first digit e.g. `(05`.
1081
+ temp = temp.replace(/^0/g, '');
1082
+ // Prepend the country code and +. We're assuming US in this case given the target demographic. Users in other countries would/should be
1083
+ // already entering a prefix so they'd shortcut out of this routine via the + prefix check.
1084
+ return `+1${temp}`;
1085
+ };
1195
1086
 
1196
1087
  /**
1197
- * Enable automatic reminders. setup_time is the number of days after the envelope is sent that the first reminder
1198
- * should be sent. interval_time is the number of days between reminders.
1088
+ * Create an array containing a sequence of integers, e.g. [START, START+1, START+2, ...] This is frequently useful
1089
+ * in rendering operations when there is no source array to .map() across.
1199
1090
  */
1200
- const createTemplateReminder = (endpoint, templateId, params) => endpoint.api //
1201
- .post(`/templates/${templateId}/reminder/`, params)
1202
- .then((r) => r.data);
1091
+ const integerSequence = (start, count) => Array(count)
1092
+ .fill(1)
1093
+ .map((_, index) => index + start);
1203
1094
  /**
1204
- * Get the reminder configuration for a template.
1095
+ * Format a profile's full name
1205
1096
  */
1206
- const getTemplateReminder = (endpoint, templateId, reminderId) => endpoint.api //
1207
- .get(`/templates/${templateId}/reminder/${reminderId}`)
1208
- .then((r) => r.data);
1097
+ const formatFullName = (profile) => profile ? `${capitalize(profile.first_name)} ${capitalize(profile.last_name)}` : 'Invalid User';
1209
1098
  /**
1210
- * Update the reminder configuration for a template.
1099
+ * Format a profile's initials
1211
1100
  */
1212
- const updateTemplateReminder = (endpoint, templateId, reminderId, params) => endpoint.api //
1213
- .put(`/templates/${templateId}/reminder/${reminderId}`, params)
1214
- .then((r) => r.data);
1101
+ const formatInitials = (profile) => profile ? `${capitalize(profile.first_name).charAt(0)} ${capitalize(profile.last_name).charAt(0)}` : '--';
1215
1102
  /**
1216
- * Delete the reminder configuration for a template.
1103
+ * Generate suggested initials for a full name, e.g. "John Doe" will yield "JD".
1217
1104
  */
1218
- const deleteTemplateReminder = (endpoint, templateId, reminderId) => endpoint.api //
1219
- .delete(`/templates/${templateId}/reminder/${reminderId}`)
1220
- .then((r) => r.data);
1105
+ const fullNameToInitials = (name) => name
1106
+ .split(' ')
1107
+ .map((word) => word[0])
1108
+ .join('');
1221
1109
 
1222
1110
  /**
1223
- * A "role" is an individual participant in a signing flow, such as a signer or CC contact. Roles are identified by
1224
- * their names, which must be unique (e.g. 'Recipient 1'). Template fields are assigned to roles for signing operations,
1225
- * so you may have 'Recipient 1 Signature 1' and so forth.
1111
+ * Create an envelope
1226
1112
  *
1227
- * @module
1228
- */
1229
- const createTemplateRole = (endpoint, templateId, params) => endpoint.api //
1230
- .post(`/templates/${templateId}/roles`, params)
1231
- .then((r) => r.data);
1232
- const getTemplateRoles = (endpoint, templateId) => endpoint.api //
1233
- .get(`/templates/${templateId}/roles`)
1234
- .then((r) => r.data);
1235
- const getTemplateRole = (endpoint, templateId, roleName) => endpoint.api //
1236
- .get(`/templates/${templateId}/roles/${roleName}`)
1237
- .then((r) => r.data);
1238
- const updateTemplateRole = (endpoint, templateId, roleName, params) => endpoint.api //
1239
- .put(`/templates/${templateId}/roles/${roleName}`, params)
1240
- .then((r) => r.data);
1241
- const deleteTemplateRole = (endpoint, templateId, roleName) => endpoint.api //
1242
- .delete(`/templates/${templateId}/roles/${roleName}`)
1243
- .then((r) => r.data);
1244
- const getTemplateRoleFields = (endpoint, templateId, roleName) => endpoint.api //
1245
- .get(`/templates/${templateId}/roles/${roleName}/fields`)
1246
- .then((r) => r.data);
1247
-
1248
- /**
1249
- * Get the template stars for a template.
1113
+ * ```typescript
1114
+ * import {Envelopes, ICreateEnvelopeRole, ICreateEnvelopeRequest} from '@verdocs/js-sdk/Envelopes';
1115
+ *
1116
+ * const role1: ICreateEnvelopeRole = {
1117
+ * type: 'signer',
1118
+ * name: 'Seller',
1119
+ * full_name: 'Paige Turner',
1120
+ * email: 'paige.turner@nomail.com',
1121
+ * phone: '',
1122
+ * sequence: 1,
1123
+ * delegator: false,
1124
+ * message: '',
1125
+ * };
1126
+ *
1127
+ * const role2: ICreateEnvelopeRole = {
1128
+ * type: 'signer',
1129
+ * name: 'Buyer',
1130
+ * full_name: 'Will Power',
1131
+ * email: 'will.power@nomail.com',
1132
+ * phone: '',
1133
+ * sequence: 2,
1134
+ * delegator: false,
1135
+ * message: '',
1136
+ * };
1137
+ *
1138
+ * const request: ICreateEnvelopeRequest = {template_id: 'd2338742-f3a1-465b-8592-806587413cc1', name: 'Bill of Sale', roles: [role1, role2]};
1139
+ * const {id, recipients} = await Envelopes.createEnvelope(VerdocsEndpoint.getDefault(), request);
1140
+ * ```
1250
1141
  */
1251
- const getStars = (endpoint, templateId) => endpoint.api //
1252
- .get(`/templates/${templateId}/stars`)
1142
+ const createEnvelope = async (endpoint, request) => endpoint.api //
1143
+ .post('/envelopes', request)
1253
1144
  .then((r) => r.data);
1254
1145
  /**
1255
- * Toggle the template star for a template.
1146
+ * Get a summary of currently active envelopes.
1147
+ *
1148
+ * ```typescript
1149
+ * import {Envelopes} from '@verdocs/js-sdk/Envelopes';
1150
+ *
1151
+ * const {action_required, completed, waiting_on_others} = await Envelopes.getSummary(VerdocsEndpoint.getDefault());
1152
+ * ```
1256
1153
  */
1257
- const toggleStar = (endpoint, templateId) => endpoint.api //
1258
- .post(`/templates/${templateId}/stars/toggle`)
1154
+ const getEnvelopesSummary = async (endpoint, page) => endpoint.api //
1155
+ .post('/envelopes/summary', { page })
1259
1156
  .then((r) => r.data);
1260
-
1261
1157
  /**
1262
- * A Tag is a user-specified label applied to a template. Tags help users organize and find Templates.
1263
- * recipients. Every Organization has a set of tags "owned" by that Organization and only visible inside it.
1264
- * Verdocs also provides a set of system-wide "featured" tags available to all Organizations.
1158
+ * Search for envelopes matching various criteria.
1265
1159
  *
1266
- * @module
1160
+ * ```typescript
1161
+ * import {Envelopes} from '@verdocs/js-sdk/Envelopes';
1162
+ *
1163
+ * const {result, page, total} = await Envelopes.search(VerdocsEndpoint.getDefault(), { ... });
1164
+ * ```
1267
1165
  */
1166
+ const searchEnvelopes = async (endpoint, params) => endpoint.api //
1167
+ .post('/envelopes/search', params)
1168
+ .then((r) => r.data);
1268
1169
  /**
1269
- * Apply a tag to a template.
1170
+ * Get a signing session for an Envelope.
1270
1171
  */
1271
- const addTemplateTag = (endpoint, templateId, params) => endpoint.api //
1272
- .post(`/templates/${templateId}/tags/`, params)
1273
- .then((r) => r.data);
1172
+ const getSigningSession = async (endpoint, params) => {
1173
+ window.console.log('[JS_SDK] getSigningSession', params, endpoint.api);
1174
+ return endpoint.api //
1175
+ .get(`/envelopes/${params.envelopeId}/recipients/${encodeURIComponent(params.roleId)}/invitation/${params.inviteCode}`)
1176
+ .then((r) => {
1177
+ // Avoiding a jsonwebtoken dependency here - we don't actually need the whole library
1178
+ const signerToken = r.headers?.signer_token || '';
1179
+ const session = decodeAccessTokenBody(signerToken);
1180
+ endpoint.setToken(signerToken);
1181
+ return { recipient: r.data, session, signerToken };
1182
+ });
1183
+ };
1274
1184
  /**
1275
- * Get all tags for a template.
1185
+ * Get the list of recipients for an Envelope.
1276
1186
  */
1277
- const getTemplateTags = (endpoint, templateId) => endpoint.api //
1278
- .get(`/templates/${templateId}/tags/`)
1187
+ const getEnvelopeRecipients = async (endpoint, envelopeId) => endpoint.api //
1188
+ .get(`/envelopes/${envelopeId}/recipients`)
1279
1189
  .then((r) => r.data);
1280
1190
  /**
1281
- * Remove a tag from a template.
1191
+ * Get all metadata for an Envelope.
1282
1192
  */
1283
- const deleteTemplateTag = (endpoint, templateId, tagName) => endpoint.api //
1284
- .post(`/templates/${templateId}/tags/${tagName}`)
1193
+ const getEnvelope = async (endpoint, envelopeId) => endpoint.api //
1194
+ .get(`/envelopes/${envelopeId}`)
1285
1195
  .then((r) => r.data);
1286
1196
  /**
1287
- * Create an Organization-wide tag.
1197
+ * Get an Envelope Document
1288
1198
  */
1289
- const createTag = (endpoint, name) => endpoint.api //
1290
- .post('/tags', { tag_name: name })
1199
+ const getEnvelopeDocument = async (endpoint, envelopeId, documentId) => endpoint.api //
1200
+ .get(`/envelopes/${envelopeId}/envelope_documents/${documentId}`)
1291
1201
  .then((r) => r.data);
1292
1202
  /**
1293
- * Get an Organization-wide tag.
1203
+ * Get a pre-signed download link for an Envelope Document. This link expires quickly, so it should
1204
+ * be accessed immediately and never shared. Content-Disposition will be set to "download".
1294
1205
  */
1295
- const getTag = (endpoint, name) => endpoint.api //
1296
- .get(`/tags/${name}`)
1206
+ const getDocumentDownloadLink = async (endpoint, envelopeId, documentId) => endpoint.api //
1207
+ .get(`/envelopes/${envelopeId}/envelope_documents/${documentId}?download=true`)
1297
1208
  .then((r) => r.data);
1298
1209
  /**
1299
- * Get all tags available for use by an Organization.
1210
+ * Get a pre-signed preview link for an Envelope Document. This link expires quickly, so it should
1211
+ * be accessed immediately and never shared. Content-Disposition will be set to "inline".
1300
1212
  */
1301
- const getAllTags = (endpoint) => endpoint.api //
1302
- .get('/tags')
1213
+ const getDocumentPreviewLink = async (endpoint, envelopeId, documentId) => endpoint.api //
1214
+ .get(`/envelopes/${envelopeId}/envelope_documents/${documentId}?preview=true`)
1303
1215
  .then((r) => r.data);
1304
-
1305
1216
  /**
1306
- * A Template defines how a Verdocs signing flow will be performed, including attachments, signing fields, and
1307
- * recipients.
1308
- *
1309
- * @module
1217
+ * Cancel an Envelope.
1310
1218
  */
1219
+ const cancelEnvelope = async (endpoint, envelopeId) => endpoint.api //
1220
+ .put(`/envelopes/${envelopeId}`, { action: 'cancel' })
1221
+ .then((r) => r.data);
1311
1222
  /**
1312
- * Get all templates accessible by the caller, with optional filters.
1313
- *
1314
- * ```typescript
1315
- * import {Templates} from '@verdocs/js-sdk/Templates';
1316
- *
1317
- * await Templates.getTemplates((VerdocsEndpoint.getDefault());
1318
- * await Templates.getTemplates((VerdocsEndpoint.getDefault(), { is_starred: true });
1319
- * await Templates.getTemplates((VerdocsEndpoint.getDefault(), { is_creator: true });
1320
- * await Templates.getTemplates((VerdocsEndpoint.getDefault(), { is_organization: true });
1321
- * ```
1223
+ * Get (binary download) a file attached to an Envelope. It is important to use this method
1224
+ * rather than a direct A HREF or similar link to set the authorization headers for the
1225
+ * request.
1322
1226
  */
1323
- const getTemplates = (endpoint, params) => endpoint.api //
1324
- .post('/templates', { params })
1227
+ const getEnvelopeFile = async (endpoint, envelopeId, documentId) => endpoint.api //
1228
+ .get(`/envelopes/${envelopeId}/envelope_documents/${documentId}?file=true`, { responseType: 'blob' })
1325
1229
  .then((r) => r.data);
1326
- // export interface IListTemplatesParams {
1327
- // name?: string;
1328
- // sharing?: 'all' | 'personal' | 'shared' | 'public';
1329
- // starred?: 'all' | 'starred' | 'unstarred';
1330
- // sort?: 'name' | 'created_at' | 'updated_at' | 'last_used_at' | 'counter' | 'star_counter';
1331
- // direction?: 'asc' | 'desc';
1332
- // page?: number;
1333
- // rows?: number;
1334
- // }
1335
1230
  /**
1336
- * Lists all templates accessible by the caller, with optional filters.
1337
- *
1338
- * ```typescript
1339
- * import {Templates} from '@verdocs/js-sdk/Templates';
1340
- *
1341
- * await Templates.listTemplates((VerdocsEndpoint.getDefault(), { sharing: 'personal', sort: 'last_used_at' });
1342
- * ```
1231
+ * Update a Document field. Typically called during the signing process as a Recipient fills in fields.
1343
1232
  */
1344
- // export const listTemplates = (endpoint: VerdocsEndpoint, params?: IListTemplatesParams) =>
1345
- // endpoint.api //
1346
- // .post<ITemplateSummaries>('/templates/list', params, {baseURL: endpoint.getBaseURLv2()})
1347
- // .then((r) => r.data);
1233
+ const updateEnvelopeField = async (endpoint, envelopeId, fieldName, value) => endpoint.api //
1234
+ .put(`/envelopes/${envelopeId}/fields/${fieldName}`, value)
1235
+ .then((r) => r.data);
1348
1236
  /**
1349
- * Get one template by its ID.
1350
- *
1351
- * ```typescript
1352
- * import {Templates} from '@verdocs/js-sdk/Templates';
1353
- *
1354
- * const template = await Templates.getTemplate((VerdocsEndpoint.getDefault(), '83da3d70-7857-4392-b876-c4592a304bc9');
1355
- * ```
1237
+ * Update a Document signature field. Signature fields are ID-driven. Call `Document.createSignature()` first to create a
1238
+ * signature for a Recipient, then call `Documents.updateDocumentFieldSignature()` to attach it to a field.
1356
1239
  */
1357
- const getTemplate = (endpoint, templateId) => endpoint.api //
1358
- .get(`/templates/${templateId}`)
1240
+ const updateEnvelopeFieldSignature = async (endpoint, envelopeId, fieldName, signatureId) => endpoint.api //
1241
+ .put(`/envelopes/${envelopeId}/fields/${fieldName}/signature/${signatureId}`)
1359
1242
  .then((r) => r.data);
1360
1243
  /**
1361
- * Get owner information for a template.
1362
- *
1363
- * ```typescript
1364
- * import {Templates} from '@verdocs/js-sdk/Templates';
1365
- *
1366
- * const template = await Templates.getTemplateOwnerInfo((VerdocsEndpoint.getDefault(), '83da3d70-7857-4392-b876-c4592a304bc9');
1367
- * ```
1244
+ * Update a Document signature field. Signature fields are ID-driven. Call `Document.createSignature()` first to create a
1245
+ * signature for a Recipient, then call `Documents.updateDocumentFieldSignature()` to attach it to a field.
1368
1246
  */
1369
- const getTemplateOwnerInfo = (endpoint, templateId) => endpoint.api //
1370
- .get(`/templates/${templateId}`)
1247
+ const updateEnvelopeFieldInitials = async (endpoint, envelopeId, fieldName, initialId) => endpoint.api //
1248
+ .put(`/envelopes/${envelopeId}/fields/${fieldName}/initial/${initialId}`)
1371
1249
  .then((r) => r.data);
1372
- const ALLOWED_CREATE_FIELDS = [
1373
- 'name',
1374
- 'is_personal',
1375
- 'is_public',
1376
- 'sender',
1377
- 'description',
1378
- 'roles',
1379
- 'fields',
1380
- ];
1381
1250
  /**
1382
- * Create a template.
1383
- *
1384
- * ```typescript
1385
- * import {Templates} from '@verdocs/js-sdk/Templates';
1386
- *
1387
- * const newTemplate = await Templates.createTemplate((VerdocsEndpoint.getDefault(), {...});
1388
- * ```
1251
+ * Upload an attachment.
1389
1252
  */
1390
- const createTemplate = (endpoint, params, onUploadProgress) => {
1391
- const options = {
1253
+ const uploadEnvelopeFieldAttachment = async (endpoint, envelopeId, fieldName, file, onUploadProgress) => {
1254
+ const formData = new FormData();
1255
+ formData.append('document', file, file.name);
1256
+ return endpoint.api //
1257
+ .put(`/envelopes/${envelopeId}/fields/${fieldName}`, formData, {
1392
1258
  timeout: 120000,
1393
1259
  onUploadProgress: (event) => {
1394
1260
  const total = event.total || 1;
1395
1261
  const loaded = event.loaded || 0;
1396
1262
  onUploadProgress?.(Math.floor((loaded * 100) / (total || 1)), loaded, total || 1);
1397
1263
  },
1398
- };
1399
- if (params.documents && params.documents[0] instanceof File) {
1400
- if (params.documents.length > 10) {
1401
- throw new Error('createTemplate() has a maximum of 10 documents that can be attached.');
1402
- }
1403
- const formData = new FormData();
1404
- ALLOWED_CREATE_FIELDS.forEach((allowedKey) => {
1405
- if (params[allowedKey] !== undefined) {
1406
- formData.append(allowedKey, params[allowedKey]);
1407
- }
1408
- });
1409
- params.documents.forEach((file) => {
1410
- formData.append('documents', file, file.name);
1411
- });
1412
- return endpoint.api.post('/templates', formData, options).then((r) => r.data);
1413
- }
1414
- else {
1415
- return endpoint.api.post('/templates', params, options).then((r) => r.data);
1416
- }
1264
+ })
1265
+ .then((r) => r.data);
1417
1266
  };
1418
1267
  /**
1419
- * Create a template.
1420
- *
1421
- * ```typescript
1422
- * import {Templates} from '@verdocs/js-sdk/Templates';
1423
- *
1424
- * const newTemplate = await Templates.createTemplatev2((VerdocsEndpoint.getDefault(), {...});
1425
- * ```
1268
+ * Delete an attachment.
1426
1269
  */
1427
- const createTemplatev2 = (endpoint, params, onUploadProgress) => {
1428
- const options = {
1270
+ const deleteEnvelopeFieldAttachment = async (endpoint, envelopeId, fieldName, file, onUploadProgress) => {
1271
+ const formData = new FormData();
1272
+ // Omitting file is the trigger here
1273
+ return endpoint.api //
1274
+ .put(`/envelopes/${envelopeId}/fields/${fieldName}`, formData, {
1429
1275
  timeout: 120000,
1430
1276
  onUploadProgress: (event) => {
1431
1277
  const total = event.total || 1;
1432
1278
  const loaded = event.loaded || 0;
1433
1279
  onUploadProgress?.(Math.floor((loaded * 100) / (total || 1)), loaded, total || 1);
1434
1280
  },
1435
- };
1436
- if (params.documents && params.documents[0] instanceof File) {
1437
- const formData = new FormData();
1438
- ALLOWED_CREATE_FIELDS.forEach((allowedKey) => {
1439
- if (params[allowedKey] !== undefined) {
1440
- formData.append(allowedKey, params[allowedKey]);
1441
- }
1442
- });
1443
- params.documents.forEach((file) => {
1444
- formData.append('documents', file, file.name);
1445
- });
1446
- return endpoint.api.post('/v2/templates', formData, options).then((r) => r.data);
1447
- }
1448
- else {
1449
- return endpoint.api.post('/v2/templates', params, options).then((r) => r.data);
1281
+ })
1282
+ .then((r) => r.data);
1283
+ };
1284
+ /**
1285
+ * Get the attached file for an attachment field (if any)
1286
+ */
1287
+ const getFieldAttachment = async (endpoint, envelopeId, fieldName) => endpoint.api //
1288
+ .get(`/envelopes/${envelopeId}/fields/${fieldName}/document`, { responseType: 'blob' })
1289
+ .then((r) => r.data);
1290
+ /**
1291
+ * Get a display URI for a given page in a file attached to an envelope document. These pages are rendered server-side
1292
+ * into PNG resources suitable for display in IMG tags although they may be used elsewhere. Note that these are intended
1293
+ * for DISPLAY ONLY, are not legally binding documents, and do not contain any encoded metadata from participants.
1294
+ */
1295
+ const getEnvelopeDocumentPageDisplayUri = async (endpoint, envelopeId, documentId, page, type = 'original') => endpoint.api
1296
+ .get(`/envelopes/${envelopeId}/envelope_documents/${documentId}/pages/${page}/image?type=${type}`, { timeout: 20000 })
1297
+ .then((r) => r.data);
1298
+ const cachedEnvelopes = {};
1299
+ /**
1300
+ * Wrapper for `getEnvelope()` that limits queries to one every 2 seconds per template ID.
1301
+ * This is intended for use in component hierarchies that all rely on the same template
1302
+ * to avoid unnecessary repeat server calls.
1303
+ */
1304
+ const throttledGetEnvelope = (endpoint, envelopeId) => {
1305
+ if (cachedEnvelopes[envelopeId] && cachedEnvelopes[envelopeId].loaded + 2000 < new Date().getTime()) {
1306
+ return cachedEnvelopes[envelopeId].envelope;
1450
1307
  }
1308
+ return getEnvelope(endpoint, envelopeId).then((envelope) => {
1309
+ cachedEnvelopes[envelopeId] = { loaded: new Date().getTime(), envelope };
1310
+ return envelope;
1311
+ });
1312
+ };
1313
+ /**a
1314
+ * Lists all envelopes accessible by the caller, with optional filters.
1315
+ *
1316
+ * ```typescript
1317
+ * import {Envelopes} from '@verdocs/js-sdk/Envelopes';
1318
+ *
1319
+ * const {totals, envelopes} = await Envelopes.listEnvelopes((VerdocsEndpoint.getDefault(), { q: 'test', sort: 'created_at' });
1320
+ * ```
1321
+ */
1322
+ const listEnvelopes = (endpoint, params) => endpoint.api //
1323
+ .post('/envelopes/list', params)
1324
+ .then((r) => r.data);
1325
+ /**
1326
+ * Get all of the envelopes that were sent using a given template.
1327
+ * NOTE: This endpoint will be retired soon. Its response is not paginated and it is typically used only to retrieve
1328
+ * "submitted data" for a template. A new endpoint will be introduced to provide this function more directly.
1329
+ * @deprecated
1330
+ */
1331
+ const getEnvelopesByTemplateId = async (endpoint, templateId) => endpoint.api //
1332
+ .get(`/envelopes?template_id=${templateId}`)
1333
+ .then((r) => r.data);
1334
+
1335
+ /**
1336
+ * Create an initials block. In a typical signing workflow, the user is asked at the beginning of the process to "adopt"
1337
+ * an initials block to be used for all initials fields in the document. Thus, this is typically called one time to
1338
+ * create and store an initials block. Thereafter, the ID of the initials block may be re-used for each initials field
1339
+ * to be "stamped" by the user.
1340
+ */
1341
+ const createInitials = (endpoint, name, initials) => {
1342
+ const data = new FormData();
1343
+ data.append('initial', initials, name);
1344
+ return endpoint.api //
1345
+ .post(`/initials`, data)
1346
+ .then((r) => r.data);
1451
1347
  };
1348
+
1349
+ /**
1350
+ * Update a recipient's status block
1351
+ */
1352
+ const updateRecipient = async (endpoint, envelopeId, roleName, params) => endpoint.api //
1353
+ .put(`/envelopes/${envelopeId}/recipients/${roleName}`, params)
1354
+ .then((r) => r.data);
1355
+ /**
1356
+ * Submit an envelope (signing is finished). Note that all fields must be valid/completed for this to succeed.
1357
+ */
1358
+ const envelopeRecipientSubmit = (endpoint, envelopeId, roleName) => updateRecipient(endpoint, envelopeId, roleName, { action: 'submit' });
1359
+ /**
1360
+ * Decline to complete an envelope (signing will not terminated).
1361
+ */
1362
+ const envelopeRecipientDecline = (endpoint, envelopeId, roleName) => updateRecipient(endpoint, envelopeId, roleName, { action: 'decline' });
1363
+ /**
1364
+ * Claim / change ownership of an envelope. This is a special-case operation only available in certain workflows.
1365
+ */
1366
+ const envelopeRecipientChangeOwner = (endpoint, envelopeId, roleName, email, fullName) => updateRecipient(endpoint, envelopeId, roleName, { action: 'owner_update', email, full_name: fullName });
1367
+ /**
1368
+ * Agree to electronic signing.
1369
+ */
1370
+ const envelopeRecipientAgree = (endpoint, envelopeId, roleName, agreed) => updateRecipient(endpoint, envelopeId, roleName, { action: 'update', agreed });
1452
1371
  /**
1453
- * Create a template from a Sharepoint asset.
1454
- *
1455
- * ```typescript
1456
- * import {Templates} from '@verdocs/js-sdk/Templates';
1457
- *
1458
- * const newTemplate = await Templates.createTemplateFromSharepoint((VerdocsEndpoint.getDefault(), {...});
1459
- * ```
1372
+ * Change a recipient's name.
1460
1373
  */
1461
- const createTemplateFromSharepoint = (endpoint, params) => {
1462
- const options = {
1463
- timeout: 120000,
1464
- };
1465
- return endpoint.api.post('/templates/from-sharepoint', params, options).then((r) => r.data);
1466
- };
1374
+ const envelopeRecipientUpdateName = (endpoint, envelopeId, roleName, fullName) => updateRecipient(endpoint, envelopeId, roleName, { action: 'update', new_full_name: fullName });
1467
1375
  /**
1468
- * Update a template.
1469
- *
1470
- * ```typescript
1471
- * import {Templates} from '@verdocs/js-sdk/Templates';
1472
- *
1473
- * const updatedTemplate = await Templates.updateTemplate((VerdocsEndpoint.getDefault(), '83da3d70-7857-4392-b876-c4592a304bc9', { name: 'New Name' });
1474
- * ```
1376
+ * Change a recipient's name.
1475
1377
  */
1476
- const updateTemplate = (endpoint, templateId, params) => endpoint.api //
1477
- .put(`/templates/${templateId}`, params)
1378
+ const envelopeRecipientPrepare = (endpoint, envelopeId, roleName, recipients) => updateRecipient(endpoint, envelopeId, roleName, { action: 'prepare', recipients });
1379
+ /**
1380
+ * Get a signing token.
1381
+ */
1382
+ const getSignerToken = (endpoint, envelopeId, roleName) => endpoint.api //
1383
+ .get(`/envelopes/${envelopeId}/recipients/${encodeURIComponent(roleName)}/signer-token`)
1478
1384
  .then((r) => r.data);
1479
1385
  /**
1480
- * Delete a template.
1481
- *
1482
- * ```typescript
1483
- * import {Templates} from '@verdocs/js-sdk/Templates';
1484
- *
1485
- * await Templates.deleteTemplate((VerdocsEndpoint.getDefault(), '83da3d70-7857-4392-b876-c4592a304bc9');
1486
- * ```
1386
+ * Get an in-person signing link.
1487
1387
  */
1488
- const deleteTemplate = (endpoint, templateId) => endpoint.api //
1489
- .delete(`/templates/${templateId}`)
1388
+ const getInPersonLink = (endpoint, envelopeId, roleName) => endpoint.api //
1389
+ .get(`/envelopes/${envelopeId}/recipients/${encodeURIComponent(roleName)}?in_person_link=true`)
1490
1390
  .then((r) => r.data);
1491
1391
  /**
1492
- * Search for templates matching various criteria.
1493
- *
1494
- * ```typescript
1495
- * import {Templates} from '@verdocs/js-sdk/Templates';
1496
- *
1497
- * const {result, page, total} = await Templates.search((VerdocsEndpoint.getDefault(), { ... });
1498
- * ```
1392
+ * Send a delegation request.
1499
1393
  */
1500
- const searchTemplates = async (endpoint, params) => endpoint.api //
1501
- .post('/templates/search', params)
1394
+ const sendDelegate = (endpoint, envelopeId, roleName) => endpoint.api //
1395
+ .post(`/envelopes/${envelopeId}/recipients/${encodeURIComponent(roleName)}/delegate`)
1502
1396
  .then((r) => r.data);
1503
1397
  /**
1504
- * Get a summary of template data, typically used to populate admin panel dashboard pages.
1505
- *
1506
- * ```typescript
1507
- * import {Templates} from '@verdocs/js-sdk/Templates';
1508
- *
1509
- * const summary = await Templates.getSummary((VerdocsEndpoint.getDefault(), 0);
1510
- * ```
1398
+ * Resend a recipient's invitation.
1511
1399
  */
1512
- const getTemplatesSummary = async (endpoint, params = {}) => endpoint.api //
1513
- .post('/templates/summary', params)
1400
+ const resendInvitation = (endpoint, envelopeId, roleName) => endpoint.api //
1401
+ .post(`/envelopes/${envelopeId}/recipients/${encodeURIComponent(roleName)}/resend_invitation`)
1514
1402
  .then((r) => r.data);
1515
- const cachedTemplates = {};
1403
+
1516
1404
  /**
1517
- * Wrapper for `getTemplate()` that limits queries to one every 2 seconds per template ID.
1518
- * This is intended for use in component hierarchies that all rely on the same template
1519
- * to avoid unnecessary repeat server calls.
1405
+ * Enable automatic reminders. setup_time is the number of days after the envelope is sent that the first reminder
1406
+ * should be sent. interval_time is the number of days between reminders.
1520
1407
  */
1521
- const throttledGetTemplate = (endpoint, templateId) => {
1522
- if (cachedTemplates[templateId] && cachedTemplates[templateId].loaded + 2000 < new Date().getTime()) {
1523
- return cachedTemplates[templateId].template;
1524
- }
1525
- return getTemplate(endpoint, templateId).then((template) => {
1526
- cachedTemplates[templateId] = { loaded: new Date().getTime(), template };
1527
- return template;
1528
- });
1529
- };
1408
+ const createEnvelopeReminder = (endpoint, envelopeId, params) => endpoint.api //
1409
+ .post(`/envelopes/${envelopeId}/reminder/`, params)
1410
+ .then((r) => r.data);
1530
1411
  /**
1531
- * List templates.
1532
- *
1533
- * ```typescript
1534
- * import {Templates} from '@verdocs/js-sdk/Templates';
1535
- *
1536
- * const {totals, templates} = await Templates.listTemplates((VerdocsEndpoint.getDefault(), { q: 'test', sort: 'created_at' }); * ```
1412
+ * Get the reminder configuration for an envelope.
1537
1413
  */
1538
- const listTemplates = async (endpoint, params = {}) => endpoint.api //
1539
- .post('/templates/list', params)
1414
+ const getEnvelopeReminder = (endpoint, envelopeId, reminderId) => endpoint.api //
1415
+ .get(`/envelopes/${envelopeId}/reminder/${reminderId}`)
1416
+ .then((r) => r.data);
1417
+ /**
1418
+ * Update the reminder configuration for an envelope.
1419
+ */
1420
+ const updateEnvelopeReminder = (endpoint, envelopeId, reminderId, params) => endpoint.api //
1421
+ .put(`/envelopes/${envelopeId}/reminder/${reminderId}`, params)
1422
+ .then((r) => r.data);
1423
+ /**
1424
+ * Delete the reminder configuration for an envelope.
1425
+ */
1426
+ const deleteEnvelopeReminder = (endpoint, envelopeId, reminderId) => endpoint.api //
1427
+ .delete(`/envelopes/${envelopeId}/reminder/${reminderId}`)
1540
1428
  .then((r) => r.data);
1541
1429
 
1542
1430
  /**
1543
- * A TemplateDocument represents a PDF or other attachment in a Template.
1431
+ * Various helpers to identify available operations for an envelope by a user.
1544
1432
  *
1545
1433
  * @module
1546
1434
  */
1547
1435
  /**
1548
- * Get all the Template Documents associated to a particular Template.
1549
- *
1550
- * ```typescript
1551
- * import {TemplateDocument} from '@verdocs/js-sdk/Templates';
1552
- *
1553
- * await TemplateDocument.geTemplateDocuments((VerdocsEndpoint.getDefault(), templateId);
1554
- * ```
1436
+ * Check to see if the user owns the envelope.
1555
1437
  */
1556
- const getTemplateDocuments = (endpoint, templateId) => endpoint.api //
1557
- .get(`/templates/${templateId}/documents/`)
1558
- .then((r) => r.data);
1438
+ const userIsEnvelopeOwner = (session, envelope) => envelope.profile_id === session?.profile_id;
1559
1439
  /**
1560
- * Get a specific Document.
1561
- *
1562
- * ```typescript
1563
- * import {TemplateDocument} from '@verdocs/js-sdk/Templates';
1564
- *
1565
- * await TemplateDocument.geTemplateDocument((VerdocsEndpoint.getDefault(), templateId,documentId);
1566
- * ```
1440
+ * Check to see if the user owns the envelope.
1567
1441
  */
1568
- const getTemplateDocument = (endpoint, templateId, documentId) => endpoint.api //
1569
- .get(`/templates/${templateId}/documents/${documentId}`)
1570
- .then((r) => r.data);
1442
+ const userIsEnvelopeRecipient = (session, envelope) => envelope.profile_id === session?.profile_id;
1571
1443
  /**
1572
- * Create a Document for a particular Template.
1573
- *
1574
- * ```typescript
1575
- * import {TemplateDocument} from '@verdocs/js-sdk/Templates';
1576
- *
1577
- * await TemplateDocument.createDocument((VerdocsEndpoint.getDefault(), templateID, params);
1578
- * ```
1444
+ * Check to see if the envelope has pending actions.
1579
1445
  */
1580
- const createTemplateDocument = (endpoint, templateId, file, onUploadProgress) => {
1581
- const formData = new FormData();
1582
- formData.append('document', file, file.name);
1583
- return endpoint.api //
1584
- .post(`/templates/${templateId}/documents`, formData, {
1585
- timeout: 120000,
1586
- onUploadProgress: (event) => {
1587
- const total = event.total || 1;
1588
- const loaded = event.loaded || 0;
1589
- onUploadProgress?.(Math.floor((loaded * 100) / (total || 1)), loaded, total || 1);
1590
- },
1591
- })
1592
- .then((r) => r.data);
1593
- };
1446
+ const envelopeIsActive = (envelope) => envelope.status !== 'complete' && envelope.status !== 'declined' && envelope.status !== 'canceled';
1594
1447
  /**
1595
- * Delete a specific Document.
1596
- *
1597
- * ```typescript
1598
- * import {TemplateDocument} from '@verdocs/js-sdk/Templates';
1599
- *
1600
- * await TemplateDocument.deleteDocument((VerdocsEndpoint.getDefault(), templateID, documentID);
1601
- * ```
1448
+ * Check to see if the envelope has been completed.
1602
1449
  */
1603
- const deleteTemplateDocument = (endpoint, templateId, documentId) => endpoint.api //
1604
- .delete(`/templates/${templateId}/documents/${documentId}`)
1605
- .then((r) => r.data);
1450
+ const envelopeIsComplete = (envelope) => envelope.status !== 'complete';
1606
1451
  /**
1607
- * Get (binary download) a file attached to a Template. It is important to use this method
1608
- * rather than a direct A HREF or similar link to set the authorization headers for the
1609
- * request.
1452
+ * Check to see if the user owns the envelope.
1610
1453
  */
1611
- const getTemplateDocumentFile = async (endpoint, templateId, documentId) => endpoint.api //
1612
- .get(`/templates/${templateId}/documents/${documentId}?file=true`, { responseType: 'blob' })
1613
- .then((r) => r.data);
1454
+ const userCanCancelEnvelope = (session, envelope) => userIsEnvelopeOwner(session, envelope) &&
1455
+ envelope.status !== 'complete' &&
1456
+ envelope.status !== 'declined' &&
1457
+ envelope.status !== 'canceled';
1614
1458
  /**
1615
- * Get (binary download) a file attached to a Template. It is important to use this method
1616
- * rather than a direct A HREF or similar link to set the authorization headers for the
1617
- * request.
1459
+ * Check to see if the user owns the envelope.
1618
1460
  */
1619
- const getTemplateDocumentThumbnail = async (endpoint, templateId, documentId) => endpoint.api //
1620
- .get(`/templates/${templateId}/documents/${documentId}?thumbnail=true`, { responseType: 'blob' })
1621
- .then((r) => r.data);
1461
+ const userCanFinishEnvelope = (session, envelope) => userIsEnvelopeOwner(session, envelope) &&
1462
+ envelope.status !== 'complete' &&
1463
+ envelope.status !== 'declined' &&
1464
+ envelope.status !== 'canceled';
1622
1465
  /**
1623
- * Get a display URI for a given page in a file attached to a template document. These pages are rendered server-side
1624
- * into PNG resources suitable for display in IMG tags although they may be used elsewhere. Note that these are intended
1625
- * for DISPLAY ONLY, are not legally binding documents, and do not contain any encoded metadata from participants. The
1626
- * original asset may be obtained by calling `getTemplateDocumentFile()` or similar.
1466
+ * Returns true if the recipient has a pending action. Note that this does not necessarily mean the recipient can act (yet).
1627
1467
  */
1628
- const getTemplateDocumentPageDisplayUri = async (endpoint, templateId, documentId, page) => endpoint.api.get(`/templates/${templateId}/documents/${documentId}/pages/${page}/image`).then((r) => r.data);
1468
+ const recipientHasAction = (recipient) => !['submitted', 'canceled', 'declined'].includes(recipient.status);
1469
+ /**
1470
+ * Returns the recipients who still have a pending action. Note that not all of these recipients may be able to act (yet).
1471
+ */
1472
+ const getRecipientsWithActions = (envelope) => (envelope?.recipients || []).filter(recipientHasAction);
1473
+ /**
1474
+ * Returns true if the recipient can act.
1475
+ */
1476
+ const recipientCanAct = (recipient, recipientsWithActions) => recipient.sequence === recipientsWithActions?.[0]?.sequence;
1477
+ /**
1478
+ * Returns true if the user can act.
1479
+ */
1480
+ const userCanAct = (email, recipientsWithActions) => {
1481
+ const recipient = recipientsWithActions.find((r) => r.email === email);
1482
+ return recipient && recipient.sequence === recipientsWithActions?.[0]?.sequence;
1483
+ };
1484
+ /**
1485
+ * Returns true if the user can act.
1486
+ */
1487
+ const userCanSignNow = (session, envelope) => {
1488
+ if (!session) {
1489
+ return false;
1490
+ }
1491
+ const recipientsWithActions = getRecipientsWithActions(envelope);
1492
+ const myRecipient = recipientsWithActions.find((r) => r.profile_id === session?.profile_id || r.email === session?.email);
1493
+ return (myRecipient &&
1494
+ envelopeIsActive(envelope) &&
1495
+ userIsEnvelopeRecipient(session, envelope) &&
1496
+ recipientCanAct(myRecipient, recipientsWithActions));
1497
+ };
1498
+ const getNextRecipient = (envelope) => {
1499
+ const recipientsWithActions = getRecipientsWithActions(envelope);
1500
+ return recipientsWithActions?.[0];
1501
+ };
1629
1502
 
1630
1503
  /**
1631
- * Get all defined validators
1632
- *
1633
- * ```typescript
1634
- * import {Documents} from '@verdocs/js-sdk/Templates';
1635
- *
1636
- * await Documents.getDocuments(templateID);
1637
- * ```
1504
+ * Create a signature block. In a typical signing workflow, the user is asked at the beginning of the process to "adopt"
1505
+ * a signature block to be used for all signature fields in the document. Thus, this is typically called one time to
1506
+ * create and store a signature block. Thereafter, the ID of the signature block may be re-used for each signature field
1507
+ * to be "stamped" by the user.
1638
1508
  */
1639
- const getValidators = (endpoint) => endpoint.api //
1640
- .get('/validators')
1641
- .then((r) => r.data);
1642
- const getValidator = (endpoint, validatorName) => endpoint.api //
1643
- .get(`/validators/${validatorName}`)
1509
+ const createSignature = (endpoint, name, signature) => {
1510
+ const data = new FormData();
1511
+ data.append('signature', signature, name);
1512
+ return endpoint.api //
1513
+ .post(`/signatures`, data)
1514
+ .then((r) => r.data);
1515
+ };
1516
+ /**
1517
+ * Get the availbable signatures for a user.
1518
+ */
1519
+ const getSignatures = (endpoint) => endpoint.api //
1520
+ .get('/signatures')
1644
1521
  .then((r) => r.data);
1645
- const EMAIL_REGEX = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
1646
- const isValidEmail = (email) => !!email && EMAIL_REGEX.test(email);
1647
- // @see https://www.regextester.com/1978
1648
- const PHONE_REGEX = /((?:\+|00)[17](?: |\-)?|(?:\+|00)[1-9]\d{0,2}(?: |\-)?|(?:\+|00)1\-\d{3}(?: |\-)?)?(0\d|\([0-9]{3}\)|[1-9]{0,3})(?:((?: |\-)[0-9]{2}){4}|((?:[0-9]{2}){4})|((?: |\-)[0-9]{3}(?: |\-)[0-9]{4})|([0-9]{7}))/;
1649
- const isValidPhone = (phone) => !!phone && PHONE_REGEX.test(phone);
1650
- const isValidRoleName = (value, roles) => roles.findIndex((role) => role.name === value) !== -1;
1651
- const TagRegEx = /^[a-zA-Z0-9-]{0,32}$/;
1652
- const isValidTag = (value, tags) => TagRegEx.test(value) || tags.findIndex((tag) => tag === value) !== -1;
1653
-
1654
1522
  /**
1655
- * Authenticate to Verdocs via user/password authentication
1656
- *
1657
- * ```typescript
1658
- * import {Auth} from '@verdocs/js-sdk/Auth';
1659
- * import {Transport} from '@verdocs/js-sdk/HTTP';
1660
- *
1661
- * const {accessToken} = await Auth.authenticateUser({ username: 'test@test.com', password: 'PASSWORD' });
1662
- * Transport.setAuthToken(accessToken);
1663
- * ```
1523
+ * Get a user's signature by ID.
1664
1524
  */
1665
- const authenticateUser = (endpoint, params) => endpoint.api //
1666
- .post('/authentication/login', params)
1525
+ const getSignature = (endpoint, signatureId) => endpoint.api //
1526
+ .get(`/signatures/${signatureId}`)
1667
1527
  .then((r) => r.data);
1668
1528
  /**
1669
- * Authenticate to Verdocs via client ID / Secret authentication. **NOTE: This is only suitable for
1670
- * NodeJS server-side applications. Never expose your Client Secret in a Web or Mobile app!** Also note
1671
- * that access tokens may be cached by server-side apps (and this is recommended) but do expire after 2
1672
- * hours. This expiration may change based on future security needs. Application developers are encouraged
1673
- * to check the `exp` expiration field in the response accessToken and renew tokens after they expire.
1674
- *
1675
- * ```typescript
1676
- * import {Auth} from '@verdocs/js-sdk/Auth';
1677
- * import {Transport} from '@verdocs/js-sdk/HTTP';
1678
- *
1679
- * const {accessToken} = await Auth.authenticateApp({ client_id: 'CLIENTID', client_secret: 'SECRET' });
1680
- * Transport.setAuthToken(accessToken);
1681
- * ```
1529
+ * Delete a user's signature.
1682
1530
  */
1683
- const authenticateApp = (endpoint, params) => endpoint.api //
1684
- .post('/authentication/login_client', {}, { headers: params })
1531
+ const deleteSignature = (endpoint, signatureId) => endpoint.api //
1532
+ .delete(`/signatures/${signatureId}`)
1685
1533
  .then((r) => r.data);
1534
+
1686
1535
  /**
1687
- * Validate a token. Only Verdocs tokens will be accepted. Most applications can decode tokens locally,
1688
- * because tokens will be validated when API calls are made anyway. However, high-security applications
1689
- * may use this endpoint to check if a token has been revoked.
1536
+ * API keys are used to authenticate server-to-server calls. (API keys should **never** be used for client-to-server operations!)
1537
+ * To generate a key, either use the Verdocs admin interface and make note of the client_id and client_secret generated, or call
1538
+ * createKey as shown below. Then call {@link Users.Auth.authenticateApp} to obtain an access token using the provided ID and
1539
+ * secret. Note that server-to-server authentication requests return shorter-lived tokens, so it is important to check the `exp`
1540
+ * field and re-authenticate as needed for subsequent calls.
1690
1541
  *
1691
- * ```typescript
1692
- * import {Auth} from '@verdocs/js-sdk/Auth';
1542
+ * API keys may be updated or rotated at any time. Regular rotation is recommended. Rotation will not expire or invalidate
1543
+ * existing server-to-server sessions, so it may be done at any time without disrupting your application.
1693
1544
  *
1694
- * const {valid} = await Auth.validateToken({ token });
1695
- * if (!valid) {
1696
- * window.alert('Session invalid or expired. Please re-authenticate.');
1697
- * }
1698
- * ```
1545
+ * @module
1699
1546
  */
1700
- const validateToken = (endpoint, params) => endpoint.api //
1701
- .post('/token/isValid', params)
1702
- .then((r) => r.data);
1703
1547
  /**
1704
- * If called before the session expires, this will refresh the caller's session and tokens.
1548
+ * Get a list of keys for a given organization. The caller must have admin access to the organization.
1705
1549
  *
1706
1550
  * ```typescript
1707
- * import {Auth} from '@verdocs/js-sdk/Auth';
1708
- * import {Transport} from '@verdocs/js-sdk/HTTP';
1551
+ * import {ApiKeys} from '@verdocs/js-sdk/Organizations';
1709
1552
  *
1710
- * const {accessToken} = await Auth.refreshTokens();
1711
- * Transport.setAuthToken(accessToken);
1553
+ * const keys = await ApiKeys.getKeys(ORGID);
1712
1554
  * ```
1713
1555
  */
1714
- const refreshTokens = (endpoint) => endpoint.api //
1715
- .get('/token')
1556
+ const getApiKeys = (endpoint, organizationId) => endpoint.api //
1557
+ .get(`/organizations/${organizationId}/api_key`)
1716
1558
  .then((r) => r.data);
1717
1559
  /**
1718
- * Update the caller's password. To help prevent CSRF attack vectors, the user's old password and email address are required.
1560
+ * Create an API key.
1719
1561
  *
1720
1562
  * ```typescript
1721
- * import {Auth} from '@verdocs/js-sdk/Auth';
1563
+ * import {ApiKeys} from '@verdocs/js-sdk/Organizations';
1722
1564
  *
1723
- * const {status, message} = await Auth.updatePassword({ email, oldPassword, newPassword });
1724
- * if (status !== 'OK') {
1725
- * window.alert(`Password reset error: ${message}`);
1726
- * }
1565
+ * await ApiKeys.createKey(ORGID, {name: NEWNAME});
1727
1566
  * ```
1728
1567
  */
1729
- const updatePassword = (endpoint, params) => endpoint.api //
1730
- .put('/user/update_password', params)
1568
+ const createApiKey = (endpoint, organizationId, params) => endpoint.api //
1569
+ .post(`/organizations/${organizationId}/api_key`, params)
1731
1570
  .then((r) => r.data);
1732
1571
  /**
1733
- * Reset the caller's password.
1572
+ * Rotate the secret for an API key. The caller must have admin access to the organization.
1734
1573
  *
1735
1574
  * ```typescript
1736
- * import {Auth} from '@verdocs/js-sdk/Auth';
1575
+ * import {ApiKeys} from '@verdocs/js-sdk/Organizations';
1737
1576
  *
1738
- * const {success} = await Auth.resetPassword({ email });
1739
- * if (status !== 'OK') {
1740
- * window.alert(`Please check your email for instructions on how to reset your password.`);
1741
- * }
1577
+ * const {client_secret: newSecret} = await ApiKeys.rotateKey(ORGID, CLIENTID);
1742
1578
  * ```
1743
1579
  */
1744
- const resetPassword = (endpoint, params) => endpoint.api //
1745
- .post('/user/reset_password', params)
1580
+ const rotateApiKey = (endpoint, organizationId, clientId) => endpoint.api //
1581
+ .put(`/organizations/${organizationId}/api_key/${clientId}/rotate`)
1746
1582
  .then((r) => r.data);
1747
1583
  /**
1748
- * Update the caller's email address.
1584
+ * Update an API key to change its assigned Profile ID or Name.
1749
1585
  *
1750
1586
  * ```typescript
1751
- * import {Auth} from '@verdocs/js-sdk/Auth';
1587
+ * import {ApiKeys} from '@verdocs/js-sdk/Organizations';
1752
1588
  *
1753
- * const {profiles} = await Auth.updateEmail({ email: newEmail });
1589
+ * await ApiKeys.updateKey(ORGID, CLIENTID, {name: NEWNAME});
1754
1590
  * ```
1755
1591
  */
1756
- const updateEmail = (endpoint, params) => endpoint.api //
1757
- .put('/user/update_email', params)
1592
+ const updateApiKey = (endpoint, organizationId, clientId, params) => endpoint.api //
1593
+ .patch(`/organizations/${organizationId}/api_key/${clientId}`, params)
1758
1594
  .then((r) => r.data);
1759
1595
  /**
1760
- * Resend the email verification request. Note that to prevent certain forms of abuse, the email address is not
1761
- * a parameter here. Instead, the caller must be authenticated as the (unverified) user. To simplify this process,
1762
- * the access token to be used may be passed directly as a parameter here. This avoids the need to set it as the
1763
- * active token on an endpoint, which may be inconvenient in workflows where it is preferable to keep the user in
1764
- * "anonymous" mode while verification is being performed.
1596
+ * Delete an API key.
1765
1597
  *
1766
1598
  * ```typescript
1767
- * import {Auth} from '@verdocs/js-sdk/Auth';
1599
+ * import {ApiKeys} from '@verdocs/js-sdk/Organizations';
1768
1600
  *
1769
- * const result = await Auth.resendVerification();
1601
+ * await ApiKeys.deleteKey(ORGID, CLIENTID);
1770
1602
  * ```
1771
1603
  */
1772
- const resendVerification = (endpoint, accessToken) => endpoint.api //
1773
- .post('/user/email_verification', {}, accessToken ? { headers: { Authorization: `Bearer ${accessToken}` } } : {})
1774
- .then((r) => r.data);
1775
- const createUser = (endpoint, params) => endpoint.api //
1776
- .post('/user', params)
1777
- .then((r) => r.data);
1778
-
1779
- // TODO
1780
- const billingPlaceholder = {};
1781
-
1782
- const getNotifications = async (endpoint) => endpoint.api //
1783
- .get('/notifications')
1604
+ const deleteApiKey = (endpoint, organizationId, clientId) => endpoint.api //
1605
+ .delete(`/organizations/${organizationId}/api_key/${clientId}`)
1784
1606
  .then((r) => r.data);
1785
1607
 
1786
1608
  /**
1787
- * Get the user's available profiles. The current profile will be marked with `current: true`.
1788
- *
1789
- * ```typescript
1790
- * import {Profiles} from '@verdocs/js-sdk/Users';
1609
+ * Organizations may contain "Groups" of user profiles, called Members. Groups may have permissions assigned that
1610
+ * apply to all Members, making it easy to configure role-based access control (RBAC) within an Organization. Note
1611
+ * that permissions are **additive**. A user may be a member of more than one group, and may also have permissions
1612
+ * assigned directly. In that case, the user will have the combined set of all permissions inherited from all
1613
+ * sources.
1791
1614
  *
1792
- * const profiles = await Profiles.getProfiles()
1793
- * ```
1615
+ * @module
1794
1616
  */
1795
- const getProfiles = (endpoint) => endpoint.api //
1796
- .get('/profiles')
1797
- .then((r) => r.data);
1798
1617
  /**
1799
- * Get the user's available profiles. The current profile will be marked with `current: true`.
1618
+ * Get a list of groups for a given organization. The caller must have admin access to the organization.
1800
1619
  *
1801
1620
  * ```typescript
1802
- * import {Profiles} from '@verdocs/js-sdk/Users';
1621
+ * import {Groups} from '@verdocs/js-sdk/Organizations';
1803
1622
  *
1804
- * const profiles = await Profiles.getCurrentProfile()
1623
+ * const groups = await Groups.getGroups(ORGID);
1805
1624
  * ```
1806
1625
  */
1807
- const getCurrentProfile = (endpoint) => endpoint.api //
1808
- .get('/profiles')
1809
- .then((r) => (r.data || []).find((profile) => profile.current));
1626
+ const getGroups = (endpoint, organizationId) => endpoint.api //
1627
+ .get(`/organizations/${organizationId}/groups`)
1628
+ .then((r) => r.data);
1810
1629
  /**
1811
- * Get a list of system roles.
1630
+ * Get a single group by name. Returns a detail record.
1812
1631
  *
1813
1632
  * ```typescript
1814
- * import {Profiles} from '@verdocs/js-sdk/Users';
1633
+ * import {Groups} from '@verdocs/js-sdk/Organizations';
1815
1634
  *
1816
- * const roles = await Profiles.getRoles();
1635
+ * const groups = await Groups.getGroups(ORGID);
1817
1636
  * ```
1818
1637
  */
1819
- const getRoles = (endpoint) => endpoint.api //
1820
- .get('/roles')
1638
+ const getGroupByName = (endpoint, organizationId, name) => endpoint.api //
1639
+ .get(`/organizations/${organizationId}/groups`, { params: { name } })
1821
1640
  .then((r) => r.data);
1822
1641
  /**
1823
- * Get a list of system roles.
1642
+ * Get the details for a group.
1824
1643
  *
1825
1644
  * ```typescript
1826
- * import {Profiles} from '@verdocs/js-sdk/Users';
1645
+ * import {Groups} from '@verdocs/js-sdk/Organizations';
1827
1646
  *
1828
- * const permissions = await Profiles.getPermissions();
1647
+ * const groups = await Groups.getGroups(ORGID);
1829
1648
  * ```
1830
1649
  */
1831
- const getPermissions = (endpoint) => endpoint.api //
1832
- .get('/permissions')
1650
+ const getGroup = (endpoint, organizationId, groupId) => endpoint.api //
1651
+ .get(`/organizations/${organizationId}/groups/${groupId}`)
1652
+ .then((r) => r.data);
1653
+ const getGroupMembers = (endpoint, organizationId, groupId) => endpoint.api //
1654
+ .get(`/organizations/${organizationId}/groups/${groupId}/members`)
1655
+ .then((r) => r.data);
1656
+ const addGroupMembers = (endpoint, organizationId, groupId, params) => endpoint.api //
1657
+ .post(`/organizations/${organizationId}/groups/${groupId}/members`, params)
1658
+ .then((r) => r.data);
1659
+ const deleteGroupMembers = (endpoint, organizationId, groupId, params) => endpoint.api //
1660
+ .put(`/organizations/${organizationId}/groups/${groupId}/delete_members`, params)
1661
+ .then((r) => r.data);
1662
+ const addGroupPermission = (endpoint, organizationId, groupId, permission) => endpoint.api //
1663
+ .post(`/organizations/${organizationId}/groups/${groupId}/permissions/${permission}`, {})
1833
1664
  .then((r) => r.data);
1665
+ const deleteGroupPermission = (endpoint, organizationId, groupId, permission) => endpoint.api //
1666
+ .delete(`/organizations/${organizationId}/groups/${groupId}/permissions/${permission}`)
1667
+ .then((r) => r.data);
1668
+
1834
1669
  /**
1835
- * Create a profile. If the caller does not have a "current" profile set, the new profile will be made current.
1670
+ * An invitation represents an opportunity for a Member to join an Organization.
1836
1671
  *
1837
- * ```typescript
1838
- * import {Profiles} from '@verdocs/js-sdk/Users';
1672
+ * @module
1673
+ */
1674
+ const getOrganizationInvitations = (endpoint, organizationId) => endpoint.api //
1675
+ .get(`/organizations/${organizationId}/invitation`)
1676
+ .then((r) => r.data);
1677
+ const createOrganizationInvitation = (endpoint, organizationId, params) => endpoint.api //
1678
+ .post(`/organizations/${organizationId}/invitation`, params)
1679
+ .then((r) => r.data);
1680
+ const deleteOrganizationInvitation = (endpoint, organizationId, email) => endpoint.api //
1681
+ .delete(`/organizations/${organizationId}/invitation/${email}`)
1682
+ .then((r) => r.data);
1683
+ const updateOrganizationInvitation = (endpoint, organizationId, email, params) => endpoint.api //
1684
+ .patch(`/organizations/${organizationId}/invitation/${email}`, params)
1685
+ .then((r) => r.data);
1686
+ const resendOrganizationInvitation = (endpoint, organizationId, email) => endpoint.api //
1687
+ .post(`/organizations/${organizationId}/invitation/${email}/resend`)
1688
+ .then((r) => r.data);
1689
+ const getOrganizationInvitation = (endpoint, organizationId, email, token) => endpoint.api //
1690
+ .get(`/organizations/${organizationId}/invitation/${email}/accept/${token}`)
1691
+ .then((r) => r.data);
1692
+ const acceptOrganizationInvitation = (endpoint, organizationId, email, token) => endpoint.api //
1693
+ .post(`/organizations/${organizationId}/invitation/${email}/accept/${token}`)
1694
+ .then((r) => r.data);
1695
+ const declineOrganizationInvitation = (endpoint, organizationId, email, token) => endpoint.api //
1696
+ .post(`/organizations/${organizationId}/invitation/${email}/decline/${token}`)
1697
+ .then((r) => r.data);
1698
+ const claimNewUser = (endpoint, organizationId, email, token) => endpoint.api //
1699
+ .put(`/organizations/${organizationId}/invitation/${email}/token/${token}/new_user`)
1700
+ .then((r) => r.data);
1701
+
1702
+ /**
1703
+ * An Organization Member (aka Profile) is an individual user with access to an organization.
1839
1704
  *
1840
- * const newProfile = await Profiles.createProfile({ first_name: 'FIRST', last_name: 'LAST', email: 'EMAIL' });
1841
- * ```
1705
+ * @module
1842
1706
  */
1843
- const createProfile = (endpoint, params) => endpoint.api //
1844
- .post('/profiles', params)
1707
+ const getOrganizationMembers = (endpoint, organizationId) => endpoint.api //
1708
+ .get(`/organizations/${organizationId}/profiles`)
1709
+ .then((r) => r.data);
1710
+ const deleteOrganizationMember = (endpoint, organizationId, profileId) => endpoint.api //
1711
+ .delete(`/organizations/${organizationId}/profiles/${profileId}`)
1712
+ .then((r) => r.data);
1713
+ const addOrganizationMemberRole = (endpoint, organizationId, profileId, roleId) => endpoint.api //
1714
+ .post(`/organizations/${organizationId}/profiles/${profileId}/role/${roleId}`)
1715
+ .then((r) => r.data);
1716
+ const deleteOrganizationMemberRole = (endpoint, organizationId, profileId, roleId) => endpoint.api //
1717
+ .delete(`/organizations/${organizationId}/profiles/${profileId}/role/${roleId}`)
1845
1718
  .then((r) => r.data);
1846
- /**
1847
- * Get a profile. The caller must have admin access to the given profile.
1848
- * TODO: Add a "public" profile endpoint for public pages
1849
- *
1850
- * ```typescript
1851
- * import {Profiles} from '@verdocs/js-sdk/Users';
1852
- *
1853
- * const profile = await Profiles.getProfile('PROFILEID');
1854
- * ```
1855
- */
1856
- const getProfile = (endpoint, profileId) => endpoint.api //
1857
- .get(`/profiles/${profileId}`)
1719
+ const getOrganizationMemberPlans = (endpoint, organizationId, profileId) => endpoint.api //
1720
+ .get(`/organizations/${organizationId}/profiles/${profileId}/plans`)
1858
1721
  .then((r) => r.data);
1722
+
1859
1723
  /**
1860
- * Get a profile's permissions. The caller must have admin access to the given profile.
1861
- *
1862
- * ```typescript
1863
- * import {Profiles} from '@verdocs/js-sdk/Users';
1724
+ * An Organization is the top level object for ownership for Members, Documents, and Templates.
1864
1725
  *
1865
- * const permissions = await Profiles.getProfilePermissions('PROFILEID');
1866
- * ```
1726
+ * @module
1867
1727
  */
1868
- const getProfilePermissions = (endpoint, profileId) => endpoint.api //
1869
- .get(`/profiles/${profileId}/permissions`)
1870
- .then((r) => r.data);
1871
1728
  /**
1872
- * Get a profile's groups.
1873
- *
1874
- * ```typescript
1875
- * import {Profiles} from '@verdocs/js-sdk/Users';
1876
- *
1877
- * const groups = await Profiles.getProfileGroups('PROFILEID');
1878
- * ```
1729
+ * Get a list of organizations the user has access to.
1879
1730
  */
1880
- const getProfileGroups = (endpoint, profileId) => endpoint.api //
1881
- .get(`/profiles/${profileId}/groups`)
1731
+ const getOrganizations = (endpoint) => endpoint.api //
1732
+ .get('/organizations')
1882
1733
  .then((r) => r.data);
1883
1734
  /**
1884
- * Switch the caller's "current" profile. The current profile is used for permissions checking and profile_id field settings
1885
- * for most operations in Verdocs. It is important to select the appropropriate profile before calling other API functions.
1886
- *
1887
- * ```typescript
1888
- * import {Profiles} from '@verdocs/js-sdk/Users';
1889
- *
1890
- * const newProfile = await Profiles.switchProfile('PROFILEID');
1891
- * ```
1735
+ * Create an organization.
1892
1736
  */
1893
- const switchProfile = (endpoint, profileId) => endpoint.api //
1894
- .post(`/profiles/${profileId}/switch`)
1737
+ const createOrganization = (endpoint) => endpoint.api //
1738
+ .post('/organizations')
1895
1739
  .then((r) => r.data);
1896
1740
  /**
1897
- * Update a profile. For future expansion, the profile ID to update is required, but currently this must also be the
1898
- * "current" profile for the caller.
1899
- *
1900
- * ```typescript
1901
- * import {Profiles} from '@verdocs/js-sdk/Users';
1902
- *
1903
- * const newProfile = await Profiles.updateProfile('PROFILEID');
1904
- * ```
1741
+ * Delete an organization.
1905
1742
  */
1906
- const updateProfile = (endpoint, profileId, params) => endpoint.api //
1907
- .put(`/profiles/${profileId}`, params)
1743
+ const deleteOrganization = (endpoint, organizationId) => endpoint.api //
1744
+ .delete(`/organizations/${organizationId}`)
1908
1745
  .then((r) => r.data);
1909
1746
  /**
1910
- * Delete a profile. If the requested profile is the caller's curent profile, the next available profile will be selected.
1911
- *
1912
- * ```typescript
1913
- * import {Profiles} from '@verdocs/js-sdk/Users';
1914
- *
1915
- * await Profiles.deleteProfile('PROFILEID');
1916
- * ```
1747
+ * Get an organization by ID.
1917
1748
  */
1918
- const deleteProfile = (endpoint, profileId) => endpoint.api //
1919
- .delete(`/profiles/${profileId}`)
1749
+ const getOrganization = (endpoint, organizationId) => endpoint.api //
1750
+ .get(`/organizations/${organizationId}`)
1920
1751
  .then((r) => r.data);
1921
1752
  /**
1922
- * Create a user account and parent organization. This endpoint is for creating a new organization. Users joining an
1923
- * existing organization should be invited, and follow their invitation links/instructions to create their accounts.
1924
- *
1925
- * ```typescript
1926
- * import {Profiles} from '@verdocs/js-sdk/Users';
1927
- *
1928
- * const newAccount = await Profiles.createBusinessAccount({
1929
- * orgName: 'ORG', email: 'a@b.com', password: '12345678', firstName: 'FIRST', lastName: 'LAST'
1930
- * });
1931
- * ```
1753
+ * Update an organization.
1932
1754
  */
1933
- const createBusinessAccount = (endpoint, params) => endpoint.api //
1934
- .post('/user/business', params)
1755
+ const updateOrganization = (endpoint, organizationId, params) => endpoint.api //
1756
+ .patch(`/organizations/${organizationId}`, params)
1935
1757
  .then((r) => r.data);
1936
- const recordSignupSurvey = (endpoint, params) => endpoint.api //
1937
- .post('/user/signup', params)
1758
+
1759
+ const getWebhooks = (endpoint) => endpoint.api //
1760
+ .get(`/v2/webhooks/organization`)
1761
+ .then((r) => r.data);
1762
+ const setWebhooks = (endpoint, params) => endpoint.api //
1763
+ .post(`/v2/webhooks/organization`, params)
1938
1764
  .then((r) => r.data);
1939
1765
 
1940
1766
  /**
1941
- * Given a `rgba(r,g,b,a)` string value, returns the hex equivalent, dropping the alpha channel.
1942
- */
1943
- function getRGB(rgba) {
1944
- const rgbNumbers = rgba.replace('rgba(', '').replace(')', '').split(',');
1945
- const rgbObject = {
1946
- red: +rgbNumbers[0],
1947
- green: +rgbNumbers[1],
1948
- blue: +rgbNumbers[2],
1949
- alpha: +rgbNumbers[3],
1950
- };
1951
- const alpha = 1 - rgbObject.alpha;
1952
- const red = Math.round((rgbObject.alpha * (rgbObject.red / 255) + alpha) * 255);
1953
- const green = Math.round((rgbObject.alpha * (rgbObject.green / 255) + alpha) * 255);
1954
- const blue = Math.round((rgbObject.alpha * (rgbObject.blue / 255) + alpha) * 255);
1955
- return '#' + rgbToHex(red) + rgbToHex(green) + rgbToHex(blue);
1956
- }
1957
- /**
1958
- * Given an RGB string value, returns the hex equivalent.
1959
- */
1960
- function rgbToHex(rgb) {
1961
- const hex = rgb.toString(16);
1962
- if (hex.length < 2) {
1963
- return '0' + hex;
1964
- }
1965
- return hex;
1966
- }
1967
- /**
1968
- * Given a signer role index, return the color code for that signer.
1969
- */
1970
- function getRGBA(roleIndex) {
1971
- switch (roleIndex % 10) {
1972
- case 0:
1973
- return roleIndex === 0 ? 'rgba(255, 193, 7, 0.4)' : 'rgba(134, 134, 134, 0.3)'; // #FFE69C
1974
- case 1:
1975
- return 'rgba(156, 39, 176, .4)'; // '#E3C3E9'
1976
- case 2:
1977
- return 'rgba(33, 150, 243, .4)'; // '#C1E1FB'
1978
- case 3:
1979
- return 'rgba(220, 231, 117, 0.3)';
1980
- case 4:
1981
- return 'rgba(121, 134, 203, 0.3)';
1982
- case 5:
1983
- return 'rgba(77, 182, 172, 0.3)';
1984
- case 6:
1985
- return 'rgba(255, 202, 165, 0.3)';
1986
- case 7:
1987
- return 'rgba(2, 247, 190, 0.3)';
1988
- case 8:
1989
- return 'rgba(255, 138, 101, 0.3)';
1990
- case 9:
1991
- return 'rgba(82, 255, 79, 0.3)';
1992
- default:
1993
- return 'rgba(229, 115, 155, 0.3)';
1994
- }
1995
- }
1996
- /**
1997
- * Given a role name, return a color code for it. This works by computing a hash code so the specific color returned
1998
- * is not specified explicitly, but will be the same for every call with the same input value.
1999
- */
2000
- function nameToRGBA(str) {
2001
- if (!!str) {
2002
- const validNum = parseInt(str.slice(-1), 10);
2003
- if (!isNaN(validNum)) {
2004
- str += (validNum * 99).toString();
2005
- }
2006
- let hash = 0;
2007
- for (let i = 0; i < str.length; i++) {
2008
- // tslint:disable-next-line:no-bitwise
2009
- hash = str.charCodeAt(i) + ((hash << 5) - hash);
2010
- }
2011
- hash = Math.round(hash / 1.3);
2012
- // tslint:disable-next-line:no-bitwise
2013
- const c = (hash & 0x00ffff08).toString(16).toUpperCase();
2014
- const hex = '#' + '00000'.substring(0, 6 - c.length) + c;
2015
- const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
2016
- const color = {
2017
- r: parseInt(result[1], 16),
2018
- g: parseInt(result[2], 16),
2019
- b: parseInt(result[3], 16),
2020
- };
2021
- return `rgba(${color.r}, ${color.g}, ${color.b}, 0.2)`;
2022
- }
2023
- }
2024
- /**
2025
- * Helper function to obtain a color code given a role name given various possible inputs.
1767
+ * Confirm whether the user has all of the specified permissions.
2026
1768
  */
2027
- function getRoleColor(name, roles, index) {
2028
- if (index) {
2029
- return getRGBA(index);
2030
- }
2031
- else if (roles && roles.length > 0) {
2032
- const roleIndex = roles.findIndex((role) => role === name);
2033
- if (roleIndex > -1) {
2034
- return getRGBA(roleIndex);
2035
- }
2036
- else {
2037
- return nameToRGBA(name);
2038
- }
2039
- }
2040
- else {
2041
- return nameToRGBA(name);
2042
- }
2043
- }
1769
+ const userHasPermissions = (session, permissions) => permissions.every((perm) => (session?.permissions || []).includes(perm));
2044
1770
 
2045
- const YEAR = 365 * 24 * 60 * 60;
2046
- // const MONTH = 30 * 24 * 60 * 60;
2047
- const WEEK = 7 * 24 * 60 * 60;
2048
- const DAY = 24 * 60 * 60;
2049
- const HOUR = 60 * 60;
2050
- const MINUTE = 60;
2051
- const formatShortTimeAgo = (val) => {
2052
- if (val === undefined || val === null) {
2053
- return '';
2054
- }
2055
- let dateInput;
2056
- if (typeof val === 'string' || typeof val === 'number') {
2057
- dateInput = new Date(val);
2058
- }
2059
- else if (typeof val === 'object') {
2060
- dateInput = val;
2061
- }
2062
- else {
2063
- return '';
2064
- }
2065
- const timeDiff = Math.floor((new Date().getTime() - dateInput.getTime()) / 1000);
2066
- if (timeDiff >= YEAR) {
2067
- return Math.floor(timeDiff / YEAR) + 'Y';
2068
- }
2069
- // if (timeDiff >= MONTH) {
2070
- // return Math.floor(timeDiff / MONTH) + 'M';
2071
- // }
2072
- if (timeDiff >= WEEK) {
2073
- return Math.floor(timeDiff / WEEK) + 'W';
2074
- }
2075
- if (timeDiff >= DAY) {
2076
- return Math.floor(timeDiff / DAY) + 'D';
2077
- }
2078
- if (timeDiff >= HOUR) {
2079
- return Math.floor(timeDiff / HOUR) + 'H';
2080
- }
2081
- if (timeDiff >= MINUTE) {
2082
- return Math.floor(timeDiff / MINUTE) + 'M';
2083
- }
2084
- return `${timeDiff}S`;
2085
- };
2086
- function timePeriod(type) {
2087
- let endDate = new Date().getTime();
2088
- const today = new Date();
2089
- const month = today.getMonth();
2090
- const year = today.getFullYear();
2091
- let startDate = null;
2092
- switch (type) {
2093
- case '30d':
2094
- startDate = endDate - 60 * 60 * 24 * 30 * 1000;
1771
+ const canPerformTemplateAction = (session, action, template) => {
1772
+ if (!template && !action.includes('create')) {
1773
+ return { canPerform: false, message: 'Missing required template object' };
1774
+ }
1775
+ // We use BOGUS here to force the option-chain in things like template?.profile_id to NOT match profile?.profile_id because if both
1776
+ // were undefined, they would actually match.
1777
+ const profile_id = session?.profile_id || 'BOGUS';
1778
+ const organization_id = session?.organization_id || 'BOGUS';
1779
+ if (!profile_id) {
1780
+ return { canPerform: false, message: 'Active session required' };
1781
+ }
1782
+ const isCreator = template?.profile_id === profile_id;
1783
+ const isSameOrg = template?.organization_id === organization_id;
1784
+ const isPersonal = template?.is_personal ?? false;
1785
+ const isPublic = template?.is_public ?? false;
1786
+ const permissionsRequired = [];
1787
+ switch (action) {
1788
+ case 'create_personal':
1789
+ permissionsRequired.push('template:creator:create:personal');
2095
1790
  break;
2096
- case '60d':
2097
- startDate = endDate - 60 * 60 * 24 * 60 * 1000;
1791
+ case 'create_org':
1792
+ permissionsRequired.push('template:creator:create:org');
2098
1793
  break;
2099
- case '6m':
2100
- startDate = endDate - 60 * 60 * 24 * 30 * 6 * 1000;
1794
+ case 'create_public':
1795
+ permissionsRequired.push('template:creator:create:public');
2101
1796
  break;
2102
- case 'this_month':
2103
- startDate = new Date(year, month, 1).getTime();
1797
+ case 'read':
1798
+ if (!isCreator) {
1799
+ if ((!isPersonal && isSameOrg) || !isPublic) {
1800
+ permissionsRequired.push('template:member:read');
1801
+ }
1802
+ }
2104
1803
  break;
2105
- case 'last_month':
2106
- startDate = new Date(year, month - 1, 1).getTime();
2107
- endDate = new Date(year, month, 0).getTime();
1804
+ case 'write':
1805
+ if (!isCreator) {
1806
+ permissionsRequired.push('template:member:read');
1807
+ permissionsRequired.push('template:member:write');
1808
+ }
2108
1809
  break;
2109
- case 'this_year':
2110
- startDate = new Date(year, 0, 1);
1810
+ case 'change_visibility_personal':
1811
+ if (isCreator) {
1812
+ permissionsRequired.push('template:creator:create:personal');
1813
+ }
1814
+ else {
1815
+ permissionsRequired.push('template:member:visibility');
1816
+ }
1817
+ break;
1818
+ case 'change_visibility_org':
1819
+ if (isCreator) {
1820
+ permissionsRequired.push('template:creator:create:org');
1821
+ }
1822
+ else {
1823
+ permissionsRequired.push('template:member:visibility');
1824
+ }
1825
+ break;
1826
+ case 'change_visibility_public':
1827
+ if (isCreator) {
1828
+ permissionsRequired.push('template:creator:create:public');
1829
+ permissionsRequired.push('template:creator:visibility');
1830
+ }
1831
+ else {
1832
+ permissionsRequired.push('template:member:visibility');
1833
+ }
1834
+ break;
1835
+ case 'delete':
1836
+ if (isCreator) {
1837
+ permissionsRequired.push('template:creator:delete');
1838
+ }
1839
+ else {
1840
+ permissionsRequired.push('template:member:delete');
1841
+ }
2111
1842
  break;
2112
- case 'all_time':
2113
1843
  default:
2114
- return null;
1844
+ return { canPerform: false, message: 'Action is not defined' };
2115
1845
  }
2116
- if (startDate === null && endDate === null) {
2117
- return null;
1846
+ if (hasRequiredPermissions(session, permissionsRequired)) {
1847
+ return { canPerform: true, message: '' };
2118
1848
  }
2119
- return {
2120
- start_time: new Date(startDate).toISOString(),
2121
- end_time: new Date(endDate).toISOString(),
2122
- };
2123
- }
1849
+ return { canPerform: false, message: `Insufficient access to perform '${action}'. Needed permissions: ${permissionsRequired.toString()}` };
1850
+ };
1851
+ const hasRequiredPermissions = (session, permissions) => permissions.every((perm) => (session?.permissions || []).includes(perm));
2124
1852
 
2125
- function getRTop(y, fieldHeight, iTextHeight, yRatio) {
2126
- return iTextHeight - (y + fieldHeight) * yRatio;
2127
- }
2128
- function getRLeft(x, ratio) {
2129
- return x * ratio;
2130
- }
2131
- function getRValue(y, ratio) {
2132
- return y * ratio;
2133
- }
2134
- function blobToBase64(image) {
2135
- const fileReader = new FileReader();
2136
- return new Promise((resolve, reject) => {
2137
- fileReader.onerror = () => {
2138
- reject(new DOMException('Problem reading blob.'));
2139
- };
2140
- fileReader.onload = () => {
2141
- resolve(fileReader.result);
2142
- };
2143
- fileReader.readAsDataURL(image);
2144
- });
2145
- }
2146
- function rescale(r, n) {
2147
- return r * n;
2148
- }
1853
+ /**
1854
+ * Add a field to a template.
1855
+ */
1856
+ const createField = (endpoint, templateId, params) => endpoint.api //
1857
+ .post(`/templates/${templateId}/fields`, params)
1858
+ .then((r) => r.data);
1859
+ /**
1860
+ * Update a template field.
1861
+ */
1862
+ const updateField = (endpoint, templateId, fieldName, params) => endpoint.api //
1863
+ .put(`/templates/${templateId}/fields/${fieldName}`, params)
1864
+ .then((r) => r.data);
1865
+ /**
1866
+ * REmove a field from a template.
1867
+ */
1868
+ const deleteField = (endpoint, templateId, fieldName) => endpoint.api //
1869
+ .delete(`/templates/${templateId}/fields/${fieldName}`)
1870
+ .then((r) => r.data);
2149
1871
 
2150
1872
  /**
2151
- * Given a File, extract the file's content as a base64 encoded data URL. The response will have a prefix that
2152
- * includes the MIME type of the file, e.g. "data:image/jpeg;base64,iVBORw0K......"
1873
+ * Enable automatic reminders. setup_time is the number of days after the envelope is sent that the first reminder
1874
+ * should be sent. interval_time is the number of days between reminders.
2153
1875
  */
2154
- const fileToDataUrl = (file) => new Promise((resolve, reject) => {
2155
- const reader = new FileReader();
2156
- reader.onload = () => resolve({
2157
- lastModified: file.lastModified,
2158
- size: file.size,
2159
- type: file.type,
2160
- name: file.name,
2161
- data: reader.result,
2162
- });
2163
- reader.onerror = reject;
2164
- if (file) {
2165
- reader.readAsDataURL(file);
2166
- }
2167
- else {
2168
- reject(new Error('Invalid file'));
2169
- }
2170
- });
1876
+ const createTemplateReminder = (endpoint, templateId, params) => endpoint.api //
1877
+ .post(`/templates/${templateId}/reminder/`, params)
1878
+ .then((r) => r.data);
2171
1879
  /**
2172
- * Trigger a download dialog to save a blob as a file on disk.
1880
+ * Get the reminder configuration for a template.
2173
1881
  */
2174
- const downloadBlob = (blob, name = 'file.pdf') => {
2175
- const blobUrl = URL.createObjectURL(blob);
2176
- const link = document.createElement('a');
2177
- link.href = blobUrl;
2178
- link.download = name;
2179
- document.body.appendChild(link);
2180
- link.dispatchEvent(new MouseEvent('click', {
2181
- bubbles: true,
2182
- cancelable: true,
2183
- view: window,
2184
- }));
2185
- document.body.removeChild(link);
2186
- };
1882
+ const getTemplateReminder = (endpoint, templateId, reminderId) => endpoint.api //
1883
+ .get(`/templates/${templateId}/reminder/${reminderId}`)
1884
+ .then((r) => r.data);
1885
+ /**
1886
+ * Update the reminder configuration for a template.
1887
+ */
1888
+ const updateTemplateReminder = (endpoint, templateId, reminderId, params) => endpoint.api //
1889
+ .put(`/templates/${templateId}/reminder/${reminderId}`, params)
1890
+ .then((r) => r.data);
1891
+ /**
1892
+ * Delete the reminder configuration for a template.
1893
+ */
1894
+ const deleteTemplateReminder = (endpoint, templateId, reminderId) => endpoint.api //
1895
+ .delete(`/templates/${templateId}/reminder/${reminderId}`)
1896
+ .then((r) => r.data);
1897
+
1898
+ /**
1899
+ * A "role" is an individual participant in a signing flow, such as a signer or CC contact. Roles are identified by
1900
+ * their names, which must be unique (e.g. 'Recipient 1'). Template fields are assigned to roles for signing operations,
1901
+ * so you may have 'Recipient 1 Signature 1' and so forth.
1902
+ *
1903
+ * @module
1904
+ */
1905
+ const createTemplateRole = (endpoint, templateId, params) => endpoint.api //
1906
+ .post(`/templates/${templateId}/roles`, params)
1907
+ .then((r) => r.data);
1908
+ const getTemplateRoles = (endpoint, templateId) => endpoint.api //
1909
+ .get(`/templates/${templateId}/roles`)
1910
+ .then((r) => r.data);
1911
+ const getTemplateRole = (endpoint, templateId, roleName) => endpoint.api //
1912
+ .get(`/templates/${templateId}/roles/${roleName}`)
1913
+ .then((r) => r.data);
1914
+ const updateTemplateRole = (endpoint, templateId, roleName, params) => endpoint.api //
1915
+ .put(`/templates/${templateId}/roles/${roleName}`, params)
1916
+ .then((r) => r.data);
1917
+ const deleteTemplateRole = (endpoint, templateId, roleName) => endpoint.api //
1918
+ .delete(`/templates/${templateId}/roles/${roleName}`)
1919
+ .then((r) => r.data);
1920
+ const getTemplateRoleFields = (endpoint, templateId, roleName) => endpoint.api //
1921
+ .get(`/templates/${templateId}/roles/${roleName}/fields`)
1922
+ .then((r) => r.data);
1923
+
1924
+ /**
1925
+ * Get the template stars for a template.
1926
+ */
1927
+ const getStars = (endpoint, templateId) => endpoint.api //
1928
+ .get(`/templates/${templateId}/stars`)
1929
+ .then((r) => r.data);
1930
+ /**
1931
+ * Toggle the template star for a template.
1932
+ */
1933
+ const toggleStar = (endpoint, templateId) => endpoint.api //
1934
+ .post(`/templates/${templateId}/stars/toggle`)
1935
+ .then((r) => r.data);
1936
+
1937
+ /**
1938
+ * A Tag is a user-specified label applied to a template. Tags help users organize and find Templates.
1939
+ * recipients. Every Organization has a set of tags "owned" by that Organization and only visible inside it.
1940
+ * Verdocs also provides a set of system-wide "featured" tags available to all Organizations.
1941
+ *
1942
+ * @module
1943
+ */
1944
+ /**
1945
+ * Apply a tag to a template.
1946
+ */
1947
+ const addTemplateTag = (endpoint, templateId, params) => endpoint.api //
1948
+ .post(`/templates/${templateId}/tags/`, params)
1949
+ .then((r) => r.data);
1950
+ /**
1951
+ * Get all tags for a template.
1952
+ */
1953
+ const getTemplateTags = (endpoint, templateId) => endpoint.api //
1954
+ .get(`/templates/${templateId}/tags/`)
1955
+ .then((r) => r.data);
1956
+ /**
1957
+ * Remove a tag from a template.
1958
+ */
1959
+ const deleteTemplateTag = (endpoint, templateId, tagName) => endpoint.api //
1960
+ .post(`/templates/${templateId}/tags/${tagName}`)
1961
+ .then((r) => r.data);
1962
+ /**
1963
+ * Create an Organization-wide tag.
1964
+ */
1965
+ const createTag = (endpoint, name) => endpoint.api //
1966
+ .post('/tags', { tag_name: name })
1967
+ .then((r) => r.data);
1968
+ /**
1969
+ * Get an Organization-wide tag.
1970
+ */
1971
+ const getTag = (endpoint, name) => endpoint.api //
1972
+ .get(`/tags/${name}`)
1973
+ .then((r) => r.data);
1974
+ /**
1975
+ * Get all tags available for use by an Organization.
1976
+ */
1977
+ const getAllTags = (endpoint) => endpoint.api //
1978
+ .get('/tags')
1979
+ .then((r) => r.data);
2187
1980
 
2188
- const Countries = [
2189
- { code: '+7 840', name: 'Abkhazia', value: '+7' },
2190
- { code: '+93', name: 'Afghanistan', value: '+93' },
2191
- { code: '+355', name: 'Albania', value: '+355' },
2192
- { code: '+213', name: 'Algeria', value: '+213' },
2193
- { code: '+1', name: 'American Samoa', value: '+1' },
2194
- { code: '+376', name: 'Andorra', value: '+376' },
2195
- { code: '+244', name: 'Angola', value: '+244' },
2196
- { code: '+1', name: 'Anguilla', value: '+1' },
2197
- { code: '+1', name: 'Antigua and Barbuda', value: '+1' },
2198
- { code: '+54', name: 'Argentina', value: '+54' },
2199
- { code: '+374', name: 'Armenia', value: '+374' },
2200
- { code: '+297', name: 'Aruba', value: '+297' },
2201
- { code: '+247', name: 'Ascension', value: '+247' },
2202
- { code: '+61', name: 'Australia', value: '+61' },
2203
- { code: '+672', name: 'Australian External Territories', value: '+672' },
2204
- { code: '+43', name: 'Austria', value: '+43' },
2205
- { code: '+994', name: 'Azerbaijan', value: '+994' },
2206
- { code: '+1', name: 'Bahamas', value: '+1' },
2207
- { code: '+973', name: 'Bahrain', value: '+973' },
2208
- { code: '+880', name: 'Bangladesh', value: '+880' },
2209
- { code: '+1', name: 'Barbados', value: '+1' },
2210
- { code: '+1', name: 'Barbuda', value: '+1' },
2211
- { code: '+375', name: 'Belarus', value: '+375' },
2212
- { code: '+32', name: 'Belgium', value: '+32' },
2213
- { code: '+501', name: 'Belize', value: '+501' },
2214
- { code: '+229', name: 'Benin', value: '+229' },
2215
- { code: '+1', name: 'Bermuda', value: '+1' },
2216
- { code: '+975', name: 'Bhutan', value: '+975' },
2217
- { code: '+591', name: 'Bolivia', value: '+591' },
2218
- { code: '+387', name: 'Bosnia and Herzegovina', value: '+387' },
2219
- { code: '+267', name: 'Botswana', value: '+267' },
2220
- { code: '+55', name: 'Brazil', value: '+55' },
2221
- { code: '+246', name: 'British Indian Ocean Territory', value: '+246' },
2222
- { code: '+1', name: 'British Virgin Islands', value: '+1' },
2223
- { code: '+673', name: 'Brunei', value: '+673' },
2224
- { code: '+359', name: 'Bulgaria', value: '+359' },
2225
- { code: '+226', name: 'Burkina Faso', value: '+226' },
2226
- { code: '+257', name: 'Burundi', value: '+257' },
2227
- { code: '+855', name: 'Cambodia', value: '+855' },
2228
- { code: '+237', name: 'Cameroon', value: '+237' },
2229
- { code: '+1', name: 'Canada', value: '+1' },
2230
- { code: '+238', name: 'Cape Verde', value: '+238' },
2231
- { code: '+1', name: 'Cayman Islands', value: '+1' },
2232
- { code: '+236', name: 'Central African Republic', value: '+236' },
2233
- { code: '+235', name: 'Chad', value: '+235' },
2234
- { code: '+56', name: 'Chile', value: '+56' },
2235
- { code: '+86', name: 'China', value: '+86' },
2236
- { code: '+61', name: 'Christmas Island', value: '+61' },
2237
- { code: '+61', name: 'Cocos-Keeling Islands', value: '+61' },
2238
- { code: '+57', name: 'Colombia', value: '+57' },
2239
- { code: '+269', name: 'Comoros', value: '+269' },
2240
- { code: '+242', name: 'Congo', value: '+242' },
2241
- { code: '+243', name: 'Congo, Dem. Rep. of (Zaire)', value: '+243' },
2242
- { code: '+682', name: 'Cook Islands', value: '+682' },
2243
- { code: '+506', name: 'Costa Rica', value: '+506' },
2244
- { code: '+385', name: 'Croatia', value: '+385' },
2245
- { code: '+53', name: 'Cuba', value: '+53' },
2246
- { code: '+599', name: 'Curacao', value: '+599' },
2247
- { code: '+537', name: 'Cyprus', value: '+537' },
2248
- { code: '+420', name: 'Czech Republic', value: '+420' },
2249
- { code: '+45', name: 'Denmark', value: '+45' },
2250
- { code: '+246', name: 'Diego Garcia', value: '+246' },
2251
- { code: '+253', name: 'Djibouti', value: '+253' },
2252
- { code: '+1', name: 'Dominica', value: '+1' },
2253
- { code: '+1', name: 'Dominican Republic', value: '+1' },
2254
- { code: '+670', name: 'East Timor', value: '+670' },
2255
- { code: '+56', name: 'Easter Island', value: '+56' },
2256
- { code: '+593', name: 'Ecuador', value: '+593' },
2257
- { code: '+20', name: 'Egypt', value: '+20' },
2258
- { code: '+503', name: 'El Salvador', value: '+503' },
2259
- { code: '+240', name: 'Equatorial Guinea', value: '+240' },
2260
- { code: '+291', name: 'Eritrea', value: '+291' },
2261
- { code: '+372', name: 'Estonia', value: '+372' },
2262
- { code: '+251', name: 'Ethiopia', value: '+251' },
2263
- { code: '+500', name: 'Falkland Islands', value: '+500' },
2264
- { code: '+298', name: 'Faroe Islands', value: '+298' },
2265
- { code: '+679', name: 'Fiji', value: '+679' },
2266
- { code: '+358', name: 'Finland', value: '+358' },
2267
- { code: '+33', name: 'France', value: '+33' },
2268
- { code: '+596', name: 'Martinique', value: '+596' },
2269
- { code: '+594', name: 'French Guiana', value: '+594' },
2270
- { code: '+689', name: 'French Polynesia', value: '+689' },
2271
- { code: '+241', name: 'Gabon', value: '+241' },
2272
- { code: '+220', name: 'Gambia', value: '+220' },
2273
- { code: '+995', name: 'Georgia', value: '+995' },
2274
- { code: '+49', name: 'Germany', value: '+49' },
2275
- { code: '+233', name: 'Ghana', value: '+233' },
2276
- { code: '+350', name: 'Gibraltar', value: '+350' },
2277
- { code: '+30', name: 'Greece', value: '+30' },
2278
- { code: '+299', name: 'Greenland', value: '+299' },
2279
- { code: '+1', name: 'Grenada', value: '+1' },
2280
- { code: '+590', name: 'Guadeloupe', value: '+590' },
2281
- { code: '+1', name: 'Guam', value: '+1' },
2282
- { code: '+502', name: 'Guatemala', value: '+502' },
2283
- { code: '+224', name: 'Guinea', value: '+224' },
2284
- { code: '+245', name: 'Guinea-Bissau', value: '+245' },
2285
- { code: '+595', name: 'Guyana', value: '+595' },
2286
- { code: '+509', name: 'Haiti', value: '+509' },
2287
- { code: '+504', name: 'Honduras', value: '+504' },
2288
- { code: '+852', name: 'Hong Kong SAR China', value: '+852' },
2289
- { code: '+36', name: 'Hungary', value: '+36' },
2290
- { code: '+354', name: 'Iceland', value: '+354' },
2291
- { code: '+91', name: 'India', value: '+91' },
2292
- { code: '+62', name: 'Indonesia', value: '+62' },
2293
- { code: '+98', name: 'Iran', value: '+98' },
2294
- { code: '+964', name: 'Iraq', value: '+964' },
2295
- { code: '+353', name: 'Ireland', value: '+353' },
2296
- { code: '+972', name: 'Israel', value: '+972' },
2297
- { code: '+39', name: 'Italy', value: '+39' },
2298
- { code: '+225', name: 'Ivory Coast', value: '+225' },
2299
- { code: '+1', name: 'Jamaica', value: '+1' },
2300
- { code: '+81', name: 'Japan', value: '+81' },
2301
- { code: '+962', name: 'Jordan', value: '+962' },
2302
- { code: '+77', name: 'Kazakhstan', value: '+7' },
2303
- { code: '+254', name: 'Kenya', value: '+254' },
2304
- { code: '+686', name: 'Kiribati', value: '+686' },
2305
- { code: '+965', name: 'Kuwait', value: '+965' },
2306
- { code: '+996', name: 'Kyrgyzstan', value: '+996' },
2307
- { code: '+856', name: 'Laos', value: '+856' },
2308
- { code: '+371', name: 'Latvia', value: '+371' },
2309
- { code: '+961', name: 'Lebanon', value: '+961' },
2310
- { code: '+266', name: 'Lesotho', value: '+266' },
2311
- { code: '+231', name: 'Liberia', value: '+231' },
2312
- { code: '+218', name: 'Libya', value: '+218' },
2313
- { code: '+423', name: 'Liechtenstein', value: '+423' },
2314
- { code: '+370', name: 'Lithuania', value: '+370' },
2315
- { code: '+352', name: 'Luxembourg', value: '+352' },
2316
- { code: '+853', name: 'Macau SAR China', value: '+853' },
2317
- { code: '+389', name: 'Macedonia', value: '+389' },
2318
- { code: '+261', name: 'Madagascar', value: '+261' },
2319
- { code: '+265', name: 'Malawi', value: '+265' },
2320
- { code: '+60', name: 'Malaysia', value: '+60' },
2321
- { code: '+960', name: 'Maldives', value: '+960' },
2322
- { code: '+223', name: 'Mali', value: '+223' },
2323
- { code: '+356', name: 'Malta', value: '+356' },
2324
- { code: '+692', name: 'Marshall Islands', value: '+692' },
2325
- { code: '+596', name: 'Martinique', value: '+596' },
2326
- { code: '+222', name: 'Mauritania', value: '+222' },
2327
- { code: '+230', name: 'Mauritius', value: '+230' },
2328
- { code: '+262', name: 'Mayotte or Réunion', value: '+262' },
2329
- { code: '+52', name: 'Mexico', value: '+52' },
2330
- { code: '+691', name: 'Micronesia', value: '+691' },
2331
- { code: '+1', name: 'Midway Island', value: '+1' },
2332
- { code: '+373', name: 'Moldova', value: '+373' },
2333
- { code: '+377', name: 'Monaco', value: '+377' },
2334
- { code: '+976', name: 'Mongolia', value: '+976' },
2335
- { code: '+382', name: 'Montenegro', value: '+382' },
2336
- { code: '+1', name: 'Montserrat', value: '+1' },
2337
- { code: '+212', name: 'Morocco', value: '+212' },
2338
- { code: '+95', name: 'Myanmar', value: '+95' },
2339
- { code: '+264', name: 'Namibia', value: '+264' },
2340
- { code: '+674', name: 'Nauru', value: '+674' },
2341
- { code: '+977', name: 'Nepal', value: '+977' },
2342
- { code: '+31', name: 'Netherlands', value: '+31' },
2343
- { code: '+599', name: 'Netherlands Antilles', value: '+599' },
2344
- { code: '+1', name: 'Nevis', value: '+1' },
2345
- { code: '+687', name: 'New Caledonia', value: '+687' },
2346
- { code: '+64', name: 'New Zealand', value: '+64' },
2347
- { code: '+505', name: 'Nicaragua', value: '+505' },
2348
- { code: '+227', name: 'Niger', value: '+227' },
2349
- { code: '+234', name: 'Nigeria', value: '+234' },
2350
- { code: '+683', name: 'Niue', value: '+683' },
2351
- { code: '+672', name: 'Norfolk Island', value: '+672' },
2352
- { code: '+850', name: 'North Korea', value: '+850' },
2353
- { code: '+1', name: 'Northern Mariana Islands', value: '+1' },
2354
- { code: '+47', name: 'Norway', value: '+47' },
2355
- { code: '+968', name: 'Oman', value: '+968' },
2356
- { code: '+92', name: 'Pakistan', value: '+92' },
2357
- { code: '+680', name: 'Palau', value: '+680' },
2358
- { code: '+970', name: 'Palestinian Territory', value: '+970' },
2359
- { code: '+507', name: 'Panama', value: '+507' },
2360
- { code: '+675', name: 'Papua New Guinea', value: '+675' },
2361
- { code: '+595', name: 'Paraguay', value: '+595' },
2362
- { code: '+51', name: 'Peru', value: '+51' },
2363
- { code: '+63', name: 'Philippines', value: '+63' },
2364
- { code: '+48', name: 'Poland', value: '+48' },
2365
- { code: '+351', name: 'Portugal', value: '+351' },
2366
- { code: '+1', name: 'Puerto Rico', value: '+1' },
2367
- { code: '+974', name: 'Qatar', value: '+974' },
2368
- { code: '+40', name: 'Romania', value: '+40' },
2369
- { code: '+7', name: 'Russia', value: '+7' },
2370
- { code: '+250', name: 'Rwanda', value: '+250' },
2371
- { code: '508', name: 'Saint Pierre and Miquelon', value: '508' },
2372
- { code: '+685', name: 'Samoa', value: '+685' },
2373
- { code: '+378', name: 'San Marino', value: '+378' },
2374
- { code: '+966', name: 'Saudi Arabia', value: '+966' },
2375
- { code: '+221', name: 'Senegal', value: '+221' },
2376
- { code: '+381', name: 'Serbia', value: '+381' },
2377
- { code: '+248', name: 'Seychelles', value: '+248' },
2378
- { code: '+232', name: 'Sierra Leone', value: '+232' },
2379
- { code: '+65', name: 'Singapore', value: '+65' },
2380
- { code: '+421', name: 'Slovakia', value: '+421' },
2381
- { code: '+386', name: 'Slovenia', value: '+386' },
2382
- { code: '+677', name: 'Solomon Islands', value: '+677' },
2383
- { code: '+27', name: 'South Africa', value: '+27' },
2384
- { code: '+500', name: 'South Georgia and the South Sandwich Islands', value: '+500' },
2385
- { code: '+82', name: 'South Korea', value: '+82' },
2386
- { code: '+34', name: 'Spain', value: '+34' },
2387
- { code: '+94', name: 'Sri Lanka', value: '+94' },
2388
- { code: '+249', name: 'Sudan', value: '+249' },
2389
- { code: '+597', name: 'Suriname', value: '+597' },
2390
- { code: '+268', name: 'Swaziland', value: '+268' },
2391
- { code: '+46', name: 'Sweden', value: '+46' },
2392
- { code: '+41', name: 'Switzerland', value: '+41' },
2393
- { code: '+963', name: 'Syria', value: '+963' },
2394
- { code: '+886', name: 'Taiwan', value: '+886' },
2395
- { code: '+992', name: 'Tajikistan', value: '+992' },
2396
- { code: '+255', name: 'Tanzania', value: '+255' },
2397
- { code: '+66', name: 'Thailand', value: '+66' },
2398
- { code: '+670', name: 'Timor Leste', value: '+670' },
2399
- { code: '+228', name: 'Togo', value: '+228' },
2400
- { code: '+690', name: 'Tokelau', value: '+690' },
2401
- { code: '+676', name: 'Tonga', value: '+676' },
2402
- { code: '+1', name: 'Trinidad and Tobago', value: '+1' },
2403
- { code: '+216', name: 'Tunisia', value: '+216' },
2404
- { code: '+90', name: 'Turkey', value: '+90' },
2405
- { code: '+993', name: 'Turkmenistan', value: '+993' },
2406
- { code: '+1', name: 'Turks and Caicos Islands', value: '+1' },
2407
- { code: '+688', name: 'Tuvalu', value: '+688' },
2408
- { code: '+1', name: 'U.S. Virgin Islands', value: '+1' },
2409
- { code: '+256', name: 'Uganda', value: '+256' },
2410
- { code: '+380', name: 'Ukraine', value: '+380' },
2411
- { code: '+971', name: 'United Arab Emirates', value: '+971' },
2412
- { code: '+44', name: 'United Kingdom', value: '+44' },
2413
- { code: '+1', name: 'United States', value: '+1' },
2414
- { code: '+598', name: 'Uruguay', value: '+598' },
2415
- { code: '+998', name: 'Uzbekistan', value: '+998' },
2416
- { code: '+678', name: 'Vanuatu', value: '+678' },
2417
- { code: '+58', name: 'Venezuela', value: '+58' },
2418
- { code: '+84', name: 'Vietnam', value: '+84' },
2419
- { code: '+1', name: 'Wake Island', value: '+1' },
2420
- { code: '+681', name: 'Wallis and Futuna', value: '+681' },
2421
- { code: '+967', name: 'Yemen', value: '+967' },
2422
- { code: '+260', name: 'Zambia', value: '+260' },
2423
- { code: '+255', name: 'Zanzibar', value: '+255' },
2424
- { code: '+263', name: 'Zimbabwe', value: '+263' },
1981
+ /**
1982
+ * A Template defines how a Verdocs signing flow will be performed, including attachments, signing fields, and
1983
+ * recipients.
1984
+ *
1985
+ * @module
1986
+ */
1987
+ /**
1988
+ * Get all templates accessible by the caller, with optional filters.
1989
+ *
1990
+ * ```typescript
1991
+ * import {Templates} from '@verdocs/js-sdk/Templates';
1992
+ *
1993
+ * await Templates.getTemplates((VerdocsEndpoint.getDefault());
1994
+ * await Templates.getTemplates((VerdocsEndpoint.getDefault(), { is_starred: true });
1995
+ * await Templates.getTemplates((VerdocsEndpoint.getDefault(), { is_creator: true });
1996
+ * await Templates.getTemplates((VerdocsEndpoint.getDefault(), { is_organization: true });
1997
+ * ```
1998
+ */
1999
+ const getTemplates = (endpoint, params) => endpoint.api //
2000
+ .post('/templates', { params })
2001
+ .then((r) => r.data);
2002
+ // export interface IListTemplatesParams {
2003
+ // name?: string;
2004
+ // sharing?: 'all' | 'personal' | 'shared' | 'public';
2005
+ // starred?: 'all' | 'starred' | 'unstarred';
2006
+ // sort?: 'name' | 'created_at' | 'updated_at' | 'last_used_at' | 'counter' | 'star_counter';
2007
+ // direction?: 'asc' | 'desc';
2008
+ // page?: number;
2009
+ // rows?: number;
2010
+ // }
2011
+ /**
2012
+ * Lists all templates accessible by the caller, with optional filters.
2013
+ *
2014
+ * ```typescript
2015
+ * import {Templates} from '@verdocs/js-sdk/Templates';
2016
+ *
2017
+ * await Templates.listTemplates((VerdocsEndpoint.getDefault(), { sharing: 'personal', sort: 'last_used_at' });
2018
+ * ```
2019
+ */
2020
+ // export const listTemplates = (endpoint: VerdocsEndpoint, params?: IListTemplatesParams) =>
2021
+ // endpoint.api //
2022
+ // .post<ITemplateSummaries>('/templates/list', params, {baseURL: endpoint.getBaseURLv2()})
2023
+ // .then((r) => r.data);
2024
+ /**
2025
+ * Get one template by its ID.
2026
+ *
2027
+ * ```typescript
2028
+ * import {Templates} from '@verdocs/js-sdk/Templates';
2029
+ *
2030
+ * const template = await Templates.getTemplate((VerdocsEndpoint.getDefault(), '83da3d70-7857-4392-b876-c4592a304bc9');
2031
+ * ```
2032
+ */
2033
+ const getTemplate = (endpoint, templateId) => endpoint.api //
2034
+ .get(`/templates/${templateId}`)
2035
+ .then((r) => r.data);
2036
+ /**
2037
+ * Get owner information for a template.
2038
+ *
2039
+ * ```typescript
2040
+ * import {Templates} from '@verdocs/js-sdk/Templates';
2041
+ *
2042
+ * const template = await Templates.getTemplateOwnerInfo((VerdocsEndpoint.getDefault(), '83da3d70-7857-4392-b876-c4592a304bc9');
2043
+ * ```
2044
+ */
2045
+ const getTemplateOwnerInfo = (endpoint, templateId) => endpoint.api //
2046
+ .get(`/templates/${templateId}`)
2047
+ .then((r) => r.data);
2048
+ const ALLOWED_CREATE_FIELDS = [
2049
+ 'name',
2050
+ 'is_personal',
2051
+ 'is_public',
2052
+ 'sender',
2053
+ 'description',
2054
+ 'roles',
2055
+ 'fields',
2425
2056
  ];
2426
- function getCountryByCode(code) {
2427
- const found = Countries.find((country) => country.code === code);
2428
- if (found)
2429
- return found;
2430
- if (isFrenchGuiana(code)) {
2431
- return { code: '+594', name: 'French Guiana', value: '+594' };
2057
+ /**
2058
+ * Create a template.
2059
+ *
2060
+ * ```typescript
2061
+ * import {Templates} from '@verdocs/js-sdk/Templates';
2062
+ *
2063
+ * const newTemplate = await Templates.createTemplate((VerdocsEndpoint.getDefault(), {...});
2064
+ * ```
2065
+ */
2066
+ const createTemplate = (endpoint, params, onUploadProgress) => {
2067
+ const options = {
2068
+ timeout: 120000,
2069
+ onUploadProgress: (event) => {
2070
+ const total = event.total || 1;
2071
+ const loaded = event.loaded || 0;
2072
+ onUploadProgress?.(Math.floor((loaded * 100) / (total || 1)), loaded, total || 1);
2073
+ },
2074
+ };
2075
+ if (params.documents && params.documents[0] instanceof File) {
2076
+ if (params.documents.length > 10) {
2077
+ throw new Error('createTemplate() has a maximum of 10 documents that can be attached.');
2078
+ }
2079
+ const formData = new FormData();
2080
+ ALLOWED_CREATE_FIELDS.forEach((allowedKey) => {
2081
+ if (params[allowedKey] !== undefined) {
2082
+ formData.append(allowedKey, params[allowedKey]);
2083
+ }
2084
+ });
2085
+ params.documents.forEach((file) => {
2086
+ formData.append('documents', file, file.name);
2087
+ });
2088
+ return endpoint.api.post('/templates', formData, options).then((r) => r.data);
2432
2089
  }
2433
- else if (isGuadeloupe(code)) {
2434
- return { code: '+590', name: 'Guadeloupe', value: '+590' };
2090
+ else {
2091
+ return endpoint.api.post('/templates', params, options).then((r) => r.data);
2435
2092
  }
2436
- else if (isMartinique(code)) {
2437
- return { code: '+596', name: 'Martinique', value: '+596' };
2093
+ };
2094
+ /**
2095
+ * Create a template.
2096
+ *
2097
+ * ```typescript
2098
+ * import {Templates} from '@verdocs/js-sdk/Templates';
2099
+ *
2100
+ * const newTemplate = await Templates.createTemplatev2((VerdocsEndpoint.getDefault(), {...});
2101
+ * ```
2102
+ */
2103
+ const createTemplatev2 = (endpoint, params, onUploadProgress) => {
2104
+ const options = {
2105
+ timeout: 120000,
2106
+ onUploadProgress: (event) => {
2107
+ const total = event.total || 1;
2108
+ const loaded = event.loaded || 0;
2109
+ onUploadProgress?.(Math.floor((loaded * 100) / (total || 1)), loaded, total || 1);
2110
+ },
2111
+ };
2112
+ if (params.documents && params.documents[0] instanceof File) {
2113
+ const formData = new FormData();
2114
+ ALLOWED_CREATE_FIELDS.forEach((allowedKey) => {
2115
+ if (params[allowedKey] !== undefined) {
2116
+ formData.append(allowedKey, params[allowedKey]);
2117
+ }
2118
+ });
2119
+ params.documents.forEach((file) => {
2120
+ formData.append('documents', file, file.name);
2121
+ });
2122
+ return endpoint.api.post('/v2/templates', formData, options).then((r) => r.data);
2438
2123
  }
2439
- else if (isMayotte(code)) {
2440
- return { code: '+262', name: 'Mayotte or Réunion', value: '+262' };
2124
+ else {
2125
+ return endpoint.api.post('/v2/templates', params, options).then((r) => r.data);
2441
2126
  }
2442
- return null;
2443
- }
2444
- function isFrenchGuiana(code) {
2445
- return '+594' === code.substring(0, 4);
2446
- }
2447
- function isGuadeloupe(code) {
2448
- return '+590' === code.substring(0, 4);
2449
- }
2450
- function isMartinique(code) {
2451
- return '+596' === code.substring(0, 4);
2452
- }
2453
- function isMayotte(code) {
2454
- return '+262' === code.substring(0, 4);
2455
- }
2456
- function getPlusOneCountry(code) {
2457
- let info = null;
2458
- switch (code.substring(0, 5)) {
2459
- case '+1684':
2460
- info = { code: '+1', name: 'American Samoa', value: '+1' };
2461
- break;
2462
- case '+1264':
2463
- info = { code: '+1', name: 'Anguilla', value: '+1' };
2464
- break;
2465
- case '+1268':
2466
- info = { code: '+1', name: 'Antigua and Barbuda', value: '+1' };
2467
- break;
2468
- case '+1242':
2469
- info = { code: '+1', name: 'Bahamas', value: '+1' };
2470
- break;
2471
- case '+1246':
2472
- info = { code: '+1', name: 'Barbados', value: '+1' };
2473
- break;
2474
- case '+1441':
2475
- info = { code: '+1', name: 'Bermuda', value: '+1' };
2476
- break;
2477
- case '+1284':
2478
- info = { code: '+1', name: 'British Virgin Islands', value: '+1' };
2479
- break;
2480
- case '+1':
2481
- info = { code: '+1', name: '', value: '+1' };
2482
- break;
2127
+ };
2128
+ /**
2129
+ * Create a template from a Sharepoint asset.
2130
+ *
2131
+ * ```typescript
2132
+ * import {Templates} from '@verdocs/js-sdk/Templates';
2133
+ *
2134
+ * const newTemplate = await Templates.createTemplateFromSharepoint((VerdocsEndpoint.getDefault(), {...});
2135
+ * ```
2136
+ */
2137
+ const createTemplateFromSharepoint = (endpoint, params) => {
2138
+ const options = {
2139
+ timeout: 120000,
2140
+ };
2141
+ return endpoint.api.post('/templates/from-sharepoint', params, options).then((r) => r.data);
2142
+ };
2143
+ /**
2144
+ * Update a template.
2145
+ *
2146
+ * ```typescript
2147
+ * import {Templates} from '@verdocs/js-sdk/Templates';
2148
+ *
2149
+ * const updatedTemplate = await Templates.updateTemplate((VerdocsEndpoint.getDefault(), '83da3d70-7857-4392-b876-c4592a304bc9', { name: 'New Name' });
2150
+ * ```
2151
+ */
2152
+ const updateTemplate = (endpoint, templateId, params) => endpoint.api //
2153
+ .put(`/templates/${templateId}`, params)
2154
+ .then((r) => r.data);
2155
+ /**
2156
+ * Delete a template.
2157
+ *
2158
+ * ```typescript
2159
+ * import {Templates} from '@verdocs/js-sdk/Templates';
2160
+ *
2161
+ * await Templates.deleteTemplate((VerdocsEndpoint.getDefault(), '83da3d70-7857-4392-b876-c4592a304bc9');
2162
+ * ```
2163
+ */
2164
+ const deleteTemplate = (endpoint, templateId) => endpoint.api //
2165
+ .delete(`/templates/${templateId}`)
2166
+ .then((r) => r.data);
2167
+ /**
2168
+ * Search for templates matching various criteria.
2169
+ *
2170
+ * ```typescript
2171
+ * import {Templates} from '@verdocs/js-sdk/Templates';
2172
+ *
2173
+ * const {result, page, total} = await Templates.search((VerdocsEndpoint.getDefault(), { ... });
2174
+ * ```
2175
+ */
2176
+ const searchTemplates = async (endpoint, params) => endpoint.api //
2177
+ .post('/templates/search', params)
2178
+ .then((r) => r.data);
2179
+ /**
2180
+ * Get a summary of template data, typically used to populate admin panel dashboard pages.
2181
+ *
2182
+ * ```typescript
2183
+ * import {Templates} from '@verdocs/js-sdk/Templates';
2184
+ *
2185
+ * const summary = await Templates.getSummary((VerdocsEndpoint.getDefault(), 0);
2186
+ * ```
2187
+ */
2188
+ const getTemplatesSummary = async (endpoint, params = {}) => endpoint.api //
2189
+ .post('/templates/summary', params)
2190
+ .then((r) => r.data);
2191
+ const cachedTemplates = {};
2192
+ /**
2193
+ * Wrapper for `getTemplate()` that limits queries to one every 2 seconds per template ID.
2194
+ * This is intended for use in component hierarchies that all rely on the same template
2195
+ * to avoid unnecessary repeat server calls.
2196
+ */
2197
+ const throttledGetTemplate = (endpoint, templateId) => {
2198
+ if (cachedTemplates[templateId] && cachedTemplates[templateId].loaded + 2000 < new Date().getTime()) {
2199
+ return cachedTemplates[templateId].template;
2483
2200
  }
2484
- return info;
2485
- }
2486
- function isCanada(code) {
2487
- const canadianAreaCodes = [
2488
- '403',
2489
- '587',
2490
- '780',
2491
- '825',
2492
- '604',
2493
- '250',
2494
- '778',
2495
- '236',
2496
- '204',
2497
- '431',
2498
- '506',
2499
- '709',
2500
- '867',
2501
- '782',
2502
- '902',
2503
- '867',
2504
- '548',
2505
- '705',
2506
- '365',
2507
- '613',
2508
- '807',
2509
- '226',
2510
- '289',
2511
- '437',
2512
- '519',
2513
- '647',
2514
- '905',
2515
- '249',
2516
- '343',
2517
- '416',
2518
- '902',
2519
- '782',
2520
- '450',
2521
- '418',
2522
- '579',
2523
- '873',
2524
- '367',
2525
- '514',
2526
- '581',
2527
- '819',
2528
- '438',
2529
- '639',
2530
- '306',
2531
- '867',
2532
- ];
2533
- const areaCode = code.substring(0, 5);
2534
- return canadianAreaCodes.findIndex((x) => '+1' + x === areaCode) > -1;
2535
- }
2536
- function isAmericanSamoa(code) {
2537
- return code.substring(0, 5) === '+1684';
2538
- }
2539
- function isDominicanRepublic(code) {
2540
- return '+1809' === code.substring(0, 5) || '+1829' === code.substring(0, 5) || '+1849' === code.substring(0, 5);
2541
- }
2542
- function isPuertoRico(code) {
2543
- return code.substring(0, 5) === '+' || code.substring(0, 5) === '+';
2544
- }
2545
- // need to finish
2546
- function getMatchingCountry(code, substrings) {
2547
- const toMatch = code.substring(0, substrings);
2548
- return Countries.filter((c) => c.code === toMatch).length;
2549
- }
2550
- // const e164Regex = new RegExp(/\+[1-9]\d{6,14}/g);
2551
- // export function simpleE164Validator(code: string) {
2552
- // return (code !== null && code.length < 16 && code.length > 6 && e164Regex.test(code)) || code === '' || code === null;
2553
- // }
2201
+ return getTemplate(endpoint, templateId).then((template) => {
2202
+ cachedTemplates[templateId] = { loaded: new Date().getTime(), template };
2203
+ return template;
2204
+ });
2205
+ };
2206
+ /**
2207
+ * List templates.
2208
+ *
2209
+ * ```typescript
2210
+ * import {Templates} from '@verdocs/js-sdk/Templates';
2211
+ *
2212
+ * const {totals, templates} = await Templates.listTemplates((VerdocsEndpoint.getDefault(), { q: 'test', sort: 'created_at' }); * ```
2213
+ */
2214
+ const listTemplates = async (endpoint, params = {}) => endpoint.api //
2215
+ .post('/templates/list', params)
2216
+ .then((r) => r.data);
2217
+
2218
+ /**
2219
+ * A TemplateDocument represents a PDF or other attachment in a Template.
2220
+ *
2221
+ * @module
2222
+ */
2223
+ /**
2224
+ * Get all the Template Documents associated to a particular Template.
2225
+ *
2226
+ * ```typescript
2227
+ * import {TemplateDocument} from '@verdocs/js-sdk/Templates';
2228
+ *
2229
+ * await TemplateDocument.geTemplateDocuments((VerdocsEndpoint.getDefault(), templateId);
2230
+ * ```
2231
+ */
2232
+ const getTemplateDocuments = (endpoint, templateId) => endpoint.api //
2233
+ .get(`/templates/${templateId}/documents/`)
2234
+ .then((r) => r.data);
2235
+ /**
2236
+ * Get a specific Document.
2237
+ *
2238
+ * ```typescript
2239
+ * import {TemplateDocument} from '@verdocs/js-sdk/Templates';
2240
+ *
2241
+ * await TemplateDocument.geTemplateDocument((VerdocsEndpoint.getDefault(), templateId,documentId);
2242
+ * ```
2243
+ */
2244
+ const getTemplateDocument = (endpoint, templateId, documentId) => endpoint.api //
2245
+ .get(`/templates/${templateId}/documents/${documentId}`)
2246
+ .then((r) => r.data);
2247
+ /**
2248
+ * Create a Document for a particular Template.
2249
+ *
2250
+ * ```typescript
2251
+ * import {TemplateDocument} from '@verdocs/js-sdk/Templates';
2252
+ *
2253
+ * await TemplateDocument.createDocument((VerdocsEndpoint.getDefault(), templateID, params);
2254
+ * ```
2255
+ */
2256
+ const createTemplateDocument = (endpoint, templateId, file, onUploadProgress) => {
2257
+ const formData = new FormData();
2258
+ formData.append('document', file, file.name);
2259
+ return endpoint.api //
2260
+ .post(`/templates/${templateId}/documents`, formData, {
2261
+ timeout: 120000,
2262
+ onUploadProgress: (event) => {
2263
+ const total = event.total || 1;
2264
+ const loaded = event.loaded || 0;
2265
+ onUploadProgress?.(Math.floor((loaded * 100) / (total || 1)), loaded, total || 1);
2266
+ },
2267
+ })
2268
+ .then((r) => r.data);
2269
+ };
2270
+ /**
2271
+ * Delete a specific Document.
2272
+ *
2273
+ * ```typescript
2274
+ * import {TemplateDocument} from '@verdocs/js-sdk/Templates';
2275
+ *
2276
+ * await TemplateDocument.deleteDocument((VerdocsEndpoint.getDefault(), templateID, documentID);
2277
+ * ```
2278
+ */
2279
+ const deleteTemplateDocument = (endpoint, templateId, documentId) => endpoint.api //
2280
+ .delete(`/templates/${templateId}/documents/${documentId}`)
2281
+ .then((r) => r.data);
2282
+ /**
2283
+ * Get (binary download) a file attached to a Template. It is important to use this method
2284
+ * rather than a direct A HREF or similar link to set the authorization headers for the
2285
+ * request.
2286
+ */
2287
+ const getTemplateDocumentFile = async (endpoint, templateId, documentId) => endpoint.api //
2288
+ .get(`/templates/${templateId}/documents/${documentId}?file=true`, { responseType: 'blob' })
2289
+ .then((r) => r.data);
2290
+ /**
2291
+ * Get (binary download) a file attached to a Template. It is important to use this method
2292
+ * rather than a direct A HREF or similar link to set the authorization headers for the
2293
+ * request.
2294
+ */
2295
+ const getTemplateDocumentThumbnail = async (endpoint, templateId, documentId) => endpoint.api //
2296
+ .get(`/templates/${templateId}/documents/${documentId}?thumbnail=true`, { responseType: 'blob' })
2297
+ .then((r) => r.data);
2298
+ /**
2299
+ * Get a display URI for a given page in a file attached to a template document. These pages are rendered server-side
2300
+ * into PNG resources suitable for display in IMG tags although they may be used elsewhere. Note that these are intended
2301
+ * for DISPLAY ONLY, are not legally binding documents, and do not contain any encoded metadata from participants. The
2302
+ * original asset may be obtained by calling `getTemplateDocumentFile()` or similar.
2303
+ */
2304
+ const getTemplateDocumentPageDisplayUri = async (endpoint, templateId, documentId, page) => endpoint.api.get(`/templates/${templateId}/documents/${documentId}/pages/${page}/image`).then((r) => r.data);
2305
+
2306
+ /**
2307
+ * Get all defined validators
2308
+ *
2309
+ * ```typescript
2310
+ * import {Documents} from '@verdocs/js-sdk/Templates';
2311
+ *
2312
+ * await Documents.getDocuments(templateID);
2313
+ * ```
2314
+ */
2315
+ const getValidators = (endpoint) => endpoint.api //
2316
+ .get('/validators')
2317
+ .then((r) => r.data);
2318
+ const getValidator = (endpoint, validatorName) => endpoint.api //
2319
+ .get(`/validators/${validatorName}`)
2320
+ .then((r) => r.data);
2321
+ const EMAIL_REGEX = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
2322
+ const isValidEmail = (email) => !!email && EMAIL_REGEX.test(email);
2323
+ // @see https://www.regextester.com/1978
2324
+ const PHONE_REGEX = /((?:\+|00)[17](?: |\-)?|(?:\+|00)[1-9]\d{0,2}(?: |\-)?|(?:\+|00)1\-\d{3}(?: |\-)?)?(0\d|\([0-9]{3}\)|[1-9]{0,3})(?:((?: |\-)[0-9]{2}){4}|((?:[0-9]{2}){4})|((?: |\-)[0-9]{3}(?: |\-)[0-9]{4})|([0-9]{7}))/;
2325
+ const isValidPhone = (phone) => !!phone && PHONE_REGEX.test(phone);
2326
+ const isValidRoleName = (value, roles) => roles.findIndex((role) => role.name === value) !== -1;
2327
+ const TagRegEx = /^[a-zA-Z0-9-]{0,32}$/;
2328
+ const isValidTag = (value, tags) => TagRegEx.test(value) || tags.findIndex((tag) => tag === value) !== -1;
2554
2329
 
2555
2330
  /**
2556
- * Capitalize the first letter of a string.
2331
+ * Authenticate to Verdocs via user/password authentication
2332
+ *
2333
+ * ```typescript
2334
+ * import {Auth} from '@verdocs/js-sdk/Auth';
2335
+ * import {Transport} from '@verdocs/js-sdk/HTTP';
2336
+ *
2337
+ * const {accessToken} = await Auth.authenticateUser({ username: 'test@test.com', password: 'PASSWORD' });
2338
+ * Transport.setAuthToken(accessToken);
2339
+ * ```
2340
+ */
2341
+ const authenticateUser = (endpoint, params) => endpoint.api //
2342
+ .post('/authentication/login', params)
2343
+ .then((r) => r.data);
2344
+ /**
2345
+ * Authenticate to Verdocs via client ID / Secret authentication. **NOTE: This is only suitable for
2346
+ * NodeJS server-side applications. Never expose your Client Secret in a Web or Mobile app!** Also note
2347
+ * that access tokens may be cached by server-side apps (and this is recommended) but do expire after 2
2348
+ * hours. This expiration may change based on future security needs. Application developers are encouraged
2349
+ * to check the `exp` expiration field in the response accessToken and renew tokens after they expire.
2350
+ *
2351
+ * ```typescript
2352
+ * import {Auth} from '@verdocs/js-sdk/Auth';
2353
+ * import {Transport} from '@verdocs/js-sdk/HTTP';
2354
+ *
2355
+ * const {accessToken} = await Auth.authenticateApp({ client_id: 'CLIENTID', client_secret: 'SECRET' });
2356
+ * Transport.setAuthToken(accessToken);
2357
+ * ```
2358
+ */
2359
+ const authenticateApp = (endpoint, params) => endpoint.api //
2360
+ .post('/authentication/login_client', {}, { headers: params })
2361
+ .then((r) => r.data);
2362
+ /**
2363
+ * Validate a token. Only Verdocs tokens will be accepted. Most applications can decode tokens locally,
2364
+ * because tokens will be validated when API calls are made anyway. However, high-security applications
2365
+ * may use this endpoint to check if a token has been revoked.
2366
+ *
2367
+ * ```typescript
2368
+ * import {Auth} from '@verdocs/js-sdk/Auth';
2369
+ *
2370
+ * const {valid} = await Auth.validateToken({ token });
2371
+ * if (!valid) {
2372
+ * window.alert('Session invalid or expired. Please re-authenticate.');
2373
+ * }
2374
+ * ```
2375
+ */
2376
+ const validateToken = (endpoint, params) => endpoint.api //
2377
+ .post('/token/isValid', params)
2378
+ .then((r) => r.data);
2379
+ /**
2380
+ * If called before the session expires, this will refresh the caller's session and tokens.
2381
+ *
2382
+ * ```typescript
2383
+ * import {Auth} from '@verdocs/js-sdk/Auth';
2384
+ * import {Transport} from '@verdocs/js-sdk/HTTP';
2385
+ *
2386
+ * const {accessToken} = await Auth.refreshTokens();
2387
+ * Transport.setAuthToken(accessToken);
2388
+ * ```
2389
+ */
2390
+ const refreshTokens = (endpoint) => endpoint.api //
2391
+ .get('/token')
2392
+ .then((r) => r.data);
2393
+ /**
2394
+ * Update the caller's password. To help prevent CSRF attack vectors, the user's old password and email address are required.
2395
+ *
2396
+ * ```typescript
2397
+ * import {Auth} from '@verdocs/js-sdk/Auth';
2398
+ *
2399
+ * const {status, message} = await Auth.updatePassword({ email, oldPassword, newPassword });
2400
+ * if (status !== 'OK') {
2401
+ * window.alert(`Password reset error: ${message}`);
2402
+ * }
2403
+ * ```
2557
2404
  */
2558
- const capitalize = (str) => str.charAt(0).toUpperCase() + str.slice(1);
2405
+ const updatePassword = (endpoint, params) => endpoint.api //
2406
+ .put('/user/update_password', params)
2407
+ .then((r) => r.data);
2559
2408
  /**
2560
- * Convert a phone-number-like string to E164 format.
2561
- * @see https://46elks.com/kb/e164
2409
+ * Reset the caller's password.
2410
+ *
2411
+ * ```typescript
2412
+ * import {Auth} from '@verdocs/js-sdk/Auth';
2413
+ *
2414
+ * const {success} = await Auth.resetPassword({ email });
2415
+ * if (status !== 'OK') {
2416
+ * window.alert(`Please check your email for instructions on how to reset your password.`);
2417
+ * }
2418
+ * ```
2562
2419
  */
2563
- const convertToE164 = (input) => {
2564
- // "(212) 555-1212" => +12125551212
2565
- // "+46766861004" => "+46766861004"
2566
- // "212-555-1212" => +12125551212
2567
- // "212.555.1212" => +12125551212
2568
- // "212 555 1212" => +12125551212
2569
- let temp = (input || '').trim();
2570
- // If we are already prefixed, assume the user did it deliberately and attempt to use what they entered. We also short-circuit blanks.
2571
- if (!temp || temp.startsWith('+')) {
2572
- return temp;
2573
- }
2574
- // Remove any spaces, parenthesis or other punctuation.
2575
- temp = temp.replace(/[^0-9]/g, '');
2576
- // If the number begins with a zero, remove the leading zero. Do not combine this with the previous step because it needs to be removed
2577
- // whether it's the actual first character e.g. `0(5)` or just the first digit e.g. `(05`.
2578
- temp = temp.replace(/^0/g, '');
2579
- // Prepend the country code and +. We're assuming US in this case given the target demographic. Users in other countries would/should be
2580
- // already entering a prefix so they'd shortcut out of this routine via the + prefix check.
2581
- return `+1${temp}`;
2582
- };
2420
+ const resetPassword = (endpoint, params) => endpoint.api //
2421
+ .post('/user/reset_password', params)
2422
+ .then((r) => r.data);
2423
+ /**
2424
+ * Update the caller's email address.
2425
+ *
2426
+ * ```typescript
2427
+ * import {Auth} from '@verdocs/js-sdk/Auth';
2428
+ *
2429
+ * const {profiles} = await Auth.updateEmail({ email: newEmail });
2430
+ * ```
2431
+ */
2432
+ const updateEmail = (endpoint, params) => endpoint.api //
2433
+ .put('/user/update_email', params)
2434
+ .then((r) => r.data);
2435
+ /**
2436
+ * Resend the email verification request. Note that to prevent certain forms of abuse, the email address is not
2437
+ * a parameter here. Instead, the caller must be authenticated as the (unverified) user. To simplify this process,
2438
+ * the access token to be used may be passed directly as a parameter here. This avoids the need to set it as the
2439
+ * active token on an endpoint, which may be inconvenient in workflows where it is preferable to keep the user in
2440
+ * "anonymous" mode while verification is being performed.
2441
+ *
2442
+ * ```typescript
2443
+ * import {Auth} from '@verdocs/js-sdk/Auth';
2444
+ *
2445
+ * const result = await Auth.resendVerification();
2446
+ * ```
2447
+ */
2448
+ const resendVerification = (endpoint, accessToken) => endpoint.api //
2449
+ .post('/user/email_verification', {}, accessToken ? { headers: { Authorization: `Bearer ${accessToken}` } } : {})
2450
+ .then((r) => r.data);
2451
+ const createUser = (endpoint, params) => endpoint.api //
2452
+ .post('/user', params)
2453
+ .then((r) => r.data);
2454
+
2455
+ // TODO
2456
+ const billingPlaceholder = {};
2457
+
2458
+ const getNotifications = async (endpoint) => endpoint.api //
2459
+ .get('/notifications')
2460
+ .then((r) => r.data);
2583
2461
 
2584
2462
  /**
2585
- * Create an array containing a sequence of integers, e.g. [START, START+1, START+2, ...] This is frequently useful
2586
- * in rendering operations when there is no source array to .map() across.
2463
+ * Get the user's available profiles. The current profile will be marked with `current: true`.
2464
+ *
2465
+ * ```typescript
2466
+ * import {Profiles} from '@verdocs/js-sdk/Users';
2467
+ *
2468
+ * const profiles = await Profiles.getProfiles()
2469
+ * ```
2587
2470
  */
2588
- const integerSequence = (start, count) => Array(count)
2589
- .fill(1)
2590
- .map((_, index) => index + start);
2471
+ const getProfiles = (endpoint) => endpoint.api //
2472
+ .get('/profiles')
2473
+ .then((r) => r.data);
2591
2474
  /**
2592
- * Format a profile's full name
2475
+ * Get the user's available profiles. The current profile will be marked with `current: true`.
2476
+ *
2477
+ * ```typescript
2478
+ * import {Profiles} from '@verdocs/js-sdk/Users';
2479
+ *
2480
+ * const profiles = await Profiles.getCurrentProfile()
2481
+ * ```
2593
2482
  */
2594
- const formatFullName = (profile) => profile ? `${capitalize(profile.first_name)} ${capitalize(profile.last_name)}` : 'Invalid User';
2483
+ const getCurrentProfile = (endpoint) => endpoint.api //
2484
+ .get('/profiles')
2485
+ .then((r) => (r.data || []).find((profile) => profile.current));
2595
2486
  /**
2596
- * Format a profile's initials
2487
+ * Get a list of system roles.
2488
+ *
2489
+ * ```typescript
2490
+ * import {Profiles} from '@verdocs/js-sdk/Users';
2491
+ *
2492
+ * const roles = await Profiles.getRoles();
2493
+ * ```
2597
2494
  */
2598
- const formatInitials = (profile) => profile ? `${capitalize(profile.first_name).charAt(0)} ${capitalize(profile.last_name).charAt(0)}` : '--';
2495
+ const getRoles = (endpoint) => endpoint.api //
2496
+ .get('/roles')
2497
+ .then((r) => r.data);
2599
2498
  /**
2600
- * Generate suggested initials for a full name, e.g. "John Doe" will yield "JD".
2499
+ * Get a list of system roles.
2500
+ *
2501
+ * ```typescript
2502
+ * import {Profiles} from '@verdocs/js-sdk/Users';
2503
+ *
2504
+ * const permissions = await Profiles.getPermissions();
2505
+ * ```
2601
2506
  */
2602
- const fullNameToInitials = (name) => name
2603
- .split(' ')
2604
- .map((word) => word[0])
2605
- .join('');
2507
+ const getPermissions = (endpoint) => endpoint.api //
2508
+ .get('/permissions')
2509
+ .then((r) => r.data);
2510
+ /**
2511
+ * Create a profile. If the caller does not have a "current" profile set, the new profile will be made current.
2512
+ *
2513
+ * ```typescript
2514
+ * import {Profiles} from '@verdocs/js-sdk/Users';
2515
+ *
2516
+ * const newProfile = await Profiles.createProfile({ first_name: 'FIRST', last_name: 'LAST', email: 'EMAIL' });
2517
+ * ```
2518
+ */
2519
+ const createProfile = (endpoint, params) => endpoint.api //
2520
+ .post('/profiles', params)
2521
+ .then((r) => r.data);
2522
+ /**
2523
+ * Get a profile. The caller must have admin access to the given profile.
2524
+ * TODO: Add a "public" profile endpoint for public pages
2525
+ *
2526
+ * ```typescript
2527
+ * import {Profiles} from '@verdocs/js-sdk/Users';
2528
+ *
2529
+ * const profile = await Profiles.getProfile('PROFILEID');
2530
+ * ```
2531
+ */
2532
+ const getProfile = (endpoint, profileId) => endpoint.api //
2533
+ .get(`/profiles/${profileId}`)
2534
+ .then((r) => r.data);
2535
+ /**
2536
+ * Get a profile's permissions. The caller must have admin access to the given profile.
2537
+ *
2538
+ * ```typescript
2539
+ * import {Profiles} from '@verdocs/js-sdk/Users';
2540
+ *
2541
+ * const permissions = await Profiles.getProfilePermissions('PROFILEID');
2542
+ * ```
2543
+ */
2544
+ const getProfilePermissions = (endpoint, profileId) => endpoint.api //
2545
+ .get(`/profiles/${profileId}/permissions`)
2546
+ .then((r) => r.data);
2547
+ /**
2548
+ * Get a profile's groups.
2549
+ *
2550
+ * ```typescript
2551
+ * import {Profiles} from '@verdocs/js-sdk/Users';
2552
+ *
2553
+ * const groups = await Profiles.getProfileGroups('PROFILEID');
2554
+ * ```
2555
+ */
2556
+ const getProfileGroups = (endpoint, profileId) => endpoint.api //
2557
+ .get(`/profiles/${profileId}/groups`)
2558
+ .then((r) => r.data);
2559
+ /**
2560
+ * Switch the caller's "current" profile. The current profile is used for permissions checking and profile_id field settings
2561
+ * for most operations in Verdocs. It is important to select the appropropriate profile before calling other API functions.
2562
+ *
2563
+ * ```typescript
2564
+ * import {Profiles} from '@verdocs/js-sdk/Users';
2565
+ *
2566
+ * const newProfile = await Profiles.switchProfile('PROFILEID');
2567
+ * ```
2568
+ */
2569
+ const switchProfile = (endpoint, profileId) => endpoint.api //
2570
+ .post(`/profiles/${profileId}/switch`)
2571
+ .then((r) => r.data);
2572
+ /**
2573
+ * Update a profile. For future expansion, the profile ID to update is required, but currently this must also be the
2574
+ * "current" profile for the caller.
2575
+ *
2576
+ * ```typescript
2577
+ * import {Profiles} from '@verdocs/js-sdk/Users';
2578
+ *
2579
+ * const newProfile = await Profiles.updateProfile('PROFILEID');
2580
+ * ```
2581
+ */
2582
+ const updateProfile = (endpoint, profileId, params) => endpoint.api //
2583
+ .put(`/profiles/${profileId}`, params)
2584
+ .then((r) => r.data);
2585
+ /**
2586
+ * Delete a profile. If the requested profile is the caller's curent profile, the next available profile will be selected.
2587
+ *
2588
+ * ```typescript
2589
+ * import {Profiles} from '@verdocs/js-sdk/Users';
2590
+ *
2591
+ * await Profiles.deleteProfile('PROFILEID');
2592
+ * ```
2593
+ */
2594
+ const deleteProfile = (endpoint, profileId) => endpoint.api //
2595
+ .delete(`/profiles/${profileId}`)
2596
+ .then((r) => r.data);
2597
+ /**
2598
+ * Create a user account and parent organization. This endpoint is for creating a new organization. Users joining an
2599
+ * existing organization should be invited, and follow their invitation links/instructions to create their accounts.
2600
+ *
2601
+ * ```typescript
2602
+ * import {Profiles} from '@verdocs/js-sdk/Users';
2603
+ *
2604
+ * const newAccount = await Profiles.createBusinessAccount({
2605
+ * orgName: 'ORG', email: 'a@b.com', password: '12345678', firstName: 'FIRST', lastName: 'LAST'
2606
+ * });
2607
+ * ```
2608
+ */
2609
+ const createBusinessAccount = (endpoint, params) => endpoint.api //
2610
+ .post('/user/business', params)
2611
+ .then((r) => r.data);
2612
+ const recordSignupSurvey = (endpoint, params) => endpoint.api //
2613
+ .post('/user/signup', params)
2614
+ .then((r) => r.data);
2606
2615
 
2607
- export { AtoB, Countries, VerdocsEndpoint, acceptOrganizationInvitation, addGroupMembers, addGroupPermission, addOrganizationMemberRole, addTemplateTag, authenticateApp, authenticateUser, billingPlaceholder, blobToBase64, canPerformTemplateAction, cancelEnvelope, capitalize, claimNewUser, convertToE164, createApiKey, createBusinessAccount, createEnvelope, createEnvelopeReminder, createField, createInitials, createOrganization, createOrganizationInvitation, createProfile, createSignature, createTag, createTemplate, createTemplateDocument, createTemplateFromSharepoint, createTemplateReminder, createTemplateRole, createTemplatev2, createUser, declineOrganizationInvitation, decodeAccessTokenBody, decodeJWTBody, deleteApiKey, deleteEnvelopeFieldAttachment, deleteEnvelopeReminder, deleteField, deleteGroupMembers, deleteGroupPermission, deleteOrganization, deleteOrganizationInvitation, deleteOrganizationMember, deleteOrganizationMemberRole, deleteProfile, deleteSignature, deleteTemplate, deleteTemplateDocument, deleteTemplateReminder, deleteTemplateRole, deleteTemplateTag, downloadBlob, envelopeIsActive, envelopeIsComplete, envelopeRecipientAgree, envelopeRecipientChangeOwner, envelopeRecipientDecline, envelopeRecipientPrepare, envelopeRecipientSubmit, envelopeRecipientUpdateName, fileToDataUrl, formatFullName, formatInitials, formatShortTimeAgo, fullNameToInitials, getAllTags, getApiKeys, getCountryByCode, getCurrentProfile, getDocumentDownloadLink, getDocumentPreviewLink, getEnvelope, getEnvelopeDocument, getEnvelopeDocumentPageDisplayUri, getEnvelopeFile, getEnvelopeRecipients, getEnvelopeReminder, getEnvelopesSummary, getFieldAttachment, getGroup, getGroupByName, getGroupMembers, getGroups, getInPersonLink, getMatchingCountry, getNextRecipient, getNotifications, getOrganization, getOrganizationInvitation, getOrganizationInvitations, getOrganizationMemberPlans, getOrganizationMembers, getOrganizations, getPermissions, getPlusOneCountry, getProfile, getProfileGroups, getProfilePermissions, getProfiles, getRGB, getRGBA, getRLeft, getRTop, getRValue, getRecipientsWithActions, getRoleColor, getRoles, getSignature, getSignatures, getSignerToken, getSigningSession, getStars, getTag, getTemplate, getTemplateDocument, getTemplateDocumentFile, getTemplateDocumentPageDisplayUri, getTemplateDocumentThumbnail, getTemplateDocuments, getTemplateOwnerInfo, getTemplateReminder, getTemplateRole, getTemplateRoleFields, getTemplateRoles, getTemplateTags, getTemplates, getTemplatesSummary, getValidator, getValidators, getWebhooks, hasRequiredPermissions, integerSequence, isAmericanSamoa, isCanada, isDominicanRepublic, isFrenchGuiana, isGuadeloupe, isMartinique, isMayotte, isPuertoRico, isValidEmail, isValidPhone, isValidRoleName, isValidTag, listEnvelopes, listTemplates, nameToRGBA, recipientCanAct, recipientHasAction, recordSignupSurvey, refreshTokens, rescale, resendInvitation, resendOrganizationInvitation, resendVerification, resetPassword, rotateApiKey, searchEnvelopes, searchTemplates, sendDelegate, setWebhooks, switchProfile, throttledGetEnvelope, throttledGetTemplate, timePeriod, toggleStar, updateApiKey, updateEmail, updateEnvelopeField, updateEnvelopeFieldInitials, updateEnvelopeFieldSignature, updateEnvelopeReminder, updateField, updateOrganization, updateOrganizationInvitation, updatePassword, updateProfile, updateRecipient, updateTemplate, updateTemplateReminder, updateTemplateRole, uploadEnvelopeFieldAttachment, userCanAct, userCanCancelEnvelope, userCanFinishEnvelope, userCanSignNow, userHasPermissions, userIsEnvelopeOwner, userIsEnvelopeRecipient, validateToken };
2616
+ export { AtoB, Countries, VerdocsEndpoint, acceptOrganizationInvitation, addGroupMembers, addGroupPermission, addOrganizationMemberRole, addTemplateTag, authenticateApp, authenticateUser, billingPlaceholder, blobToBase64, canPerformTemplateAction, cancelEnvelope, capitalize, claimNewUser, convertToE164, createApiKey, createBusinessAccount, createEnvelope, createEnvelopeReminder, createField, createInitials, createOrganization, createOrganizationInvitation, createProfile, createSignature, createTag, createTemplate, createTemplateDocument, createTemplateFromSharepoint, createTemplateReminder, createTemplateRole, createTemplatev2, createUser, declineOrganizationInvitation, decodeAccessTokenBody, decodeJWTBody, deleteApiKey, deleteEnvelopeFieldAttachment, deleteEnvelopeReminder, deleteField, deleteGroupMembers, deleteGroupPermission, deleteOrganization, deleteOrganizationInvitation, deleteOrganizationMember, deleteOrganizationMemberRole, deleteProfile, deleteSignature, deleteTemplate, deleteTemplateDocument, deleteTemplateReminder, deleteTemplateRole, deleteTemplateTag, downloadBlob, envelopeIsActive, envelopeIsComplete, envelopeRecipientAgree, envelopeRecipientChangeOwner, envelopeRecipientDecline, envelopeRecipientPrepare, envelopeRecipientSubmit, envelopeRecipientUpdateName, fileToDataUrl, formatFullName, formatInitials, formatShortTimeAgo, fullNameToInitials, getAllTags, getApiKeys, getCountryByCode, getCurrentProfile, getDocumentDownloadLink, getDocumentPreviewLink, getEnvelope, getEnvelopeDocument, getEnvelopeDocumentPageDisplayUri, getEnvelopeFile, getEnvelopeRecipients, getEnvelopeReminder, getEnvelopesByTemplateId, getEnvelopesSummary, getFieldAttachment, getGroup, getGroupByName, getGroupMembers, getGroups, getInPersonLink, getMatchingCountry, getNextRecipient, getNotifications, getOrganization, getOrganizationInvitation, getOrganizationInvitations, getOrganizationMemberPlans, getOrganizationMembers, getOrganizations, getPermissions, getPlusOneCountry, getProfile, getProfileGroups, getProfilePermissions, getProfiles, getRGB, getRGBA, getRLeft, getRTop, getRValue, getRecipientsWithActions, getRoleColor, getRoles, getSignature, getSignatures, getSignerToken, getSigningSession, getStars, getTag, getTemplate, getTemplateDocument, getTemplateDocumentFile, getTemplateDocumentPageDisplayUri, getTemplateDocumentThumbnail, getTemplateDocuments, getTemplateOwnerInfo, getTemplateReminder, getTemplateRole, getTemplateRoleFields, getTemplateRoles, getTemplateTags, getTemplates, getTemplatesSummary, getValidator, getValidators, getWebhooks, hasRequiredPermissions, integerSequence, isAmericanSamoa, isCanada, isDominicanRepublic, isFrenchGuiana, isGuadeloupe, isMartinique, isMayotte, isPuertoRico, isValidEmail, isValidPhone, isValidRoleName, isValidTag, listEnvelopes, listTemplates, nameToRGBA, recipientCanAct, recipientHasAction, recordSignupSurvey, refreshTokens, rescale, resendInvitation, resendOrganizationInvitation, resendVerification, resetPassword, rotateApiKey, searchEnvelopes, searchTemplates, sendDelegate, setWebhooks, switchProfile, throttledGetEnvelope, throttledGetTemplate, timePeriod, toggleStar, updateApiKey, updateEmail, updateEnvelopeField, updateEnvelopeFieldInitials, updateEnvelopeFieldSignature, updateEnvelopeReminder, updateField, updateOrganization, updateOrganizationInvitation, updatePassword, updateProfile, updateRecipient, updateTemplate, updateTemplateReminder, updateTemplateRole, uploadEnvelopeFieldAttachment, userCanAct, userCanCancelEnvelope, userCanFinishEnvelope, userCanSignNow, userHasPermissions, userIsEnvelopeOwner, userIsEnvelopeRecipient, validateToken };
2608
2617
  //# sourceMappingURL=index.mjs.map