@odla-ai/chapter 0.51.0 → 0.52.1
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/README.md +110 -8
- package/dist/{chunk-JXX4BFDP.js → chunk-4M2PN5K3.js} +8 -2
- package/dist/chunk-4M2PN5K3.js.map +1 -0
- package/dist/{chunk-UAXWA5BL.js → chunk-TEHCORNC.js} +31 -12
- package/dist/chunk-TEHCORNC.js.map +1 -0
- package/dist/{chunk-4EA5V4JE.js → chunk-WWF2TO3H.js} +239 -136
- package/dist/chunk-WWF2TO3H.js.map +1 -0
- package/dist/{copy-context-Ddat__H5.d.ts → copy-context-qvFo6eA7.d.ts} +12 -6
- package/dist/index.cjs +91 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +71 -13
- package/dist/index.d.ts +71 -13
- package/dist/index.js +91 -8
- package/dist/index.js.map +1 -1
- package/dist/ui/admin/index.d.ts +14 -3
- package/dist/ui/admin/index.js +4 -2
- package/dist/ui/index.d.ts +2 -2
- package/dist/ui/index.js +5 -3
- package/dist/ui/member/index.d.ts +20 -14
- package/dist/ui/member/index.js +2 -2
- package/dist/worker/index.cjs +912 -354
- package/dist/worker/index.cjs.map +1 -1
- package/dist/worker/index.d.cts +48 -10
- package/dist/worker/index.d.ts +48 -10
- package/dist/worker/index.js +912 -354
- package/dist/worker/index.js.map +1 -1
- package/package.json +2 -1
- package/dist/chunk-4EA5V4JE.js.map +0 -1
- package/dist/chunk-JXX4BFDP.js.map +0 -1
- package/dist/chunk-UAXWA5BL.js.map +0 -1
|
@@ -26,7 +26,7 @@ type TextFields$1<Key extends string> = {
|
|
|
26
26
|
[Field in Key]: string;
|
|
27
27
|
};
|
|
28
28
|
/** User-visible language for sharing, delivery state, and leader rollups. */
|
|
29
|
-
type AdminNetworkCopy = TextFields$1<"title" | "allowlistDescription" | "sharing" | "shareWith" | "shared" | "shareFailed" | "deliveryFailed" | "loadingRollup" | "loadRollupFailed" | "overview" | "configuredFollowers" | "reachableFollowers" | "recordsAcrossFollowers" | "noFollowers" | "followers" | "available" | "unavailable" | "transportReachable" | "transportUnavailable" | "transportNotChecked" | "bindingTransport" | "urlTransport" | "activeConfiguration" | "noActiveConfiguration" | "publicSiteAvailable" | "publicSiteUnavailable" | "publicSiteNotChecked" | "recordTotals" | "noRecordTotals">;
|
|
29
|
+
type AdminNetworkCopy = TextFields$1<"title" | "allowlistDescription" | "sharing" | "shareWith" | "shared" | "shareFailed" | "deliveryFailed" | "loadingRollup" | "loadRollupFailed" | "overview" | "configuredFollowers" | "reachableFollowers" | "recordsAcrossFollowers" | "noFollowers" | "followers" | "available" | "unavailable" | "transportReachable" | "transportUnavailable" | "transportNotChecked" | "edgeUnpaired" | "edgeUnpairedHint" | "bindingTransport" | "urlTransport" | "activeConfiguration" | "noActiveConfiguration" | "publicSiteAvailable" | "publicSiteUnavailable" | "publicSiteNotChecked" | "recordTotals" | "noRecordTotals">;
|
|
30
30
|
|
|
31
31
|
/** Copy for the person record panels: lifecycle actions, comms, scheduling, billing and meetings. */
|
|
32
32
|
type AdminRecordsCopy = {
|
|
@@ -57,7 +57,7 @@ interface ChapterCopy {
|
|
|
57
57
|
* agree rather than merely restating the policy. Set it to an empty string
|
|
58
58
|
* to render the checkbox with the policy as its only label.
|
|
59
59
|
*/
|
|
60
|
-
payment: TextFields<"setupFailed" | "preparing" | "pending" | "processing" | "payAndContinue" | "incomplete" | "consent" | "foundingMember" | "foundingDiscount">;
|
|
60
|
+
payment: TextFields<"setupFailed" | "preparing" | "pending" | "processing" | "payAndContinue" | "incomplete" | "consent" | "foundingMember" | "foundingDiscount" | "standardRate" | "yourRate">;
|
|
61
61
|
done: TextFields<"label" | "calendarInvite" | "memberArea">;
|
|
62
62
|
accepted: TextFields<"label" | "body">;
|
|
63
63
|
gift: TextFields<"chooseSelf" | "optionsLabel" | "label" | "body" | "save" | "rotate" | "rotateFailed" | "claimTitle" | "claimBody" | "code" | "redeem" | "redeemed" | "redeemFailed">;
|
|
@@ -79,7 +79,7 @@ interface ChapterCopy {
|
|
|
79
79
|
availability: TextFields<"loading" | "loadFailed" | "saved" | "title" | "days" | "startHour" | "endHour" | "slotMinutes" | "minNoticeHours" | "windowDays" | "timezone" | "summaryTemplate" | "save"> & {
|
|
80
80
|
dayLabels: readonly string[];
|
|
81
81
|
};
|
|
82
|
-
email: TextFields<"loading" | "loadFailed" | "saved" | "sent" | "testFailed" | "delivery" | "notificationAddress" | "replyTo" | "debugInbox" | "debugInboxHint" | "sendTest" | "enabled" | "subject" | "body" | "save" | "sendLog" | "sentColumn" | "templateColumn" | "statusColumn" | "toColumn" | "failed" | "redirected" | "delivered">;
|
|
82
|
+
email: TextFields<"loading" | "loadFailed" | "saved" | "sent" | "testFailed" | "delivery" | "notificationAddress" | "replyTo" | "fromName" | "fromNameHint" | "debugInbox" | "debugInboxHint" | "sendTest" | "enabled" | "subject" | "body" | "save" | "sendLog" | "sentColumn" | "templateColumn" | "statusColumn" | "toColumn" | "failed" | "redirected" | "delivered">;
|
|
83
83
|
meetings: TextFields<"loading" | "loadFailed" | "cancelConfirm" | "newStartPrompt" | "parseFailed" | "agenda" | "empty" | "unknown" | "drift" | "meet" | "reschedule" | "cancel">;
|
|
84
84
|
admission: TextFields<"title" | "description" | "email" | "decision" | "expires" | "note" | "waive" | "require" | "add" | "ledger" | "loading" | "consumed" | "revoked" | "expired" | "active" | "local" | "parent" | "revoke">;
|
|
85
85
|
network: AdminNetworkCopy;
|
|
@@ -215,7 +215,10 @@ type DbRules = Record<string, Rule>;
|
|
|
215
215
|
|
|
216
216
|
/** One follower site a leader can push CRM records to. The secret VALUE never
|
|
217
217
|
* lives in config: `secretName` names the leader tenant's vaulted copy of the
|
|
218
|
-
* follower's `network_share_secret`.
|
|
218
|
+
* follower's `network_share_secret`. Both slots are declared by
|
|
219
|
+
* `createChapterIntegration` and filled together by
|
|
220
|
+
* `odla-ai chapter edge pair --leader <leader> --follower <id>`; until then
|
|
221
|
+
* every leader-side surface reports the edge as `edge_unpaired`. */
|
|
219
222
|
interface ChapterNetworkTarget {
|
|
220
223
|
/** Stable lowercase slug used by the UI, audit tags, and default secret name. */
|
|
221
224
|
id: string;
|
|
@@ -460,9 +463,12 @@ interface EmailTemplate {
|
|
|
460
463
|
interface ChapterEmails {
|
|
461
464
|
notificationEmail: string;
|
|
462
465
|
replyTo?: string;
|
|
466
|
+
/** Display name on outbound lifecycle mail (`Tori Horton <from@…>`); the
|
|
467
|
+
* address itself stays the Worker's `EMAIL_FROM`. Absent ⇒ bare address. */
|
|
468
|
+
fromName?: string;
|
|
463
469
|
debugEmail?: string;
|
|
464
|
-
/** Operational lifecycle templates: adminNotification /
|
|
465
|
-
* prepEmail / onboardingInvite, each `{ subject, text, enabled? }`. */
|
|
470
|
+
/** Operational lifecycle templates: adminNotification / submitConfirmation /
|
|
471
|
+
* paymentConfirmation / prepEmail / onboardingInvite, each `{ subject, text, enabled? }`. */
|
|
466
472
|
templates?: Record<string, EmailTemplate>;
|
|
467
473
|
}
|
|
468
474
|
/** Booking rules for the intro-call scheduler (stored as schedulingJson). */
|
package/dist/index.cjs
CHANGED
|
@@ -31,6 +31,7 @@ __export(src_exports, {
|
|
|
31
31
|
CHAPTER_PROMOTION_ADAPTER: () => CHAPTER_PROMOTION_ADAPTER,
|
|
32
32
|
DEFAULT_CHAPTER_COPY: () => DEFAULT_CHAPTER_COPY,
|
|
33
33
|
DEFAULT_SHARE_FIELDS: () => DEFAULT_SHARE_FIELDS,
|
|
34
|
+
EDGE_UNPAIRED: () => EDGE_UNPAIRED,
|
|
34
35
|
GIFT_OFFER_CATALOG_VERSION: () => GIFT_OFFER_CATALOG_VERSION,
|
|
35
36
|
JOURNEY_ENDINGS: () => JOURNEY_ENDINGS,
|
|
36
37
|
JOURNEY_STAGES: () => JOURNEY_STAGES,
|
|
@@ -111,6 +112,7 @@ __export(src_exports, {
|
|
|
111
112
|
defaultCrm: () => defaultCrm,
|
|
112
113
|
defineChapter: () => defineChapter,
|
|
113
114
|
drainMembershipEffects: () => drainMembershipEffects,
|
|
115
|
+
edgeUnpaired: () => edgeUnpaired,
|
|
114
116
|
emailGroupFrom: () => emailGroupFrom,
|
|
115
117
|
endForSlot: () => endForSlot,
|
|
116
118
|
exportChapterPromotion: () => exportChapterPromotion,
|
|
@@ -170,6 +172,7 @@ __export(src_exports, {
|
|
|
170
172
|
normalizeSharedRecord: () => normalizeSharedRecord,
|
|
171
173
|
normalizeWebhookEvent: () => normalizeWebhookEvent,
|
|
172
174
|
offerableTiers: () => offerableTiers,
|
|
175
|
+
pairingCommand: () => pairingCommand,
|
|
173
176
|
paymentsReady: () => paymentsReady,
|
|
174
177
|
personInputFromApp: () => personInputFromApp,
|
|
175
178
|
planDelivery: () => planDelivery,
|
|
@@ -777,7 +780,7 @@ var giftRedemptionAttemptsEntity = { attrs: {
|
|
|
777
780
|
} };
|
|
778
781
|
|
|
779
782
|
// src/payment-recovery-schema.ts
|
|
780
|
-
var field = (type, unique = false) => ({ type, unique, indexed: type !== "json", optional
|
|
783
|
+
var field = (type, unique = false, optional = false) => ({ type, unique, indexed: type !== "json", optional });
|
|
781
784
|
var paymentRecoveryReviewsEntity = { attrs: {
|
|
782
785
|
id: field("string", true),
|
|
783
786
|
eventId: field("string"),
|
|
@@ -786,7 +789,9 @@ var paymentRecoveryReviewsEntity = { attrs: {
|
|
|
786
789
|
previousDigest: field("string"),
|
|
787
790
|
providerDigest: field("string"),
|
|
788
791
|
scope: field("string"),
|
|
789
|
-
previousState: field("json")
|
|
792
|
+
previousState: field("json"),
|
|
793
|
+
action: field("string", false, true),
|
|
794
|
+
reason: field("string", false, true)
|
|
790
795
|
} };
|
|
791
796
|
|
|
792
797
|
// src/schema-stripe.ts
|
|
@@ -982,7 +987,7 @@ var boolean = (flags = {}) => ({
|
|
|
982
987
|
indexed: flags.indexed ?? false,
|
|
983
988
|
optional: false
|
|
984
989
|
});
|
|
985
|
-
var json2 = () => ({ type: "json", unique: false, indexed: false, optional: false });
|
|
990
|
+
var json2 = (flags = {}) => ({ type: "json", unique: false, indexed: false, optional: flags.optional ?? false });
|
|
986
991
|
var id4 = () => string2({ unique: true, indexed: true });
|
|
987
992
|
var events = { attrs: {
|
|
988
993
|
id: id4(),
|
|
@@ -1011,6 +1016,10 @@ var exceptions = { attrs: {
|
|
|
1011
1016
|
status: string2({ indexed: true }),
|
|
1012
1017
|
resolvedDigest: string2({ optional: true }),
|
|
1013
1018
|
incomingDigest: string2({ optional: true }),
|
|
1019
|
+
incomingFact: json2({ optional: true }),
|
|
1020
|
+
reviewedDigest: string2({ optional: true }),
|
|
1021
|
+
resolvedBy: string2({ optional: true }),
|
|
1022
|
+
reviewId: string2({ optional: true }),
|
|
1014
1023
|
detail: json2(),
|
|
1015
1024
|
updatedAt: number2({ indexed: true })
|
|
1016
1025
|
} };
|
|
@@ -1149,6 +1158,7 @@ var groups = {
|
|
|
1149
1158
|
stripePublishableKey: attr7("string", { optional: true }),
|
|
1150
1159
|
notificationEmail: attr7("string"),
|
|
1151
1160
|
replyTo: attr7("string"),
|
|
1161
|
+
fromName: attr7("string", { optional: true }),
|
|
1152
1162
|
debugEmail: attr7("string", { optional: true }),
|
|
1153
1163
|
calendarLink: attr7("string", { optional: true }),
|
|
1154
1164
|
disclaimerText: attr7("string"),
|
|
@@ -1345,6 +1355,13 @@ function defaultCrm(mode) {
|
|
|
1345
1355
|
};
|
|
1346
1356
|
}
|
|
1347
1357
|
|
|
1358
|
+
// src/named-seat-accepted-template.ts
|
|
1359
|
+
var SEAT_ACCEPTED_TEMPLATE = {
|
|
1360
|
+
enabled: true,
|
|
1361
|
+
subject: "{{recipientName}} accepted your {{chapterName}} seat",
|
|
1362
|
+
text: "Hi {{firstName}},\n\n{{recipientName}} has accepted the {{tierName}} seat you purchased at {{chapterName}}. They will complete their own application and any membership requirements from here; nothing more is needed from you.\n\nWarmly,\n{{chapterName}}"
|
|
1363
|
+
};
|
|
1364
|
+
|
|
1348
1365
|
// src/group.ts
|
|
1349
1366
|
var DEFAULT_SCHEDULING = {
|
|
1350
1367
|
slotMinutes: 45,
|
|
@@ -1366,7 +1383,16 @@ ${name}`;
|
|
|
1366
1383
|
text: `A new application came in for ${name}.
|
|
1367
1384
|
|
|
1368
1385
|
Name: {{firstName}} {{lastName}}
|
|
1369
|
-
Email: {{email}}
|
|
1386
|
+
Email: {{email}}
|
|
1387
|
+
Tier: {{tier}}
|
|
1388
|
+
|
|
1389
|
+
Review it: {{adminUrl}}`
|
|
1390
|
+
},
|
|
1391
|
+
submitConfirmation: {
|
|
1392
|
+
subject: `We received your application to ${name}`,
|
|
1393
|
+
text: `Hi {{firstName}},
|
|
1394
|
+
|
|
1395
|
+
Thanks for applying to ${name}. {{submitNextStep}}${sign}`
|
|
1370
1396
|
},
|
|
1371
1397
|
paymentConfirmation: {
|
|
1372
1398
|
subject: `Welcome to ${name}`,
|
|
@@ -1378,14 +1404,17 @@ Your membership payment{{paymentAmountSummary}} is confirmed. {{paymentNextStep}
|
|
|
1378
1404
|
subject: `Your ${name} intro call`,
|
|
1379
1405
|
text: `Hi {{firstName}},
|
|
1380
1406
|
|
|
1381
|
-
Looking forward to our call
|
|
1407
|
+
You are all set{{paymentAmountSummary}}. Looking forward to our call on {{startAt}}.
|
|
1408
|
+
|
|
1409
|
+
Join here: {{meetingLink}}${sign}`
|
|
1382
1410
|
},
|
|
1383
1411
|
onboardingInvite: {
|
|
1384
1412
|
subject: `You're in, ${name}`,
|
|
1385
1413
|
text: `Hi {{firstName}},
|
|
1386
1414
|
|
|
1387
1415
|
Welcome to ${name}. Your member area is here: {{membersUrl}}${sign}`
|
|
1388
|
-
}
|
|
1416
|
+
},
|
|
1417
|
+
seatAccepted: SEAT_ACCEPTED_TEMPLATE
|
|
1389
1418
|
};
|
|
1390
1419
|
}
|
|
1391
1420
|
function buildGroupSeed(config) {
|
|
@@ -1414,6 +1443,7 @@ function buildGroupSeed(config) {
|
|
|
1414
1443
|
schedulingJson: scheduling
|
|
1415
1444
|
};
|
|
1416
1445
|
if (emails?.debugEmail) row2.debugEmail = emails.debugEmail;
|
|
1446
|
+
if (emails?.fromName?.trim()) row2.fromName = emails.fromName.trim();
|
|
1417
1447
|
if (policy.commitmentText) row2.commitmentText = policy.commitmentText;
|
|
1418
1448
|
if (policy.normsText) row2.normsText = policy.normsText;
|
|
1419
1449
|
return row2;
|
|
@@ -1634,6 +1664,8 @@ var DEFAULT_ADMIN_COPY = {
|
|
|
1634
1664
|
delivery: "Delivery",
|
|
1635
1665
|
notificationAddress: "Notification address",
|
|
1636
1666
|
replyTo: "Reply-to",
|
|
1667
|
+
fromName: "From name",
|
|
1668
|
+
fromNameHint: "Shown as the sender; the address stays the Worker's configured one.",
|
|
1637
1669
|
debugInbox: "Debug inbox",
|
|
1638
1670
|
debugInboxHint: "Non-production sends redirect here.",
|
|
1639
1671
|
sendTest: "Send test",
|
|
@@ -1705,6 +1737,8 @@ var DEFAULT_ADMIN_COPY = {
|
|
|
1705
1737
|
transportReachable: "transport reachable",
|
|
1706
1738
|
transportUnavailable: "transport unavailable",
|
|
1707
1739
|
transportNotChecked: "transport not checked",
|
|
1740
|
+
edgeUnpaired: "edge unpaired",
|
|
1741
|
+
edgeUnpairedHint: "This follower's shared secret is not in the leader vault, so nothing can be signed. Pair both vaults from an enrolled machine:",
|
|
1708
1742
|
bindingTransport: "service binding {binding}",
|
|
1709
1743
|
urlTransport: "public URL transport",
|
|
1710
1744
|
activeConfiguration: "active configuration r{revision}",
|
|
@@ -1804,7 +1838,9 @@ var DEFAULT_JOIN_COPY = {
|
|
|
1804
1838
|
incomplete: "The payment did not complete. Please try again.",
|
|
1805
1839
|
consent: "I have read and agree to the pricing and refund policy above.",
|
|
1806
1840
|
foundingMember: "Founding member rate",
|
|
1807
|
-
foundingDiscount: "Founding discount"
|
|
1841
|
+
foundingDiscount: "Founding discount",
|
|
1842
|
+
standardRate: "Standard rate",
|
|
1843
|
+
yourRate: "Your rate"
|
|
1808
1844
|
},
|
|
1809
1845
|
done: {
|
|
1810
1846
|
label: "You're booked",
|
|
@@ -2433,6 +2469,10 @@ function defineChapter(config) {
|
|
|
2433
2469
|
if (!config.emails || typeof config.emails.notificationEmail !== "string" || config.emails.notificationEmail === "") {
|
|
2434
2470
|
throw new Error("defineChapter.emails.notificationEmail: required in chapter mode");
|
|
2435
2471
|
}
|
|
2472
|
+
const fromName = config.emails.fromName;
|
|
2473
|
+
if (fromName !== void 0 && (typeof fromName !== "string" || /[\r\n<>]/.test(fromName) || fromName.trim().length > 100)) {
|
|
2474
|
+
throw new Error("defineChapter.emails.fromName: must be one line of at most 100 characters with no angle brackets");
|
|
2475
|
+
}
|
|
2436
2476
|
if (!config.prices || typeof config.prices.standardCents !== "number") {
|
|
2437
2477
|
throw new Error("defineChapter.prices.standardCents: required in chapter mode");
|
|
2438
2478
|
}
|
|
@@ -3428,6 +3468,7 @@ function createChapterIntegration(chapter, options = {}) {
|
|
|
3428
3468
|
description: "Signing secret for the read-only network commercial Stripe webhook endpoint.",
|
|
3429
3469
|
required: true
|
|
3430
3470
|
});
|
|
3471
|
+
secrets.push(...federationEdgeSecrets(chapter));
|
|
3431
3472
|
return {
|
|
3432
3473
|
id: "chapter",
|
|
3433
3474
|
title: `Chapter: ${chapter.name}`,
|
|
@@ -3471,6 +3512,41 @@ function createChapterIntegration(chapter, options = {}) {
|
|
|
3471
3512
|
runbooks
|
|
3472
3513
|
};
|
|
3473
3514
|
}
|
|
3515
|
+
function federationEdgeSecrets(chapter) {
|
|
3516
|
+
const secrets = chapter.network.targets.map((target) => ({
|
|
3517
|
+
name: target.secretName,
|
|
3518
|
+
description: `Shared secret for the signed federation edge to follower "${target.id}"; pair both vaults with "odla-ai chapter edge pair --leader ${chapter.id} --follower ${target.id}".`,
|
|
3519
|
+
required: true,
|
|
3520
|
+
edge: { role: "leader", peers: [target.id] }
|
|
3521
|
+
}));
|
|
3522
|
+
const peers = [.../* @__PURE__ */ new Set([
|
|
3523
|
+
...chapter.network.readers.map((reader) => reader.id),
|
|
3524
|
+
...(chapter.builderLibrary?.sources ?? []).map((source) => source.sourceId)
|
|
3525
|
+
])];
|
|
3526
|
+
if (peers.length > 0) secrets.push({
|
|
3527
|
+
name: "network_share_secret",
|
|
3528
|
+
description: `Shared secret every declared leader (${peers.join(", ")}) signs federation requests with; pair it with "odla-ai chapter edge pair --leader <leader> --follower ${chapter.id}".`,
|
|
3529
|
+
required: true,
|
|
3530
|
+
edge: { role: "follower", peers }
|
|
3531
|
+
});
|
|
3532
|
+
return secrets;
|
|
3533
|
+
}
|
|
3534
|
+
|
|
3535
|
+
// src/network-edge.ts
|
|
3536
|
+
var EDGE_UNPAIRED = "edge_unpaired";
|
|
3537
|
+
function pairingCommand(leaderId, targetId, env) {
|
|
3538
|
+
const scope2 = env ? ` --env ${env}` : "";
|
|
3539
|
+
return `odla-ai chapter edge pair --leader ${leaderId} --follower ${targetId}${scope2}`;
|
|
3540
|
+
}
|
|
3541
|
+
function edgeUnpaired(leaderId, target, env) {
|
|
3542
|
+
return {
|
|
3543
|
+
code: EDGE_UNPAIRED,
|
|
3544
|
+
target: target.id,
|
|
3545
|
+
secretName: target.secretName,
|
|
3546
|
+
message: `edge to "${target.id}" is unpaired: leader vault slot "${target.secretName}" is empty`,
|
|
3547
|
+
hint: pairingCommand(leaderId, target.id, env)
|
|
3548
|
+
};
|
|
3549
|
+
}
|
|
3474
3550
|
|
|
3475
3551
|
// src/membership-policy.ts
|
|
3476
3552
|
function seatPurchaseDeadline(offering, member) {
|
|
@@ -6840,6 +6916,12 @@ function planDelivery(input) {
|
|
|
6840
6916
|
}
|
|
6841
6917
|
|
|
6842
6918
|
// src/notify.ts
|
|
6919
|
+
function fromAddress(configured, name) {
|
|
6920
|
+
const display = name?.trim();
|
|
6921
|
+
if (!display) return configured;
|
|
6922
|
+
const angled = configured.match(/<([^>]+)>/);
|
|
6923
|
+
return { name: display, email: (angled ? angled[1] : configured).trim() };
|
|
6924
|
+
}
|
|
6843
6925
|
async function sendTemplated(deps, input) {
|
|
6844
6926
|
const { emailLog: emailLog2 } = await deps.db.query({ emailLog: { $: { where: { dedupeKey: input.dedupeKey } } } });
|
|
6845
6927
|
const prior = Array.isArray(emailLog2) ? emailLog2 : [];
|
|
@@ -6902,7 +6984,7 @@ async function sendTemplated(deps, input) {
|
|
|
6902
6984
|
let messageId;
|
|
6903
6985
|
try {
|
|
6904
6986
|
const response = await deps.sender.send({
|
|
6905
|
-
from: deps.from,
|
|
6987
|
+
from: fromAddress(deps.from, input.group.fromName),
|
|
6906
6988
|
to: [decision.to],
|
|
6907
6989
|
subject: String(row2.subject),
|
|
6908
6990
|
text: String(row2.body),
|
|
@@ -6935,6 +7017,7 @@ function emailGroupFrom(row2) {
|
|
|
6935
7017
|
name: String(row2.name ?? ""),
|
|
6936
7018
|
replyTo: str2(row2.replyTo) ?? "",
|
|
6937
7019
|
debugEmail: str2(row2.debugEmail),
|
|
7020
|
+
fromName: str2(row2.fromName),
|
|
6938
7021
|
refundPolicyText: str2(row2.refundPolicyText),
|
|
6939
7022
|
commitmentText: str2(row2.commitmentText),
|
|
6940
7023
|
normsText: str2(row2.normsText),
|