@aglyn/aglyn 1.0.0-beta.293 → 1.0.0-beta.296

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aglyn/aglyn",
3
- "version": "1.0.0-beta.293",
3
+ "version": "1.0.0-beta.296",
4
4
  "license": "Apache-2.0",
5
5
  "homepage": "https://aglyn.com",
6
6
  "repository": {
@@ -37,16 +37,16 @@
37
37
  "./package.json": "./package.json"
38
38
  },
39
39
  "dependencies": {
40
- "@aglyn/shared-data-enums": "1.0.0-beta.293",
41
- "@aglyn/shared-data-mdi": "1.0.0-beta.293",
42
- "@aglyn/shared-data-types": "1.0.0-beta.293",
43
- "@aglyn/shared-util-email": "1.0.0-beta.293",
44
- "@aglyn/shared-util-first-touch": "1.0.0-beta.293",
45
- "@aglyn/shared-util-http": "1.0.0-beta.293",
46
- "@aglyn/shared-util-logger": "1.0.0-beta.293",
47
- "@aglyn/shared-util-timestamp": "1.0.0-beta.293",
48
- "@aglyn/shared-util-tools": "1.0.0-beta.293",
49
- "@aglyn/shared-util-vendor": "1.0.0-beta.293",
40
+ "@aglyn/shared-data-enums": "1.0.0-beta.296",
41
+ "@aglyn/shared-data-mdi": "1.0.0-beta.296",
42
+ "@aglyn/shared-data-types": "1.0.0-beta.296",
43
+ "@aglyn/shared-util-email": "1.0.0-beta.296",
44
+ "@aglyn/shared-util-first-touch": "1.0.0-beta.296",
45
+ "@aglyn/shared-util-http": "1.0.0-beta.296",
46
+ "@aglyn/shared-util-logger": "1.0.0-beta.296",
47
+ "@aglyn/shared-util-timestamp": "1.0.0-beta.296",
48
+ "@aglyn/shared-util-tools": "1.0.0-beta.296",
49
+ "@aglyn/shared-util-vendor": "1.0.0-beta.296",
50
50
  "@data-driven-forms/react-form-renderer": "^4.2.0",
51
51
  "@msgpack/msgpack": "^3.1.3",
52
52
  "@types/unist": "^3.0.3",
@@ -69,7 +69,13 @@ export declare const CONTACT_TAG_MAX_LENGTH = 60;
69
69
  * neither can be done over a string somebody typed. `note` is the plain
70
70
  * entry — something worth writing down that was not a conversation — and
71
71
  * `other` the escape hatch for the kind none of these name.
72
+ *
73
+ * The message kinds — a text, WhatsApp, Facebook Messenger, Instagram and
74
+ * LinkedIn — are the channels a conversation with a customer actually runs
75
+ * on beside a call or an email. Each is its own kind rather than an `other`
76
+ * with the channel typed into the body, so the timeline shows the channel
77
+ * and a report counts it.
72
78
  */
73
- export declare const CRM_ACTIVITY_KINDS: readonly ["call", "email", "meeting", "note", "other"];
79
+ export declare const CRM_ACTIVITY_KINDS: readonly ["call", "email", "text", "whatsapp", "messenger", "instagram", "linkedin", "meeting", "note", "other"];
74
80
  export type CrmActivityKind = (typeof CRM_ACTIVITY_KINDS)[number];
75
81
  export declare function isCrmActivityKind(value: unknown): value is CrmActivityKind;
@@ -79,9 +79,20 @@ export function isCrmTaskKind(value) {
79
79
  * neither can be done over a string somebody typed. `note` is the plain
80
80
  * entry — something worth writing down that was not a conversation — and
81
81
  * `other` the escape hatch for the kind none of these name.
82
+ *
83
+ * The message kinds — a text, WhatsApp, Facebook Messenger, Instagram and
84
+ * LinkedIn — are the channels a conversation with a customer actually runs
85
+ * on beside a call or an email. Each is its own kind rather than an `other`
86
+ * with the channel typed into the body, so the timeline shows the channel
87
+ * and a report counts it.
82
88
  */ export const CRM_ACTIVITY_KINDS = [
83
89
  'call',
84
90
  'email',
91
+ 'text',
92
+ 'whatsapp',
93
+ 'messenger',
94
+ 'instagram',
95
+ 'linkedin',
85
96
  'meeting',
86
97
  'note',
87
98
  'other'
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../libs/aglyn/src/lib/app-utils/crm-kinds.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * The CRM's fixed vocabularies — lifecycle stages, task kinds, activity\n * kinds — and the guards that check a value against them.\n *\n * A leaf module with no imports, re-exported by `crm.ts`, so every existing\n * `crm` import keeps working. It is separate because the actions builder\n * validates an automation step against these lists, and the actions builder\n * ships with the element renderer to every published page: importing them\n * from `crm.ts` put the whole CRM record model — companies, deals, tasks,\n * the contact facet helpers it reads — in front of every visitor to check a\n * string against a four-item list.\n *\n * Only the lists, their types, their guards and the task horizon live here.\n * The on-screen labels stay in `crm.ts`, beside the records they describe.\n */\n\n/**\n * Where a person sits in the relationship, as one of a fixed list.\n *\n * A fixed list rather than free text so that a report can count people per\n * stage and a filter can select one, and in the order a person usually moves\n * through them so a picker reads as a progression. `other` is the escape\n * hatch for a business whose funnel has a step none of these name; it is a\n * deliberate stage, not an absent one.\n */\nexport const CONTACT_LIFECYCLE_STAGES = [\n 'subscriber',\n 'lead',\n 'marketing-qualified',\n 'sales-qualified',\n 'opportunity',\n 'customer',\n 'evangelist',\n 'other',\n] as const\n\nexport type ContactLifecycleStage = (typeof CONTACT_LIFECYCLE_STAGES)[number]\n\nexport function isContactLifecycleStage(\n value: unknown,\n): value is ContactLifecycleStage {\n return (\n typeof value === 'string' &&\n (CONTACT_LIFECYCLE_STAGES as readonly string[]).includes(value)\n )\n}\n\n/**\n * What a task is, as a fixed list.\n *\n * A const array rather than a bare union because two surfaces have to\n * enumerate it — the task form's picker and the automation step that creates\n * a task without a form — and a union cannot be iterated at run time.\n */\nexport const CRM_TASK_KINDS = ['call', 'email', 'meeting', 'todo'] as const\nexport type CrmTaskKind = (typeof CRM_TASK_KINDS)[number]\n\nexport function isCrmTaskKind(value: unknown): value is CrmTaskKind {\n return (\n typeof value === 'string' &&\n (CRM_TASK_KINDS as readonly string[]).includes(value)\n )\n}\n\n/**\n * How far ahead an automation may date a task, in days.\n *\n * A year, because the longest follow-up anybody schedules from a trigger is\n * an annual renewal check, and a task dated further out than that is one\n * nobody will find on the list when it comes due.\n */\nexport const CRM_TASK_MAX_DUE_DAYS = 365\n\n/** Longest tag an automation may write — the console's own tag field cap. */\nexport const CONTACT_TAG_MAX_LENGTH = 60\n\n/**\n * What a person can log, in the order the picker offers them (AGL-2600).\n *\n * A fixed list rather than free text for the reason the lifecycle stages are\n * one: a report counts calls per week and a filter selects meetings, and\n * neither can be done over a string somebody typed. `note` is the plain\n * entry — something worth writing down that was not a conversation — and\n * `other` the escape hatch for the kind none of these name.\n */\nexport const CRM_ACTIVITY_KINDS = ['call', 'email', 'meeting', 'note', 'other'] as const\n\nexport type CrmActivityKind = (typeof CRM_ACTIVITY_KINDS)[number]\n\nexport function isCrmActivityKind(value: unknown): value is CrmActivityKind {\n return (\n typeof value === 'string' &&\n (CRM_ACTIVITY_KINDS as readonly string[]).includes(value)\n )\n}\n"],"names":["CONTACT_LIFECYCLE_STAGES","isContactLifecycleStage","value","includes","CRM_TASK_KINDS","isCrmTaskKind","CRM_TASK_MAX_DUE_DAYS","CONTACT_TAG_MAX_LENGTH","CRM_ACTIVITY_KINDS","isCrmActivityKind"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;;;;;;;;;;;;CAcC,GAED;;;;;;;;CAQC,GACD,OAAO,MAAMA,2BAA2B;IACtC;IACA;IACA;IACA;IACA;IACA;IACA;IACA;CACD,CAAS;AAIV,OAAO,SAASC,wBACdC,KAAc;IAEd,OACE,OAAOA,UAAU,YACjB,AAACF,yBAA+CG,QAAQ,CAACD;AAE7D;AAEA;;;;;;CAMC,GACD,OAAO,MAAME,iBAAiB;IAAC;IAAQ;IAAS;IAAW;CAAO,CAAS;AAG3E,OAAO,SAASC,cAAcH,KAAc;IAC1C,OACE,OAAOA,UAAU,YACjB,AAACE,eAAqCD,QAAQ,CAACD;AAEnD;AAEA;;;;;;CAMC,GACD,OAAO,MAAMI,wBAAwB,IAAG;AAExC,2EAA2E,GAC3E,OAAO,MAAMC,yBAAyB,GAAE;AAExC;;;;;;;;CAQC,GACD,OAAO,MAAMC,qBAAqB;IAAC;IAAQ;IAAS;IAAW;IAAQ;CAAQ,CAAS;AAIxF,OAAO,SAASC,kBAAkBP,KAAc;IAC9C,OACE,OAAOA,UAAU,YACjB,AAACM,mBAAyCL,QAAQ,CAACD;AAEvD"}
1
+ {"version":3,"sources":["../../../../../../libs/aglyn/src/lib/app-utils/crm-kinds.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * The CRM's fixed vocabularies — lifecycle stages, task kinds, activity\n * kinds — and the guards that check a value against them.\n *\n * A leaf module with no imports, re-exported by `crm.ts`, so every existing\n * `crm` import keeps working. It is separate because the actions builder\n * validates an automation step against these lists, and the actions builder\n * ships with the element renderer to every published page: importing them\n * from `crm.ts` put the whole CRM record model — companies, deals, tasks,\n * the contact facet helpers it reads — in front of every visitor to check a\n * string against a four-item list.\n *\n * Only the lists, their types, their guards and the task horizon live here.\n * The on-screen labels stay in `crm.ts`, beside the records they describe.\n */\n\n/**\n * Where a person sits in the relationship, as one of a fixed list.\n *\n * A fixed list rather than free text so that a report can count people per\n * stage and a filter can select one, and in the order a person usually moves\n * through them so a picker reads as a progression. `other` is the escape\n * hatch for a business whose funnel has a step none of these name; it is a\n * deliberate stage, not an absent one.\n */\nexport const CONTACT_LIFECYCLE_STAGES = [\n 'subscriber',\n 'lead',\n 'marketing-qualified',\n 'sales-qualified',\n 'opportunity',\n 'customer',\n 'evangelist',\n 'other',\n] as const\n\nexport type ContactLifecycleStage = (typeof CONTACT_LIFECYCLE_STAGES)[number]\n\nexport function isContactLifecycleStage(\n value: unknown,\n): value is ContactLifecycleStage {\n return (\n typeof value === 'string' &&\n (CONTACT_LIFECYCLE_STAGES as readonly string[]).includes(value)\n )\n}\n\n/**\n * What a task is, as a fixed list.\n *\n * A const array rather than a bare union because two surfaces have to\n * enumerate it — the task form's picker and the automation step that creates\n * a task without a form — and a union cannot be iterated at run time.\n */\nexport const CRM_TASK_KINDS = ['call', 'email', 'meeting', 'todo'] as const\nexport type CrmTaskKind = (typeof CRM_TASK_KINDS)[number]\n\nexport function isCrmTaskKind(value: unknown): value is CrmTaskKind {\n return (\n typeof value === 'string' &&\n (CRM_TASK_KINDS as readonly string[]).includes(value)\n )\n}\n\n/**\n * How far ahead an automation may date a task, in days.\n *\n * A year, because the longest follow-up anybody schedules from a trigger is\n * an annual renewal check, and a task dated further out than that is one\n * nobody will find on the list when it comes due.\n */\nexport const CRM_TASK_MAX_DUE_DAYS = 365\n\n/** Longest tag an automation may write — the console's own tag field cap. */\nexport const CONTACT_TAG_MAX_LENGTH = 60\n\n/**\n * What a person can log, in the order the picker offers them (AGL-2600).\n *\n * A fixed list rather than free text for the reason the lifecycle stages are\n * one: a report counts calls per week and a filter selects meetings, and\n * neither can be done over a string somebody typed. `note` is the plain\n * entry — something worth writing down that was not a conversation — and\n * `other` the escape hatch for the kind none of these name.\n *\n * The message kinds — a text, WhatsApp, Facebook Messenger, Instagram and\n * LinkedIn — are the channels a conversation with a customer actually runs\n * on beside a call or an email. Each is its own kind rather than an `other`\n * with the channel typed into the body, so the timeline shows the channel\n * and a report counts it.\n */\nexport const CRM_ACTIVITY_KINDS = [\n 'call',\n 'email',\n 'text',\n 'whatsapp',\n 'messenger',\n 'instagram',\n 'linkedin',\n 'meeting',\n 'note',\n 'other',\n] as const\n\nexport type CrmActivityKind = (typeof CRM_ACTIVITY_KINDS)[number]\n\nexport function isCrmActivityKind(value: unknown): value is CrmActivityKind {\n return (\n typeof value === 'string' &&\n (CRM_ACTIVITY_KINDS as readonly string[]).includes(value)\n )\n}\n"],"names":["CONTACT_LIFECYCLE_STAGES","isContactLifecycleStage","value","includes","CRM_TASK_KINDS","isCrmTaskKind","CRM_TASK_MAX_DUE_DAYS","CONTACT_TAG_MAX_LENGTH","CRM_ACTIVITY_KINDS","isCrmActivityKind"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;;;;;;;;;;;;CAcC,GAED;;;;;;;;CAQC,GACD,OAAO,MAAMA,2BAA2B;IACtC;IACA;IACA;IACA;IACA;IACA;IACA;IACA;CACD,CAAS;AAIV,OAAO,SAASC,wBACdC,KAAc;IAEd,OACE,OAAOA,UAAU,YACjB,AAACF,yBAA+CG,QAAQ,CAACD;AAE7D;AAEA;;;;;;CAMC,GACD,OAAO,MAAME,iBAAiB;IAAC;IAAQ;IAAS;IAAW;CAAO,CAAS;AAG3E,OAAO,SAASC,cAAcH,KAAc;IAC1C,OACE,OAAOA,UAAU,YACjB,AAACE,eAAqCD,QAAQ,CAACD;AAEnD;AAEA;;;;;;CAMC,GACD,OAAO,MAAMI,wBAAwB,IAAG;AAExC,2EAA2E,GAC3E,OAAO,MAAMC,yBAAyB,GAAE;AAExC;;;;;;;;;;;;;;CAcC,GACD,OAAO,MAAMC,qBAAqB;IAChC;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;CACD,CAAS;AAIV,OAAO,SAASC,kBAAkBP,KAAc;IAC9C,OACE,OAAOA,UAAU,YACjB,AAACM,mBAAyCL,QAAQ,CAACD;AAEvD"}
@@ -734,7 +734,11 @@ export type CrmEmailDirection = 'outbound' | 'inbound';
734
734
  export type CrmCallDirection = CrmEmailDirection | 'internal';
735
735
  /** An activity's direction: a call's three, of which an email takes the first two. */
736
736
  export type CrmActivityDirection = CrmCallDirection;
737
- /** The directions each kind takes, in the order a select lists them; none for the rest. */
737
+ /**
738
+ * The directions each kind takes, in the order a select lists them; none for
739
+ * the rest. A message travels the way an email does: one the team sent, or
740
+ * one the customer wrote.
741
+ */
738
742
  export declare const CRM_ACTIVITY_DIRECTIONS: Readonly<Partial<Record<CrmActivityKind, readonly CrmActivityDirection[]>>>;
739
743
  export declare const CRM_ACTIVITY_DIRECTION_LABELS: Record<CrmActivityDirection, string>;
740
744
  /** `value` when `kind` takes it as a direction, else `null`. */
@@ -505,10 +505,31 @@ export const CRM_TASK_KIND_LABELS = {
505
505
  /** How an activity kind reads on screen — typed so a kind cannot ship unlabeled. */ export const CRM_ACTIVITY_KIND_LABELS = {
506
506
  call: 'Call',
507
507
  email: 'Email',
508
+ text: 'Text message',
509
+ whatsapp: 'WhatsApp',
510
+ messenger: 'Facebook Messenger',
511
+ instagram: 'Instagram',
512
+ linkedin: 'LinkedIn',
508
513
  meeting: 'Meeting',
509
514
  note: 'Note',
510
515
  other: 'Other'
511
516
  };
517
+ /**
518
+ * How a kind reads after a direction — "Inbound call", "Outbound WhatsApp
519
+ * message". Its own map rather than the label lowercased, because a brand
520
+ * keeps its capitals and a channel's name is not the thing that was sent.
521
+ */ const CRM_ACTIVITY_KIND_NOUNS = {
522
+ call: 'call',
523
+ email: 'email',
524
+ text: 'text message',
525
+ whatsapp: 'WhatsApp message',
526
+ messenger: 'Messenger message',
527
+ instagram: 'Instagram message',
528
+ linkedin: 'LinkedIn message',
529
+ meeting: 'meeting',
530
+ note: 'note',
531
+ other: 'other'
532
+ };
512
533
  /**
513
534
  * Whether a kind takes an outcome and a duration.
514
535
  *
@@ -625,7 +646,11 @@ export function isCrmEmailDeliveryState(value) {
625
646
  ] : []
626
647
  ];
627
648
  }
628
- /** The directions each kind takes, in the order a select lists them; none for the rest. */ export const CRM_ACTIVITY_DIRECTIONS = {
649
+ /**
650
+ * The directions each kind takes, in the order a select lists them; none for
651
+ * the rest. A message travels the way an email does: one the team sent, or
652
+ * one the customer wrote.
653
+ */ export const CRM_ACTIVITY_DIRECTIONS = {
629
654
  call: [
630
655
  'outbound',
631
656
  'inbound',
@@ -634,6 +659,26 @@ export function isCrmEmailDeliveryState(value) {
634
659
  email: [
635
660
  'outbound',
636
661
  'inbound'
662
+ ],
663
+ text: [
664
+ 'outbound',
665
+ 'inbound'
666
+ ],
667
+ whatsapp: [
668
+ 'outbound',
669
+ 'inbound'
670
+ ],
671
+ messenger: [
672
+ 'outbound',
673
+ 'inbound'
674
+ ],
675
+ instagram: [
676
+ 'outbound',
677
+ 'inbound'
678
+ ],
679
+ linkedin: [
680
+ 'outbound',
681
+ 'inbound'
637
682
  ]
638
683
  };
639
684
  export const CRM_ACTIVITY_DIRECTION_LABELS = {
@@ -648,10 +693,12 @@ export const CRM_ACTIVITY_DIRECTION_LABELS = {
648
693
  return allowed.includes(text) ? text : null;
649
694
  }
650
695
  /** "Inbound call", "Outbound email", "Internal call" — or the kind alone with no direction. */ export function crmActivityKindTitle(kind, direction) {
651
- var _CRM_ACTIVITY_KIND_LABELS_kind;
696
+ var _CRM_ACTIVITY_KIND_LABELS_kind, _CRM_ACTIVITY_KIND_NOUNS_kind;
652
697
  const known = crmActivityDirection(kind, direction);
653
- const noun = (_CRM_ACTIVITY_KIND_LABELS_kind = CRM_ACTIVITY_KIND_LABELS[kind]) != null ? _CRM_ACTIVITY_KIND_LABELS_kind : String(kind);
654
- return known ? `${CRM_ACTIVITY_DIRECTION_LABELS[known]} ${noun.toLowerCase()}` : noun;
698
+ const label = (_CRM_ACTIVITY_KIND_LABELS_kind = CRM_ACTIVITY_KIND_LABELS[kind]) != null ? _CRM_ACTIVITY_KIND_LABELS_kind : String(kind);
699
+ if (!known) return label;
700
+ const noun = (_CRM_ACTIVITY_KIND_NOUNS_kind = CRM_ACTIVITY_KIND_NOUNS[kind]) != null ? _CRM_ACTIVITY_KIND_NOUNS_kind : label.toLowerCase();
701
+ return `${CRM_ACTIVITY_DIRECTION_LABELS[known]} ${noun}`;
655
702
  }
656
703
  /**
657
704
  * The activity row a sent one-to-one email is logged as (AGL-2615).