feat(engagement): the engagement system — cutover 3 of 7 (edge → main)
#180
@@ -44,6 +44,27 @@ const AMBIENT_VARIABLES = Object.freeze([
|
|||||||
{ name: 'year', type: 'string', required: true, example: '2026' },
|
{ name: 'year', type: 'string', required: true, example: '2026' },
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
|
// The per-DELIVERY additions, which are a different thing from the ambient set
|
||||||
|
// above and are declared separately because they apply to a different set of
|
||||||
|
// templates.
|
||||||
|
//
|
||||||
|
// `emailChannel.deliver` computes an unsubscribe token per recipient and merges
|
||||||
|
// it LAST over the projection, so a body may always reference it — but a template
|
||||||
|
// bound to a TRIGGER takes its variable list from that trigger's declaration
|
||||||
|
// (`variablesFor`), and a trigger has no business declaring a fact about how the
|
||||||
|
// mail was delivered. Without these, `{{unsubscribeUrl}}` renders correctly and
|
||||||
|
// then the save-time undeclared-variable check refuses the first operator who
|
||||||
|
// tries to EDIT the body around it.
|
||||||
|
//
|
||||||
|
// Found in Phase 11b, where module-uo's sixteen in-universe bodies are the first
|
||||||
|
// trigger-bound templates in the system to carry an unsubscribe line of their
|
||||||
|
// own: core's generic `notify.event` declares it in its own seed and is bound to
|
||||||
|
// no trigger, so nothing had ever taken this path.
|
||||||
|
const DELIVERY_VARIABLES = Object.freeze([
|
||||||
|
{ name: 'unsubscribeUrl', type: 'string', required: false, example: 'https://example.com/unsubscribe/abc123' },
|
||||||
|
])
|
||||||
|
|
||||||
// A tiny helper so the block arrays below read as content rather than as JSON.
|
// A tiny helper so the block arrays below read as content rather than as JSON.
|
||||||
const text = (id, body, opts = {}) => ({
|
const text = (id, body, opts = {}) => ({
|
||||||
id,
|
id,
|
||||||
@@ -296,4 +317,4 @@ function seedByKey(key) {
|
|||||||
return SEEDS.find((s) => s.key === key) || null
|
return SEEDS.find((s) => s.key === key) || null
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { SEEDS, AMBIENT_VARIABLES, seedByKey }
|
module.exports = { SEEDS, AMBIENT_VARIABLES, DELIVERY_VARIABLES, seedByKey }
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ const templatesDb = require('../model/engagement/engagementTemplates.db')
|
|||||||
const settings = require('../model/settings/settings.model')
|
const settings = require('../model/settings/settings.model')
|
||||||
const brand = require('../config/brand')
|
const brand = require('../config/brand')
|
||||||
const emailBlocks = require('../emailBlocks')
|
const emailBlocks = require('../emailBlocks')
|
||||||
const { SEEDS, AMBIENT_VARIABLES, seedByKey } = require('./templateSeeds')
|
const { SEEDS, AMBIENT_VARIABLES, DELIVERY_VARIABLES, seedByKey } = require('./templateSeeds')
|
||||||
// The trigger registry lives with the module registries, not here — a trigger is
|
// The trigger registry lives with the module registries, not here — a trigger is
|
||||||
// something a MODULE declares (see engagement/index.js's header).
|
// something a MODULE declares (see engagement/index.js's header).
|
||||||
const { eventTrigger } = require('../modules/registries')
|
const { eventTrigger } = require('../modules/registries')
|
||||||
@@ -84,6 +84,11 @@ function variablesFor(template) {
|
|||||||
if (template && template.trigger_id) {
|
if (template && template.trigger_id) {
|
||||||
const declared = eventTrigger(template.trigger_id)
|
const declared = eventTrigger(template.trigger_id)
|
||||||
if (declared && Array.isArray(declared.variables)) own.push(...declared.variables)
|
if (declared && Array.isArray(declared.variables)) own.push(...declared.variables)
|
||||||
|
// A trigger-bound body is engagement mail, and engagement mail always carries
|
||||||
|
// an unsubscribe the channel computes per recipient. A trigger declares what
|
||||||
|
// HAPPENED and has no business declaring how the mail was sent, so the
|
||||||
|
// delivery facts are added here rather than to every declaration.
|
||||||
|
own.push(...DELIVERY_VARIABLES)
|
||||||
} else if (template && template.seed_key) {
|
} else if (template && template.seed_key) {
|
||||||
const seed = seedByKey(template.seed_key)
|
const seed = seedByKey(template.seed_key)
|
||||||
if (seed) own.push(...seed.variables)
|
if (seed) own.push(...seed.variables)
|
||||||
|
|||||||
Reference in New Issue
Block a user