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