@aglyn/aglyn 1.0.0-beta.151 → 1.0.0-beta.153
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/package.json +10 -10
- package/src/lib/app-utils/crm-csv.d.ts +10 -3
- package/src/lib/app-utils/crm-csv.js +37 -2
- package/src/lib/app-utils/crm-csv.js.map +1 -1
- package/src/lib/app-utils/crm-email-templates.js +15 -0
- package/src/lib/app-utils/crm-email-templates.js.map +1 -1
- package/src/lib/app-utils/crm.d.ts +69 -2
- package/src/lib/app-utils/crm.js +126 -1
- package/src/lib/app-utils/crm.js.map +1 -1
- package/src/lib/app-utils/docs-help.generated.d.ts +1 -1
- package/src/lib/app-utils/docs-help.generated.js +2 -0
- package/src/lib/app-utils/docs-help.generated.js.map +1 -1
- package/src/lib/app-utils/docs-index.generated.js +30 -16
- package/src/lib/app-utils/docs-index.generated.js.map +1 -1
- package/src/lib/app-utils/email-starter-policy.js +5 -3
- package/src/lib/app-utils/email-starter-policy.js.map +1 -1
- package/src/lib/app-utils/notifications.d.ts +11 -0
- package/src/lib/app-utils/notifications.js +11 -1
- package/src/lib/app-utils/notifications.js.map +1 -1
- package/src/lib/app-utils/plan-entitlements.d.ts +34 -0
- package/src/lib/app-utils/plan-entitlements.js +40 -0
- package/src/lib/app-utils/plan-entitlements.js.map +1 -1
- package/src/lib/app-utils/server.d.ts +0 -1
- package/src/lib/app-utils/server.js +0 -1
- package/src/lib/app-utils/server.js.map +1 -1
- package/src/lib/plugin-manager/first-party-plugins.generated.js +1 -0
- package/src/lib/plugin-manager/first-party-plugins.generated.js.map +1 -1
- package/src/lib/plugin-manager/plugin-artifact-inventory.d.ts +145 -0
- package/src/lib/plugin-manager/plugin-artifact-inventory.js +126 -0
- package/src/lib/plugin-manager/plugin-artifact-inventory.js.map +1 -0
- package/src/lib/plugin-manager/plugin-contact-capture.d.ts +32 -1
- package/src/lib/plugin-manager/plugin-contact-capture.js.map +1 -1
- package/src/lib/plugin-manager/plugin-lead-conversion.d.ts +67 -0
- package/src/lib/plugin-manager/plugin-lead-conversion.js +93 -0
- package/src/lib/plugin-manager/plugin-lead-conversion.js.map +1 -0
- package/src/lib/plugin-manager/plugin-org-capacity.d.ts +12 -0
- package/src/lib/plugin-manager/plugin-org-capacity.js.map +1 -1
- package/src/lib/plugin-manager/plugin-permissions.d.ts +7 -0
- package/src/lib/plugin-manager/plugin-permissions.js +30 -0
- package/src/lib/plugin-manager/plugin-permissions.js.map +1 -1
- package/src/lib/plugin-manager/plugin-record-timeline.d.ts +8 -1
- package/src/lib/plugin-manager/plugin-record-timeline.js.map +1 -1
- package/src/lib/plugin-manager/plugin-trust-signing.d.ts +51 -0
- package/src/lib/plugin-manager/plugin-trust-signing.js +119 -0
- package/src/lib/plugin-manager/plugin-trust-signing.js.map +1 -0
- package/src/lib/app-utils/marketplace-verification.d.ts +0 -95
- package/src/lib/app-utils/marketplace-verification.js +0 -81
- package/src/lib/app-utils/marketplace-verification.js.map +0 -1
- package/src/lib/app-utils/publisher-attestation.d.ts +0 -99
- package/src/lib/app-utils/publisher-attestation.js +0 -158
- package/src/lib/app-utils/publisher-attestation.js.map +0 -1
package/src/lib/app-utils/crm.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
1
2
|
/**
|
|
2
3
|
* @license
|
|
3
4
|
* Copyright 2026 Aglyn LLC
|
|
@@ -41,7 +42,7 @@
|
|
|
41
42
|
*
|
|
42
43
|
* Pure data module: types, constants and the small helpers every surface
|
|
43
44
|
* would otherwise write for itself. No Firestore, no React.
|
|
44
|
-
*/ import {
|
|
45
|
+
*/ import { normalizeAddress, normalizePhone } from "../foundation/index.js";
|
|
45
46
|
import { consentGroupScope } from "./consent-groups.js";
|
|
46
47
|
import { CONTACT_LIFECYCLE_STAGES, isContactLifecycleStage } from "./crm-kinds.js";
|
|
47
48
|
import { CONTACT_FACETS_FIELD, CONTACT_SOURCE_LABELS, normalizeContactEmail, readContactFacet } from "./contacts.js";
|
|
@@ -1443,6 +1444,130 @@ export function parseCrmMemberRef(value) {
|
|
|
1443
1444
|
export function isCrmLeadStatus(value) {
|
|
1444
1445
|
return typeof value === 'string' && CRM_LEAD_STATUSES.includes(value);
|
|
1445
1446
|
}
|
|
1447
|
+
/*==========================================
|
|
1448
|
+
* THE LEAD'S OWN PROFILE (AGL-3231).
|
|
1449
|
+
*
|
|
1450
|
+
* A Salesforce lead is a record of its own: it carries the person AND
|
|
1451
|
+
* their company as text — company, title, phone, website, address, the
|
|
1452
|
+
* source that produced it — and none of it is a contact until the lead
|
|
1453
|
+
* converts, when the convert step hands every field to the contact and the
|
|
1454
|
+
* account it creates. A lead that held only an address and a name could
|
|
1455
|
+
* not be worked without a contact beside it, which is how one person came
|
|
1456
|
+
* to sit in both lists; these fields are what let the lead stand alone.
|
|
1457
|
+
*
|
|
1458
|
+
* ## Text, not links
|
|
1459
|
+
*
|
|
1460
|
+
* `company` is the company's NAME, never a company id. A lead has not been
|
|
1461
|
+
* qualified, so the account it names may not deserve a record yet — a
|
|
1462
|
+
* thousand imported leads must not mint a thousand companies — and the
|
|
1463
|
+
* conversion is where the text becomes a link: it finds the company by
|
|
1464
|
+
* that name or by the address's domain, or creates it. The `companyId` on
|
|
1465
|
+
* `CrmLeadFields` is the conversion's stamp, written once, and never what
|
|
1466
|
+
* a lead carries while it is open.
|
|
1467
|
+
*
|
|
1468
|
+
* ## The same shapes the contact keeps
|
|
1469
|
+
*
|
|
1470
|
+
* The phone is E.164 through `normalizePhone`, the address is
|
|
1471
|
+
* `AglynPostalAddress` through `normalizeAddress`, tags are lower-cased and
|
|
1472
|
+
* capped as the contact's are, and the website is normalized as a
|
|
1473
|
+
* company's is — so the conversion copies values rather than translating
|
|
1474
|
+
* them, and a lead typed in the drawer and a contact typed in its drawer
|
|
1475
|
+
* refuse the same phone number in the same sentence.
|
|
1476
|
+
*
|
|
1477
|
+
* ## `leadSource` beside `sources`
|
|
1478
|
+
*
|
|
1479
|
+
* `sources` is the capture door's record of which SURFACES met the person
|
|
1480
|
+
* — `signup`, `booking`, `form:{id}`, `import` — and no file may rewrite
|
|
1481
|
+
* it. `leadSource` is what Salesforce calls Lead Source: free text the
|
|
1482
|
+
* team or the file supplies ("Sales Navigator", "Trade show"), reported on
|
|
1483
|
+
* and filtered by, and never derived. Two fields because they answer two
|
|
1484
|
+
* questions, and a file that could write the first would be rewriting the
|
|
1485
|
+
* site's own history.
|
|
1486
|
+
*=========================================*/ /** The longest text one profile field holds — the contact's own cap. */ export const CRM_LEAD_TEXT_MAX = 120;
|
|
1487
|
+
/** The most tags one lead keeps — the contact's own cap. */ export const CRM_LEAD_TAGS_MAX = 20;
|
|
1488
|
+
/** The longest note a lead keeps — the lead page's own cap. */ export const CRM_LEAD_NOTES_MAX = 4000;
|
|
1489
|
+
/** The profile's keys, in the order a card lists them. */ export const CRM_LEAD_PROFILE_KEYS = [
|
|
1490
|
+
'company',
|
|
1491
|
+
'jobTitle',
|
|
1492
|
+
'phone',
|
|
1493
|
+
'website',
|
|
1494
|
+
'address',
|
|
1495
|
+
'tags',
|
|
1496
|
+
'leadSource'
|
|
1497
|
+
];
|
|
1498
|
+
/** The sentence an unreadable phone number is refused with, under the field. */ export const CRM_LEAD_PHONE_REFUSAL = 'That phone number could not be read. Enter it with its country code, like ' + '+1 512 555 0107.';
|
|
1499
|
+
/** The sentence an unreadable website is refused with, under the field. */ export const CRM_LEAD_WEBSITE_REFUSAL = 'Enter a web address, like acme.com';
|
|
1500
|
+
/**
|
|
1501
|
+
* Tags as a lead stores them: lower-cased, trimmed, deduplicated, capped —
|
|
1502
|
+
* from an array or a comma-separated string, so a file cell and a form
|
|
1503
|
+
* field are one input.
|
|
1504
|
+
*/ export function normalizeCrmLeadTags(value) {
|
|
1505
|
+
const items = Array.isArray(value) ? value : typeof value === 'string' ? value.split(',') : [];
|
|
1506
|
+
return [
|
|
1507
|
+
...new Set(items.map((tag)=>String(tag != null ? tag : '').trim().slice(0, 40).toLowerCase()).filter(Boolean))
|
|
1508
|
+
].slice(0, CRM_LEAD_TAGS_MAX);
|
|
1509
|
+
}
|
|
1510
|
+
/**
|
|
1511
|
+
* Read a profile off an untrusted body, one field at a time.
|
|
1512
|
+
*
|
|
1513
|
+
* Every key the body names is answered: as a normalized value, as `null`
|
|
1514
|
+
* when the body cleared it (an empty string, `null`, an empty list, a blank
|
|
1515
|
+
* address), or as an error under the field when the value cannot be
|
|
1516
|
+
* stored as typed. Keys the body does not name are not in the answer, so
|
|
1517
|
+
* a caller can write exactly what was asked. A `website` is normalized the
|
|
1518
|
+
* way a company's is; a phone the way a contact's is; both refuse rather
|
|
1519
|
+
* than store a value the record would then render as a link to nowhere.
|
|
1520
|
+
*/ export function normalizeCrmLeadProfile(input) {
|
|
1521
|
+
const body = input != null ? input : {};
|
|
1522
|
+
const patch = {};
|
|
1523
|
+
const errors = {};
|
|
1524
|
+
const text = (key)=>{
|
|
1525
|
+
var _body_key;
|
|
1526
|
+
if (!(key in body)) return;
|
|
1527
|
+
const value = String((_body_key = body[key]) != null ? _body_key : '').trim().replace(/\s+/g, ' ').slice(0, CRM_LEAD_TEXT_MAX);
|
|
1528
|
+
patch[key] = value || null;
|
|
1529
|
+
};
|
|
1530
|
+
text('company');
|
|
1531
|
+
text('jobTitle');
|
|
1532
|
+
text('leadSource');
|
|
1533
|
+
if ('phone' in body) {
|
|
1534
|
+
var _body_phone;
|
|
1535
|
+
const raw = String((_body_phone = body['phone']) != null ? _body_phone : '').trim();
|
|
1536
|
+
if (!raw) patch.phone = null;
|
|
1537
|
+
else {
|
|
1538
|
+
const phone = normalizePhone(raw);
|
|
1539
|
+
if (phone) patch.phone = phone;
|
|
1540
|
+
else errors.phone = CRM_LEAD_PHONE_REFUSAL;
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1543
|
+
if ('website' in body) {
|
|
1544
|
+
var _body_website;
|
|
1545
|
+
const raw = String((_body_website = body['website']) != null ? _body_website : '').trim();
|
|
1546
|
+
if (!raw) patch.website = null;
|
|
1547
|
+
else {
|
|
1548
|
+
const website = normalizeCompanyWebsite(raw);
|
|
1549
|
+
if (website) patch.website = website;
|
|
1550
|
+
else errors.website = CRM_LEAD_WEBSITE_REFUSAL;
|
|
1551
|
+
}
|
|
1552
|
+
}
|
|
1553
|
+
if ('address' in body) {
|
|
1554
|
+
const raw = body['address'];
|
|
1555
|
+
patch.address = raw && typeof raw === 'object' && !Array.isArray(raw) ? normalizeAddress(raw) : null;
|
|
1556
|
+
}
|
|
1557
|
+
if ('tags' in body) {
|
|
1558
|
+
const tags = normalizeCrmLeadTags(body['tags']);
|
|
1559
|
+
patch.tags = tags.length ? tags : null;
|
|
1560
|
+
}
|
|
1561
|
+
return {
|
|
1562
|
+
patch,
|
|
1563
|
+
errors
|
|
1564
|
+
};
|
|
1565
|
+
}
|
|
1566
|
+
/** The name a lead is listed under: the name it carries, else its address. */ export function crmLeadDisplayName(lead) {
|
|
1567
|
+
var _ref, _ref1;
|
|
1568
|
+
const name = String((_ref = lead == null ? void 0 : lead['name']) != null ? _ref : '').trim();
|
|
1569
|
+
return name || String((_ref1 = lead == null ? void 0 : lead['email']) != null ? _ref1 : '').trim();
|
|
1570
|
+
}
|
|
1446
1571
|
/**
|
|
1447
1572
|
* A lead's status as the list and the filter should read it.
|
|
1448
1573
|
*
|