@aglyn/plugins-marketing 1.0.0-beta.219 → 1.0.0-beta.220

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.
Files changed (54) hide show
  1. package/README.md +3 -1
  2. package/package.json +16 -16
  3. package/src/lib/components/besigner-section-experiments.d.ts +20 -0
  4. package/src/lib/components/besigner-section-experiments.js +128 -0
  5. package/src/lib/components/besigner-section-experiments.js.map +1 -0
  6. package/src/lib/components/campaign-conversions-card.js +1 -1
  7. package/src/lib/components/campaign-conversions-card.js.map +1 -1
  8. package/src/lib/components/campaign-members-section.js +4 -3
  9. package/src/lib/components/campaign-members-section.js.map +1 -1
  10. package/src/lib/components/campaign-reach-sections.js +4 -1
  11. package/src/lib/components/campaign-reach-sections.js.map +1 -1
  12. package/src/lib/components/campaign-report-card.js +2 -2
  13. package/src/lib/components/campaign-report-card.js.map +1 -1
  14. package/src/lib/components/conversion-attribution.component.d.ts +1 -1
  15. package/src/lib/components/conversion-attribution.component.js +1 -1
  16. package/src/lib/components/conversion-attribution.component.js.map +1 -1
  17. package/src/lib/components/record-attribution-widget.js +1 -1
  18. package/src/lib/components/record-attribution-widget.js.map +1 -1
  19. package/src/lib/components/site-runtime.js +2 -2
  20. package/src/lib/components/site-runtime.js.map +1 -1
  21. package/src/lib/constants/operator-alerts.js +4 -1
  22. package/src/lib/constants/operator-alerts.js.map +1 -1
  23. package/src/lib/declarations.server.d.ts +3 -1
  24. package/src/lib/declarations.server.js +17 -1
  25. package/src/lib/declarations.server.js.map +1 -1
  26. package/src/lib/model/campaign-conversions.d.ts +301 -0
  27. package/src/lib/model/campaign-conversions.js +252 -0
  28. package/src/lib/model/campaign-conversions.js.map +1 -0
  29. package/src/lib/model/campaign-kind.d.ts +50 -0
  30. package/src/lib/model/campaign-kind.js +52 -0
  31. package/src/lib/model/campaign-kind.js.map +1 -0
  32. package/src/lib/model/campaign-members-query.js +1 -1
  33. package/src/lib/model/campaign-members-query.js.map +1 -1
  34. package/src/lib/model/campaign-revenue.d.ts +327 -0
  35. package/src/lib/model/campaign-revenue.js +332 -0
  36. package/src/lib/model/campaign-revenue.js.map +1 -0
  37. package/src/lib/model/index.d.ts +3 -0
  38. package/src/lib/model/index.js +4 -1
  39. package/src/lib/model/index.js.map +1 -1
  40. package/src/lib/model/overlay-record-list.d.ts +33 -0
  41. package/src/lib/model/overlay-record-list.js +53 -0
  42. package/src/lib/model/overlay-record-list.js.map +1 -0
  43. package/src/lib/plugin.js +12 -0
  44. package/src/lib/plugin.js.map +1 -1
  45. package/src/lib/server/campaign-manage.js +19 -60
  46. package/src/lib/server/campaign-manage.js.map +1 -1
  47. package/src/lib/server/campaign-send.d.ts +1 -1
  48. package/src/lib/server/campaign-send.js +23 -7
  49. package/src/lib/server/campaign-send.js.map +1 -1
  50. package/src/lib/server/email-events.js +9 -10
  51. package/src/lib/server/email-events.js.map +1 -1
  52. package/src/lib/server/overlay-beacon.d.ts +46 -0
  53. package/src/lib/server/overlay-beacon.js +76 -0
  54. package/src/lib/server/overlay-beacon.js.map +1 -0
@@ -14,7 +14,7 @@ import { _ as _extends } from "@swc/helpers/_/_extends";
14
14
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
15
  * See the License for the specific language governing permissions and
16
16
  * limitations under the License.
17
- */ import { checkQuota, contactMatchesSegment, isEmailTopicId, DEFAULT_CAMPAIGN_TOPIC_ID, readMarketingBasis, resolveMarketingConsentPolicy, splitByMarketingConsent, createResourceUid, decodeStoredNodes, emailStarterSendBlock, resolveBrandingProfile, seenOnlyThroughGrant, siteLockdownFromDocs, visibleToHost } from "@aglyn/aglyn/server";
17
+ */ import { checkQuota, contactMatchesSegment, isSubscriptionTopicId, DEFAULT_SUBSCRIPTION_TOPIC_ID, readMarketingBasis, resolveMarketingConsentPolicy, splitByMarketingConsent, createResourceUid, decodeStoredNodes, emailStarterSendBlock, resolveBrandingProfile, seenOnlyThroughGrant, siteLockdownFromDocs, visibleToHost } from "@aglyn/aglyn/server";
18
18
  import { renderRecipientEmail } from "@aglyn/aglyn/app-utils/recipient-email-render";
19
19
  import { composeHostComponentNodes } from "@aglyn/aglyn/app-utils/load-referenced-components";
20
20
  import { assignExperimentVariant } from "../model/index.js";
@@ -72,6 +72,7 @@ import { campaignSendSearchFields } from "../model/campaign-list-query.js";
72
72
  import { createHash } from "crypto";
73
73
  import { EMAIL_MAX_AUDIENCE_PER_SEND, EMAIL_MAX_RECIPIENTS_PER_SEND, createProviderRequestPacer, effectiveReputationPolicy, HOST_SENDERS_COLLECTION, isEmailConfigured, rateLimitedRetryAtMs, readHostSender, sendEmail, sendingIdentityRefusal, sentAsStamp } from "@aglyn/shared-util-email";
74
74
  import { campaignBatchPlan } from "./campaign-batch-plan.js";
75
+ import { stampRecordEmailReach } from "@aglyn/aglyn/plugin-manager/plugin-record-email-state";
75
76
  /*
76
77
  * The List-Unsubscribe setting sequences share (AGL-3307), from its LEAF
77
78
  * module: the specs that reach this file spread the real barrel under their
@@ -450,10 +451,10 @@ export async function performCampaignSend(options) {
450
451
  * two different parameter tuples — see `signedSubject` in the email plugin's
451
452
  * `unsubscribe-link.ts`. Refused at the point the topic ENTERS the send, so
452
453
  * the link that leaves it is unambiguous by construction.
453
- */ if (options.topicId && !isEmailTopicId(options.topicId)) {
454
+ */ if (options.topicId && !isSubscriptionTopicId(options.topicId)) {
454
455
  throw new CampaignSendError('Invalid topicId', 400);
455
456
  }
456
- const topicId = options.topicId || DEFAULT_CAMPAIGN_TOPIC_ID;
457
+ const topicId = options.topicId || DEFAULT_SUBSCRIPTION_TOPIC_ID;
457
458
  /**
458
459
  * Whether this send ADDS to an email that already exists, rather than
459
460
  * starting one.
@@ -1132,14 +1133,21 @@ export async function performCampaignSend(options) {
1132
1133
  * merchant who cannot send and cannot find out why will open a ticket
1133
1134
  * that says the product is broken.
1134
1135
  */ if (reputation.blocked) {
1136
+ var _ref4;
1137
+ var _orgForHost_org4;
1135
1138
  // The merchant is told by the refusal; the operator, once a day per
1136
1139
  // workspace, so a tripped breaker on a shared domain is looked at
1137
1140
  // before it is reinstated (AGL-3377).
1138
1141
  await raiseOperatorAlert(MARKETING_REPUTATION_BREAKER, {
1139
1142
  dedupeKey: orgId,
1143
+ // The findings in numbers, and the workspace by name off the org doc
1144
+ // this send already holds. `reputation.reason` is the merchant's
1145
+ // refusal, written to them, so it is not staff's copy.
1140
1146
  context: {
1141
1147
  orgId,
1142
- reason: reputation.reason
1148
+ orgName: String((_ref4 = orgForHost == null ? void 0 : (_orgForHost_org4 = orgForHost.org) == null ? void 0 : _orgForHost_org4['name']) != null ? _ref4 : '').trim(),
1149
+ windowDays: reputation.windowDays,
1150
+ detail: reputation.findings.filter((finding)=>finding.actionable).map((finding)=>finding.detail).join(' ')
1143
1151
  },
1144
1152
  orgId
1145
1153
  });
@@ -1477,14 +1485,14 @@ export async function performCampaignSend(options) {
1477
1485
  * back on the clock and this screen finds it released — and actioning the
1478
1486
  * row cancels it.
1479
1487
  */ if (!options.followUp) {
1480
- var _ref4, _hostSnapshot_data, _options_fromName, _sendingIdentity_from, _options_replyTo, _options_preheader, _options_plainText, _experiment_variants;
1488
+ var _ref5, _hostSnapshot_data, _options_fromName, _sendingIdentity_from, _options_replyTo, _options_preheader, _options_plainText, _experiment_variants;
1481
1489
  const sendRef = sends.doc(campaignId);
1482
1490
  const screened = await screenOutboundSend({
1483
1491
  kind: 'campaign',
1484
1492
  path: sendRef.path,
1485
1493
  hostId,
1486
1494
  orgId,
1487
- org: (_ref4 = orgForHost == null ? void 0 : orgForHost.org) != null ? _ref4 : null,
1495
+ org: (_ref5 = orgForHost == null ? void 0 : orgForHost.org) != null ? _ref5 : null,
1488
1496
  host: (_hostSnapshot_data = hostSnapshot.data()) != null ? _hostSnapshot_data : null,
1489
1497
  subject,
1490
1498
  fromName: (_options_fromName = options.fromName) != null ? _options_fromName : null,
@@ -2071,6 +2079,14 @@ export async function performCampaignSend(options) {
2071
2079
  * follow-up, which is also safe but loses the feature over a transient.
2072
2080
  */ if (options.recordCampaign !== false) {
2073
2081
  await recordCampaignReach(sends.doc(campaignId), reached);
2082
+ // The record system hears who it reached, so a lead nobody had touched
2083
+ // moves to Nurturing (AGL-3446). A test send reached nobody's lead, so it
2084
+ // is left out with the reach record. Never throws.
2085
+ await stampRecordEmailReach({
2086
+ orgId,
2087
+ hostId,
2088
+ emails: reached
2089
+ });
2074
2090
  /*
2075
2091
  * And who it decided NOT to mail, under a field of its own.
2076
2092
  *
@@ -2865,7 +2881,7 @@ function storedSendOptionsFrom(snapshot, hostId, senderUid, followUp) {
2865
2881
  * An empty value is not an error: it means "the composer did not say", which
2866
2882
  * `performCampaignSend` resolves to the default topic.
2867
2883
  */ const topicId = String((_ref10 = (_req_body14 = req.body) == null ? void 0 : _req_body14.topicId) != null ? _ref10 : '');
2868
- if (topicId && !isEmailTopicId(topicId)) {
2884
+ if (topicId && !isSubscriptionTopicId(topicId)) {
2869
2885
  return res.status(400).json({
2870
2886
  error: 'Unknown topic'
2871
2887
  });