crexperium-sdk 1.2.5 → 1.2.7

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.js CHANGED
@@ -18,7 +18,7 @@ class Config {
18
18
  this.apiToken = options.apiToken;
19
19
  }
20
20
  // Set defaults
21
- this.baseUrl = options.baseUrl || 'https://crxperium.applikuapp.com';
21
+ this.baseUrl = options.baseUrl || 'https://budget-api-s366in24na-uc.a.run.app';
22
22
  this.timeout = options.timeout ?? 30000; // 30 seconds
23
23
  this.maxRetries = options.maxRetries ?? 3;
24
24
  this.retryDelay = options.retryDelay ?? 1000; // 1 second
@@ -453,53 +453,134 @@ class ContactsResource extends BaseResource {
453
453
  /**
454
454
  * Identify a contact (create or update by multiple identifiers)
455
455
  *
456
- * Accepts at least ONE of: externalId, visitorId, email, or phone
456
+ * Accepts at least ONE of: externalId, visitorId, email, phone, emailAddresses, or phoneNumbers
457
457
  * Priority: externalId > visitorId > email > phone
458
458
  *
459
+ * When creating a new contact, at least one of email/emailAddresses OR phone/phoneNumbers is required.
460
+ * All name fields are optional.
461
+ *
459
462
  * @example
460
- * // Identify by external ID (after login)
463
+ * // Identify by email only
461
464
  * await client.contacts.identify({
462
- * externalId: 'user_123',
463
- * email: 'user@example.com',
464
- * firstName: 'John'
465
+ * email: 'user@example.com'
465
466
  * });
466
467
  *
467
468
  * @example
468
- * // Identify by visitor ID (anonymous → known)
469
+ * // Identify by phone only
469
470
  * await client.contacts.identify({
470
- * visitorId: client.visitorId.getVisitorId(),
471
- * email: 'user@example.com'
471
+ * phone: '+1234567890',
472
+ * firstName: 'John'
472
473
  * });
473
474
  *
474
475
  * @example
475
- * // Identify by email only
476
+ * // Identify with multiple emails/phones
476
477
  * await client.contacts.identify({
477
- * email: 'user@example.com',
478
- * firstName: 'John'
478
+ * externalId: 'user_123',
479
+ * emailAddresses: ['user@example.com', 'alt@example.com'],
480
+ * phoneNumbers: ['+1234567890']
479
481
  * });
480
482
  *
481
483
  * @example
482
- * // Identify by phone only
484
+ * // Identify by visitor ID (anonymous → known)
483
485
  * await client.contacts.identify({
484
- * phone: '+1234567890'
486
+ * visitorId: client.visitorId.getVisitorId(),
487
+ * email: 'user@example.com'
485
488
  * });
486
489
  */
487
490
  async identify(options) {
488
491
  // Validate that at least one identifier is provided
489
- if (!options.externalId && !options.visitorId && !options.email && !options.phone) {
490
- throw new Error('At least one identifier is required: externalId, visitorId, email, or phone');
492
+ const hasIdentifier = !!(options.externalId ||
493
+ options.visitorId ||
494
+ options.email ||
495
+ options.phone ||
496
+ (options.emailAddresses && options.emailAddresses.length > 0) ||
497
+ (options.phoneNumbers && options.phoneNumbers.length > 0));
498
+ if (!hasIdentifier) {
499
+ throw new Error('At least one identifier is required: externalId, visitorId, email, phone, emailAddresses, or phoneNumbers');
500
+ }
501
+ // Build email_addresses array
502
+ const emailAddresses = [...(options.emailAddresses || [])];
503
+ if (options.email && !emailAddresses.includes(options.email)) {
504
+ emailAddresses.unshift(options.email); // Primary email goes first
505
+ }
506
+ // Build phone_numbers array
507
+ const phoneNumbers = [...(options.phoneNumbers || [])];
508
+ if (options.phone && !phoneNumbers.includes(options.phone)) {
509
+ phoneNumbers.unshift(options.phone); // Primary phone goes first
510
+ }
511
+ // Build request data
512
+ const data = {
513
+ ...this.toSnakeCase(options),
514
+ email_addresses: emailAddresses.length > 0 ? emailAddresses : undefined,
515
+ phone_numbers: phoneNumbers.length > 0 ? phoneNumbers : undefined,
516
+ };
517
+ // Remove single email/phone since they're now in arrays
518
+ if (emailAddresses.length > 0) {
519
+ delete data.email;
491
520
  }
492
- const data = this.cleanObject(this.toSnakeCase(options));
493
- return this.http.post('/api/v1/contacts/identify/', data);
521
+ if (phoneNumbers.length > 0) {
522
+ delete data.phone;
523
+ }
524
+ const cleanedData = this.cleanObject(data);
525
+ return this.http.post('/api/v1/contacts/identify/', cleanedData);
494
526
  }
495
527
  /**
496
528
  * Create a new contact
529
+ *
530
+ * At least one of email/emailAddresses OR phone/phoneNumbers is required.
531
+ * All name fields (firstName, lastName) are optional.
532
+ *
533
+ * @example
534
+ * // Create with email only
535
+ * await client.contacts.create({
536
+ * email: 'user@example.com'
537
+ * });
538
+ *
539
+ * @example
540
+ * // Create with phone only
541
+ * await client.contacts.create({
542
+ * phone: '+1234567890',
543
+ * firstName: 'John'
544
+ * });
545
+ *
546
+ * @example
547
+ * // Create with multiple emails/phones
548
+ * await client.contacts.create({
549
+ * emailAddresses: ['user@example.com', 'alt@example.com'],
550
+ * phoneNumbers: ['+1234567890'],
551
+ * firstName: 'Jane',
552
+ * lastName: 'Doe'
553
+ * });
497
554
  */
498
555
  async create(data) {
499
- if (!data.email && !data.external_id) {
500
- throw new Error('Either email or external_id is required');
556
+ // Build email_addresses array
557
+ const emailAddresses = [...(data.emailAddresses || [])];
558
+ if (data.email && !emailAddresses.includes(data.email)) {
559
+ emailAddresses.unshift(data.email);
560
+ }
561
+ // Build phone_numbers array
562
+ const phoneNumbers = [...(data.phoneNumbers || [])];
563
+ if (data.phone && !phoneNumbers.includes(data.phone)) {
564
+ phoneNumbers.unshift(data.phone);
565
+ }
566
+ // Validate at least one contact method
567
+ if (emailAddresses.length === 0 && phoneNumbers.length === 0) {
568
+ throw new Error('At least one contact method is required: provide either email/emailAddresses or phone/phoneNumbers');
569
+ }
570
+ // Build request data
571
+ const requestData = {
572
+ ...this.toSnakeCase(data),
573
+ email_addresses: emailAddresses.length > 0 ? emailAddresses : undefined,
574
+ phone_numbers: phoneNumbers.length > 0 ? phoneNumbers : undefined,
575
+ };
576
+ // Remove single email/phone since they're now in arrays
577
+ if (emailAddresses.length > 0) {
578
+ delete requestData.email;
501
579
  }
502
- const cleanedData = this.cleanObject(this.toSnakeCase(data));
580
+ if (phoneNumbers.length > 0) {
581
+ delete requestData.phone;
582
+ }
583
+ const cleanedData = this.cleanObject(requestData);
503
584
  return this.http.post('/api/v1/contacts/', cleanedData);
504
585
  }
505
586
  /**