mailery 0.15.0 → 0.16.0

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/server/adapters/vars.ts","../src/server/adapters/mongo.ts","../src/server/providers/webhook-tolerance.ts","../src/server/providers/sendgrid.ts","../src/shared/schemas.ts","../src/server/config.ts","../src/server/models/index.ts","../src/server/events.ts","../src/server/provider-lookup.ts","../src/server/tokens.ts","../src/server/unsubscribe.ts","../src/server/queues/bull.ts","../src/server/queues/agenda.ts","../src/server/queues/noop.ts","../src/server/queues/index.ts","../src/server/runner/triggers.ts","../src/server/templates/sender-domain.ts","../src/server/runner/health.ts","../src/server/runner/webhook.ts","../src/server/runner/predicate.ts","../src/server/runner/delivery-window.ts","../src/server/templates/render.ts","../src/server/runner/send.ts","../src/server/runner/suppression.ts","../src/server/runner/step.ts","../src/server/runner/sweep.ts","../src/server/runner/broadcasts.ts","../src/server/runner/bounce-promotion.ts","../src/server/runner/dnsbl.ts","../src/server/runner/postmaster.ts","../src/server/runner/snds.ts","../src/server/runner/dmarc.ts","../src/server/unsub-journal.ts","../src/server/runner/pending-unsubs.ts","../src/server/runner/tick.ts","../src/server/mailer.ts","../src/server/index.ts","../src/server/providers/null.ts","../src/server/templates/linter.ts","../src/server/api/admin.ts","../src/shared/enums.ts","../src/server/api/setup-status.ts","../src/server/runner/hygiene.ts","../src/server/runner/mail-tester.ts","../src/server/api/wrap.ts","../src/server/api/dmarc-inbound.ts","../src/server/api/public.ts","../src/shared/options.ts"],"names":["RESERVED_VAR_KEYS","z","MongoContactAdapter","ObjectId","SendGridProvider","sgMail","crypto","IORedis","QUEUE_NAMES","counter","mjml2html","htmlToText","Handlebars","branchKey","DAY_MS","dns","net","psl","path","FETCH_TIMEOUT_MS","safeText","dst","XMLParser","fs","randomBytes","processScheduledBroadcasts","assertNoReservedVarKeys","ObjectIdCtor","cursor","__filename","fileURLToPath","__dirname","Router","express","r","report","multer","createHash","timingSafeEqual"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,IAAA,YAAA,GAAA,EAAA;AAAA,QAAA,CAAA,YAAA,EAAA;AAAA,EAAA,iBAAA,EAAA,MAAAA,yBAAA;AAAA,EAAA,uBAAA,EAAA,MAAA,uBAAA;AAAA,EAAA,UAAA,EAAA,MAAA,UAAA;AAAA,EAAA,WAAA,EAAA,MAAA,WAAA;AAAA,EAAA,cAAA,EAAA,MAAA;AAAA,CAAA,CAAA;AAsDO,SAAS,WAAgC,OAAA,EAAyC;AACvF,EAAA,OAAO,OAAA;AACT;AAoBO,SAAS,wBAAwB,OAAA,EAA4B;AAClE,EAAA,MAAM,IAAA,GAAO,eAAe,OAAO,CAAA;AACnC,EAAA,MAAM,QAAQ,IAAA,IAAQ,OAAO,IAAA,KAAS,QAAA,GAAY,KAAa,UAAA,GAAa,MAAA;AAC5E,EAAA,IAAI,CAAC,KAAA,EAAO;AACZ,EAAA,MAAM,UAAUA,yBAAA,CAAkB,MAAA,CAAO,CAAC,CAAA,KAAM,KAAK,KAAK,CAAA;AAC1D,EAAA,IAAI,OAAA,CAAQ,SAAS,CAAA,EAAG;AACtB,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,6CAAA,EAAgD,OAAA,CAAQ,IAAA,CAAK,IAAI,CAAC,CAAA,+EAAA;AAAA,KAEpE;AAAA,EACF;AACF;AAGO,SAAS,eAAe,OAAA,EAA+C;AAC5E,EAAA,OAAOC,MAAE,YAAA,CAAa,OAAA,CAAQ,QAAQ,EAAE,EAAA,EAAI,UAAU,CAAA;AACxD;AAOA,eAAsB,WAAA,CACpB,OAAA,EACA,OAAA,EACA,IAAA,EACkC;AAClC,EAAA,IAAI,CAAC,OAAA,EAAS,OAAO,EAAC;AACtB,EAAA,MAAM,QAAA,GAAW,MAAM,OAAA,CAAQ,OAAA,CAAQ,SAAS,IAAI,CAAA;AACpD,EAAA,IAAI,CAAC,QAAA,IAAY,OAAO,QAAA,KAAa,QAAA,SAAiB,EAAC;AAGvD,EAAA,MAAM,GAAA,GAA+B,EAAE,GAAI,QAAA,EAAqC;AAChF,EAAA,KAAA,MAAW,CAAA,IAAKD,yBAAA,EAAmB,OAAO,GAAA,CAAI,CAAC,CAAA;AAC/C,EAAA,OAAO,GAAA;AACT;AAlDaA;AA9Db,IAAA,SAAA,GAAA,KAAA,CAAA;AAAA,EAAA,6BAAA,GAAA;AA8DO,IAAMA,yBAAA,GAAoB;AAAA,MAC/B,SAAA;AAAA,MACA,MAAA;AAAA,MACA,OAAA;AAAA,MACA,gBAAA;AAAA,MACA,kBAAA;AAAA,MACA,qBAAA;AAAA,MACA;AAAA,KACF;AAAA,EAAA;AAAA,CAAA,CAAA;;;ACtEA,IAAA,aAAA,GAAA,EAAA;AAAA,QAAA,CAAA,aAAA,EAAA;AAAA,EAAA,mBAAA,EAAA,MAAAE;AAAA,CAAA,CAAA;AA8NA,SAAS,cAAc,CAAA,EAAoB;AACzC,EAAA,OAAO,OAAO,CAAA,KAAM,QAAA,IAAY,iBAAA,CAAkB,KAAK,CAAC,CAAA;AAC1D;AA9LaA;AAlCb,IAAA,UAAA,GAAA,KAAA,CAAA;AAAA,EAAA,8BAAA,GAAA;AAkCO,IAAMA,8BAAN,MAAoD;AAAA,MACxC,GAAA;AAAA,MACA,UAAA;AAAA,MACA,OAAA;AAAA,MACA,SAAA;AAAA,MACA,YAAA;AAAA,MACA,cAAA;AAAA,MACA,WAAA;AAAA,MACA,iBAAA;AAAA,MACA,SAAA;AAAA,MAEjB,YAAY,IAAA,EAAkC;AAC5C,QAAA,IAAA,CAAK,GAAA,GAAM,IAAA,CAAK,EAAA,CAAG,UAAA,CAAW,KAAK,UAAU,CAAA;AAC7C,QAAA,IAAA,CAAK,UAAA,GAAa,KAAK,UAAA,IAAc,OAAA;AACrC,QAAA,IAAA,CAAK,OAAA,GAAU,KAAK,OAAA,IAAW,KAAA;AAC/B,QAAA,IAAA,CAAK,SAAA,GAAY,KAAK,SAAA,IAAa,IAAA;AACnC,QAAA,IAAA,CAAK,YAAA,GAAe,CAAC,CAAC,IAAA,CAAK,YAAA;AAC3B,QAAA,IAAA,CAAK,cAAA,GAAiB,KAAK,cAAA,IAAkB,SAAA;AAC7C,QAAA,IAAA,CAAK,cAAc,IAAA,CAAK,SAAA,IAAa,IAAA,CAAK,gBAAA,CAAiB,KAAK,IAAI,CAAA;AACpE,QAAA,IAAA,CAAK,oBAAoB,IAAA,CAAK,eAAA,IAAmB,IAAA,CAAK,sBAAA,CAAuB,KAAK,IAAI,CAAA;AACtF,QAAA,IAAA,CAAK,SAAA,GAAY,KAAK,SAAA,IAAa,GAAA;AAGnC,QAAA,IAAI,IAAA,CAAK,YAAA,IAAgB,IAAA,CAAK,SAAA,EAAW;AACvC,UAAA,IAAA,CAAK,OAAA,GAAU,IAAA,CAAK,WAAA,CAAY,IAAA,CAAK,IAAI,CAAA;AACzC,UAAA,IAAA,CAAK,UAAA,GAAa,IAAA,CAAK,cAAA,CAAe,IAAA,CAAK,IAAI,CAAA;AAAA,QACjD;AAAA,MACF;AAAA,MAEA,MAAM,QAAQ,UAAA,EAA6C;AACzD,QAAA,MAAM,MAAA,GAAS,IAAA,CAAK,QAAA,CAAS,UAAU,CAAA;AACvC,QAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,GAAA,CAAI,QAAQ,MAAM,CAAA;AACzC,QAAA,OAAO,GAAA,GAAM,IAAA,CAAK,WAAA,CAAY,GAAG,CAAA,GAAI,IAAA;AAAA,MACvC;AAAA,MAEA,MAAM,WAAW,KAAA,EAAwC;AACvD,QAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,GAAA,CAAI,OAAA,CAAQ,EAAE,CAAC,IAAA,CAAK,UAAU,GAAG,KAAA,CAAM,WAAA,IAAe,CAAA;AAC7E,QAAA,OAAO,GAAA,GAAM,IAAA,CAAK,WAAA,CAAY,GAAG,CAAA,GAAI,IAAA;AAAA,MACvC;AAAA,MAEA,MAAM,SAAS,WAAA,EAAsD;AACnE,QAAA,IAAI,WAAA,CAAY,MAAA,KAAW,CAAA,EAAG,2BAAW,GAAA,EAAI;AAC7C,QAAA,MAAM,WAAA,GAAc,WAAA,CAAY,KAAA,CAAM,aAAa,CAAA;AACnD,QAAA,MAAM,GAAA,GAAa,WAAA,GAAc,WAAA,CAAY,GAAA,CAAI,CAAC,MAAM,IAAIC,gBAAAA,CAAS,CAAC,CAAC,CAAA,GAAI,WAAA;AAC3E,QAAA,MAAM,OAAO,MAAM,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,EAAE,CAAC,IAAA,CAAK,OAAO,GAAG,EAAE,GAAA,EAAK,GAAA,EAAI,EAAG,EAAE,OAAA,EAAQ;AAC3E,QAAA,MAAM,GAAA,uBAAU,GAAA,EAAqB;AACrC,QAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,UAAA,MAAM,CAAA,GAAI,IAAA,CAAK,WAAA,CAAY,GAAG,CAAA;AAC9B,UAAA,GAAA,CAAI,GAAA,CAAI,CAAA,CAAE,UAAA,EAAY,CAAC,CAAA;AAAA,QACzB;AACA,QAAA,OAAO,GAAA;AAAA,MACT;AAAA,MAEA,MAAM,KAAA,CACJ,MAAA,EACA,IAAA,EACuD;AACvD,QAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,iBAAA,CAAkB,MAAM,CAAA;AAC3C,QAAA,MAAM,QAAQ,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,KAAA,EAAO,KAAK,SAAS,CAAA;AAIjD,QAAA,IAAI,KAAK,MAAA,EAAQ;AACf,UAAA,MAAM,SAAA,GAAY,aAAA,CAAc,IAAA,CAAK,MAAM,CAAA,GAAI,IAAIA,gBAAAA,CAAS,IAAA,CAAK,MAAM,CAAA,GAAI,IAAA,CAAK,MAAA;AAC/E,UAAC,KAAA,CAAc,IAAA,CAAK,OAAO,CAAA,GAAI,EAAE,GAAK,KAAA,CAAc,IAAA,CAAK,OAAO,CAAA,IAAK,EAAC,EAAI,KAAK,SAAA,EAAU;AAAA,QAC5F;AAEA,QAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,GAAA,CACrB,KAAK,KAAK,CAAA,CACV,KAAK,EAAE,CAAC,KAAK,OAAO,GAAG,GAAG,CAAA,CAC1B,MAAM,KAAA,GAAQ,CAAC,EACf,OAAA,EAAQ;AAEX,QAAA,MAAM,OAAA,GAAU,KAAK,MAAA,GAAS,KAAA;AAC9B,QAAA,MAAM,QAAQ,OAAA,GAAU,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,KAAK,CAAA,GAAI,IAAA;AAC/C,QAAA,MAAM,QAAA,GAAW,MAAM,GAAA,CAAI,CAAC,MAAM,IAAA,CAAK,WAAA,CAAY,CAAC,CAAC,CAAA;AACrD,QAAA,MAAM,IAAA,GAAO,KAAA,CAAM,KAAA,CAAM,MAAA,GAAS,CAAC,CAAA;AACnC,QAAA,MAAM,UAAA,GAAa,WAAW,IAAA,GAAO,MAAA,CAAQ,KAAa,IAAA,CAAK,OAAO,CAAC,CAAA,GAAI,MAAA;AAC3E,QAAA,OAAO,EAAE,UAAU,UAAA,EAAW;AAAA,MAChC;AAAA,MAEA,MAAM,MAAM,MAAA,EAAwC;AAClD,QAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,iBAAA,CAAkB,MAAM,CAAA;AAC3C,QAAA,OAAO,MAAM,IAAA,CAAK,GAAA,CAAI,cAAA,CAAe,KAAK,CAAA;AAAA,MAC5C;AAAA,MAEA,OAAA;AAAA,MACA,UAAA;AAAA;AAAA;AAAA;AAAA,MAMQ,SAAS,UAAA,EAAiC;AAChD,QAAA,IAAI,IAAA,CAAK,OAAA,KAAY,KAAA,IAAS,aAAA,CAAc,UAAU,CAAA,EAAG;AACvD,UAAA,OAAO,EAAE,GAAA,EAAK,IAAIA,gBAAAA,CAAS,UAAU,CAAA,EAAE;AAAA,QACzC;AACA,QAAA,OAAO,EAAE,CAAC,IAAA,CAAK,OAAO,GAAG,UAAA,EAAW;AAAA,MACtC;AAAA,MAEQ,iBAAiB,GAAA,EAAmB;AAC1C,QAAA,MAAM,OAAA,GAAU,KAAK,SAAA,GAAY,GAAA,CAAI,KAAK,SAAS,CAAA,IAAK,EAAC,GAAI,EAAC;AAC9D,QAAA,MAAM,IAAA,GACJ,IAAA,CAAK,cAAA,KAAmB,SAAA,GAAA,CACnB,MAAM,OAAA,CAAQ,OAAO,CAAA,GAAI,OAAA,GAAU,EAAC,EAAG,GAAA,CAAI,CAAC,MAAW,MAAA,CAAO,CAAA,CAAE,IAAA,IAAQ,CAAC,CAAC,CAAA,GAAA,CAC1E,KAAA,CAAM,OAAA,CAAQ,OAAO,CAAA,GAAI,OAAA,GAAU,EAAC,EAAG,GAAA,CAAI,CAAC,CAAA,KAAW,MAAA,CAAO,CAAC,CAAC,CAAA;AAEvE,QAAA,MAAM,aAAa,MAAA,CAAO,GAAA,CAAI,IAAA,CAAK,OAAO,KAAK,EAAE,CAAA;AACjD,QAAA,MAAM,KAAA,GAAQ,OAAO,GAAA,CAAI,IAAA,CAAK,UAAU,CAAA,IAAK,EAAE,EAAE,WAAA,EAAY;AAG7D,QAAA,MAAM,SAAkC,EAAC;AACzC,QAAA,KAAA,MAAW,CAAC,CAAA,EAAG,CAAC,KAAK,MAAA,CAAO,OAAA,CAAQ,GAAG,CAAA,EAAG;AACxC,UAAA,IAAI,CAAA,KAAM,KAAK,OAAA,IAAW,CAAA,KAAM,KAAK,UAAA,IAAc,CAAA,KAAM,KAAK,SAAA,EAAW;AACzE,UAAA,MAAA,CAAO,CAAC,CAAA,GAAI,CAAA;AAAA,QACd;AAEA,QAAA,OAAO;AAAA,UACL,UAAA;AAAA,UACA,KAAA;AAAA,UACA,IAAA;AAAA,UACA,MAAA;AAAA,UACA,UAAU,OAAO,GAAA,CAAI,QAAA,KAAa,QAAA,GAAW,IAAI,QAAA,GAAW,MAAA;AAAA,UAC5D,QAAQ,OAAO,GAAA,CAAI,MAAA,KAAW,QAAA,GAAW,IAAI,MAAA,GAAS;AAAA,SACxD;AAAA,MACF;AAAA,MAEQ,uBAAuB,MAAA,EAAoC;AACjE,QAAA,MAAM,IAA6B,EAAC;AAEpC,QAAA,IAAI,MAAA,CAAO,OAAA,IAAW,MAAA,CAAO,OAAA,CAAQ,SAAS,CAAA,EAAG;AAC/C,UAAA,CAAA,CAAE,IAAA,CAAK,UAAU,CAAA,GAAI,EAAE,GAAA,EAAK,MAAA,CAAO,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,WAAA,EAAa,CAAA,EAAE;AAAA,QACzE;AACA,QAAA,IAAI,MAAA,CAAO,YAAA,IAAgB,MAAA,CAAO,YAAA,CAAa,SAAS,CAAA,EAAG;AACzD,UAAA,MAAM,WAAA,GAAc,MAAA,CAAO,YAAA,CAAa,KAAA,CAAM,aAAa,CAAA;AAC3D,UAAA,CAAA,CAAE,IAAA,CAAK,OAAO,CAAA,GAAI;AAAA,YAChB,GAAA,EAAK,WAAA,GAAc,MAAA,CAAO,YAAA,CAAa,GAAA,CAAI,CAAC,CAAA,KAAM,IAAIA,gBAAAA,CAAS,CAAC,CAAC,CAAA,GAAI,MAAA,CAAO;AAAA,WAC9E;AAAA,QACF;AACA,QAAA,IAAI,OAAO,WAAA,EAAa;AACtB,UAAA,CAAA,CAAE,MAAA,CAAO,WAAA,CAAY,KAAK,CAAA,GAAI,OAAO,WAAA,CAAY,KAAA;AAAA,QACnD;AACA,QAAA,IAAI,OAAO,OAAA,EAAS;AAClB,UAAA,CAAA,CAAE,MAAA,CAAO,QAAQ,KAAK,CAAA,GAAI,EAAE,GAAA,EAAK,MAAA,CAAO,QAAQ,MAAA,EAAO;AAAA,QACzD;AACA,QAAA,IAAI,OAAO,WAAA,EAAa;AACtB,UAAA,CAAA,CAAE,MAAA,CAAO,WAAW,CAAA,GAAI,EAAE,SAAS,IAAA,EAAK;AAAA,QAC1C;AACA,QAAA,IAAI,MAAA,CAAO,YAAA,IAAgB,MAAA,CAAO,aAAA,EAAe;AAC/C,UAAA,MAAM,IAAS,EAAC;AAChB,UAAA,IAAI,MAAA,CAAO,YAAA,EAAc,CAAA,CAAE,IAAA,GAAO,MAAA,CAAO,YAAA;AACzC,UAAA,IAAI,MAAA,CAAO,aAAA,EAAe,CAAA,CAAE,IAAA,GAAO,MAAA,CAAO,aAAA;AAC1C,UAAA,CAAA,CAAE,SAAA,GAAY,CAAA;AAAA,QAChB;AACA,QAAA,IAAI,KAAK,SAAA,EAAW;AAClB,UAAA,IAAI,OAAO,MAAA,EAAQ;AACjB,YAAA,CAAA,CAAE,IAAA,CAAK,SAAS,CAAA,GAAI,MAAA,CAAO,MAAA;AAAA,UAC7B;AACA,UAAA,IAAI,MAAA,CAAO,QAAA,IAAY,MAAA,CAAO,QAAA,CAAS,SAAS,CAAA,EAAG;AACjD,YAAA,CAAA,CAAE,KAAK,SAAS,CAAA,GAAI,EAAE,GAAA,EAAK,OAAO,QAAA,EAAS;AAAA,UAC7C;AAAA,QACF;AACA,QAAA,OAAO,CAAA;AAAA,MACT;AAAA,MAEA,MAAc,WAAA,CAAY,UAAA,EAAoB,IAAA,EAA+B;AAC3E,QAAA,IAAI,CAAC,IAAA,CAAK,SAAA,IAAa,IAAA,CAAK,WAAW,CAAA,EAAG;AAC1C,QAAA,MAAM,KAAA,GACJ,IAAA,CAAK,cAAA,KAAmB,SAAA,GACpB,IAAA,CAAK,GAAA,CAAI,CAAC,IAAA,MAAU,EAAE,IAAA,EAAK,CAAE,CAAA,GAC7B,IAAA;AACN,QAAA,MAAM,KAAK,GAAA,CAAI,SAAA,CAAU,IAAA,CAAK,QAAA,CAAS,UAAU,CAAA,EAAG;AAAA,UAClD,SAAA,EAAW,EAAE,CAAC,IAAA,CAAK,SAAS,GAAG,EAAE,KAAA,EAAO,KAAA,EAAM;AAAE,SACjD,CAAA;AAAA,MACH;AAAA,MAEA,MAAc,cAAA,CAAe,UAAA,EAAoB,IAAA,EAA+B;AAC9E,QAAA,IAAI,CAAC,IAAA,CAAK,SAAA,IAAa,IAAA,CAAK,WAAW,CAAA,EAAG;AAC1C,QAAA,MAAM,QACJ,IAAA,CAAK,cAAA,KAAmB,SAAA,GACpB,EAAE,KAAK,IAAA,CAAK,GAAA,CAAI,CAAC,IAAA,MAAU,EAAE,IAAA,EAAK,CAAE,GAAE,GACtC,EAAE,KAAK,IAAA,EAAK;AAClB,QAAA,MAAM,KAAK,GAAA,CAAI,SAAA,CAAU,IAAA,CAAK,QAAA,CAAS,UAAU,CAAA,EAAG;AAAA,UAClD,OAAO,EAAE,CAAC,IAAA,CAAK,SAAS,GAAG,KAAA;AAAM,SAClC,CAAA;AAAA,MACH;AAAA,KACF;AAAA,EAAA;AAAA,CAAA,CAAA;;;ACtLO,SAAS,+BACd,MAAA,EACQ;AACR,EAAA,IAAI,MAAA,KAAW,KAAA,IAAS,MAAA,KAAW,CAAA,EAAG,OAAO,CAAA;AAC7C,EAAA,IAAI,MAAA,KAAW,MAAA,IAAa,MAAA,KAAW,IAAA,EAAM,OAAO,iCAAA;AACpD,EAAA,IAAI,OAAO,WAAW,QAAA,IAAY,CAAC,OAAO,QAAA,CAAS,MAAM,CAAA,IAAK,MAAA,GAAS,CAAA,EAAG;AACxE,IAAA,OAAO,iCAAA;AAAA,EACT;AACA,EAAA,OAAO,MAAA;AACT;AAaO,SAAS,wBACd,YAAA,EACA,gBAAA,EACA,GAAA,mBAAY,IAAI,MAAK,EACZ;AAGT,EAAA,IAAI,gBAAA,KAAqB,GAAG,OAAO,IAAA;AACnC,EAAA,IAAI,CAAC,cAAc,OAAO,KAAA;AAK1B,EAAA,IAAI,CAAC,YAAA,CAAa,IAAA,CAAK,YAAY,GAAG,OAAO,KAAA;AAE7C,EAAA,MAAM,WAAA,GAAc,MAAA,CAAO,YAAY,CAAA,GAAI,GAAA;AAC3C,EAAA,IAAI,CAAC,MAAA,CAAO,QAAA,CAAS,WAAW,GAAG,OAAO,KAAA;AAE1C,EAAA,MAAM,UAAU,IAAA,CAAK,GAAA,CAAI,GAAA,CAAI,OAAA,KAAY,WAAW,CAAA;AACpD,EAAA,OAAO,WAAW,gBAAA,GAAmB,GAAA;AACvC;AAhFA,IAsBa,iCAAA;AAtBb,IAAA,sBAAA,GAAA,KAAA,CAAA;AAAA,EAAA,2CAAA,GAAA;AAsBO,IAAM,iCAAA,GAAoC,GAAA;AAAA,EAAA;AAAA,CAAA,CAAA;;;ACtBjD,IAAA,gBAAA,GAAA,EAAA;AAAA,QAAA,CAAA,gBAAA,EAAA;AAAA,EAAA,gBAAA,EAAA,MAAAC;AAAA,CAAA,CAAA;AA8HA,SAAS,uBAAuB,CAAA,EAAgC;AAC9D,EAAA,MAAM,IAAA,GAAO,YAAA,CAAa,CAAA,CAAE,KAAK,CAAA;AACjC,EAAA,IAAI,CAAC,MAAM,OAAO,IAAA;AAClB,EAAA,OAAO;AAAA,IACL,IAAA;AAAA,IACA,iBAAiB,MAAA,CAAO,CAAA,CAAE,WAAA,IAAe,CAAA,CAAE,SAAS,CAAA,IAAK,CAAA,EAAG,CAAA,CAAE,KAAK,IAAI,CAAA,CAAE,SAAS,CAAA,CAAA,EAAI,CAAA,CAAE,KAAK,CAAA,CAAE,CAAA;AAAA,IAC/F,mBAAmB,MAAA,CAAO,CAAA,CAAE,iBAAiB,CAAA,CAAE,SAAS,KAAK,EAAE,CAAA;AAAA,IAC/D,OAAO,MAAA,CAAO,CAAA,CAAE,KAAA,IAAS,EAAE,EAAE,WAAA,EAAY;AAAA,IACzC,YAAY,IAAI,IAAA,CAAK,OAAO,CAAA,CAAE,SAAS,IAAI,GAAI,CAAA;AAAA,IAC/C,OAAA,EAAS;AAAA,MACP,UAAA,EACE,EAAE,KAAA,KAAU,QAAA,GAAY,EAAE,IAAA,KAAS,QAAA,GAAW,SAAS,MAAA,GAAU,MAAA;AAAA,MACnE,cAAc,CAAA,CAAE,MAAA;AAAA,MAChB,YAAY,CAAA,CAAE,GAAA;AAAA,MACd,WAAW,CAAA,CAAE,SAAA;AAAA,MACb,WAAW,CAAA,CAAE;AAAA;AACf,GACF;AACF;AAEA,SAAS,aAAa,OAAA,EAAiD;AACrE,EAAA,QAAQ,OAAA;AAAS,IACf,KAAK,WAAA;AACH,MAAA,OAAO,WAAA;AAAA,IACT,KAAK,MAAA;AACH,MAAA,OAAO,MAAA;AAAA,IACT,KAAK,OAAA;AACH,MAAA,OAAO,OAAA;AAAA,IACT,KAAK,QAAA;AAAA,IACL,KAAK,SAAA;AACH,MAAA,OAAO,QAAA;AAAA,IACT,KAAK,YAAA;AACH,MAAA,OAAO,aAAA;AAAA,IACT,KAAK,aAAA;AAAA,IACL,KAAK,mBAAA;AACH,MAAA,OAAO,aAAA;AAAA,IACT;AACE,MAAA,OAAO,IAAA;AAAA;AAEb;AArKA,IA+CM,eACA,YAAA,CAAA,CAEOA;AAlDb,IAAA,aAAA,GAAA,KAAA,CAAA;AAAA,EAAA,kCAAA,GAAA;AAqBA,IAAA,sBAAA,EAAA;AA0BA,IAAM,aAAA,GAAgB,wCAAA;AACtB,IAAM,YAAA,GAAe,wCAAA;AAEd,IAAMA,2BAAN,MAA+C;AAAA,MAMpD,YAA6B,IAAA,EAA+B;AAA/B,QAAA,IAAA,CAAA,IAAA,GAAA,IAAA;AAC3B,QAAAC,uBAAA,CAAO,SAAA,CAAU,KAAK,MAAM,CAAA;AAC5B,QAAA,IAAA,CAAK,iBAAA,GAAoB,KAAK,iBAAA,IAAqB,EAAA;AACnD,QAAA,IAAA,CAAK,uBAAA,GAA0B,8BAAA,CAA+B,IAAA,CAAK,uBAAuB,CAAA;AAAA,MAC5F;AAAA,MAJ6B,IAAA;AAAA,MALpB,IAAA,GAAO,UAAA;AAAA,MACP,iBAAA;AAAA;AAAA,MAEA,uBAAA;AAAA,MAQT,MAAM,KAAK,IAAA,EAAqC;AAC9C,QAAA,MAAM,GAAA,GAA+B;AAAA,UACnC,IAAI,IAAA,CAAK,EAAA;AAAA,UACT,MAAM,EAAE,IAAA,EAAM,KAAK,QAAA,EAAU,KAAA,EAAO,KAAK,SAAA,EAAU;AAAA,UACnD,SAAS,IAAA,CAAK,OAAA;AAAA,UACd,SAAS,IAAA,CAAK,OAAA;AAAA,UACd,MAAM,IAAA,CAAK,IAAA;AAAA;AAAA;AAAA;AAAA,UAIX,GAAI,KAAK,IAAA,GAAO,EAAE,MAAM,IAAA,CAAK,IAAA,KAAS,EAAC;AAAA,UACvC,SAAS,IAAA,CAAK,OAAA;AAAA,UACd,YAAY,IAAA,CAAK,WAAA;AAAA,UACjB,gBAAA,EAAkB;AAAA;AAAA,YAEhB,aAAA,EAAe,EAAE,MAAA,EAAQ,KAAA,EAAO,YAAY,KAAA,EAAM;AAAA,YAClD,YAAA,EAAc,EAAE,MAAA,EAAQ,KAAA;AAAM,WAChC;AAAA,UACA,YAAA,EAAc;AAAA,YACZ,aAAa,EAAE,MAAA,EAAQ,IAAA,CAAK,IAAA,CAAK,WAAW,KAAA;AAAM;AACpD,SACF;AAEA,QAAA,MAAM,CAAC,QAAQ,CAAA,GAAI,MAAMA,uBAAA,CAAO,KAAK,GAAG,CAAA;AACxC,QAAA,MAAM,UAAA,GACH,SAAS,OAAA,CAAQ,cAAc,KAA4B,CAAA,GAAA,EAAM,IAAA,CAAK,KAAK,CAAA,CAAA;AAC9E,QAAA,OAAO;AAAA,UACL,UAAA;AAAA,UACA,MAAA,EAAQ,QAAA,CAAS,UAAA,GAAa,GAAA,GAAM,UAAA,GAAa,UAAA;AAAA,UACjD,GAAA,EAAK;AAAA,SACP;AAAA,MACF;AAAA,MAEA,MAAM,aAAA,CAAc,OAAA,EAAiB,OAAA,EAAmD;AACtF,QAAA,IAAI,CAAC,IAAA,CAAK,IAAA,CAAK,sBAAA,EAAwB,OAAO,KAAA;AAC9C,QAAA,MAAM,GAAA,GAAM,QAAQ,aAAa,CAAA;AACjC,QAAA,MAAM,EAAA,GAAK,QAAQ,YAAY,CAAA;AAC/B,QAAA,IAAI,CAAC,GAAA,IAAO,CAAC,EAAA,EAAI,OAAO,KAAA;AAExB,QAAA,MAAM,OAAA,GAAU,MAAA,CAAO,MAAA,CAAO,CAAC,MAAA,CAAO,KAAK,EAAA,EAAI,MAAM,CAAA,EAAG,OAAO,CAAC,CAAA;AAChE,QAAA,IAAI;AACF,UAAA,MAAM,QAAA,GAAWC,wBAAAA,CAAO,YAAA,CAAa,QAAQ,CAAA;AAC7C,UAAA,QAAA,CAAS,OAAO,OAAO,CAAA;AACvB,UAAA,IAAI,CAAC,SAAS,MAAA,CAAO,IAAA,CAAK,KAAK,sBAAA,EAAwB,GAAA,EAAK,QAAQ,CAAA,EAAG,OAAO,KAAA;AAAA,QAChF,CAAA,CAAA,MAAQ;AACN,UAAA,OAAO,KAAA;AAAA,QACT;AAOA,QAAA,OAAO,uBAAA,CAAwB,EAAA,EAAI,IAAA,CAAK,uBAAuB,CAAA;AAAA,MACjE;AAAA,MAEA,mBAAmB,OAAA,EAAqC;AACtD,QAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,OAAO,CAAA,SAAU,EAAC;AACrC,QAAA,OAAO,OAAA,CACJ,GAAA,CAAI,CAAC,GAAA,KAAQ,sBAAA,CAAuB,GAAG,CAAC,CAAA,CACxC,MAAA,CAAO,CAAC,CAAA,KAA4B,CAAA,KAAM,IAAI,CAAA;AAAA,MACnD;AAAA,KACF;AAAA,EAAA;AAAA,CAAA,CAAA;AC5GO,IAAM,gBAAA,GAAmBL,MAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA,CAAE,IAAI,GAAG,CAAA;AAClD,IAAM,WAAA,GAAcA,MAAE,MAAA,EAAO,CAAE,OAAM,CAAE,WAAA,GAAc,IAAA,EAAK;AAC1D,IAAM,UAAA,GAAaA,KAAA,CACvB,MAAA,EAAO,CACP,GAAA,CAAI,CAAC,CAAA,CACL,GAAA,CAAI,GAAG,CAAA,CACP,KAAA,CAAM,mCAAA,EAAqC,yBAAyB,CAAA;AAMhE,IAAM,eAAA,GAAkBA,MAAE,MAAA,CAAO;AAAA,EACtC,SAAA,EAAWA,MAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA,CAAE,IAAI,GAAG,CAAA;AAAA,EACpC,UAAA,EAAY,gBAAA;AAAA,EACZ,UAAA,EAAYA,KAAA,CAAE,MAAA,CAAOA,KAAA,CAAE,MAAA,IAAUA,KAAA,CAAE,OAAA,EAAS,CAAA,CAAE,QAAA,EAAS;AAAA,EACvD,SAAA,EAAWA,KAAA,CAAE,MAAA,EAAO,CAAE,GAAA,CAAI,CAAC,CAAA,CAAE,GAAA,CAAI,GAAG,CAAA,CAAE,QAAA;AACxC,CAAC,CAAA;AAGM,IAAM,mBAAA,GAAsBA,MAAE,MAAA,CAAO;AAAA,EAC1C,IAAA,EAAMA,MAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA,CAAE,IAAI,GAAG,CAAA;AAAA,EAC/B,cAAcA,KAAA,CAAE,IAAA,CAAK,CAAC,kBAAA,EAAoB,cAAA,EAAgB,YAAY,CAAC;AACzE,CAAC,CAAA;AAGM,IAAM,wBAAA,GAA2BA,MAAE,MAAA,CAAO;AAAA,EAC/C,UAAA,EAAY,gBAAA;AAAA,EACZ,MAAA,EAAQA,MAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA,CAAE,IAAI,GAAG,CAAA;AAAA,EACjC,gBAAA,EAAkBA,KAAA,CAAE,IAAA,EAAK,CAAE,QAAA,EAAS;AAAA,EACpC,SAAA,EAAWA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC/B,gBAAA,EAAkBA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA;AAC/B,CAAC,CAAA;AAGM,IAAM,yBAAyBA,KAAA,CAAE,IAAA,CAAK,CAAC,KAAA,EAAO,WAAA,EAAa,eAAe,CAAC,CAAA;AAC3E,IAAM,uBAAA,GAA0BA,MAAE,IAAA,CAAK;AAAA,EAC5C,cAAA;AAAA,EACA,aAAA;AAAA,EACA,WAAA;AAAA,EACA,QAAA;AAAA,EACA,aAAA;AAAA,EACA;AACF,CAAC,CAAA;AAEM,IAAM,sBAAA,GAAyBA,MAAE,MAAA,CAAO;AAAA,EAC7C,KAAA,EAAO,WAAA;AAAA,EACP,KAAA,EAAO,sBAAA;AAAA,EACP,MAAA,EAAQ,uBAAA,CAAwB,OAAA,CAAQ,cAAc,CAAA;AAAA,EACtD,MAAA,EAAQA,MAAE,MAAA,EAAO,CAAE,IAAI,GAAG,CAAA,CAAE,QAAQ,QAAQ,CAAA;AAAA,EAC5C,OAAOA,KAAA,CAAE,MAAA,GAAS,GAAA,CAAI,IAAI,EAAE,QAAA;AAC9B,CAAC,CAAA;AAGM,IAAM,mBAAA,GAAsBA,MAAE,MAAA,CAAO;AAAA,EAC1C,KAAA,EAAO,WAAA;AAAA,EACP,KAAA,EAAO,sBAAA;AAAA,EACP,MAAA,EAAQA,KAAA,CAAE,IAAA,CAAK,CAAC,cAAA,EAAgB,eAAe,WAAA,EAAa,QAAA,EAAU,eAAA,EAAiB,aAAa,CAAC,CAAA;AAAA,EACrG,MAAA,EAAQA,MAAE,MAAA,EAAO,CAAE,IAAI,GAAG,CAAA,CAAE,QAAQ,QAAQ,CAAA;AAAA,EAC5C,OAAOA,KAAA,CAAE,MAAA,GAAS,GAAA,CAAI,IAAI,EAAE,QAAA,EAAS;AAAA,EACrC,SAAA,EAAWA,KAAA,CAAE,IAAA,EAAK,CAAE,QAAA;AACtB,CAAC,CAAA;AAGM,IAAM,cAAA,GAAiBA,MAAE,MAAA,CAAO;AAAA,EACrC,UAAA,EAAY,gBAAA;AAAA,EACZ,GAAA,EAAKA,MAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA,CAAE,IAAI,GAAG;AAChC,CAAC,CAAA;AAGM,IAAM,oBAAA,GAAuBA,MAAE,MAAA,CAAO;AAAA,EAC3C,QAAA,EAAU,UAAA;AAAA,EACV,UAAA,EAAY,gBAAA;AAAA,EACZ,MAAA,EAAQA,KAAA,CAAE,MAAA,EAAO,CAAE,GAAA,CAAI,CAAC,CAAA,CAAE,GAAA,CAAI,GAAG,CAAA,CAAE,QAAA,EAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAe5C,wBAAwBA,KAAA,CACrB,MAAA;AAAA,IACCA,KAAA,CAAE,MAAA,EAAO,CAAE,KAAA,CAAM,iBAAiB,CAAA;AAAA,IAClCA,KAAA,CAAE,KAAA,CAAM,CAACA,KAAA,CAAE,QAAO,EAAGA,KAAA,CAAE,MAAA,EAAO,EAAGA,MAAE,OAAA,EAAQ,EAAGA,KAAA,CAAE,IAAA,EAAM,CAAC;AAAA,IAExD,QAAA;AACL,CAAC,CAAA;AAGM,IAAM,2BAA2B,oBAAA,CAAqB,IAAA,CAAK,EAAE,QAAA,EAAU,MAAM,CAAA;AAG7E,IAAM,qBAAA,GAAwBA,MAAE,MAAA,CAAO;AAAA,EAC5C,YAAA,EAAc,UAAA;AAAA,EACd,UAAA,EAAY,gBAAA;AAAA,EACZ,IAAA,EAAMA,KAAA,CAAE,MAAA,CAAOA,KAAA,CAAE,MAAA,IAAUA,KAAA,CAAE,OAAA,EAAS,CAAA,CAAE,QAAA,EAAS;AAAA,EACjD,gBAAA,EAAkBA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACtC,SAAA,EAAWA,MAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA,CAAE,IAAI,GAAG;AACtC,CAAC,CAAA;AAOM,IAAM,iBAAqCA,KAAA,CAAE,IAAA;AAAA,EAAK,MACvDA,KAAA,CAAE,kBAAA,CAAmB,MAAA,EAAQ;AAAA,IAC3BA,MAAE,MAAA,CAAO;AAAA,MACP,IAAA,EAAMA,KAAA,CAAE,OAAA,CAAQ,MAAM,CAAA;AAAA,MACtB,OAAOA,KAAA,CAAE,MAAA,EAAO,CAAE,GAAA,GAAM,QAAA,EAAS;AAAA,MACjC,IAAA,EAAMA,MAAE,IAAA,CAAK,CAAC,WAAW,OAAA,EAAS,MAAA,EAAQ,OAAO,CAAC;AAAA,KACnD,CAAA;AAAA,IACDA,MAAE,MAAA,CAAO;AAAA,MACP,IAAA,EAAMA,KAAA,CAAE,OAAA,CAAQ,WAAW,CAAA;AAAA,MAC3B,IAAA,EAAM,eAAA;AAAA,MACN,SAASA,KAAA,CAAE,IAAA,CAAK,CAAC,UAAA,EAAY,MAAM,CAAC;AAAA,KACrC,CAAA;AAAA,IACDA,MAAE,MAAA,CAAO;AAAA,MACP,IAAA,EAAMA,KAAA,CAAE,OAAA,CAAQ,QAAQ,CAAA;AAAA,MACxB,IAAA,EAAM,eAAA;AAAA,MACN,WAAA,EAAaA,KAAA,CAAE,KAAA,CAAM,cAAc,CAAA;AAAA,MACnC,YAAA,EAAcA,KAAA,CAAE,KAAA,CAAM,cAAc;AAAA,KACrC,CAAA;AAAA,IACDA,MAAE,MAAA,CAAO;AAAA,MACP,IAAA,EAAMA,KAAA,CAAE,OAAA,CAAQ,MAAM,CAAA;AAAA,MACtB,YAAA,EAAc,UAAA;AAAA,MACd,gBAAA,EAAkBA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,MACtC,IAAA,EAAMA,KAAA,CAAE,MAAA,CAAOA,KAAA,CAAE,MAAA,IAAUA,KAAA,CAAE,OAAA,EAAS,CAAA,CAAE,QAAA,EAAS;AAAA,MACjD,QAAA,EAAUA,MACP,MAAA,CAAO;AAAA,QACN,YAAA,EAAcA,KAAA,CAAE,OAAA,EAAQ,CAAE,QAAA,EAAS;AAAA,QACnC,SAAA,EAAWA,MAAE,MAAA,EAAO,CAAE,MAAM,2BAAA,EAA6B,gBAAgB,EAAE,QAAA,EAAS;AAAA,QACpF,kBAAA,EAAoBA,KAAA,CAAE,OAAA,EAAQ,CAAE,QAAA,EAAS;AAAA,QACzC,QAAA,EAAUA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA;AAAS,OAC/B,EACA,QAAA;AAAS,KACb,CAAA;AAAA,IACDA,MAAE,MAAA,CAAO;AAAA,MACP,IAAA,EAAMA,KAAA,CAAE,OAAA,CAAQ,KAAK,CAAA;AAAA,MACrB,SAASA,KAAA,CAAE,KAAA,CAAMA,MAAE,MAAA,EAAQ,EAAE,QAAA,EAAS;AAAA,MACtC,YAAYA,KAAA,CAAE,KAAA,CAAMA,MAAE,MAAA,EAAQ,EAAE,QAAA;AAAS,KAC1C,CAAA;AAAA,IACDA,MAAE,MAAA,CAAO;AAAA,MACP,IAAA,EAAMA,KAAA,CAAE,OAAA,CAAQ,YAAY,CAAA;AAAA,MAC5B,SAAA,EAAWA,MAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA,CAAE,IAAI,GAAG,CAAA;AAAA,MACpC,UAAA,EAAYA,KAAA,CAAE,MAAA,CAAOA,KAAA,CAAE,MAAA,IAAUA,KAAA,CAAE,OAAA,EAAS,CAAA,CAAE,QAAA;AAAS,KACxD,CAAA;AAAA,IACDA,MAAE,MAAA,CAAO;AAAA,MACP,IAAA,EAAMA,KAAA,CAAE,OAAA,CAAQ,SAAS,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAKzB,GAAA,EAAKA,KAAA,CAAE,MAAA,EAAO,CAAE,GAAA,EAAI;AAAA,MACpB,MAAA,EAAQA,MAAE,IAAA,CAAK,CAAC,QAAQ,KAAK,CAAC,EAAE,QAAA,EAAS;AAAA,MACzC,OAAA,EAASA,KAAA,CAAE,MAAA,CAAOA,KAAA,CAAE,MAAA,IAAUA,KAAA,CAAE,OAAA,EAAS,CAAA,CAAE,QAAA,EAAS;AAAA,MACpD,WAAA,EAAaA,MAAE,IAAA,CAAK,CAAC,QAAQ,UAAU,CAAC,EAAE,QAAA;AAAS,KACpD,CAAA;AAAA,IACDA,MAAE,MAAA,CAAO;AAAA,MACP,IAAA,EAAMA,KAAA,CAAE,OAAA,CAAQ,MAAM,CAAA;AAAA,MACtB,MAAA,EAAQA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA;AAAS,KAC7B;AAAA,GACF;AACH,CAAA;AAEO,IAAM,kBAAsCA,KAAA,CAAE,IAAA;AAAA,EAAK,MACxDA,MAAE,KAAA,CAAM;AAAA,IACNA,MAAE,MAAA,CAAO,EAAE,QAAQA,KAAA,CAAE,MAAA,IAAU,CAAA;AAAA,IAC/BA,MAAE,MAAA,CAAO,EAAE,WAAWA,KAAA,CAAE,MAAA,IAAU,CAAA;AAAA,IAClCA,MAAE,MAAA,CAAO,EAAE,WAAA,EAAaA,KAAA,CAAE,OAAO,EAAE,KAAA,EAAOA,KAAA,CAAE,MAAA,IAAU,KAAA,EAAOA,KAAA,CAAE,SAAQ,EAAG,GAAG,CAAA;AAAA,IAC7EA,MAAE,MAAA,CAAO,EAAE,aAAaA,KAAA,CAAE,MAAA,IAAU,CAAA;AAAA,IACpCA,MAAE,MAAA,CAAO;AAAA,MACP,qBAAA,EAAuBA,MAAE,MAAA,CAAO;AAAA,QAC9B,GAAA,EAAKA,KAAA,CAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA;AAAA,QACrB,OAAOA,KAAA,CAAE,KAAA,CAAM,CAACA,KAAA,CAAE,QAAO,EAAGA,KAAA,CAAE,MAAA,EAAO,EAAGA,MAAE,OAAA,EAAQ,EAAGA,KAAA,CAAE,IAAA,EAAM,CAAC;AAAA,OAC/D;AAAA,KACF,CAAA;AAAA,IACDA,KAAA,CAAE,MAAA,CAAO,EAAE,qBAAA,EAAuBA,KAAA,CAAE,QAAO,CAAE,GAAA,CAAI,CAAC,CAAA,EAAG,CAAA;AAAA,IACrDA,MAAE,MAAA,CAAO;AAAA,MACP,aAAA,EAAeA,MAAE,MAAA,EAAO;AAAA,MACxB,cAAA,EAAgBA,KAAA,CAAE,OAAA,EAAQ,CAAE,QAAA,EAAS;AAAA,MACrC,UAAA,EAAYA,MAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,GAAW,QAAA;AAAS,KAClD,CAAA;AAAA,IACDA,MAAE,MAAA,CAAO;AAAA,MACP,gBAAA,EAAkBA,MAAE,MAAA,EAAO;AAAA,MAC3B,UAAA,EAAYA,MAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,GAAW,QAAA;AAAS,KAClD,CAAA;AAAA,IACDA,MAAE,MAAA,CAAO;AAAA,MACP,kBAAA,EAAoBA,MAAE,IAAA,CAAK,CAAC,cAAc,cAAA,EAAgB,aAAA,EAAe,SAAA,EAAW,YAAY,CAAC;AAAA,KAClG,CAAA;AAAA,IACDA,MAAE,MAAA,CAAO;AAAA,MACP,SAAA,EAAWA,MAAE,MAAA,CAAO;AAAA,QAClB,YAAA,EAAc,WAAW,QAAA,EAAS;AAAA,QAClC,cAAA,EAAgBA,KAAA,CAAE,OAAA,EAAQ,CAAE,QAAA,EAAS;AAAA,QACrC,UAAA,EAAYA,MAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,GAAW,QAAA;AAAS,OAClD;AAAA,KACF,CAAA;AAAA,IACDA,MAAE,MAAA,CAAO;AAAA,MACP,UAAA,EAAYA,MAAE,MAAA,CAAO;AAAA,QACnB,YAAA,EAAc,WAAW,QAAA,EAAS;AAAA,QAClC,cAAA,EAAgBA,KAAA,CAAE,OAAA,EAAQ,CAAE,QAAA,EAAS;AAAA,QACrC,UAAA,EAAYA,MAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,GAAW,QAAA;AAAS,OAClD;AAAA,KACF,CAAA;AAAA,IACDA,MAAE,MAAA,CAAO;AAAA,MACP,sBAAA,EAAwBA,MAAE,MAAA,CAAO;AAAA,QAC/B,YAAA,EAAc,WAAW,QAAA,EAAS;AAAA,QAClC,cAAA,EAAgBA,KAAA,CAAE,OAAA,EAAQ,CAAE,QAAA,EAAS;AAAA,QACrC,UAAA,EAAYA,MAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,GAAW,QAAA;AAAS,OAClD;AAAA,KACF,CAAA;AAAA,IACDA,MAAE,MAAA,CAAO;AAAA,MACP,uBAAA,EAAyBA,MAAE,MAAA,CAAO;AAAA,QAChC,YAAA,EAAc,WAAW,QAAA,EAAS;AAAA,QAClC,cAAA,EAAgBA,KAAA,CAAE,OAAA,EAAQ,CAAE,QAAA,EAAS;AAAA,QACrC,UAAA,EAAYA,MAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,GAAW,QAAA;AAAS,OAClD;AAAA,KACF,CAAA;AAAA,IACDA,MAAE,MAAA,CAAO;AAAA,MACP,cAAA,EAAgBA,MAAE,MAAA,CAAO,EAAE,OAAOA,KAAA,CAAE,MAAA,GAAS,GAAA,EAAI,CAAE,UAAS,EAAG,UAAA,EAAYA,MAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,IAAY;AAAA,KACzG,CAAA;AAAA,IACDA,MAAE,MAAA,CAAO;AAAA,MACP,eAAA,EAAiBA,MAAE,MAAA,CAAO,EAAE,OAAOA,KAAA,CAAE,MAAA,GAAS,GAAA,EAAI,CAAE,UAAS,EAAG,UAAA,EAAYA,MAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,IAAY;AAAA,KAC1G,CAAA;AAAA,IACDA,KAAA,CAAE,OAAO,EAAE,GAAA,EAAKA,MAAE,KAAA,CAAM,eAAe,GAAG,CAAA;AAAA,IAC1CA,KAAA,CAAE,OAAO,EAAE,GAAA,EAAKA,MAAE,KAAA,CAAM,eAAe,GAAG,CAAA;AAAA,IAC1CA,KAAA,CAAE,MAAA,CAAO,EAAE,GAAA,EAAK,iBAAiB;AAAA,GAClC;AACH,CAAA;;;AChNO,IAAM,0BAAA,GAA8C;AAAA,EACzD,EAAE,IAAA,EAAM,kBAAA,EAAoB,KAAA,EAAO,cAAA,EAAe;AAAA,EAClD,EAAE,IAAA,EAAM,iBAAA,EAAmB,KAAA,EAAO,OAAA,EAAQ;AAAA,EAC1C,EAAE,IAAA,EAAM,iBAAA,EAAmB,KAAA,EAAO,OAAA;AACpC,CAAA;AAEO,IAAM,sBAAA,GAA0C;AAAA,EACrD,EAAE,IAAA,EAAM,kBAAA,EAAoB,KAAA,EAAO,cAAA,EAAe;AAAA,EAClD,EAAE,IAAA,EAAM,wBAAA,EAA0B,KAAA,EAAO,WAAA,EAAY;AAAA,EACrD,EAAE,IAAA,EAAM,iBAAA,EAAmB,KAAA,EAAO,OAAA,EAAQ;AAAA,EAC1C,EAAE,IAAA,EAAM,gBAAA,EAAkB,KAAA,EAAO,SAAA;AACnC,CAAA;AAkWO,IAAM,QAAA,GAAW;AAAA,EACtB,gBAAA,EAAkB,SAAA;AAAA,EAClB,kBAAA,EAAoB,KAAA;AAAA,EACpB,4BAAA,EAA8B,EAAA;AAAA,EAC9B,+BAAA,EAAiC,KAAA;AAAA,EACjC,yBAAA,EAA2B,GAAA;AAAA,EAC3B,eAAA,EAAiB,kBAAA;AAAA,EACjB,oBAAA,EAAsB,CAAA;AAAA,EACtB,8BAAA,EAAgC,GAAA;AAAA,EAChC,yBAAA,EAA2B,GAAA;AAAA,EAC3B,0BAAA,EAA4B,GAAA;AAAA,EAC5B,UAAA,EAAY,KAAA;AAAA,EACZ,mBAAA,EAAqB,EAAA;AAAA,EACrB,eAAA,EAAiB,CAAA;AAAA,EACjB,iBAAA,EAAmB,EAAA;AAAA,EACnB,4BAAA,EAA8B,CAAA;AAAA,EAC9B,6BAAA,EAA+B,EAAA;AAAA,EAC/B,oBAAA,EAAsB,CAAA;AAAA,EACtB,iBAAA,EAAmB,CAAA;AAAA,EACnB,UAAA,EAAY,IAAA;AAAA,EACZ,WAAA,EAAa,IAAA;AAAA,EACb,eAAA,EAAiB,KAAA;AAAA,EACjB,iBAAA,EAAmB,KAAA;AAAA,EACnB,yBAAA,EAA2B,KAAA;AAAA,EAC3B,uBAAA,EAAyB;AAC3B,CAAA;AAEO,IAAM,wBAAA,GAAqD;AAAA,EAChE,qBAAA,EAAuB,CAAA;AAAA,EACvB,oBAAA,EAAsB,GAAA;AAAA,EACtB,yBAAA,EAA2B,CAAA;AAAA,EAC3B,0BAAA,EAA4B,EAAA;AAAA,EAC5B,aAAA,EAAe,EAAA;AAAA,EACf,kBAAA,EAAoB;AACtB,CAAA;AAEO,SAAS,cAAc,CAAA,EAAiC;AAC7D,EAAA,OAAO;AAAA,IACL,GAAG,CAAA;AAAA,IACH,gBAAA,EAAkB,CAAA,CAAE,gBAAA,IAAoB,QAAA,CAAS,gBAAA;AAAA,IACjD,kBAAA,EAAoB,CAAA,CAAE,kBAAA,IAAsB,QAAA,CAAS,kBAAA;AAAA,IACrD,4BAAA,EAA8B,CAAA,CAAE,4BAAA,IAAgC,QAAA,CAAS,4BAAA;AAAA,IACzE,+BAAA,EAAiC,CAAA,CAAE,+BAAA,IAAmC,QAAA,CAAS,+BAAA;AAAA,IAC/E,yBAAA,EAA2B,CAAA,CAAE,yBAAA,IAA6B,QAAA,CAAS,yBAAA;AAAA,IACnE,eAAA,EAAiB,CAAA,CAAE,eAAA,IAAmB,QAAA,CAAS,eAAA;AAAA,IAC/C,oBAAA,EAAsB,CAAA,CAAE,oBAAA,IAAwB,QAAA,CAAS,oBAAA;AAAA,IACzD,8BAAA,EAAgC,CAAA,CAAE,8BAAA,IAAkC,QAAA,CAAS,8BAAA;AAAA,IAC7E,yBAAA,EAA2B,CAAA,CAAE,yBAAA,IAA6B,QAAA,CAAS,yBAAA;AAAA,IACnE,0BAAA,EAA4B,CAAA,CAAE,0BAAA,IAA8B,QAAA,CAAS,0BAAA;AAAA,IACrE,UAAA,EAAY,CAAA,CAAE,UAAA,IAAc,QAAA,CAAS,UAAA;AAAA,IACrC,mBAAA,EAAqB,CAAA,CAAE,mBAAA,IAAuB,QAAA,CAAS,mBAAA;AAAA,IACvD,eAAA,EAAiB,CAAA,CAAE,eAAA,IAAmB,QAAA,CAAS,eAAA;AAAA,IAC/C,iBAAA,EAAmB,CAAA,CAAE,iBAAA,IAAqB,QAAA,CAAS,iBAAA;AAAA,IACnD,4BAAA,EAA8B,CAAA,CAAE,4BAAA,IAAgC,QAAA,CAAS,4BAAA;AAAA,IACzE,6BAAA,EAA+B,CAAA,CAAE,6BAAA,IAAiC,QAAA,CAAS,6BAAA;AAAA,IAC3E,oBAAA,EAAsB,CAAA,CAAE,oBAAA,IAAwB,QAAA,CAAS,oBAAA;AAAA,IACzD,iBAAA,EAAmB,CAAA,CAAE,iBAAA,IAAqB,QAAA,CAAS,iBAAA;AAAA,IACnD,UAAA,EAAY,CAAA,CAAE,UAAA,IAAc,QAAA,CAAS,UAAA;AAAA,IACrC,WAAA,EAAa,CAAA,CAAE,WAAA,IAAe,QAAA,CAAS,WAAA;AAAA,IACvC,eAAA,EAAiB,CAAA,CAAE,eAAA,IAAmB,QAAA,CAAS,eAAA;AAAA,IAC/C,iBAAA,EAAmB,CAAA,CAAE,iBAAA,IAAqB,QAAA,CAAS,iBAAA;AAAA,IACnD,yBAAA,EAA2B,CAAA,CAAE,yBAAA,IAA6B,QAAA,CAAS,yBAAA;AAAA,IACnE,uBAAA,EAAyB,CAAA,CAAE,uBAAA,IAA2B,QAAA,CAAS,uBAAA;AAAA,IAC/D,cAAA,EAAgB,EAAE,GAAG,wBAAA,EAA0B,GAAI,CAAA,CAAE,cAAA,IAAkB,EAAC;AAAG,GAC7E;AACF;;;AC3CO,IAAM,aAAA,GAAgB,KAAA;AAEtB,SAAS,cAAA,CAAe,cAA6B,IAAA,EAA4B;AACtF,EAAA,OAAO,CAAA,EAAA,EAAK,YAAA,IAAgB,UAAU,CAAA,GAAA,EAAM,IAAI,CAAA,CAAA;AAClD;AA2MO,SAAS,cAAA,CAAe,EAAA,EAAQ,MAAA,GAAS,SAAA,EAAwB;AACtE,EAAA,OAAO;AAAA,IACL,aAAA,EAAe,EAAA,CAAG,UAAA,CAA4B,CAAA,EAAG,MAAM,CAAA,aAAA,CAAe,CAAA;AAAA,IACtE,KAAA,EAAO,EAAA,CAAG,UAAA,CAAoB,CAAA,EAAG,MAAM,CAAA,KAAA,CAAO,CAAA;AAAA,IAC9C,MAAA,EAAQ,EAAA,CAAG,UAAA,CAAqB,CAAA,EAAG,MAAM,CAAA,MAAA,CAAQ,CAAA;AAAA,IACjD,KAAA,EAAO,EAAA,CAAG,UAAA,CAAoB,CAAA,EAAG,MAAM,CAAA,KAAA,CAAO,CAAA;AAAA,IAC9C,YAAA,EAAc,EAAA,CAAG,UAAA,CAA2B,CAAA,EAAG,MAAM,CAAA,aAAA,CAAe,CAAA;AAAA,IACpE,QAAA,EAAU,EAAA,CAAG,UAAA,CAAuB,CAAA,EAAG,MAAM,CAAA,SAAA,CAAW,CAAA;AAAA,IACxD,SAAA,EAAW,EAAA,CAAG,UAAA,CAAwB,CAAA,EAAG,MAAM,CAAA,SAAA,CAAW,CAAA;AAAA,IAC1D,gBAAA,EAAkB,EAAA,CAAG,UAAA,CAA+B,CAAA,EAAG,MAAM,CAAA,iBAAA,CAAmB,CAAA;AAAA,IAChF,KAAA,EAAO,EAAA,CAAG,UAAA,CAAoB,CAAA,EAAG,MAAM,CAAA,KAAA,CAAO,CAAA;AAAA,IAC9C,YAAA,EAAc,EAAA,CAAG,UAAA,CAA2B,CAAA,EAAG,MAAM,CAAA,YAAA,CAAc,CAAA;AAAA,IACnE,UAAA,EAAY,EAAA,CAAG,UAAA,CAAyB,CAAA,EAAG,MAAM,CAAA,UAAA,CAAY,CAAA;AAAA,IAC7D,MAAA,EAAQ,EAAA,CAAG,UAAA,CAAsB,CAAA,EAAG,MAAM,CAAA,MAAA,CAAQ,CAAA;AAAA,IAClD,QAAA,EAAU,EAAA,CAAG,UAAA,CAAwB,CAAA,EAAG,MAAM,CAAA,SAAA,CAAW,CAAA;AAAA,IACzD,aAAA,EAAe,EAAA,CAAG,UAAA,CAA4B,CAAA,EAAG,MAAM,CAAA,cAAA,CAAgB,CAAA;AAAA,IACvE,MAAA,EAAQ,EAAA,CAAG,UAAA,CAAsB,CAAA,EAAG,MAAM,CAAA,MAAA,CAAQ,CAAA;AAAA,IAClD,WAAA,EAAa,EAAA,CAAG,UAAA,CAA0B,CAAA,EAAG,MAAM,CAAA,YAAA,CAAc,CAAA;AAAA,IACjE,WAAA,EAAa,EAAA,CAAG,UAAA,CAA0B,CAAA,EAAG,MAAM,CAAA,YAAA,CAAc,CAAA;AAAA,IACjE,mBAAA,EAAqB,EAAA,CAAG,UAAA,CAAkC,CAAA,EAAG,MAAM,CAAA,oBAAA,CAAsB,CAAA;AAAA,IACzF,aAAA,EAAe,EAAA,CAAG,UAAA,CAA4B,CAAA,EAAG,MAAM,CAAA,cAAA,CAAgB,CAAA;AAAA,IACvE,YAAA,EAAc,EAAA,CAAG,UAAA,CAA2B,CAAA,EAAG,MAAM,CAAA,aAAA,CAAe,CAAA;AAAA,IACpE,aAAA,EAAe,EAAA,CAAG,UAAA,CAA4B,CAAA,EAAG,MAAM,CAAA,cAAA,CAAgB,CAAA;AAAA,IACvE,eAAA,EAAiB,EAAA,CAAG,UAAA,CAA8B,CAAA,EAAG,MAAM,CAAA,iBAAA,CAAmB,CAAA;AAAA,IAC9E,gBAAA,EAAkB,EAAA,CAAG,UAAA,CAA+B,CAAA,EAAG,MAAM,CAAA,kBAAA,CAAoB;AAAA,GACnF;AACF;AAMA,eAAsB,aAAA,CAAc,EAAA,EAAQ,MAAA,GAAS,SAAA,EAA0B;AAC7E,EAAA,MAAM,CAAA,GAAI,cAAA,CAAe,EAAA,EAAI,MAAM,CAAA;AAEnC,EAAA,MAAM,QAAQ,GAAA,CAAI;AAAA,IAChB,CAAA,CAAE,cAAc,aAAA,CAAc;AAAA,MAC5B,EAAE,GAAA,EAAK,EAAE,YAAY,CAAA,EAAE,EAAG,QAAQ,IAAA,EAAK;AAAA,MACvC,EAAE,GAAA,EAAK,EAAE,QAAQ,CAAA,EAAG,cAAA,EAAgB,IAAG;AAAE,KAC1C,CAAA;AAAA,IACD,CAAA,CAAE,MAAM,aAAA,CAAc;AAAA,MACpB,EAAE,GAAA,EAAK,EAAE,OAAO,CAAA,EAAE,EAAG,QAAQ,IAAA,EAAK;AAAA,MAClC,EAAE,GAAA,EAAK,EAAE,QAAQ,CAAA,EAAG,SAAA,EAAW,IAAG;AAAE,KACrC,CAAA;AAAA,IACD,CAAA,CAAE,OAAO,aAAA,CAAc;AAAA,MACrB,EAAE,GAAA,EAAK,EAAE,WAAW,CAAA,EAAE,EAAG,QAAQ,IAAA,EAAK;AAAA,MACtC,EAAE,GAAA,EAAK,EAAE,YAAY,CAAA,EAAG,UAAA,EAAY,IAAG,EAAE;AAAA,MACzC,EAAE,GAAA,EAAK,EAAE,MAAM,CAAA,EAAG,UAAA,EAAY,IAAG,EAAE;AAAA,MACnC,EAAE,GAAA,EAAK,EAAE,MAAM,CAAA,EAAG,SAAA,EAAW,GAAE,EAAE;AAAA,MACjC,EAAE,GAAA,EAAK,EAAE,YAAY,CAAA,EAAG,IAAA,EAAM,GAAE;AAAE,KACnC,CAAA;AAAA,IACD,CAAA,CAAE,MAAM,aAAA,CAAc;AAAA,MACpB,EAAE,GAAA,EAAK,EAAE,MAAM,CAAA,EAAE,EAAG,QAAQ,IAAA,EAAK;AAAA,MACjC,EAAE,KAAK,EAAE,OAAA,EAAS,GAAG,cAAA,EAAgB,CAAA,EAAG,mBAAA,EAAqB,CAAA,EAAE;AAAE,KAClE,CAAA;AAAA,IACD,CAAA,CAAE,YAAA,CAAa,aAAA,CAAc,CAAC,EAAE,GAAA,EAAK,EAAE,MAAA,EAAQ,CAAA,EAAG,SAAS,CAAA,EAAE,EAAG,MAAA,EAAQ,IAAA,EAAM,CAAC,CAAA;AAAA,IAC/E,CAAA,CAAE,SAAS,aAAA,CAAc;AAAA,MACvB,EAAE,GAAA,EAAK,EAAE,QAAQ,CAAA,EAAG,YAAA,EAAc,GAAE,EAAE;AAAA,MACtC,EAAE,GAAA,EAAK,EAAE,YAAY,CAAA,EAAG,MAAA,EAAQ,GAAE,EAAE;AAAA,MACpC,EAAE,GAAA,EAAK,EAAE,QAAQ,CAAA,EAAG,MAAA,EAAQ,GAAE,EAAE;AAAA,MAChC;AAAA,QACE,GAAA,EAAK,EAAE,MAAA,EAAQ,CAAA,EAAG,kBAAkB,CAAA,EAAE;AAAA,QACtC,MAAA,EAAQ,IAAA;AAAA,QACR,yBAAyB,EAAE,gBAAA,EAAkB,EAAE,KAAA,EAAO,UAAS;AAAE;AACnE,KACD,CAAA;AAAA,IACD,CAAA,CAAE,UAAU,aAAA,CAAc;AAAA,MACxB,EAAE,GAAA,EAAK,EAAE,MAAM,CAAA,EAAE,EAAG,QAAQ,IAAA,EAAK;AAAA,MACjC,EAAE,GAAA,EAAK,EAAE,IAAA,EAAM,GAAE,EAAE;AAAA,MACnB,EAAE,GAAA,EAAK,EAAE,IAAA,EAAM,GAAE;AAAE,KACpB,CAAA;AAAA,IACD,CAAA,CAAE,gBAAA,CAAiB,aAAA,CAAc,CAAC,EAAE,GAAA,EAAK,EAAE,UAAA,EAAY,CAAA,EAAG,SAAS,CAAA,EAAE,EAAG,MAAA,EAAQ,IAAA,EAAM,CAAC,CAAA;AAAA,IACvF,CAAA,CAAE,MAAM,aAAA,CAAc;AAAA,MACpB,EAAE,GAAA,EAAK,EAAE,WAAW,CAAA,EAAE,EAAG,QAAQ,IAAA,EAAK;AAAA,MACtC,EAAE,GAAA,EAAK,EAAE,YAAY,CAAA,EAAG,MAAA,EAAQ,IAAG,EAAE;AAAA,MACrC,EAAE,GAAA,EAAK,EAAE,YAAY,CAAA,EAAG,MAAA,EAAQ,IAAG,EAAE;AAAA,MACrC,EAAE,GAAA,EAAK,EAAE,WAAW,CAAA,EAAE,EAAG,QAAQ,IAAA,EAAK;AAAA,MACtC,EAAE,GAAA,EAAK,EAAE,aAAa,CAAA,EAAE,EAAG,QAAQ,IAAA,EAAK;AAAA,MACxC,EAAE,GAAA,EAAK,EAAE,mBAAmB,CAAA,EAAE,EAAG,QAAQ,IAAA,EAAK;AAAA,MAC9C,EAAE,GAAA,EAAK,EAAE,QAAQ,CAAA,EAAG,QAAA,EAAU,GAAE,EAAE;AAAA,MAClC,EAAE,GAAA,EAAK,EAAE,QAAQ,CAAA,EAAG,SAAA,EAAW,GAAE;AAAE,KACpC,CAAA;AAAA,IACD,CAAA,CAAE,aAAa,aAAA,CAAc;AAAA,MAC3B,EAAE,GAAA,EAAK,EAAE,KAAA,EAAO,CAAA,EAAG,OAAO,CAAA,EAAE,EAAG,MAAA,EAAQ,IAAA,EAAM,yBAAyB,EAAE,KAAA,EAAO,EAAE,KAAA,EAAO,QAAA,IAAW,EAAE;AAAA,MACrG,EAAE,GAAA,EAAK,EAAE,SAAA,EAAW,GAAE,EAAE;AAAA,MACxB,EAAE,GAAA,EAAK,EAAE,OAAA,EAAS,IAAG;AAAE,KACxB,CAAA;AAAA,IACD,CAAA,CAAE,WAAW,aAAA,CAAc;AAAA,MACzB,EAAE,GAAA,EAAK,EAAE,MAAM,CAAA,EAAE,EAAG,QAAQ,IAAA,EAAK;AAAA,MACjC,EAAE,GAAA,EAAK,EAAE,QAAQ,CAAA,EAAG,WAAA,EAAa,GAAE;AAAE,KACtC,CAAA;AAAA,IACD,CAAA,CAAE,OAAO,aAAA,CAAc;AAAA,MACrB,EAAE,GAAA,EAAK,EAAE,QAAQ,CAAA,EAAG,UAAA,EAAY,GAAE,EAAE;AAAA,MACpC,EAAE,GAAA,EAAK,EAAE,qBAAqB,CAAA,EAAE,EAAG,QAAQ,IAAA;AAAK,KACjD,CAAA;AAAA,IACD,CAAA,CAAE,SAAS,aAAA,CAAc;AAAA,MACvB,EAAE,GAAA,EAAK,EAAE,UAAA,EAAY,IAAG,EAAE;AAAA,MAC1B,EAAE,KAAK,EAAE,qBAAA,EAAuB,GAAG,aAAA,EAAe,CAAA,EAAG,UAAA,EAAY,EAAA,EAAG,EAAE;AAAA,MACtE,EAAE,GAAA,EAAK,EAAE,OAAO,CAAA,EAAG,UAAA,EAAY,IAAG;AAAE,KACrC,CAAA;AAAA,IACD,CAAA,CAAE,cAAc,aAAA,CAAc;AAAA,MAC5B,EAAE,KAAK,EAAE,QAAA,EAAU,GAAG,eAAA,EAAiB,CAAA,EAAE,EAAG,MAAA,EAAQ,IAAA,EAAK;AAAA,MACzD,EAAE,GAAA,EAAK,EAAE,iBAAA,EAAmB,GAAE,EAAE;AAAA,MAChC,EAAE,GAAA,EAAK,EAAE,WAAW,CAAA,EAAG,UAAA,EAAY,GAAE;AAAE,KACxC,CAAA;AAAA,IACD,CAAA,CAAE,YAAY,aAAA,CAAc;AAAA,MAC1B,EAAE,KAAK,EAAE,UAAA,EAAY,GAAG,GAAA,EAAK,CAAA,EAAE,EAAG,MAAA,EAAQ,IAAA,EAAK;AAAA,MAC/C,EAAE,GAAA,EAAK,EAAE,GAAA,EAAK,GAAE;AAAE,KACnB,CAAA;AAAA,IACD,CAAA,CAAE,OAAO,aAAA,CAAc;AAAA,MACrB,EAAE,GAAA,EAAK,EAAE,cAAc,CAAA,EAAG,IAAA,EAAM,GAAE,EAAE;AAAA,MACpC,EAAE,GAAA,EAAK,EAAE,MAAA,EAAQ,GAAE,EAAE;AAAA;AAAA,MAErB,EAAE,GAAA,EAAK,EAAE,SAAA,EAAW,IAAG;AAAE,KAC1B,CAAA;AAAA,IACD,CAAA,CAAE,YAAY,aAAA,CAAc;AAAA,MAC1B,EAAE,KAAK,EAAE,MAAA,EAAQ,GAAG,IAAA,EAAM,CAAA,EAAE,EAAG,MAAA,EAAQ,IAAA,EAAK;AAAA;AAAA,MAE5C,EAAE,KAAK,EAAE,MAAA,EAAQ,GAAG,MAAA,EAAQ,CAAA,EAAG,IAAA,EAAM,CAAA,EAAE,EAAE;AAAA;AAAA;AAAA;AAAA,MAIzC,EAAE,GAAA,EAAK,EAAE,KAAA,EAAO,CAAA,IAAK,kBAAA,EAAoB,EAAA,GAAK,EAAA,GAAK,EAAA,GAAK,EAAA;AAAG,KAC5D,CAAA;AAAA,IACD,CAAA,CAAE,oBAAoB,aAAA,CAAc;AAAA,MAClC,EAAE,KAAK,EAAE,MAAA,EAAQ,GAAG,IAAA,EAAM,CAAA,EAAE,EAAG,MAAA,EAAQ,IAAA,EAAK;AAAA,MAC5C,EAAE,GAAA,EAAK,EAAE,QAAQ,CAAA,EAAG,SAAA,EAAW,IAAG,EAAE;AAAA,MACpC,EAAE,GAAA,EAAK,EAAE,gBAAA,EAAkB,GAAE;AAAE,KAChC,CAAA;AAAA,IACD,CAAA,CAAE,cAAc,aAAA,CAAc;AAAA,MAC5B,EAAE,KAAK,EAAE,EAAA,EAAI,GAAG,aAAA,EAAe,CAAA,EAAE,EAAG,MAAA,EAAQ,IAAA,EAAK;AAAA,MACjD,EAAE,GAAA,EAAK,EAAE,IAAI,CAAA,EAAG,SAAA,EAAW,IAAG,EAAE;AAAA,MAChC,EAAE,GAAA,EAAK,EAAE,YAAA,EAAc,GAAE;AAAE,KAC5B,CAAA;AAAA,IACD,CAAA,CAAE,aAAa,aAAA,CAAc;AAAA,MAC3B,EAAE,KAAK,EAAE,QAAA,EAAU,GAAG,OAAA,EAAS,CAAA,EAAE,EAAG,MAAA,EAAQ,IAAA,EAAK;AAAA,MACjD,EAAE,GAAA,EAAK,EAAE,QAAQ,CAAA,EAAG,QAAA,EAAU,IAAG,EAAE;AAAA;AAAA,MAEnC,EAAE,GAAA,EAAK,EAAE,QAAA,EAAU,IAAG,EAAE;AAAA,MACxB,EAAE,GAAA,EAAK,EAAE,UAAA,EAAY,IAAG;AAAE,KAC3B,CAAA;AAAA,IACD,CAAA,CAAE,cAAc,aAAA,CAAc;AAAA,MAC5B,EAAE,KAAK,EAAE,QAAA,EAAU,GAAG,QAAA,EAAU,CAAA,EAAE,EAAG,MAAA,EAAQ,IAAA,EAAK;AAAA,MAClD,EAAE,GAAA,EAAK,EAAE,QAAQ,CAAA,EAAG,GAAA,EAAK,IAAG,EAAE;AAAA,MAC9B,EAAE,GAAA,EAAK,EAAE,UAAU,CAAA,EAAG,GAAA,EAAK,IAAG,EAAE;AAAA,MAChC,EAAE,GAAA,EAAK,EAAE,UAAA,EAAY,GAAE;AAAE;AAAA,KAC1B,CAAA;AAAA,IACD,CAAA,CAAE,gBAAgB,aAAA,CAAc;AAAA,MAC9B,EAAE,GAAA,EAAK,EAAE,IAAI,CAAA,EAAE,EAAG,QAAQ,IAAA;AAAK,KAChC,CAAA;AAAA,IACD,CAAA,CAAE,iBAAiB,aAAA,CAAc;AAAA,MAC/B,EAAE,GAAA,EAAK,EAAE,YAAY,CAAA,EAAE,EAAG,QAAQ,IAAA,EAAK;AAAA,MACvC,EAAE,GAAA,EAAK,EAAE,cAAc,CAAA,EAAG,SAAA,EAAW,IAAG,EAAE;AAAA;AAAA,MAE1C,EAAE,GAAA,EAAK,EAAE,WAAW,CAAA,EAAE,EAAG,oBAAoB,CAAA;AAAE,KAChD;AAAA,GACF,CAAA;AAKD,EAAA,MAAM,CAAA,CAAE,OAAO,SAAA,CAAU,EAAE,KAAK,WAAA,EAAoB,CAAA,CAAE,KAAA,CAAM,MAAM;AAAA,EAAC,CAAC,CAAA;AACtE;ACjxBO,IAAM,gBAAN,MAAoB;AAAA,EACR,QAAA,uBAAe,GAAA,EAA0B;AAAA,EAE1D,SAAS,GAAA,EAA8B;AACrC,IAAA,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,GAAA,CAAI,IAAA,EAAM,IAAI,YAAY,CAAA;AAAA,EAC9C;AAAA,EAEA,IAAI,IAAA,EAAuB;AACzB,IAAA,OAAO,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,IAAI,CAAA;AAAA,EAC/B;AAAA,EAEA,OAAO,IAAA,EAAwC;AAC7C,IAAA,OAAO,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,IAAI,CAAA;AAAA,EAC/B;AAAA,EAEA,IAAA,GAA4B;AAC1B,IAAA,OAAO,KAAA,CAAM,IAAA,CAAK,IAAA,CAAK,QAAA,EAAU,CAAC,CAAC,IAAA,EAAM,YAAY,CAAA,MAAO,EAAE,IAAA,EAAM,YAAA,EAAa,CAAE,CAAA;AAAA,EACrF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,SAAA,CACE,IAAA,EACA,UAAA,EACA,SAAA,EACA,GAAA,EACe;AACf,IAAA,IAAI,WAAW,OAAO,SAAA;AACtB,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,IAAI,CAAA;AACrC,IAAA,IAAI,CAAC,QAAQ,OAAO,IAAA;AAEpB,IAAA,QAAQ,MAAA;AAAQ,MACd,KAAK,kBAAA;AACH,QAAA,OAAO,CAAA,EAAG,UAAU,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA;AAAA,MAC9B,KAAK,cAAA;AACH,QAAA,OAAO,GAAG,UAAU,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA,EAAI,MAAA,CAAO,GAAG,CAAC,CAAA,CAAA;AAAA,MAC7C,KAAK,YAAA;AACH,QAAA,OAAO,GAAG,UAAU,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA,EAAI,UAAU,CAAA,CAAA;AAAA;AAC9C,EACF;AACF,CAAA;AAEA,SAAS,OAAO,CAAA,EAAiB;AAC/B,EAAA,OAAO,CAAA,CAAE,WAAA,EAAY,CAAE,KAAA,CAAM,GAAG,EAAE,CAAA;AACpC;AAEA,SAAS,QAAA,GAAmB;AAC1B,EAAA,OAAOK,wBAAA,CAAO,WAAA,CAAY,CAAC,CAAA,CAAE,SAAS,KAAK,CAAA;AAC7C;;;ACnCA,IAAM,gBAAA,GAAmB,CAAC,MAAA,EAAQ,eAAA,EAAiB,oBAAoB,CAAA;AAEvE,SAAS,eAAe,SAAA,EAA+C;AACrE,EAAA,IAAI,CAAC,SAAA,IAAa,OAAO,SAAA,KAAc,UAAU,OAAO,KAAA;AACxD,EAAA,MAAM,CAAA,GAAI,SAAA;AACV,EAAA,OAAO,gBAAA,CAAiB,MAAM,CAAC,CAAA,KAAM,OAAO,CAAA,CAAE,CAAC,MAAM,UAAU,CAAA;AACjE;AAOO,SAAS,eAAA,CACd,WACA,IAAA,EACqB;AACrB,EAAA,IAAI,OAAO,SAAS,QAAA,IAAY,CAAC,OAAO,MAAA,CAAO,SAAA,EAAW,IAAI,CAAA,EAAG,OAAO,IAAA;AACxE,EAAA,MAAM,SAAA,GAAqB,UAAU,IAAI,CAAA;AACzC,EAAA,OAAO,cAAA,CAAe,SAAS,CAAA,GAAI,SAAA,GAAY,IAAA;AACjD;AAOO,SAAS,wBAAwB,SAAA,EAAmD;AACzF,EAAA,OAAO,MAAA,CAAO,IAAA,CAAK,SAAS,CAAA,CACzB,MAAA,CAAO,CAAC,IAAA,KAAS,eAAA,CAAgB,SAAA,EAAW,IAAI,CAAA,KAAM,IAAI,EAC1D,IAAA,EAAK;AACV;AC1CO,SAAS,oBAAA,CACd,SACA,MAAA,EACQ;AACR,EAAA,MAAM,IAAA,GAAO,KAAK,SAAA,CAAU;AAAA,IAC1B,CAAA,EAAG,OAAA,CAAQ,KAAA,CAAM,WAAA,EAAY;AAAA,IAC7B,GAAG,OAAA,CAAQ,KAAA;AAAA,IACX,CAAA,EAAG,OAAA,CAAQ,SAAA,CAAU,OAAA;AAAQ,GAC9B,CAAA;AACD,EAAA,MAAM,UAAU,MAAA,CAAO,MAAA,CAAO,IAAA,CAAK,IAAA,EAAM,MAAM,CAAC,CAAA;AAChD,EAAA,MAAM,IAAA,GAAOA,yBAAO,UAAA,CAAW,QAAA,EAAU,MAAM,CAAA,CAAE,MAAA,CAAO,OAAO,CAAA,CAAE,MAAA,EAAO;AACxE,EAAA,OAAO,CAAA,EAAG,OAAO,CAAA,CAAA,EAAI,MAAA,CAAO,IAAI,CAAC,CAAA,CAAA;AACnC;AAEO,SAAS,uBACd,KAAA,EACA,MAAA,EACA,GAAA,mBAAY,IAAI,MAAK,EACW;AAChC,EAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,KAAA,CAAM,GAAG,CAAA;AAC7B,EAAA,IAAI,KAAA,CAAM,MAAA,KAAW,CAAA,EAAG,OAAO,IAAA;AAC/B,EAAA,MAAM,CAAC,OAAA,EAAS,MAAM,CAAA,GAAI,KAAA;AAE1B,EAAA,MAAM,QAAA,GAAWA,yBAAO,UAAA,CAAW,QAAA,EAAU,MAAM,CAAA,CAAE,MAAA,CAAO,OAAO,CAAA,CAAE,MAAA,EAAO;AAC5E,EAAA,IAAI,MAAA;AACJ,EAAA,IAAI;AACF,IAAA,MAAA,GAAS,aAAa,MAAM,CAAA;AAAA,EAC9B,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,IAAI,QAAA,CAAS,MAAA,KAAW,MAAA,CAAO,MAAA,EAAQ,OAAO,IAAA;AAC9C,EAAA,IAAI,CAACA,wBAAAA,CAAO,eAAA,CAAgB,QAAA,EAAU,MAAM,GAAG,OAAO,IAAA;AAEtD,EAAA,IAAI,IAAA;AACJ,EAAA,IAAI;AACF,IAAA,IAAA,GAAO,KAAK,KAAA,CAAM,YAAA,CAAa,OAAO,CAAA,CAAE,QAAA,CAAS,MAAM,CAAC,CAAA;AAAA,EAC1D,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,IAAI,CAAC,IAAA,CAAK,CAAA,IAAK,CAAC,IAAA,CAAK,KAAK,OAAO,IAAA,CAAK,CAAA,KAAM,QAAA,EAAU,OAAO,IAAA;AAC7D,EAAA,IAAI,IAAA,CAAK,CAAA,GAAI,GAAA,CAAI,OAAA,IAAW,OAAO,IAAA;AACnC,EAAA,IAAI,IAAA,CAAK,MAAM,KAAA,IAAS,IAAA,CAAK,MAAM,WAAA,IAAe,IAAA,CAAK,CAAA,KAAM,eAAA,EAAiB,OAAO,IAAA;AAErF,EAAA,OAAO;AAAA,IACL,OAAO,IAAA,CAAK,CAAA;AAAA,IACZ,OAAO,IAAA,CAAK,CAAA;AAAA,IACZ,SAAA,EAAW,IAAI,IAAA,CAAK,IAAA,CAAK,CAAC;AAAA,GAC5B;AACF;AAcA,IAAM,eAAA,GAAqC,CAAC,MAAA,EAAQ,OAAO,CAAA;AAcpD,IAAM,mBAAA,GAAsB;AAcnC,SAAS,eAAA,CAAgB,OAAsB,MAAA,EAAqC;AAClF,EAAA,MAAM,OAAO,MAAA,CAAO,MAAA,KAAW,SAAY,EAAA,GAAK,CAAA,CAAA,EAAI,OAAO,MAAM,CAAA,CAAA;AACjE,EAAA,OAAO,oBAAoB,KAAK,CAAA,CAAA,EAAI,MAAA,CAAO,MAAM,GAAG,IAAI,CAAA,CAAA;AAC1D;AAUO,SAAS,iBAAA,CACd,KAAA,EACA,MAAA,EACA,MAAA,EACQ;AACR,EAAA,IAAI,CAAC,eAAA,CAAgB,QAAA,CAAS,KAAK,CAAA,EAAG;AACpC,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,iCAAA,EAAoC,MAAA,CAAO,KAAK,CAAC,CAAA,CAAE,CAAA;AAAA,EACrE;AACA,EAAA,MAAM,GAAA,GAAMA,wBAAAA,CAAO,UAAA,CAAW,QAAA,EAAU,MAAM,CAAA,CAAE,MAAA,CAAO,eAAA,CAAgB,KAAA,EAAO,MAAM,CAAC,CAAA,CAAE,MAAA,EAAO;AAC9F,EAAA,OAAO,MAAA,CAAO,GAAG,CAAA,CAAE,KAAA,CAAM,GAAG,mBAAmB,CAAA;AACjD;AAUO,SAAS,mBAAA,CACd,KAAA,EACA,KAAA,EACA,MAAA,EACA,MAAA,EACS;AACT,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,EAAU,OAAO,KAAA;AACtC,EAAA,IAAI,CAAC,eAAA,CAAgB,QAAA,CAAS,KAAK,GAAG,OAAO,KAAA;AAC7C,EAAA,IAAI,KAAA,CAAM,MAAA,KAAW,mBAAA,EAAqB,OAAO,KAAA;AACjD,EAAA,MAAM,QAAA,GAAW,OAAO,IAAA,CAAK,iBAAA,CAAkB,OAAO,MAAA,EAAQ,MAAM,GAAG,MAAM,CAAA;AAC7E,EAAA,MAAM,MAAA,GAAS,MAAA,CAAO,IAAA,CAAK,KAAA,EAAO,MAAM,CAAA;AACxC,EAAA,IAAI,QAAA,CAAS,MAAA,KAAW,MAAA,CAAO,MAAA,EAAQ,OAAO,KAAA;AAC9C,EAAA,OAAOA,wBAAAA,CAAO,eAAA,CAAgB,QAAA,EAAU,MAAM,CAAA;AAChD;AAEA,SAAS,OAAO,GAAA,EAAqB;AACnC,EAAA,OAAO,GAAA,CAAI,QAAA,CAAS,QAAQ,CAAA,CAAE,QAAQ,KAAA,EAAO,GAAG,CAAA,CAAE,OAAA,CAAQ,KAAA,EAAO,GAAG,CAAA,CAAE,OAAA,CAAQ,OAAO,EAAE,CAAA;AACzF;AAEA,SAAS,aAAa,CAAA,EAAmB;AACvC,EAAA,MAAM,MAAA,GAAS,CAAA,CAAE,OAAA,CAAQ,IAAA,EAAM,GAAG,CAAA,CAAE,OAAA,CAAQ,IAAA,EAAM,GAAG,IAAI,KAAA,CAAM,KAAA,CAAA,CAAO,CAAA,CAAE,MAAA,GAAS,KAAK,CAAC,CAAA;AACvF,EAAA,OAAO,MAAA,CAAO,IAAA,CAAK,MAAA,EAAQ,QAAQ,CAAA;AACrC;AAKO,SAAS,UAAU,KAAA,EAAuB;AAC/C,EAAA,OAAOA,wBAAAA,CAAO,WAAW,QAAQ,CAAA,CAAE,OAAO,KAAK,CAAA,CAAE,OAAO,KAAK,CAAA;AAC/D;AAeO,SAAS,YAAA,CAAa,SAA0B,MAAA,EAAwB;AAC7E,EAAA,MAAM,IAAA,GAAO,KAAK,SAAA,CAAU;AAAA,IAC1B,GAAG,OAAA,CAAQ,UAAA;AAAA,IACX,CAAA,EAAG,OAAA,CAAQ,SAAA,CAAU,OAAA,EAAQ;AAAA,IAC7B,CAAA,EAAG;AAAA,GACJ,CAAA;AACD,EAAA,MAAM,UAAU,MAAA,CAAO,MAAA,CAAO,IAAA,CAAK,IAAA,EAAM,MAAM,CAAC,CAAA;AAChD,EAAA,MAAM,IAAA,GAAOA,yBAAO,UAAA,CAAW,QAAA,EAAU,MAAM,CAAA,CAAE,MAAA,CAAO,OAAO,CAAA,CAAE,MAAA,EAAO;AACxE,EAAA,OAAO,CAAA,EAAG,OAAO,CAAA,CAAA,EAAI,MAAA,CAAO,IAAI,CAAC,CAAA,CAAA;AACnC;AAEO,SAAS,eAAe,KAAA,EAAe,MAAA,EAAgB,GAAA,mBAAY,IAAI,MAAK,EAA2B;AAC5G,EAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,KAAA,CAAM,GAAG,CAAA;AAC7B,EAAA,IAAI,KAAA,CAAM,MAAA,KAAW,CAAA,EAAG,OAAO,IAAA;AAC/B,EAAA,MAAM,CAAC,OAAA,EAAS,MAAM,CAAA,GAAI,KAAA;AAE1B,EAAA,MAAM,QAAA,GAAWA,yBAAO,UAAA,CAAW,QAAA,EAAU,MAAM,CAAA,CAAE,MAAA,CAAO,OAAO,CAAA,CAAE,MAAA,EAAO;AAC5E,EAAA,IAAI,MAAA;AACJ,EAAA,IAAI;AACF,IAAA,MAAA,GAAS,aAAa,MAAM,CAAA;AAAA,EAC9B,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,IAAI,QAAA,CAAS,MAAA,KAAW,MAAA,CAAO,MAAA,EAAQ,OAAO,IAAA;AAC9C,EAAA,IAAI,CAACA,wBAAAA,CAAO,eAAA,CAAgB,QAAA,EAAU,MAAM,GAAG,OAAO,IAAA;AAEtD,EAAA,IAAI,IAAA;AACJ,EAAA,IAAI;AACF,IAAA,IAAA,GAAO,KAAK,KAAA,CAAM,YAAA,CAAa,OAAO,CAAA,CAAE,QAAA,CAAS,MAAM,CAAC,CAAA;AAAA,EAC1D,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,IAAI,CAAC,IAAA,CAAK,CAAA,IAAK,OAAO,IAAA,CAAK,MAAM,QAAA,IAAY,IAAA,CAAK,CAAA,KAAM,KAAA,EAAO,OAAO,IAAA;AACtE,EAAA,IAAI,IAAA,CAAK,CAAA,GAAI,GAAA,CAAI,OAAA,IAAW,OAAO,IAAA;AAEnC,EAAA,OAAO,EAAE,YAAY,IAAA,CAAK,CAAA,EAAG,WAAW,IAAI,IAAA,CAAK,IAAA,CAAK,CAAC,CAAA,EAAE;AAC3D;;;ACtMA,eAAsB,iBACpB,WAAA,EACA,KAAA,EACA,GAAA,mBAAY,IAAI,MAAK,EACN;AACf,EAAA,MAAM,aAAa,KAAA,CAAM,KAAA;AAEzB,EAAA,MAAM,YAAY,YAAA,CAAa,SAAA;AAAA,IAC7B,EAAE,KAAA,EAAO,UAAA,EAAY,KAAA,EAAO,MAAM,KAAA,EAAM;AAAA,IACxC;AAAA,MACE,YAAA,EAAc;AAAA,QACZ,KAAA,EAAO,UAAA;AAAA,QACP,SAAA,EAAW,UAAU,UAAU,CAAA;AAAA,QAC/B,OAAO,KAAA,CAAM,KAAA;AAAA;AAAA,QAEb,MAAA,EAAQ,cAAA;AAAA,QACR,QAAQ,KAAA,CAAM,MAAA;AAAA,QACd,KAAA,EAAO,MAAM,KAAA,IAAS,IAAA;AAAA,QACtB,OAAA,EAAS,GAAA;AAAA,QACT,SAAA,EAAW;AAAA;AACb,KACF;AAAA,IACA,EAAE,QAAQ,IAAA;AAAK,GACjB;AAEA,EAAA,MAAM,YAAY,aAAA,CAAc,SAAA;AAAA,IAC9B,EAAE,kBAAkB,UAAA,EAAW;AAAA,IAC/B;AAAA,MACE,IAAA,EAAM;AAAA,QACJ,MAAA,EAAQ,cAAA;AAAA,QACR,cAAA,EAAgB,GAAA;AAAA,QAChB,mBAAmB,KAAA,CAAM,MAAA;AAAA,QACzB,SAAA,EAAW;AAAA;AACb;AACF,GACF;AACF;AC9BA,IAAM,WAAA,GAAc;AAAA,EAClB,IAAA,EAAM,aAAA;AAAA,EACN,OAAA,EAAS,gBAAA;AAAA,EACT,IAAA,EAAM,aAAA;AAAA,EACN,OAAA,EAAS;AACX,CAAA;AAEO,IAAM,UAAA,GAAN,MAAM,WAAA,CAAkC;AAAA,EACpC,MAAA;AAAA,EACD,KAAA;AAAA,EACA,UAAA;AAAA,EACA,OAAA,GAAmF,IAAA;AAAA,EACnF,IAAA;AAAA,EAER,aAAa,MAAA,CAAO,WAAA,EAAqC,MAAA,EAAsC;AAC7F,IAAA,IAAI,IAAA;AACJ,IAAA,IAAI;AACF,MAAA,IAAA,GAAQ,MAAM,OAAO,QAAQ,CAAA;AAAA,IAC/B,CAAA,CAAA,MAAQ;AACN,MAAA,MAAM,IAAI,KAAA;AAAA,QACR;AAAA,OACF;AAAA,IACF;AACA,IAAA,IAAI,MAAA,EAAQ,QAAA,CAAS,GAAG,CAAA,EAAG;AACzB,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,0BAA0B,MAAM,CAAA,wEAAA;AAAA,OAClC;AAAA,IACF;AACA,IAAA,MAAM,QAAQ,WAAA,CAAY,WAAW,CAAA,GAAK,WAAA,GAA0B,QAAQ,WAA2B,CAAA;AACvG,IAAA,OAAO,IAAI,WAAA,CAAW,IAAA,EAAM,KAAA,EAAO,MAAM,CAAA;AAAA,EAC3C;AAAA,EAEQ,MAAA;AAAA,EAEA,WAAA,CAAY,IAAA,EAAkB,KAAA,EAAgB,MAAA,EAAiB;AACrE,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AACZ,IAAA,IAAA,CAAK,KAAA,GAAQ,KAAA;AACb,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AAId,IAAA,MAAM,IAAA,GAAO;AAAA,MACX,UAAA,EAAY,KAAA;AAAA,MACZ,MAAA;AAAA,MACA,iBAAA,EAAmB;AAAA,QACjB,kBAAkB,EAAE,GAAA,EAAK,EAAA,GAAK,IAAA,EAAM,OAAO,GAAA,EAAK;AAAA,QAChD,YAAA,EAAc,EAAE,GAAA,EAAK,CAAA,GAAI,KAAK,IAAA;AAAK;AACrC,KACF;AACA,IAAA,IAAA,CAAK,UAAA,GAAa;AAAA,MAChB,MAAM,IAAI,IAAA,CAAK,KAAA,CAAM,WAAA,CAAY,MAAM,IAAI,CAAA;AAAA,MAC3C,SAAS,IAAI,IAAA,CAAK,KAAA,CAAM,WAAA,CAAY,SAAS,IAAI,CAAA;AAAA,MACjD,MAAM,IAAI,IAAA,CAAK,KAAA,CAAM,WAAA,CAAY,MAAM,IAAI,CAAA;AAAA,MAC3C,SAAS,IAAI,IAAA,CAAK,KAAA,CAAM,WAAA,CAAY,SAAS,IAAI;AAAA,KACnD;AACA,IAAA,IAAA,CAAK,MAAA,GAAS;AAAA,MACZ,IAAA,EAAM,cAAA,CAAe,IAAA,CAAK,UAAA,CAAW,IAAI,CAAA;AAAA,MACzC,OAAA,EAAS,cAAA,CAAe,IAAA,CAAK,UAAA,CAAW,OAAO,CAAA;AAAA,MAC/C,IAAA,EAAM,cAAA,CAAe,IAAA,CAAK,UAAA,CAAW,IAAI,CAAA;AAAA,MACzC,OAAA,EAAS,cAAA,CAAe,IAAA,CAAK,UAAA,CAAW,OAAO;AAAA,KACjD;AAAA,EACF;AAAA,EAEA,MAAM,sBAAsB,eAAA,EAAwC;AAClE,IAAA,MAAO,IAAA,CAAK,WAAW,IAAA,CAAa,kBAAA;AAAA,MAClC,oBAAA;AAAA,MACA,EAAE,KAAA,EAAO,eAAA,GAAkB,GAAA,EAAK;AAAA,MAChC;AAAA,QACE,IAAA,EAAM,MAAA;AAAA,QACN,MAAM,EAAC;AAAA,QACP,IAAA,EAAM,EAAE,gBAAA,EAAkB,EAAE,KAAA,EAAO,EAAA,EAAG,EAAG,YAAA,EAAc,EAAE,KAAA,EAAO,EAAA,EAAG;AAAE;AACvE,KACF;AAAA,EACF;AAAA,EAEA,MAAM,aAAa,IAAA,EAAyC;AAC1D,IAAA,IAAI,KAAK,OAAA,EAAS;AAElB,IAAA,MAAM,OAAO,EAAE,UAAA,EAAY,KAAK,KAAA,EAAO,MAAA,EAAQ,KAAK,MAAA,EAAO;AAC3D,IAAA,MAAM,EAAE,MAAA,EAAO,GAAI,IAAA,CAAK,IAAA;AAExB,IAAA,MAAM,OAAO,IAAI,MAAA;AAAA,MACf,WAAA,CAAY,IAAA;AAAA,MACZ,OAAO,GAAA,KAAa,IAAA,CAAK,QAAA,CAAS,IAAA,CAAK,IAAI,IAAI,CAAA;AAAA,MAC/C,EAAE,GAAG,IAAA,EAAM,WAAA,EAAa,CAAA;AAAE,KAC5B;AACA,IAAA,MAAM,UAAU,IAAI,MAAA;AAAA,MAClB,WAAA,CAAY,OAAA;AAAA,MACZ,OAAO,GAAA,KAAa,IAAA,CAAK,QAAA,CAAS,OAAA,CAAQ,IAAI,IAAI,CAAA;AAAA,MAClD,EAAE,GAAG,IAAA,EAAM,WAAA,EAAa,EAAA;AAAG,KAC7B;AACA,IAAA,MAAM,OAAO,IAAI,MAAA;AAAA,MACf,WAAA,CAAY,IAAA;AAAA,MACZ,OAAO,GAAA,KAAa,IAAA,CAAK,QAAA,CAAS,IAAA,CAAK,IAAI,IAAI,CAAA;AAAA,MAC/C;AAAA,QACE,GAAG,IAAA;AAAA,QACH,WAAA,EAAa,KAAK,WAAA,CAAY,IAAA;AAAA,QAC9B,OAAA,EAAS,IAAA,CAAK,aAAA,GACV,EAAE,GAAA,EAAK,IAAA,CAAK,aAAA,CAAc,GAAA,EAAK,QAAA,EAAU,IAAA,CAAK,aAAA,CAAc,UAAA,EAAW,GACvE;AAAA;AACN,KACF;AACA,IAAA,MAAM,UAAU,IAAI,MAAA;AAAA,MAClB,WAAA,CAAY,OAAA;AAAA,MACZ,OAAO,GAAA,KAAa,IAAA,CAAK,QAAA,CAAS,OAAA,CAAQ,IAAI,IAAI,CAAA;AAAA,MAClD,EAAE,GAAG,IAAA,EAAM,WAAA,EAAa,CAAA;AAAE,KAC5B;AAEA,IAAA,IAAA,CAAK,OAAA,GAAU,EAAE,IAAA,EAAM,OAAA,EAAS,MAAM,OAAA,EAAQ;AAAA,EAChD;AAAA,EAEA,MAAM,WAAA,GAA6B;AACjC,IAAA,IAAI,CAAC,KAAK,OAAA,EAAS;AACnB,IAAA,MAAM,QAAQ,GAAA,CAAI;AAAA,MAChB,IAAA,CAAK,OAAA,CAAQ,IAAA,CAAK,KAAA,EAAM;AAAA,MACxB,IAAA,CAAK,OAAA,CAAQ,OAAA,CAAQ,KAAA,EAAM;AAAA,MAC3B,IAAA,CAAK,OAAA,CAAQ,IAAA,CAAK,KAAA,EAAM;AAAA,MACxB,IAAA,CAAK,OAAA,CAAQ,OAAA,CAAQ,KAAA;AAAM,KAC5B,CAAA;AACD,IAAA,IAAA,CAAK,OAAA,GAAU,IAAA;AAAA,EACjB;AAAA,EAEA,MAAM,KAAA,GAAuB;AAC3B,IAAA,MAAM,KAAK,WAAA,EAAY;AACvB,IAAA,MAAM,QAAQ,GAAA,CAAI;AAAA,MAChB,IAAA,CAAK,UAAA,CAAW,IAAA,CAAK,KAAA,EAAM;AAAA,MAC3B,IAAA,CAAK,UAAA,CAAW,OAAA,CAAQ,KAAA,EAAM;AAAA,MAC9B,IAAA,CAAK,UAAA,CAAW,IAAA,CAAK,KAAA,EAAM;AAAA,MAC3B,IAAA,CAAK,UAAA,CAAW,OAAA,CAAQ,KAAA;AAAM,KAC/B,CAAA;AAAA,EACH;AACF,CAAA;AAEA,SAAS,eAAe,CAAA,EAAoB;AAC1C,EAAA,OAAO;AAAA,IACL,GAAA,EAAK,CAAC,IAAA,EAAM,IAAA,EAAM,SAAS,CAAA,CAAE,GAAA,CAAI,IAAA,EAAM,IAAA,EAAa,IAAW,CAAA;AAAA,IAC/D,eAAA,EAAiB,MAAM,CAAA,CAAE,eAAA,EAAgB;AAAA,IACzC,kBAAkB,YAAY;AAC5B,MAAA,MAAM,CAAC,MAAA,EAAQ,OAAO,CAAA,GAAI,MAAM,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,CAAE,cAAA,EAAe,EAAG,CAAA,CAAE,eAAA,EAAiB,CAAC,CAAA;AACrF,MAAA,OAAO,MAAA,GAAS,OAAA;AAAA,IAClB,CAAA;AAAA,IACA,eAAA,EAAiB,MAAM,CAAA,CAAE,eAAA,EAAgB;AAAA,IACzC,KAAA,EAAO,MAAM,CAAA,CAAE,KAAA;AAAM,GACvB;AACF;AAEA,SAAS,YAAY,CAAA,EAAqB;AACxC,EAAA,OAAO,CAAC,CAAC,CAAA,IAAK,OAAO,CAAA,KAAM,QAAA,IAAY,OAAQ,CAAA,CAAU,GAAA,KAAQ,UAAA,IAAc,OAAQ,CAAA,CAAU,GAAA,KAAQ,UAAA;AAC3G;AAEA,SAAS,QAAQ,IAAA,EAA6B;AAC5C,EAAA,MAAM,MAAA,GAAyB;AAAA,IAC7B,oBAAA,EAAsB,IAAA;AAAA;AAAA,IACtB,gBAAA,EAAkB;AAAA,GACpB;AACA,EAAA,IAAI,KAAK,GAAA,EAAK,OAAO,IAAIC,wBAAA,CAAQ,IAAA,CAAK,KAAK,MAAM,CAAA;AACjD,EAAA,OAAO,IAAIA,wBAAA,CAAQ;AAAA,IACjB,GAAG,MAAA;AAAA,IACH,IAAA,EAAM,KAAK,IAAA,IAAQ,WAAA;AAAA,IACnB,IAAA,EAAM,KAAK,IAAA,IAAQ,IAAA;AAAA,IACnB,UAAU,IAAA,CAAK,QAAA;AAAA,IACf,IAAI,IAAA,CAAK,EAAA;AAAA,IACT,UAAU,IAAA,CAAK,QAAA;AAAA,IACf,GAAA,EAAK,IAAA,CAAK,GAAA,GAAM,EAAC,GAAI;AAAA,GACtB,CAAA;AACH;;;AClJA,IAAMC,YAAAA,GAAc;AAAA,EAClB,IAAA,EAAM,aAAA;AAAA,EACN,OAAA,EAAS,gBAAA;AAAA,EACT,IAAA,EAAM,aAAA;AAAA,EACN,OAAA,EAAS;AACX,CAAA;AAGA,IAAM,kBAAA,GAAqB,aAAA;AAG3B,IAAM,6BAAA,GAAgC,CAAA;AAGtC,IAAM,wBAAA,GAA2B,KAAK,EAAA,GAAK,GAAA;AAiBpC,IAAM,YAAA,GAAN,MAAM,aAAA,CAAoC;AAAA,EACtC,MAAA;AAAA,EACD,MAAA;AAAA,EACA,SAAA;AAAA,EACA,WAAA,GAAiC,IAAA;AAAA,EACjC,OAAA,GAAU,KAAA;AAAA,EAElB,aAAa,OAAO,IAAA,EAAkD;AACpE,IAAA,IAAI,SAAA;AACJ,IAAA,IAAI,UAAA;AACJ,IAAA,IAAI;AACF,MAAA,SAAA,GAAa,MAAM,OAAO,QAAQ,CAAA;AAClC,MAAA,UAAA,GAAc,MAAM,OAAO,yBAAyB,CAAA;AAAA,IACtD,CAAA,CAAA,MAAQ;AACN,MAAA,MAAM,IAAI,KAAA;AAAA,QACR;AAAA,OACF;AAAA,IACF;AAEA,IAAA,MAAM,cAAA,GAAiB,IAAA,CAAK,cAAA,IAAkB,aAAA,CAAc,KAAK,MAAM,CAAA;AACvE,IAAA,MAAM,OAAA,GAAU,IAAI,UAAA,CAAW,YAAA,CAAa;AAAA,MAC1C,OAAO,IAAA,CAAK,EAAA;AAAA,MACZ,UAAA,EAAY;AAAA,KACb,CAAA;AAED,IAAA,MAAM,MAAA,GAAS,IAAI,SAAA,CAAU,MAAA,CAAO;AAAA,MAClC,OAAA;AAAA,MACA,YAAA,EAAc,CAAA,EAAG,IAAA,CAAK,mBAAA,IAAuB,CAAC,CAAA,QAAA,CAAA;AAAA,MAC9C,mBAAA,EAAA,CAAsB,IAAA,CAAK,mBAAA,IAAuB,EAAA,GAAK,EAAA,IAAM,GAAA;AAAA,MAC7D,cAAA,EAAgB,EAAA;AAAA,MAChB,kBAAA,EAAoB,CAAA;AAAA;AAAA;AAAA,MAGpB,gBAAA,EAAkB;AAAA,KACZ,CAAA;AAER,IAAA,MAAM,aAAA,GAAgB,KAAK,sBAAA,IAA0B,6BAAA;AAIrD,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,CAAK,EAAA,CAAG,UAAA,CAAW,cAAc,CAAA,CAAE,WAAA,CAAY,EAAE,QAAA,EAAU,CAAA,EAAE,EAAG,EAAE,MAAA,EAAQ,MAAM,CAAA;AAAA,IACxF,SAAS,GAAA,EAAK;AACZ,MAAA,OAAA,CAAQ,KAAA,CAAM,mEAAmE,GAAG,CAAA;AAAA,IACtF;AAEA,IAAA,OAAO,IAAI,aAAA,CAAa,MAAA,EAAQ,WAAW,IAAA,CAAK,EAAA,EAAI,gBAAgB,aAAa,CAAA;AAAA,EACnF;AAAA,EAEQ,EAAA;AAAA,EACA,QAAA;AAAA,EACA,mBAAA;AAAA,EACA,UAAA,GAAoD,IAAA;AAAA,EAEpD,WAAA,CACN,MAAA,EACA,SAAA,EACA,EAAA,EACA,gBACA,mBAAA,EACA;AACA,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AACd,IAAA,IAAA,CAAK,SAAA,GAAY,SAAA;AACjB,IAAA,IAAA,CAAK,EAAA,GAAK,EAAA;AACV,IAAA,IAAA,CAAK,QAAA,GAAW,cAAA;AAChB,IAAA,IAAA,CAAK,mBAAA,GAAsB,mBAAA;AAC3B,IAAA,IAAA,CAAK,MAAA,GAAS;AAAA,MACZ,IAAA,EAAM,IAAA,CAAK,YAAA,CAAaA,YAAAA,CAAY,IAAI,CAAA;AAAA,MACxC,OAAA,EAAS,IAAA,CAAK,YAAA,CAAaA,YAAAA,CAAY,OAAO,CAAA;AAAA,MAC9C,IAAA,EAAM,IAAA,CAAK,YAAA,CAAaA,YAAAA,CAAY,IAAI,CAAA;AAAA,MACxC,OAAA,EAAS,IAAA,CAAK,YAAA,CAAaA,YAAAA,CAAY,OAAO;AAAA,KAChD;AAAA,EACF;AAAA,EAEQ,aAAa,IAAA,EAAwB;AAC3C,IAAA,OAAO;AAAA,MACL,GAAA,EAAK,OAAO,QAAA,EAAkB,IAAA,EAAe,IAAA,KAAsB;AACjE,QAAA,MAAM,OAAA,GAAmC,EAAE,GAAI,IAAA,EAAgB;AAC/D,QAAA,IAAI,MAAM,KAAA,EAAO;AACf,UAAA,OAAA,CAAQ,UAAU,IAAA,CAAK,KAAA;AACvB,UAAA,IAAI,MAAM,IAAA,CAAK,WAAA,CAAY,IAAA,EAAM,IAAA,CAAK,KAAK,CAAA,EAAG;AAAA,QAChD;AACA,QAAA,MAAM,GAAA,GAAM,IAAA,CAAK,MAAA,CAAO,MAAA,CAAO,MAAM,OAAc,CAAA;AACnD,QAAA,IAAI,IAAA,EAAM,KAAA,EAAO,GAAA,CAAI,QAAA,CAAS,IAAI,IAAA,CAAK,IAAA,CAAK,GAAA,EAAI,GAAI,IAAA,CAAK,KAAK,CAAC,CAAA;AAC/D,QAAA,MAAM,IAAI,IAAA,EAAK;AAAA,MACjB,CAAA;AAAA,MACA,iBAAiB,YAAY;AAC3B,QAAA,OAAO,IAAA,CAAK,cAAA,EAAe,CAAE,cAAA,CAAe;AAAA,UAC1C,IAAA;AAAA,UACA,GAAA,EAAK,CAAC,EAAE,QAAA,EAAU,IAAA,EAAK,EAAG,EAAE,QAAA,EAAU,EAAE,OAAA,EAAS,KAAA,EAAM,EAAG,CAAA;AAAA,UAC1D,SAAA,EAAW,EAAE,IAAA,kBAAM,IAAI,MAAK;AAAE,SAC/B,CAAA;AAAA,MACH,CAAA;AAAA,MACA,OAAO,YAAY;AAAA,MAAC;AAAA,KACtB;AAAA,EACF;AAAA;AAAA,EAGQ,cAAA,GAAiB;AACvB,IAAA,OAAO,IAAA,CAAK,EAAA,CAAG,UAAA,CAAW,IAAA,CAAK,QAAQ,CAAA;AAAA,EACzC;AAAA,EAEA,MAAc,WAAA,CAAY,IAAA,EAAc,KAAA,EAAiC;AACvE,IAAA,OAAO,IAAA,CAAK,cAAA,EAAe,CAAE,OAAA,CAAQ;AAAA,MACnC,IAAA;AAAA,MACA,cAAA,EAAgB,KAAA;AAAA,MAChB,GAAA,EAAK,CAAC,EAAE,cAAA,EAAgB,IAAA,EAAK,EAAG,EAAE,cAAA,EAAgB,EAAE,OAAA,EAAS,KAAA,EAAM,EAAG;AAAA,KACvE,CAAA;AAAA,EACH;AAAA,EAEA,MAAM,sBAAsB,eAAA,EAAwC;AAMlE,IAAA,MAAM,KAAK,MAAA,CAAO,KAAA,CAAM,GAAG,eAAe,CAAA,QAAA,CAAA,EAAYA,aAAY,IAAI,CAAA;AAAA,EACxE;AAAA,EAEA,MAAM,aAAa,IAAA,EAAyC;AAC1D,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,SAAA,CAAU,iBAAA,CAAkB,WAAA;AAE7C,IAAA,IAAI,KAAK,aAAA,EAAe;AACtB,MAAA,IAAI;AACF,QAAA,MAAM,UAAA,GAAA,CAAc,MAAM,OAAO,YAAY,CAAA,EAAG,OAAA;AAChD,QAAA,IAAA,CAAK,WAAA,GAAc,IAAI,UAAA,CAAW;AAAA,UAChC,OAAA,EAAS,KAAK,IAAA,CAAK,IAAA,CAAK,cAAc,UAAA,GAAa,IAAA,CAAK,cAAc,GAAG,CAAA;AAAA,UACzE,aAAA,EAAe,KAAK,WAAA,CAAY;AAAA,SACjC,CAAA;AAAA,MACH,CAAA,CAAA,MAAQ;AACN,QAAA,MAAM,IAAI,KAAA;AAAA,UACR;AAAA,SACF;AAAA,MACF;AAAA,IACF;AAEA,IAAA,MAAM,YAAA,GAAe,GAAA,CAAI,EAAE,KAAA,EAAO,KAAQ,UAAA,EAAY,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,KAAK,aAAA,GAAgB,CAAC,CAAA,EAAG,MAAA,EAAQ,GAAG,CAAA;AAEtG,IAAA,IAAA,CAAK,MAAA,CAAO,MAAA,CAAOA,YAAAA,CAAY,IAAA,EAAM,OAAO,GAAA,KAAa;AACvD,MAAA,MAAM,IAAA,CAAK,QAAA,CAAS,IAAA,CAAK,GAAA,CAAI,MAAM,IAAI,CAAA;AAAA,IACzC,CAAA,EAAG,EAAE,WAAA,EAAa,CAAA,EAAG,CAAA;AAErB,IAAA,IAAA,CAAK,MAAA,CAAO,MAAA,CAAOA,YAAAA,CAAY,OAAA,EAAS,OAAO,GAAA,KAAa;AAC1D,MAAA,MAAM,IAAA,CAAK,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,MAAM,IAAW,CAAA;AAAA,IACnD,GAAG,EAAE,WAAA,EAAa,EAAA,EAAI,OAAA,EAAS,cAAc,CAAA;AAE7C,IAAA,IAAA,CAAK,MAAA,CAAO,MAAA,CAAOA,YAAAA,CAAY,IAAA,EAAM,OAAO,GAAA,KAAa;AACvD,MAAA,MAAM,IAAA,GAAO,IAAI,KAAA,CAAM,IAAA;AACvB,MAAA,IAAI,KAAK,WAAA,EAAa;AACpB,QAAA,MAAM,IAAA,CAAK,YAAY,QAAA,CAAS,MAAM,KAAK,QAAA,CAAS,IAAA,CAAK,IAAI,CAAC,CAAA;AAAA,MAChE,CAAA,MAAO;AACL,QAAA,MAAM,IAAA,CAAK,QAAA,CAAS,IAAA,CAAK,IAAI,CAAA;AAAA,MAC/B;AAAA,IACF,CAAA,EAAG,EAAE,WAAA,EAAa,IAAA,CAAK,YAAY,IAAA,EAAM,OAAA,EAAS,cAAc,CAAA;AAEhE,IAAA,IAAA,CAAK,MAAA,CAAO,MAAA,CAAOA,YAAAA,CAAY,OAAA,EAAS,OAAO,GAAA,KAAa;AAC1D,MAAA,MAAM,IAAA,CAAK,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,MAAM,IAAW,CAAA;AAAA,IACnD,GAAG,EAAE,WAAA,EAAa,CAAA,EAAG,OAAA,EAAS,cAAc,CAAA;AAE5C,IAAA,IAAI,CAAC,KAAK,OAAA,EAAS;AACjB,MAAA,MAAM,IAAA,CAAK,OAAO,KAAA,EAAM;AACxB,MAAA,IAAA,CAAK,OAAA,GAAU,IAAA;AACf,MAAA,IAAA,CAAK,mBAAA,EAAoB;AAAA,IAC3B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,mBAAA,GAA4B;AAClC,IAAA,IAAI,IAAA,CAAK,mBAAA,IAAuB,CAAA,IAAK,IAAA,CAAK,UAAA,EAAY;AACtD,IAAA,KAAK,KAAK,eAAA,EAAgB;AAC1B,IAAA,IAAA,CAAK,aAAa,WAAA,CAAY,MAAM,KAAK,IAAA,CAAK,eAAA,IAAmB,wBAAwB,CAAA;AAEzF,IAAA,IAAA,CAAK,WAAW,KAAA,IAAQ;AAAA,EAC1B;AAAA;AAAA,EAGA,MAAM,eAAA,GAAmC;AACvC,IAAA,MAAM,MAAA,GAAS,IAAI,IAAA,CAAK,IAAA,CAAK,GAAA,KAAQ,IAAA,CAAK,mBAAA,GAAsB,EAAA,GAAK,IAAA,GAAO,GAAI,CAAA;AAChF,IAAA,IAAI;AACF,MAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,cAAA,GAAiB,UAAA,CAAW;AAAA,QACjD,QAAA,EAAU,EAAE,GAAA,EAAK,MAAA,EAAO;AAAA;AAAA,QAExB,gBAAgB,EAAE,GAAA,EAAK,CAAC,IAAA,EAAM,MAAS,CAAA,EAAE;AAAA;AAAA;AAAA,QAGzC,IAAA,EAAM;AAAA,UACJ,EAAE,KAAK,CAAC,EAAE,WAAW,IAAA,EAAK,EAAG,EAAE,SAAA,EAAW,EAAE,SAAS,KAAA,EAAM,IAAK,EAAE,SAAA,EAAW,EAAE,GAAA,EAAK,MAAA,EAAO,EAAG,CAAA,EAAE;AAAA,UAChG,EAAE,KAAK,CAAC,EAAE,UAAU,IAAA,EAAK,EAAG,EAAE,QAAA,EAAU,EAAE,SAAS,KAAA,EAAM,IAAK,EAAE,QAAA,EAAU,EAAE,GAAA,EAAK,MAAA,EAAO,EAAG,CAAA;AAAE;AAC/F,OACD,CAAA;AACD,MAAA,OAAO,IAAI,YAAA,IAAgB,CAAA;AAAA,IAC7B,SAAS,GAAA,EAAK;AACZ,MAAA,OAAA,CAAQ,KAAA,CAAM,oCAAoC,GAAG,CAAA;AACrD,MAAA,OAAO,CAAA;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAM,WAAA,GAA6B;AACjC,IAAA,IAAI,KAAK,UAAA,EAAY;AACnB,MAAA,aAAA,CAAc,KAAK,UAAU,CAAA;AAC7B,MAAA,IAAA,CAAK,UAAA,GAAa,IAAA;AAAA,IACpB;AACA,IAAA,IAAI,CAAC,KAAK,OAAA,EAAS;AACnB,IAAA,MAAM,IAAA,CAAK,OAAO,IAAA,EAAK;AACvB,IAAA,IAAA,CAAK,OAAA,GAAU,KAAA;AACf,IAAA,IAAI,KAAK,WAAA,EAAa;AACpB,MAAA,MAAM,IAAA,CAAK,YAAY,IAAA,CAAK,EAAE,iBAAiB,IAAA,EAAM,CAAA,CAAE,KAAA,CAAM,MAAM;AAAA,MAAC,CAAC,CAAA;AACrE,MAAA,IAAA,CAAK,WAAA,GAAc,IAAA;AAAA,IACrB;AAAA,EACF;AAAA,EAEA,MAAM,KAAA,GAAuB;AAC3B,IAAA,MAAM,KAAK,WAAA,EAAY;AAAA,EACzB;AACF,CAAA;AAOO,SAAS,cAAc,MAAA,EAAyB;AACrD,EAAA,IAAI,CAAC,QAAQ,OAAO,kBAAA;AACpB,EAAA,IAAI,CAAC,kBAAA,CAAmB,IAAA,CAAK,MAAM,CAAA,EAAG;AACpC,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,0BAA0B,MAAM,CAAA,oGAAA;AAAA,KAClC;AAAA,EACF;AACA,EAAA,OAAO,CAAA,EAAG,kBAAkB,CAAA,CAAA,EAAI,MAAM,CAAA,CAAA;AACxC;;;AC3SA,SAAS,YAAA,GAAyB;AAChC,EAAA,OAAO;AAAA,IACL,KAAK,YAAY,MAAA;AAAA,IACjB,iBAAiB,YAAY,CAAA;AAAA,IAC7B,OAAO,YAAY;AAAA,GACrB;AACF;AAEO,IAAM,aAAN,MAAwC;AAAA,EACpC,MAAA,GAAiB;AAAA,IACxB,MAAM,YAAA,EAAa;AAAA,IACnB,SAAS,YAAA,EAAa;AAAA,IACtB,MAAM,YAAA,EAAa;AAAA,IACnB,SAAS,YAAA;AAAa,GACxB;AAAA,EAEA,MAAM,sBAAsB,gBAAA,EAAyC;AAAA,EAErE;AAAA,EAEA,MAAM,aAAa,KAAA,EAA0C;AAAA,EAE7D;AAAA,EAEA,MAAM,WAAA,GAA6B;AAAA,EAEnC;AAAA,EAEA,MAAM,KAAA,GAAuB;AAAA,EAE7B;AACF,CAAA;;;AClBA,eAAsB,iBAAA,CACpB,QACA,UAAA,EACsB;AACtB,EAAA,QAAQ,OAAO,MAAA;AAAQ,IACrB,KAAK,MAAA;AACH,MAAA,OAAO,UAAA,CAAW,MAAA,CAAO,MAAA,CAAO,KAAA,EAAO,OAAO,MAAM,CAAA;AAAA,IACtD,KAAK,QAAA;AACH,MAAA,OAAO,aAAa,MAAA,CAAO;AAAA,QACzB,EAAA,EAAI,OAAO,EAAA,IAAM,UAAA;AAAA,QACjB,qBAAqB,MAAA,CAAO,mBAAA;AAAA,QAC5B,qBAAqB,MAAA,CAAO,mBAAA;AAAA,QAC5B,gBAAgB,MAAA,CAAO,cAAA;AAAA,QACvB,QAAQ,MAAA,CAAO,MAAA;AAAA,QACf,wBAAwB,MAAA,CAAO;AAAA,OAChC,CAAA;AAAA,IACH,KAAK,MAAA;AACH,MAAA,OAAO,IAAI,UAAA,EAAW;AAAA,IACxB,SAAS;AAGP,MAAA,MAAM,IAAI,MAAM,CAAA,6BAAA,CAA+B,CAAA;AAAA,IACjD;AAAA;AAEJ;;;ACzCA,IAAM,UAAA,GAAa,GAAA;AAQnB,IAAM,eAAA,GAAkB,GAAA;AAExB,eAAsB,+BAA+B,GAAA,EAAmC;AACtF,EAAA,MAAM,KAAA,GAAQ,MAAM,GAAA,CAAI,WAAA,CAAY,KAAA,CAAM,IAAA,CAAK,EAAE,OAAA,EAAS,IAAA,EAAM,cAAA,EAAgB,OAAA,EAAS,EAAE,OAAA,EAAQ;AACnG,EAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,IAAA,MAAM,mBAAA,CAAoB,MAAM,GAAG,CAAA;AAAA,EACrC;AACF;AAEA,eAAe,mBAAA,CAAoB,MAAe,GAAA,EAAmC;AACnF,EAAA,MAAM,SAAA,GAAY,KAAK,OAAA,CAAQ,SAAA;AAC/B,EAAA,IAAI,CAAC,SAAA,EAAW;AAKhB,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,iBAAA,IAAqB,IAAA,CAAK,SAAA;AAC7C,EAAA,MAAM,WAAW,IAAI,IAAA,CAAK,KAAA,CAAM,OAAA,KAAY,eAAe,CAAA;AAE3D,EAAA,MAAM,MAAA,GAAS,MAAM,GAAA,CAAI,WAAA,CAAY,MAAA,CAClC,KAAK,EAAE,IAAA,EAAM,SAAA,EAAW,SAAA,EAAW,EAAE,GAAA,EAAK,UAAS,EAAG,CAAA,CACtD,IAAA,CAAK,EAAE,SAAA,EAAW,CAAA,EAAG,CAAA,CACrB,KAAA,CAAM,UAAU,CAAA,CAChB,OAAA,EAAQ;AAEX,EAAA,IAAI,MAAA,CAAO,WAAW,CAAA,EAAG;AAEzB,EAAA,KAAA,MAAW,SAAS,MAAA,EAAQ;AAC1B,IAAA,MAAM,YAAA,CAAa,IAAA,EAAM,KAAA,EAAO,GAAG,CAAA;AAAA,EACrC;AAEA,EAAA,MAAM,eAAA,GAAkB,MAAA,CAAO,MAAA,CAAO,MAAA,GAAS,CAAC,CAAA,CAAG,SAAA;AACnD,EAAA,IAAI,eAAA,CAAgB,OAAA,EAAQ,GAAI,KAAA,CAAM,SAAQ,EAAG;AAC/C,IAAA,MAAM,GAAA,CAAI,YAAY,KAAA,CAAM,SAAA;AAAA,MAC1B,EAAE,GAAA,EAAK,IAAA,CAAK,GAAA,EAAI;AAAA,MAChB,EAAE,MAAM,EAAE,iBAAA,EAAmB,iBAAiB,SAAA,kBAAW,IAAI,IAAA,EAAK,EAAE;AAAE,KACxE;AAAA,EACF;AACF;AAEA,eAAe,YAAA,CAAa,IAAA,EAAe,KAAA,EAAiB,GAAA,EAAmC;AAC7F,EAAA,IAAI,IAAA,CAAK,QAAQ,IAAA,EAAM;AACrB,IAAA,MAAM,QAAA,GAAW,MAAM,GAAA,CAAI,WAAA,CAAY,QAAA,CAAS,OAAA;AAAA,MAC9C,EAAE,UAAA,EAAY,KAAA,CAAM,UAAA,EAAY,MAAA,EAAQ,KAAK,GAAA,EAAI;AAAA,MACjD,EAAE,UAAA,EAAY,EAAE,GAAA,EAAK,GAAE;AAAE,KAC3B;AACA,IAAA,IAAI,QAAA,EAAU;AAAA,EAChB;AAIA,EAAA,MAAM,GAAA,GAAM,MAAM,GAAA,CAAI,WAAA,CAAY,aAAA,CAAc,QAAQ,EAAE,UAAA,EAAY,KAAA,CAAM,UAAA,EAAY,CAAA;AACxF,EAAA,IAAI,CAAC,GAAA,IAAO,GAAA,CAAI,MAAA,KAAW,YAAA,EAAc;AAEzC,EAAA,IAAI,MAAA;AACJ,EAAA,IAAI;AACF,IAAA,MAAA,GAAS,MAAM,GAAA,CAAI,WAAA,CAAY,QAAA,CAAS,SAAA,CAAU;AAAA,MAChD,YAAY,KAAA,CAAM,UAAA;AAAA,MAClB,QAAQ,IAAA,CAAK,GAAA;AAAA,MACb,UAAU,IAAA,CAAK,IAAA;AAAA,MACf,aAAa,IAAA,CAAK,OAAA;AAAA,MAClB,cAAc,GAAA,CAAI,gBAAA;AAAA,MAClB,YAAA,EAAc,EAAE,IAAA,EAAM,KAAA,CAAM,IAAA,EAAM,UAAA,EAAY,KAAA,CAAM,UAAA,IAAc,EAAC,EAAG,UAAA,EAAY,KAAA,CAAM,UAAA,EAAW;AAAA,MACnG,kBAAkB,KAAA,CAAM,SAAA;AAAA,MACxB,SAAA,sBAAe,IAAA,EAAK;AAAA,MACpB,MAAA,EAAQ,QAAA;AAAA,MACR,gBAAA,EAAkB,CAAA;AAAA,MAClB,mBAAmB,EAAC;AAAA,MACpB,YAAA,sBAAkB,IAAA,EAAK;AAAA,MACvB,sBAAA,EAAwB,CAAA;AAAA,MACxB,SAAS,CAAC,EAAE,SAAA,EAAW,CAAA,CAAA,EAAI,QAAQ,SAAA,EAAW,EAAA,kBAAI,IAAI,IAAA,IAAQ,OAAA,EAAS,EAAE,gBAAgB,KAAA,CAAM,SAAA,IAAa,CAAA;AAAA,MAC5G,QAAA,EAAU,IAAA;AAAA,MACV,UAAA,EAAY,IAAA;AAAA,MACZ,SAAA,sBAAe,IAAA,EAAK;AAAA,MACpB,SAAA,sBAAe,IAAA;AAAK,KACrB,CAAA;AAAA,EACH,SAAS,GAAA,EAAU;AAEjB,IAAA,IAAI,GAAA,EAAK,IAAA,KAAS,IAAA,EAAO,MAAM,GAAA;AAC/B,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,GAAA,CAAI,MAAA,CAAO,OAAA,CAAQ,GAAA,CAAI,SAAA,EAAW,EAAE,SAAA,EAAW,MAAA,CAAO,MAAA,CAAO,UAAU,CAAA,EAAG,CAAA;AAClF;;;ACpEO,SAAS,oBAAA,CACd,SAAA,EACA,YAAA,EACA,QAAA,EACwB;AACxB,EAAA,IAAI,CAAC,QAAA,IAAY,MAAA,CAAO,IAAA,CAAK,QAAQ,CAAA,CAAE,MAAA,KAAW,CAAA,EAAG,OAAO,EAAE,EAAA,EAAI,IAAA,EAAK;AAEvE,EAAA,MAAM,MAAA,GAAS,cAAc,SAAS,CAAA;AACtC,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,OAAO;AAAA,MACL,EAAA,EAAI,KAAA;AAAA,MACJ,IAAA,EAAM,eAAA;AAAA,MACN,MAAA,EAAQ,sBAAsB,SAAS,CAAA,+BAAA;AAAA,KACzC;AAAA,EACF;AAEA,EAAA,MAAM,KAAA,GAAQ,SAAS,MAAM,CAAA;AAC7B,EAAA,IAAI,CAAC,KAAA,EAAO;AACV,IAAA,MAAM,QAAQ,MAAA,CAAO,IAAA,CAAK,QAAQ,CAAA,CAAE,KAAK,IAAI,CAAA;AAC7C,IAAA,OAAO;AAAA,MACL,EAAA,EAAI,KAAA;AAAA,MACJ,IAAA,EAAM,qBAAA;AAAA,MACN,MAAA,EAAQ,CAAA,eAAA,EAAkB,MAAM,CAAA,6CAAA,EAAgD,KAAK,CAAA,CAAA;AAAA,KACvF;AAAA,EACF;AAEA,EAAA,IAAI,MAAM,IAAA,KAAS,MAAA,EAAQ,OAAO,EAAE,IAAI,IAAA,EAAK;AAC7C,EAAA,IAAI,KAAA,CAAM,SAAS,YAAA,EAAc;AAC/B,IAAA,OAAO;AAAA,MACL,EAAA,EAAI,KAAA;AAAA,MACJ,IAAA,EAAM,YAAA;AAAA,MACN,QAAQ,CAAA,eAAA,EAAkB,MAAM,uBAAuB,KAAA,CAAM,IAAI,uCAAuC,YAAY,CAAA;AAAA,KACtH;AAAA,EACF;AAEA,EAAA,OAAO,EAAE,IAAI,IAAA,EAAK;AACpB;AAEO,SAAS,cAAc,KAAA,EAA8B;AAC1D,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,EAAU,OAAO,IAAA;AACtC,EAAA,MAAM,EAAA,GAAK,KAAA,CAAM,WAAA,CAAY,GAAG,CAAA;AAChC,EAAA,IAAI,MAAM,CAAA,IAAK,EAAA,KAAO,KAAA,CAAM,MAAA,GAAS,GAAG,OAAO,IAAA;AAC/C,EAAA,OAAO,MAAM,KAAA,CAAM,EAAA,GAAK,CAAC,CAAA,CAAE,WAAA,GAAc,IAAA,EAAK;AAChD;;;ACvCA,IAAM,aAAA,GAAgB;AAAA,EACpB,IAAA,EAAM,CAAA;AAAA,EACN,SAAA,EAAW,CAAA;AAAA,EACX,OAAA,EAAS,CAAA;AAAA,EACT,WAAA,EAAa,CAAA;AAAA,EACb,WAAA,EAAa,CAAA;AAAA,EACb,UAAA,EAAY,CAAA;AAAA,EACZ,YAAA,EAAc;AAChB,CAAA;AAEA,IAAM,UAAA,GAAa;AAAA,EACjB,UAAA,EAAY,CAAA;AAAA,EACZ,cAAA,EAAgB,CAAA;AAAA,EAChB,aAAA,EAAe,CAAA;AAAA,EACf,WAAA,EAAa;AACf,CAAA;AASA,eAAsB,mBAAA,CACpB,GAAA,EACAC,QAAAA,EACA,IAAA,EACA,KAAK,CAAA,EACU;AACf,EAAA,MAAM,QAAA,GAAW,GAAA,CAAI,MAAA,CAAO,cAAA,CAAe,gBAAgB,EAAA,GAAK,GAAA;AAChE,EAAA,MAAM,SAAkC,EAAC;AAEzC,EAAA,MAAA,CAAO,IAAA,CAAK,cAAc,GAAA,EAAK,aAAA,EAAe,MAAM,IAAA,EAAMA,QAAAA,EAAS,EAAA,EAAI,QAAQ,CAAC,CAAA;AAEhF,EAAA,IAAI,IAAA,EAAM;AAKR,IAAA,MAAM,SAAS,IAAA,CAAK,SAAA,GAAY,aAAA,CAAc,IAAA,CAAK,SAAS,CAAA,GAAI,IAAA;AAChE,IAAA,IAAI,MAAA,EAAQ;AACV,MAAA,MAAM,EAAA,GAAK,cAAA,CAAe,MAAA,EAAQ,IAAA,CAAK,IAAI,CAAA;AAC3C,MAAA,MAAA,CAAO,IAAA,CAAK,aAAA,CAAc,GAAA,EAAK,EAAA,EAAI,MAAA,EAAQ,KAAK,IAAA,EAAMA,QAAAA,EAAS,EAAA,EAAI,QAAQ,CAAC,CAAA;AAAA,IAC9E;AAAA,EACF;AAEA,EAAA,MAAM,OAAA,CAAQ,IAAI,MAAM,CAAA;AAC1B;AAEA,eAAe,cACb,GAAA,EACA,GAAA,EACA,cACA,IAAA,EACAA,QAAAA,EACA,IACA,QAAA,EACe;AACf,EAAA,MAAM,GAAA,CAAI,YAAY,MAAA,CAAO,SAAA;AAAA,IAC3B,EAAE,GAAA,EAAI;AAAA,IACN;AAAA,MACE,MAAM,EAAE,CAAC,YAAYA,QAAO,CAAA,CAAE,GAAG,EAAA,EAAG;AAAA,MACpC,YAAA,EAAc;AAAA,QACZ,GAAA;AAAA,QACA,YAAA;AAAA,QACA,IAAA;AAAA,QACA,eAAA,sBAAqB,IAAA,EAAK;AAAA,QAC1B,gBAAA,EAAkB,QAAA;AAAA,QAClB,MAAA,EAAQ,SAAA;AAAA,QACR,SAAA,EAAW,IAAA;AAAA,QACX,aAAA,EAAe,IAAA;AAAA,QACf,iBAAA,EAAmB,IAAA;AAAA,QACnB,KAAA,EAAO,EAAE,GAAG,UAAA;AAAW,OACzB;AAAA,MACA,IAAA,EAAM,EAAE,SAAA,kBAAW,IAAI,MAAK;AAAE,KAChC;AAAA,IACA,EAAE,QAAQ,IAAA;AAAK,GACjB;AACF;AAOA,eAAsB,eAAe,GAAA,EAAmC;AACtE,EAAA,MAAM,EAAA,GAAK,IAAI,MAAA,CAAO,cAAA;AACtB,EAAA,MAAM,QAAA,GAAW,EAAA,CAAG,aAAA,GAAgB,EAAA,GAAK,GAAA;AAEzC,EAAA,MAAM,IAAA,GAAO,MAAM,GAAA,CAAI,WAAA,CAAY,OAAO,IAAA,CAAK,EAAE,CAAA,CAAE,OAAA,EAAQ;AAC3D,EAAA,IAAI,IAAA,CAAK,WAAW,CAAA,EAAG;AAIvB,EAAA,MAAM,SAAS,IAAA,CAAK,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,QAAQ,aAAa,CAAA;AACvD,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,MAAM,cAAc,GAAA,EAAK,aAAA,EAAe,MAAM,IAAA,EAAM,MAAA,EAAQ,GAAG,QAAQ,CAAA;AAAA,EACzE;AAEA,EAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,IAAA,MAAM,KAAA,GAAQ,IAAI,GAAA,KAAQ,aAAA;AAC1B,IAAA,MAAM,SAAA,GAAY,KAAK,GAAA,EAAI,GAAI,IAAI,IAAA,CAAK,GAAA,CAAI,eAAe,CAAA,CAAE,OAAA,EAAQ;AAErE,IAAA,IAAI,SAAA,GAAY,QAAA,IAAY,GAAA,CAAI,MAAA,KAAW,SAAA,EAAW;AAKpD,MAAA,MAAM,GAAA,CAAI,YAAY,MAAA,CAAO,SAAA;AAAA,QAC3B,EAAE,GAAA,EAAK,GAAA,CAAI,GAAA,EAAI;AAAA,QACf;AAAA,UACE,IAAA,EAAM;AAAA,YACJ,eAAA,sBAAqB,IAAA,EAAK;AAAA,YAC1B,gBAAA,EAAkB,QAAA;AAAA,YAClB,QAAA,EAAU,EAAE,GAAG,aAAA,EAAc;AAAA,YAC7B,KAAA,EAAO,EAAE,GAAG,UAAA,EAAW;AAAA,YACvB,MAAA,EAAQ,SAAA;AAAA,YACR,SAAA,sBAAe,IAAA;AAAK;AACtB;AACF,OACF;AACA,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,IAAI,GAAA,CAAI,QAAA;AACd,IAAA,MAAM,KAAA,GAAQ,EAAE,IAAA,IAAQ,CAAA;AACxB,IAAA,MAAM,KAAA,GAAQ;AAAA,MACZ,UAAA,EAAY,EAAE,OAAA,GAAU,KAAA;AAAA,MACxB,cAAA,EAAgB,EAAE,WAAA,GAAc,KAAA;AAAA,MAChC,aAAA,EAAe,EAAE,UAAA,GAAa,KAAA;AAAA,MAC9B,WAAA,EAAa,EAAE,YAAA,GAAe;AAAA,KAChC;AAEA,IAAA,MAAM,GAAA,CAAI,YAAY,MAAA,CAAO,SAAA;AAAA,MAC3B,EAAE,GAAA,EAAK,GAAA,CAAI,GAAA,EAAI;AAAA,MACf,EAAE,MAAM,EAAE,KAAA,EAAO,2BAAW,IAAI,IAAA,IAAO;AAAE,KAC3C;AAGA,IAAA,IAAI,KAAA,EAAO;AAEX,IAAA,IAAI,CAAA,CAAE,IAAA,GAAO,EAAA,CAAG,kBAAA,EAAoB;AACpC,IAAA,IAAI,GAAA,CAAI,WAAW,SAAA,EAAW;AAE9B,IAAA,IAAI,aAAA,GAA+B,IAAA;AACnC,IAAA,IAAI,KAAA,CAAM,cAAA,GAAiB,GAAA,IAAO,EAAA,CAAG,qBAAA,EAAuB;AAC1D,MAAA,aAAA,GAAgB,CAAA,iBAAA,EAAA,CAAqB,MAAM,cAAA,GAAiB,GAAA,EAAK,QAAQ,CAAC,CAAC,CAAA,KAAA,EAAQ,EAAA,CAAG,qBAAqB,CAAA,CAAA,CAAA;AAAA,IAC7G,CAAA,MAAA,IAAW,KAAA,CAAM,aAAA,GAAgB,GAAA,IAAO,GAAG,oBAAA,EAAsB;AAC/D,MAAA,aAAA,GAAgB,CAAA,eAAA,EAAA,CAAmB,MAAM,aAAA,GAAgB,GAAA,EAAK,QAAQ,CAAC,CAAC,CAAA,KAAA,EAAQ,EAAA,CAAG,oBAAoB,CAAA,CAAA,CAAA;AAAA,IACzG,CAAA,MAAA,IAAW,KAAA,CAAM,UAAA,GAAa,GAAA,IAAO,GAAG,yBAAA,EAA2B;AACjE,MAAA,aAAA,GAAgB,CAAA,qBAAA,EAAA,CAAyB,MAAM,UAAA,GAAa,GAAA,EAAK,QAAQ,CAAC,CAAC,CAAA,KAAA,EAAQ,EAAA,CAAG,yBAAyB,CAAA,CAAA,CAAA;AAAA,IACjH;AAEA,IAAA,IAAI,aAAA,EAAe;AAKjB,MAAA,MAAM,MAAA,GAAS,MAAM,GAAA,CAAI,WAAA,CAAY,MAAA,CAAO,SAAA;AAAA,QAC1C,EAAE,GAAA,EAAK,GAAA,CAAI,GAAA,EAAK,MAAA,EAAQ,EAAE,GAAA,EAAK,CAAC,SAAA,EAAW,UAAU,CAAA,EAAE,EAAE;AAAA,QACzD,EAAE,IAAA,EAAM,EAAE,MAAA,EAAQ,WAAW,SAAA,kBAAW,IAAI,IAAA,EAAK,EAAG,aAAA,EAAe,SAAA,kBAAW,IAAI,IAAA,IAAO;AAAE,OAC7F;AACA,MAAA,IAAI,MAAA,CAAO,gBAAgB,CAAA,EAAG;AAE5B,QAAA,IAAI,IAAI,KAAA,EAAO;AACb,UAAA,IAAI;AACF,YAAA,MAAM,IAAI,KAAA,CAAM;AAAA,cACd,KAAA,EAAO,wBAAA;AAAA,cACP,MAAA,EAAQ,aAAA;AAAA,cACR,QAAA,EAAU;AAAA,gBACR,UAAA,EAAY,eAAA;AAAA,gBACZ,EAAA,EAAI,MAAA,CAAO,GAAA,CAAI,GAAG,CAAA;AAAA,gBAClB,MAAM,CAAA,EAAG,GAAA,CAAI,gBAAgB,UAAU,CAAA,CAAA,EAAI,IAAI,IAAI,CAAA;AAAA,eACrD;AAAA,cACA,WAAA,EAAa;AAAA,aACd,CAAA;AAAA,UACH,CAAA,CAAA,MAAQ;AAAA,UAER;AAAA,QACF;AACA,QAAA,IAAI,GAAA,CAAI,OAAO,oBAAA,EAAsB;AACnC,UAAA,IAAI;AACF,YAAA,MAAM,GAAA,CAAI,OAAO,oBAAA,CAAqB;AAAA,cACpC,MAAA,EAAQ,IAAI,GAAA,CAAI,YAAA,IAAgB,UAAU,CAAA,GAAA,EAAM,GAAA,CAAI,IAAI,CAAA,EAAA,EAAK,aAAa,CAAA,CAAA;AAAA,cAC1E;AAAA,aACD,CAAA;AAAA,UACH,CAAA,CAAA,MAAQ;AAAA,UAER;AAAA,QACF;AAAA,MACF;AACA,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,KAAA,CAAM,WAAA,GAAc,GAAA,IAAO,EAAA,CAAG,0BAAA,EAA4B;AAC5D,MAAA,IAAI,GAAA,CAAI,WAAW,UAAA,EAAY;AAC7B,QAAA,MAAM,GAAA,CAAI,YAAY,MAAA,CAAO,SAAA;AAAA,UAC3B,EAAE,GAAA,EAAK,GAAA,CAAI,GAAA,EAAI;AAAA,UACf,EAAE,MAAM,EAAE,MAAA,EAAQ,YAAY,SAAA,kBAAW,IAAI,IAAA,EAAK,EAAE;AAAE,SACxD;AAAA,MACF;AAAA,IACF,CAAA,MAAA,IAAW,GAAA,CAAI,MAAA,KAAW,UAAA,EAAY;AACpC,MAAA,MAAM,GAAA,CAAI,YAAY,MAAA,CAAO,SAAA;AAAA,QAC3B,EAAE,GAAA,EAAK,GAAA,CAAI,GAAA,EAAI;AAAA,QACf,EAAE,MAAM,EAAE,MAAA,EAAQ,WAAW,SAAA,kBAAW,IAAI,IAAA,EAAK,EAAE;AAAE,OACvD;AAAA,IACF;AAAA,EACF;AACF;AAOA,eAAsB,eAAA,CACpB,GAAA,EACA,SAAA,EACA,IAAA,EAC2B;AAC3B,EAAA,MAAM,MAAA,GAAS,SAAA,GAAY,aAAA,CAAc,SAAS,CAAA,GAAI,IAAA;AACtD,EAAA,MAAM,EAAA,GAAK,cAAA,CAAe,MAAA,EAAQ,IAAI,CAAA;AACtC,EAAA,OAAO,IAAI,WAAA,CAAY,MAAA,CAAO,QAAQ,EAAE,GAAA,EAAK,IAAI,CAAA;AACnD;AAOO,SAAS,uBAAuB,IAAA,EAA+C;AAIpF,EAAA,MAAM,OAAA,GAAU,IAAA,CAAK,MAAA,CAAO,CAAC,CAAA,KAAM,OAAO,CAAA,CAAE,GAAA,KAAQ,QAAA,IAAY,CAAA,CAAE,GAAA,CAAI,UAAA,CAAW,IAAI,CAAC,CAAA;AACtF,EAAA,IAAI,OAAA,CAAQ,WAAW,CAAA,EAAG;AACxB,IAAA,OAAO,IAAA,CAAK,MAAA,KAAW,CAAA,GAAI,IAAA,GAAO,SAAA;AAAA,EACpC;AACA,EAAA,IAAI,OAAA,CAAQ,KAAK,CAAC,CAAA,KAAM,EAAE,MAAA,KAAW,SAAS,GAAG,OAAO,SAAA;AACxD,EAAA,IAAI,OAAA,CAAQ,KAAK,CAAC,CAAA,KAAM,EAAE,MAAA,KAAW,UAAU,GAAG,OAAO,UAAA;AACzD,EAAA,OAAO,SAAA;AACT;;;AC3QA,SAAS,aAAa,IAAA,EAAqD;AACzE,EAAA,IAAI,CAAC,MAAM,OAAO,IAAA;AAClB,EAAA,OAAO,EAAE,SAAA,EAAW,IAAA,CAAK,SAAA,EAAW,IAAA,EAAM,KAAK,IAAA,EAAK;AACtD;AASA,eAAsB,qBAAA,CACpB,GAAA,EACA,IAAA,GAAiC,EAAC,EACnB;AACf,EAAA,MAAM,MAAA,GAAkC,EAAE,SAAA,EAAW,KAAA,EAAM;AAC3D,EAAA,IAAI,KAAK,WAAA,EAAa;AACpB,IAAA,MAAA,CAAO,UAAA,GAAa,EAAE,GAAA,EAAK,IAAI,IAAA,CAAK,KAAK,GAAA,EAAI,GAAI,IAAA,CAAK,WAAW,CAAA,EAAE;AAAA,EACrE;AACA,EAAA,MAAM,KAAA,GAAQ,MAAM,GAAA,CAAI,WAAA,CAAY,aAAA,CAAc,IAAA,CAAK,MAAM,CAAA,CAAE,KAAA,CAAM,GAAG,CAAA,CAAE,OAAA,EAAQ;AAElF,EAAA,KAAA,MAAW,OAAO,KAAA,EAAO;AAMvB,IAAA,MAAM,OAAA,GAAU,MAAM,GAAA,CAAI,WAAA,CAAY,aAAA,CAAc,gBAAA;AAAA,MAClD,EAAE,GAAA,EAAK,GAAA,CAAI,GAAA,EAAK,WAAW,KAAA,EAAM;AAAA,MACjC,EAAE,IAAA,EAAM,EAAE,SAAA,EAAW,MAAK;AAAE,KAC9B;AACA,IAAA,IAAI,CAAC,OAAA,EAAS;AAEd,IAAA,IAAI;AAGF,MAAA,MAAM,UAAA,GAAc,IAAI,GAAA,EAAa,UAAA;AACrC,MAAA,MAAM,OAAA,GAAU,UAAA,EAAY,OAAA,IAAW,EAAC;AACxC,MAAA,MAAM,iBAAA;AAAA,QACJ;AAAA,UACE,MAAM,GAAA,CAAI,cAAA;AAAA,UACV,iBAAiB,GAAA,CAAI,eAAA;AAAA,UACrB,mBAAmB,GAAA,CAAI,iBAAA;AAAA,UACvB,OAAO,GAAA,CAAI,KAAA;AAAA,UACX,YAAY,GAAA,CAAI,UAAA;AAAA,UAChB;AAAA,SACF;AAAA,QACA;AAAA,OACF;AAAA,IACF,SAAS,GAAA,EAAK;AACZ,MAAA,OAAA,CAAQ,KAAA,CAAM,iCAAiC,EAAE,EAAA,EAAI,OAAO,GAAA,CAAI,GAAG,CAAA,EAAG,GAAA,EAAK,CAAA;AAAA,IAC7E;AAAA,EACF;AACF;AAEA,eAAsB,iBAAA,CAAkB,OAAwB,GAAA,EAAmC;AACjG,EAAA,MAAM,IAAA,GAAO,MAAM,GAAA,CAAI,WAAA,CAAY,KAAA,CAAM,OAAA;AAAA,IACvC,KAAA,CAAM,oBACF,EAAE,GAAA,EAAK,CAAC,EAAE,iBAAA,EAAmB,MAAM,iBAAA,EAAkB,EAAG,EAAE,WAAA,EAAa,KAAA,CAAM,OAAO,CAAA,KACpF,EAAE,WAAA,EAAa,MAAM,KAAA,EAAM;AAAA,IAC/B,EAAE,IAAA,EAAM,EAAE,QAAA,EAAU,IAAG;AAAE,GAC3B;AAEA,EAAA,QAAQ,MAAM,IAAA;AAAM,IAClB,KAAK,WAAA;AACH,MAAA,IAAI,IAAA,EAAM;AACR,QAAA,MAAM,GAAA,CAAI,YAAY,KAAA,CAAM,SAAA;AAAA,UAC1B,EAAE,GAAA,EAAK,IAAA,CAAK,GAAA,EAAI;AAAA,UAChB,EAAE,MAAM,EAAE,MAAA,EAAQ,aAAa,WAAA,EAAa,KAAA,CAAM,YAAW;AAAE,SACjE;AAAA,MACF;AACA,MAAA,MAAM,mBAAA,CAAoB,GAAA,EAAK,WAAA,EAAa,YAAA,CAAa,IAAI,CAAC,CAAA;AAC9D,MAAA;AAAA,IAEF,KAAK,MAAA;AACH,MAAA,IAAI,IAAA,EAAM;AACR,QAAA,MAAM,GAAA,CAAI,YAAY,KAAA,CAAM,SAAA;AAAA,UAC1B,EAAE,GAAA,EAAK,IAAA,CAAK,GAAA,EAAI;AAAA,UAChB;AAAA,YACE,IAAA,EAAM;AAAA,cACJ,QAAA,EAAU,IAAA,CAAK,QAAA,IAAY,KAAA,CAAM,UAAA;AAAA,cACjC,MAAA,EAAQ,IAAA,CAAK,MAAA,KAAW,MAAA,GAAS,cAAc,IAAA,CAAK;AAAA,aACtD;AAAA,YACA,IAAA,EAAM,EAAE,SAAA,EAAW,CAAA;AAAE;AACvB,SACF;AAAA,MACF;AACA,MAAA;AAAA,IAEF,KAAK,OAAA;AACH,MAAA,IAAI,IAAA,EAAM;AACR,QAAA,MAAM,GAAA,CAAI,YAAY,KAAA,CAAM,SAAA;AAAA,UAC1B,EAAE,GAAA,EAAK,IAAA,CAAK,GAAA,EAAI;AAAA,UAChB;AAAA,YACE,MAAM,EAAE,YAAA,EAAc,IAAA,CAAK,YAAA,IAAgB,MAAM,UAAA,EAAW;AAAA,YAC5D,IAAA,EAAM,EAAE,UAAA,EAAY,CAAA,EAAE;AAAA,YACtB,KAAA,EAAO;AAAA,cACL,YAAA,EAAc;AAAA,gBACZ,GAAA,EAAK,KAAA,CAAM,OAAA,CAAQ,UAAA,IAAc,EAAA;AAAA,gBACjC,MAAA,EAAQ,EAAA;AAAA,gBACR,WAAW,KAAA,CAAM;AAAA;AACnB;AACF;AACF,SACF;AAAA,MACF;AACA,MAAA;AAAA,IAEF,KAAK,QAAA,EAAU;AACb,MAAA,MAAM,UAAA,GAAa,KAAA,CAAM,OAAA,CAAQ,UAAA,IAAc,MAAA;AAC/C,MAAA,IAAI,IAAA,EAAM;AACR,QAAA,MAAM,GAAA,CAAI,YAAY,KAAA,CAAM,SAAA;AAAA,UAC1B,EAAE,GAAA,EAAK,IAAA,CAAK,GAAA,EAAI;AAAA,UAChB;AAAA,YACE,IAAA,EAAM;AAAA,cACJ,MAAA,EAAQ,SAAA;AAAA,cACR,UAAA;AAAA,cACA,YAAA,EAAc,KAAA,CAAM,OAAA,CAAQ,YAAA,IAAgB;AAAA;AAC9C;AACF,SACF;AAAA,MACF;AACA,MAAA,IAAI,eAAe,MAAA,EAAQ;AACzB,QAAA,MAAM,YAAA,CAAa,GAAA,EAAK,KAAA,CAAM,KAAA,EAAO,eAAe,KAAK,CAAA;AACzD,QAAA,MAAM,GAAA,CAAI,YAAY,aAAA,CAAc,SAAA;AAAA,UAClC,EAAE,gBAAA,EAAkB,KAAA,CAAM,KAAA,EAAM;AAAA,UAChC,EAAE,MAAM,EAAE,MAAA,EAAQ,WAAW,SAAA,kBAAW,IAAI,IAAA,EAAK,EAAE;AAAE,SACvD;AAAA,MACF;AACA,MAAA;AACE,QAAA,MAAM,IAAA,GAAO,aAAa,IAAI,CAAA;AAC9B,QAAA,MAAM,mBAAA,CAAoB,GAAA,EAAK,SAAA,EAAW,IAAI,CAAA;AAC9C,QAAA,MAAM,oBAAoB,GAAA,EAAK,UAAA,KAAe,MAAA,GAAS,aAAA,GAAgB,eAAe,IAAI,CAAA;AAAA,MAC5F;AACA,MAAA;AAAA,IACF;AAAA,IAEA,KAAK,WAAA;AAAA,IACL,KAAK,aAAA;AACH,MAAA,IAAI,IAAA,EAAM;AACR,QAAA,MAAM,GAAA,CAAI,YAAY,KAAA,CAAM,SAAA;AAAA,UAC1B,EAAE,GAAA,EAAK,IAAA,CAAK,GAAA,EAAI;AAAA,UAChB,EAAE,MAAM,EAAE,YAAA,EAAc,MAAM,UAAA,EAAY,MAAA,EAAQ,cAAa;AAAE,SACnE;AAAA,MACF;AACA,MAAA,MAAM,YAAA,CAAa,GAAA,EAAK,KAAA,CAAM,KAAA,EAAO,aAAa,KAAK,CAAA;AACvD,MAAA,MAAM,GAAA,CAAI,YAAY,aAAA,CAAc,SAAA;AAAA,QAClC,EAAE,gBAAA,EAAkB,KAAA,CAAM,KAAA,EAAM;AAAA,QAChC,EAAE,MAAM,EAAE,MAAA,EAAQ,cAAc,SAAA,kBAAW,IAAI,IAAA,EAAK,EAAE;AAAE,OAC1D;AACA,MAAA,MAAM,mBAAA,CAAoB,GAAA,EAAK,YAAA,EAAc,YAAA,CAAa,IAAI,CAAC,CAAA;AAC/D,MAAA;AAAA,IAEF,KAAK,aAAA;AACH,MAAA,IAAI,IAAA,EAAM;AACR,QAAA,MAAM,IAAI,WAAA,CAAY,KAAA,CAAM,SAAA,CAAU,EAAE,KAAK,IAAA,CAAK,GAAA,EAAI,EAAG,EAAE,MAAM,EAAE,cAAA,EAAgB,KAAA,CAAM,UAAA,IAAc,CAAA;AAAA,MACzG;AACA,MAAA,MAAM,YAAA,CAAa,GAAA,EAAK,KAAA,CAAM,KAAA,EAAO,gBAAgB,WAAW,CAAA;AAChE,MAAA,MAAM,GAAA,CAAI,YAAY,aAAA,CAAc,SAAA;AAAA,QAClC,EAAE,gBAAA,EAAkB,KAAA,CAAM,KAAA,EAAM;AAAA,QAChC;AAAA,UACE,IAAA,EAAM;AAAA,YACJ,MAAA,EAAQ,cAAA;AAAA,YACR,gBAAgB,KAAA,CAAM,UAAA;AAAA,YACtB,iBAAA,EAAmB,cAAA;AAAA,YACnB,SAAA,sBAAe,IAAA;AAAK;AACtB;AACF,OACF;AACA,MAAA;AAAA;AAEN;AAEA,eAAe,YAAA,CACb,GAAA,EACA,KAAA,EACA,MAAA,EACA,KAAA,EACe;AACf,EAAA,MAAM,UAAA,GAAa,MAAM,WAAA,EAAY;AACrC,EAAA,MAAM,GAAA,CAAI,YAAY,YAAA,CAAa,SAAA;AAAA,IACjC,EAAE,KAAA,EAAO,UAAA,EAAY,KAAA,EAAM;AAAA,IAC3B;AAAA,MACE,YAAA,EAAc;AAAA,QACZ,KAAA,EAAO,UAAA;AAAA,QACP,SAAA,EAAW,UAAU,UAAU,CAAA;AAAA,QAC/B,KAAA;AAAA,QACA,MAAA;AAAA,QACA,MAAA,EAAQ,kBAAA;AAAA,QACR,KAAA,EAAO,IAAA;AAAA,QACP,OAAA,sBAAa,IAAA,EAAK;AAAA,QAClB,SAAA,EAAW;AAAA;AACb,KACF;AAAA,IACA,EAAE,QAAQ,IAAA;AAAK,GACjB;AACF;;;ACjLO,IAAM,iBAAA,GAAoB;AAEjC,eAAsB,iBAAA,CACpB,WACA,GAAA,EACkB;AAClB,EAAA,MAAM,CAAA,GAAI,SAAA;AAEV,EAAA,IAAI,QAAA,IAAY,GAAG,OAAO,GAAA,CAAI,QAAQ,IAAA,CAAK,QAAA,CAAS,EAAE,MAAM,CAAA;AAC5D,EAAA,IAAI,WAAA,IAAe,GAAG,OAAO,CAAC,IAAI,OAAA,CAAQ,IAAA,CAAK,QAAA,CAAS,CAAA,CAAE,SAAS,CAAA;AAEnE,EAAA,IAAI,iBAAiB,CAAA,EAAG;AACtB,IAAA,OAAO,GAAA,CAAI,QAAQ,MAAA,CAAO,CAAA,CAAE,YAAY,KAAK,CAAA,KAAM,EAAE,WAAA,CAAY,KAAA;AAAA,EACnE;AACA,EAAA,IAAI,iBAAiB,CAAA,EAAG;AACtB,IAAA,OAAO,GAAA,CAAI,OAAA,CAAQ,MAAA,CAAO,CAAA,CAAE,WAAW,CAAA,KAAM,MAAA;AAAA,EAC/C;AAIA,EAAA,IAAI,2BAA2B,CAAA,EAAG;AAChC,IAAA,OAAA,CACG,GAAA,CAAI,GAAA,CAAI,YAAA,EAAc,UAAA,IAAc,EAAC,EAAG,CAAA,CAAE,qBAAA,CAAsB,GAAG,CAAA,KACpE,CAAA,CAAE,qBAAA,CAAsB,KAAA;AAAA,EAE5B;AACA,EAAA,IAAI,2BAA2B,CAAA,EAAG;AAChC,IAAA,OAAO,OAAA,CAAA,CAAS,IAAI,GAAA,CAAI,YAAA,EAAc,cAAc,EAAC,EAAG,CAAA,CAAE,qBAAqB,CAAC,CAAA;AAAA,EAClF;AAEA,EAAA,IAAI,wBAAwB,CAAA,EAAG;AAC7B,IAAA,MAAM,GAAA,GAAM,MAAM,GAAA,CAAI,WAAA,CAAY,aAAA,CAAc,OAAA,CAAQ,EAAE,UAAA,EAAY,GAAA,CAAI,OAAA,CAAQ,UAAA,EAAY,CAAA;AAC9F,IAAA,OAAO,GAAA,EAAK,WAAW,CAAA,CAAE,kBAAA;AAAA,EAC3B;AAEA,EAAA,IAAI,mBAAmB,CAAA,EAAG;AACxB,IAAA,OAAO,QAAA,CAAS,GAAA,EAAK,CAAA,CAAE,aAAA,EAAe,EAAE,cAAA,EAAgB,CAAA,CAAE,cAAA,EAAgB,UAAA,EAAY,CAAA,CAAE,UAAA,EAAY,CAAA;AAAA,EACtG;AACA,EAAA,IAAI,sBAAsB,CAAA,EAAG;AAC3B,IAAA,OAAO,CAAE,MAAM,QAAA,CAAS,GAAA,EAAK,CAAA,CAAE,kBAAkB,EAAE,UAAA,EAAY,CAAA,CAAE,UAAA,EAAY,CAAA;AAAA,EAC/E;AAEA,EAAA,IAAI,WAAA,IAAe,CAAA,EAAG,OAAO,MAAM,gBAAA,CAAiB,KAAK,QAAA,EAAU,CAAA,CAAE,SAAA,EAAW,KAAK,CAAA,GAAI,CAAA;AACzF,EAAA,IAAI,YAAA,IAAgB,CAAA,EAAG,OAAO,MAAM,gBAAA,CAAiB,KAAK,SAAA,EAAW,CAAA,CAAE,UAAA,EAAY,KAAK,CAAA,GAAI,CAAA;AAC5F,EAAA,IAAI,wBAAA,IAA4B,CAAA,EAAG,OAAO,MAAM,gBAAA,CAAiB,KAAK,QAAA,EAAU,CAAA,CAAE,sBAAA,EAAwB,IAAI,CAAA,GAAI,CAAA;AAClH,EAAA,IAAI,yBAAA,IAA6B,CAAA,EAAG,OAAO,MAAM,gBAAA,CAAiB,KAAK,SAAA,EAAW,CAAA,CAAE,uBAAA,EAAyB,IAAI,CAAA,GAAI,CAAA;AACrH,EAAA,IAAI,gBAAA,IAAoB,CAAA,EAAG,OAAO,MAAM,gBAAA,CAAiB,GAAA,EAAK,QAAA,EAAU,CAAA,CAAE,cAAA,EAAgB,IAAI,CAAA,IAAK,CAAA,CAAE,cAAA,CAAe,KAAA;AACpH,EAAA,IAAI,iBAAA,IAAqB,CAAA,EAAG,OAAO,MAAM,gBAAA,CAAiB,GAAA,EAAK,SAAA,EAAW,CAAA,CAAE,eAAA,EAAiB,IAAI,CAAA,IAAK,CAAA,CAAE,eAAA,CAAgB,KAAA;AAExH,EAAA,IAAI,SAAS,CAAA,EAAG;AACd,IAAA,KAAA,MAAW,GAAA,IAAO,EAAE,GAAA,EAAK;AACvB,MAAA,IAAI,CAAE,MAAM,iBAAA,CAAkB,GAAA,EAAK,GAAG,GAAI,OAAO,KAAA;AAAA,IACnD;AACA,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,IAAI,SAAS,CAAA,EAAG;AACd,IAAA,KAAA,MAAW,GAAA,IAAO,EAAE,GAAA,EAAK;AACvB,MAAA,IAAI,MAAM,iBAAA,CAAkB,GAAA,EAAK,GAAG,GAAG,OAAO,IAAA;AAAA,IAChD;AACA,IAAA,OAAO,KAAA;AAAA,EACT;AACA,EAAA,IAAI,SAAS,CAAA,EAAG;AACd,IAAA,OAAO,CAAE,MAAM,iBAAA,CAAkB,CAAA,CAAE,KAAK,GAAG,CAAA;AAAA,EAC7C;AAEA,EAAA,OAAO,KAAA;AACT;AAEA,eAAe,QAAA,CACb,GAAA,EACA,IAAA,EACA,IAAA,EACkB;AAClB,EAAA,MAAM,SAAc,EAAE,UAAA,EAAY,GAAA,CAAI,OAAA,CAAQ,YAAY,IAAA,EAAK;AAC/D,EAAA,MAAM,KAAA,GAAQ,mBAAA,CAAoB,GAAA,EAAK,IAAI,CAAA;AAC3C,EAAA,IAAI,KAAA,EAAO,MAAA,CAAO,UAAA,GAAa,EAAE,KAAK,KAAA,EAAM;AAC5C,EAAA,MAAM,KAAA,GAAQ,MAAM,GAAA,CAAI,WAAA,CAAY,MAAA,CAAO,OAAA,CAAQ,MAAA,EAAQ,EAAE,UAAA,EAAY,EAAE,GAAA,EAAK,CAAA,IAAK,CAAA;AACrF,EAAA,OAAO,CAAC,CAAC,KAAA;AACX;AAEA,eAAe,gBAAA,CACb,GAAA,EACA,IAAA,EACA,IAAA,EACA,WAAA,EACiB;AACjB,EAAA,MAAM,MAAA,GAAc,EAAE,UAAA,EAAY,GAAA,CAAI,QAAQ,UAAA,EAAW;AACzD,EAAA,IAAI,IAAA,CAAK,YAAA,EAAc,MAAA,CAAO,YAAA,GAAe,IAAA,CAAK,YAAA;AAClD,EAAA,IAAI,SAAS,QAAA,EAAU,MAAA,CAAO,QAAA,GAAW,EAAE,KAAK,IAAA,EAAK;AACrD,EAAA,IAAI,SAAS,SAAA,EAAW,MAAA,CAAO,YAAA,GAAe,EAAE,KAAK,IAAA,EAAK;AAC1D,EAAA,MAAM,KAAA,GAAQ,mBAAA,CAAoB,GAAA,EAAK,IAAI,CAAA;AAC3C,EAAA,IAAI,KAAA,SAAc,IAAA,KAAS,QAAA,GAAW,aAAa,cAAc,CAAA,GAAI,EAAE,GAAA,EAAK,KAAA,EAAM;AAElF,EAAA,IAAI,CAAC,WAAA,EAAa;AAChB,IAAA,OAAO,MAAM,GAAA,CAAI,WAAA,CAAY,KAAA,CAAM,eAAe,MAAM,CAAA;AAAA,EAC1D;AAKA,EAAA,MAAM,IAAA,GAAO,MAAM,GAAA,CAAI,WAAA,CAAY,KAAA,CAAM,IAAA,CAAK,MAAM,CAAA,CAAE,KAAA,CAAM,GAAI,CAAA,CAAE,OAAA,EAAQ;AAC1E,EAAA,MAAM,KAAA,GAAQ,GAAA,CAAI,SAAA,EAAW,gBAAA,IAAoB,iBAAA;AACjD,EAAA,MAAM,cAAA,GAAiB,GAAA,CAAI,SAAA,EAAW,cAAA,IAAkB,CAAA;AACxD,EAAA,IAAI,CAAA,GAAI,CAAA;AACR,EAAA,KAAA,MAAW,KAAK,IAAA,EAAM;AACpB,IAAA,MAAM,GAAA,GAAM,CAAA;AACZ,IAAA,MAAM,KAAA,GACJ,SAAS,QAAA,GACL,YAAA,CAAa,KAAK,KAAA,EAAO,cAAc,KACtC,GAAA,CAAI,YAAA,IAAgB,EAAC,EAAG,IAAA,CAAK,CAAC,CAAA,KAAM,CAAC,eAAe,CAAA,CAAE,SAAA,EAAW,KAAK,CAAC,CAAA;AAC9E,IAAA,IAAI,KAAA,EAAO,CAAA,EAAA;AAAA,EACb;AACA,EAAA,OAAO,CAAA;AACT;AAmBA,SAAS,cAAA,CAAe,IAA+B,KAAA,EAAwB;AAC7E,EAAA,IAAI,OAAO,EAAA,KAAO,QAAA,IAAY,GAAG,IAAA,EAAK,KAAM,IAAI,OAAO,KAAA;AACvD,EAAA,OAAO,KAAA,CAAM,KAAK,EAAE,CAAA;AACtB;AASA,SAAS,YAAA,CAAa,IAAA,EAAe,KAAA,EAAe,cAAA,EAAiC;AACnF,EAAA,MAAM,KAAA,GACJ,KAAK,KAAA,IAAS,IAAA,CAAK,MAAM,MAAA,GAAS,CAAA,GAC9B,KAAK,KAAA,GACL,IAAA,CAAK,WACH,CAAC,EAAE,UAAU,IAAA,CAAK,QAAA,EAAU,WAAW,IAAA,EAAM,IAC7C,EAAC;AACT,EAAA,OAAO,KAAA,CAAM,IAAA,CAAK,CAAC,CAAA,KAAM;AACvB,IAAA,IAAI,cAAA,CAAe,CAAA,CAAE,SAAA,EAAW,KAAK,GAAG,OAAO,KAAA;AAC/C,IAAA,IAAI,eAAe,CAAA,CAAE,QAAA,EAAU,KAAK,QAAA,EAAU,cAAc,GAAG,OAAO,KAAA;AACtE,IAAA,OAAO,IAAA;AAAA,EACT,CAAC,CAAA;AACH;AAWA,SAAS,cAAA,CAAe,QAAA,EAAmB,QAAA,EAAmB,cAAA,EAAiC;AAC7F,EAAA,IAAI,CAAC,cAAA,IAAkB,cAAA,IAAkB,CAAA,EAAG,OAAO,KAAA;AACnD,EAAA,IAAI,EAAE,QAAA,YAAoB,IAAA,CAAA,IAAS,EAAE,QAAA,YAAoB,OAAO,OAAO,KAAA;AACvE,EAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,OAAA,EAAQ,GAAI,SAAS,OAAA,EAAQ;AACpD,EAAA,IAAI,CAAC,MAAA,CAAO,QAAA,CAAS,KAAK,CAAA,IAAK,KAAA,GAAQ,GAAG,OAAO,KAAA;AACjD,EAAA,OAAO,KAAA,GAAQ,cAAA;AACjB;AAEA,SAAS,mBAAA,CAAoB,KAAuB,IAAA,EAAsE;AACxH,EAAA,MAAM,GAAA,GAAM,GAAA,CAAI,GAAA,oBAAO,IAAI,IAAA,EAAK;AAChC,EAAA,IAAI,IAAA,CAAK,cAAA,EAAgB,OAAO,GAAA,CAAI,GAAA,CAAI,SAAA;AACxC,EAAA,IAAI,IAAA,CAAK,UAAA,IAAc,IAAA,CAAK,UAAA,GAAa,CAAA,EAAG;AAC1C,IAAA,OAAO,IAAI,IAAA,CAAK,GAAA,CAAI,OAAA,EAAQ,GAAI,KAAK,UAAA,GAAa,EAAA,GAAK,EAAA,GAAK,EAAA,GAAK,GAAI,CAAA;AAAA,EACvE;AACA,EAAA,OAAO,IAAA;AACT;;;ACnMA,IAAM,uBAAuB,EAAA,GAAK,GAAA;AAE3B,SAAS,mBAAA,CACd,GAAA,EACA,MAAA,EACA,eAAA,EACM;AACN,EAAA,MAAM,EAAA,GAAK,YAAA,CAAa,MAAA,EAAQ,eAAe,CAAA;AAC/C,EAAA,IAAI,SAAA,GAAY,GAAA;AAEhB,EAAA,IAAI,OAAO,SAAA,EAAW;AACpB,IAAA,MAAM,CAAC,EAAA,EAAI,EAAE,CAAA,GAAI,MAAA,CAAO,UAAU,KAAA,CAAM,GAAG,CAAA,CAAE,GAAA,CAAI,MAAM,CAAA;AACvD,IAAA,MAAM,KAAA,GAAQ,UAAA,CAAW,SAAA,EAAW,EAAE,CAAA;AACtC,IAAA,MAAM,SAAA,GAAY,YAAA,CAAa,KAAA,CAAM,CAAA,EAAG,KAAA,CAAM,IAAI,KAAA,CAAM,CAAA,EAAG,EAAA,EAAI,EAAA,EAAI,EAAE,CAAA;AACrE,IAAA,IAAI,SAAA,CAAU,OAAA,EAAQ,GAAI,SAAA,CAAU,SAAQ,EAAG;AAC7C,MAAA,SAAA,GAAY,SAAA;AAAA,IACd,WAAW,SAAA,CAAU,OAAA,KAAY,SAAA,CAAU,OAAA,KAAY,oBAAA,EAAsB;AAC3E,MAAA,MAAM,IAAA,GAAO,YAAA,CAAa,KAAA,EAAO,CAAC,CAAA;AAClC,MAAA,SAAA,GAAY,YAAA,CAAa,KAAK,CAAA,EAAG,IAAA,CAAK,IAAI,IAAA,CAAK,CAAA,EAAG,EAAA,EAAI,EAAA,EAAI,EAAE,CAAA;AAAA,IAC9D;AAAA,EAEF;AAEA,EAAA,IAAI,OAAO,YAAA,EAAc;AACvB,IAAA,KAAA,IAAS,KAAA,GAAQ,CAAA,EAAG,KAAA,GAAQ,CAAA,EAAG,KAAA,EAAA,EAAS;AACtC,MAAA,MAAM,KAAA,GAAQ,UAAA,CAAW,SAAA,EAAW,EAAE,CAAA;AACtC,MAAA,IAAI,KAAA,CAAM,OAAA,KAAY,KAAA,IAAS,KAAA,CAAM,YAAY,KAAA,EAAO;AACxD,MAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,OAAA,KAAY,KAAA,GAAQ,CAAA,GAAI,CAAA;AAC5C,MAAA,MAAM,KAAA,GAAQ,YAAA,CAAa,KAAA,EAAO,KAAK,CAAA;AAGvC,MAAA,SAAA,GAAY,YAAA,CAAa,KAAA,CAAM,CAAA,EAAG,KAAA,CAAM,EAAA,EAAI,KAAA,CAAM,CAAA,EAAG,KAAA,CAAM,EAAA,EAAI,KAAA,CAAM,EAAA,EAAI,EAAE,CAAA;AAAA,IAC7E;AAAA,EACF;AAEA,EAAA,OAAO,SAAA;AACT;AAEA,SAAS,YAAA,CAAa,QAAwB,eAAA,EAAkC;AAC9E,EAAA,MAAM,UAAA,GAAa;AAAA,IACjB,MAAA,CAAO,qBAAqB,eAAA,GAAkB,MAAA;AAAA,IAC9C,MAAA,CAAO,QAAA;AAAA,IACP;AAAA,GACF;AACA,EAAA,KAAA,MAAW,MAAM,UAAA,EAAY;AAC3B,IAAA,IAAI,EAAA,IAAM,eAAA,CAAgB,EAAE,CAAA,EAAG,OAAO,EAAA;AAAA,EACxC;AACA,EAAA,OAAO,KAAA;AACT;AAEA,IAAM,cAAA,uBAAqB,GAAA,EAAqB;AAEhD,SAAS,gBAAgB,EAAA,EAAqB;AAC5C,EAAA,MAAM,MAAA,GAAS,cAAA,CAAe,GAAA,CAAI,EAAE,CAAA;AACpC,EAAA,IAAI,MAAA,KAAW,QAAW,OAAO,MAAA;AACjC,EAAA,IAAI,EAAA,GAAK,IAAA;AACT,EAAA,IAAI;AACF,IAAA,IAAI,KAAK,cAAA,CAAe,OAAA,EAAS,EAAE,QAAA,EAAU,IAAI,CAAA;AAAA,EACnD,CAAA,CAAA,MAAQ;AACN,IAAA,EAAA,GAAK,KAAA;AAAA,EACP;AACA,EAAA,cAAA,CAAe,GAAA,CAAI,IAAI,EAAE,CAAA;AACzB,EAAA,OAAO,EAAA;AACT;AAYA,IAAM,cAAA,uBAAqB,GAAA,EAAiC;AAE5D,SAAS,aAAa,EAAA,EAAiC;AACrD,EAAA,IAAI,CAAA,GAAI,cAAA,CAAe,GAAA,CAAI,EAAE,CAAA;AAC7B,EAAA,IAAI,CAAC,CAAA,EAAG;AACN,IAAA,CAAA,GAAI,IAAI,IAAA,CAAK,cAAA,CAAe,OAAA,EAAS;AAAA,MACnC,QAAA,EAAU,EAAA;AAAA,MACV,IAAA,EAAM,SAAA;AAAA,MACN,KAAA,EAAO,SAAA;AAAA,MACP,GAAA,EAAK,SAAA;AAAA,MACL,IAAA,EAAM,SAAA;AAAA,MACN,MAAA,EAAQ,SAAA;AAAA,MACR,MAAA,EAAQ,SAAA;AAAA,MACR,OAAA,EAAS,OAAA;AAAA,MACT,MAAA,EAAQ;AAAA,KACT,CAAA;AACD,IAAA,cAAA,CAAe,GAAA,CAAI,IAAI,CAAC,CAAA;AAAA,EAC1B;AACA,EAAA,OAAO,CAAA;AACT;AAEA,SAAS,UAAA,CAAW,MAAY,EAAA,EAAwB;AACtD,EAAA,MAAM,QAAgC,EAAC;AACvC,EAAA,KAAA,MAAW,CAAA,IAAK,YAAA,CAAa,EAAE,CAAA,CAAE,aAAA,CAAc,IAAI,CAAA,EAAG,KAAA,CAAM,CAAA,CAAE,IAAI,CAAA,GAAI,CAAA,CAAE,KAAA;AACxE,EAAA,OAAO;AAAA,IACL,CAAA,EAAG,MAAA,CAAO,KAAA,CAAM,IAAI,CAAA;AAAA,IACpB,EAAA,EAAI,MAAA,CAAO,KAAA,CAAM,KAAK,CAAA;AAAA,IACtB,CAAA,EAAG,MAAA,CAAO,KAAA,CAAM,GAAG,CAAA;AAAA,IACnB,EAAA,EAAI,MAAA,CAAO,KAAA,CAAM,IAAI,CAAA,GAAI,EAAA;AAAA;AAAA,IACzB,EAAA,EAAI,MAAA,CAAO,KAAA,CAAM,MAAM,CAAA;AAAA,IACvB,EAAA,EAAI,MAAA,CAAO,KAAA,CAAM,MAAM,CAAA;AAAA,IACvB,SAAS,KAAA,CAAM;AAAA,GACjB;AACF;AAGA,SAAS,aAAa,CAAA,EAAW,EAAA,EAAY,CAAA,EAAW,EAAA,EAAY,IAAY,EAAA,EAAkB;AAChG,EAAA,IAAI,EAAA,GAAK,KAAK,GAAA,CAAI,CAAA,EAAG,KAAK,CAAA,EAAG,CAAA,EAAG,EAAA,EAAI,EAAA,EAAI,CAAC,CAAA;AACzC,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,CAAA,EAAG,CAAA,EAAA,EAAK;AAC1B,IAAA,MAAM,IAAI,UAAA,CAAW,IAAI,IAAA,CAAK,EAAE,GAAG,EAAE,CAAA;AACrC,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,CAAA,CAAE,GAAG,CAAA,CAAE,EAAA,GAAK,CAAA,EAAG,CAAA,CAAE,GAAG,CAAA,CAAE,EAAA,EAAI,CAAA,CAAE,EAAA,EAAI,EAAE,EAAE,CAAA;AAC3D,IAAA,MAAM,SAAS,KAAA,GAAQ,EAAA;AACvB,IAAA,EAAA,GAAK,IAAA,CAAK,IAAI,CAAA,EAAG,EAAA,GAAK,GAAG,CAAA,EAAG,EAAA,EAAI,EAAA,EAAI,CAAC,CAAA,GAAI,MAAA;AAAA,EAC3C;AACA,EAAA,OAAO,IAAI,KAAK,EAAE,CAAA;AACpB;AAGA,SAAS,YAAA,CAAa,GAAe,IAAA,EAAoD;AACvF,EAAA,MAAM,EAAA,GAAK,IAAI,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,CAAA,CAAE,CAAA,EAAG,CAAA,CAAE,EAAA,GAAK,CAAA,EAAG,CAAA,CAAE,CAAA,GAAI,IAAI,CAAC,CAAA;AACvD,EAAA,OAAO,EAAE,CAAA,EAAG,EAAA,CAAG,cAAA,EAAe,EAAG,EAAA,EAAI,EAAA,CAAG,WAAA,EAAY,GAAI,CAAA,EAAG,CAAA,EAAG,EAAA,CAAG,YAAW,EAAE;AAChF;AC/GA,eAAsB,gBAAgB,IAAA,EAAsC;AAC1E,EAAA,MAAM,GAAA,GAAM,MAAMC,0BAAA,CAAU,IAAA,EAAM,EAAE,eAAA,EAAiB,MAAA,EAAQ,MAAA,EAAQ,KAAA,EAAO,CAAA;AAC5E,EAAA,MAAM,SAAA,GAAY,eAAA,CAAgB,GAAA,CAAI,IAAI,CAAA;AAC1C,EAAA,OAAO,EAAE,MAAM,GAAA,CAAI,IAAA,EAAM,WAAW,MAAA,EAAQ,GAAA,CAAI,MAAA,IAAU,EAAC,EAAE;AAC/D;AAOA,eAAsB,qBAAqB,OAAA,EAA0C;AACnF,EAAA,MAAM,EAAE,MAAA,EAAO,GAAI,MAAM,OAAO,kBAAkB,CAAA;AAClD,EAAA,MAAM,IAAA,GAAO,MAAM,MAAA,CAAO,OAAc,CAAA;AACxC,EAAA,MAAM,SAAA,GAAY,gBAAgB,IAAI,CAAA;AACtC,EAAA,OAAO,EAAE,IAAA,EAAM,SAAA,EAAW,MAAA,EAAQ,EAAC,EAAE;AACvC;AAGO,SAAS,gBAAgB,IAAA,EAAsB;AACpD,EAAA,OAAOC,mBAAW,IAAA,EAAM;AAAA,IACtB,QAAA,EAAU,EAAA;AAAA,IACV,SAAA,EAAW;AAAA,MACT,EAAE,QAAA,EAAU,KAAA,EAAO,MAAA,EAAQ,MAAA,EAAO;AAAA,MAClC,EAAE,QAAA,EAAU,GAAA,EAAK,SAAS,EAAE,wBAAA,EAA0B,MAAK;AAAE;AAC/D,GACD,EAAE,IAAA,EAAK;AACV;AAmDA,IAAM,UAAA,GAA6B,EAAE,QAAA,EAAU,IAAA,EAAK;AAOpD,eAAsB,cAAA,CACpB,QAAA,EACA,GAAA,EACA,IAAA,GAAsB,EAAC,EACI;AAC3B,EAAA,MAAM,EAAA,GAAK,cAAA,CAAe,IAAA,CAAK,OAAO,CAAA;AAItC,EAAA,MAAM,UAAU,EAAA,CAAG,OAAA,CAAQ,QAAA,CAAS,OAAO,EAAE,GAAG,CAAA;AAChD,EAAA,MAAM,YAAY,EAAA,CAAG,OAAA,CAAQ,QAAA,CAAS,SAAS,EAAE,GAAG,CAAA;AAGpD,EAAA,IAAI,IAAA;AACJ,EAAA,IAAI,QAAA,CAAS,KAAK,IAAA,EAAM;AACtB,IAAA,IAAA,GAAO,GAAG,OAAA,CAAQ,QAAA,CAAS,IAAA,CAAK,IAAI,EAAE,GAAG,CAAA;AAAA,EAC3C,CAAA,MAAO;AACL,IAAA,MAAM,QAAA,GAAW,MAAM,eAAA,CAAgB,QAAA,CAAS,KAAK,IAAI,CAAA;AACzD,IAAA,IAAA,GAAO,EAAA,CAAG,OAAA,CAAQ,QAAA,CAAS,IAAI,EAAE,GAAG,CAAA;AAAA,EACtC;AAEA,EAAA,MAAM,SAAA,GAAY,QAAA,CAAS,IAAA,CAAK,SAAA,GAC5B,GAAG,OAAA,CAAQ,QAAA,CAAS,IAAA,CAAK,SAAA,EAAW,UAAU,CAAA,CAAE,GAAG,CAAA,GACnD,gBAAgB,IAAI,CAAA;AAExB,EAAA,OAAO;AAAA,IACL,OAAA;AAAA,IACA,SAAA;AAAA,IACA,IAAA;AAAA,IACA,SAAA;AAAA,IACA,UAAU,QAAA,CAAS,QAAA;AAAA,IACnB,WAAW,QAAA,CAAS,SAAA;AAAA,IACpB,SAAS,QAAA,CAAS;AAAA,GACpB;AACF;AA0CO,SAAS,aAAA,CAAc,MAAc,IAAA,EAAuC;AACjF,EAAA,MAAM,QAAA,GAAW,IAAI,GAAA,CAAA,CAAK,IAAA,CAAK,YAAA,IAAgB,EAAC,EAAG,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,EAAM,CAAC,CAAA;AACvE,EAAA,MAAM,QAAgD,EAAC;AACvD,EAAA,MAAM,IAAA,uBAAW,GAAA,EAAoB;AAErC,EAAA,IAAI,GAAA,GAAM,IAAA;AAEV,EAAA,IAAI,KAAK,WAAA,EAAa;AACpB,IAAA,GAAA,GAAM,GAAA,CAAI,QAAQ,+CAAA,EAAiD,CAAC,MAAM,GAAA,EAAK,EAAA,EAAI,QAAQ,IAAA,KAAS;AAGlG,MAAA,MAAM,GAAA,GAAM,mBAAmB,MAAM,CAAA;AACrC,MAAA,IAAI,sBAAA,CAAuB,GAAA,EAAK,QAAA,EAAU,IAAI,GAAG,OAAO,IAAA;AACxD,MAAA,IAAI,MAAA,GAAS,IAAA,CAAK,GAAA,CAAI,GAAG,CAAA;AACzB,MAAA,IAAI,CAAC,MAAA,EAAQ;AACX,QAAA,MAAA,GAAS,SAAA,CAAU,GAAG,IAAA,CAAK,MAAM,IAAI,GAAG,CAAA,CAAA,EAAI,KAAA,CAAM,MAAM,CAAA,CAAE,CAAA;AAC1D,QAAA,IAAA,CAAK,GAAA,CAAI,KAAK,MAAM,CAAA;AACpB,QAAA,KAAA,CAAM,IAAA,CAAK,EAAE,MAAA,EAAQ,GAAA,EAAK,CAAA;AAAA,MAC5B;AACA,MAAA,MAAM,GAAA,GAAM,IAAA,CAAK,aAAA,GACb,CAAA,CAAA,EAAI,kBAAkB,OAAA,EAAS,EAAE,MAAA,EAAQ,IAAA,CAAK,QAAQ,MAAA,EAAO,EAAG,IAAA,CAAK,aAAa,CAAC,CAAA,CAAA,GACnF,EAAA;AACJ,MAAA,MAAM,OAAA,GAAU,CAAA,EAAG,IAAA,CAAK,SAAS,CAAA,SAAA,EAAY,KAAK,MAAM,CAAA,CAAA,EAAI,MAAM,CAAA,EAAG,GAAG,CAAA,CAAA;AACxE,MAAA,OAAO,CAAA,EAAA,EAAK,GAAG,CAAA,MAAA,EAAS,OAAO,IAAI,IAAI,CAAA,CAAA,CAAA;AAAA,IACzC,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,IAAI,KAAK,UAAA,EAAY;AACnB,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,aAAA,GACb,CAAA,CAAA,EAAI,kBAAkB,MAAA,EAAQ,EAAE,MAAA,EAAQ,IAAA,CAAK,MAAA,EAAO,EAAG,IAAA,CAAK,aAAa,CAAC,CAAA,CAAA,GAC1E,EAAA;AACJ,IAAA,MAAM,KAAA,GAAQ,aAAa,IAAA,CAAK,SAAS,WAAW,IAAA,CAAK,MAAM,GAAG,GAAG,CAAA,mEAAA,CAAA;AACrE,IAAA,IAAI,WAAA,CAAY,IAAA,CAAK,GAAG,CAAA,EAAG;AACzB,MAAA,GAAA,GAAM,GAAA,CAAI,OAAA,CAAQ,WAAA,EAAa,CAAA,EAAG,KAAK,CAAA,OAAA,CAAS,CAAA;AAAA,IAClD,CAAA,MAAO;AACL,MAAA,GAAA,GAAM,GAAA,GAAM,KAAA;AAAA,IACd;AAAA,EACF;AAEA,EAAA,OAAO,EAAE,IAAA,EAAM,GAAA,EAAK,KAAA,EAAM;AAC5B;AAEA,SAAS,sBAAA,CAAuB,GAAA,EAAa,QAAA,EAAuB,OAAA,EAA0B;AAC5F,EAAA,IAAI,CAAC,KAAK,OAAO,IAAA;AACjB,EAAA,IAAI,GAAA,CAAI,UAAA,CAAW,GAAG,CAAA,EAAG,OAAO,IAAA;AAChC,EAAA,IAAI,GAAA,CAAI,WAAW,IAAI,CAAA,IAAK,IAAI,UAAA,CAAW,GAAG,GAAG,OAAO,IAAA;AACxD,EAAA,IAAI,SAAS,GAAA,CAAI,GAAA,CAAI,IAAA,EAAM,GAAG,OAAO,IAAA;AACrC,EAAA,IAAI,kCAAA,CAAmC,IAAA,CAAK,OAAO,CAAA,EAAG,OAAO,IAAA;AAU7D,EAAA,IAAI,CAAC,SAAA,CAAU,GAAG,CAAA,EAAG,OAAO,IAAA;AAC5B,EAAA,OAAO,KAAA;AACT;AAGA,SAAS,UAAU,GAAA,EAAsB;AACvC,EAAA,IAAI,MAAA;AACJ,EAAA,IAAI;AACF,IAAA,MAAA,GAAS,IAAI,GAAA,CAAI,GAAA,CAAI,IAAA,EAAM,CAAA;AAAA,EAC7B,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,KAAA;AAAA,EACT;AACA,EAAA,OAAO,MAAA,CAAO,QAAA,KAAa,OAAA,IAAW,MAAA,CAAO,QAAA,KAAa,QAAA;AAC5D;AAEA,IAAM,cAAA,GAAyC;AAAA,EAC7C,GAAA,EAAK,GAAA;AAAA,EACL,EAAA,EAAI,GAAA;AAAA,EACJ,EAAA,EAAI,GAAA;AAAA,EACJ,IAAA,EAAM,GAAA;AAAA,EACN,IAAA,EAAM,GAAA;AAAA,EACN,IAAA,EAAM;AACR,CAAA;AAOA,SAAS,mBAAmB,KAAA,EAAuB;AACjD,EAAA,OAAO,KAAA,CAAM,OAAA,CAAQ,uCAAA,EAAyC,CAAC,OAAO,IAAA,KAAiB;AACrF,IAAA,IAAI,IAAA,CAAK,CAAC,CAAA,KAAM,GAAA,EAAK;AACnB,MAAA,MAAM,IAAA,GACJ,KAAK,CAAC,CAAA,KAAM,OAAO,IAAA,CAAK,CAAC,MAAM,GAAA,GAC3B,QAAA,CAAS,KAAK,KAAA,CAAM,CAAC,GAAG,EAAE,CAAA,GAC1B,SAAS,IAAA,CAAK,KAAA,CAAM,CAAC,CAAA,EAAG,EAAE,CAAA;AAChC,MAAA,IAAI,CAAC,OAAO,QAAA,CAAS,IAAI,KAAK,IAAA,GAAO,CAAA,IAAK,IAAA,GAAO,OAAA,EAAU,OAAO,KAAA;AAClE,MAAA,IAAI;AACF,QAAA,OAAO,MAAA,CAAO,cAAc,IAAI,CAAA;AAAA,MAClC,CAAA,CAAA,MAAQ;AACN,QAAA,OAAO,KAAA;AAAA,MACT;AAAA,IACF;AACA,IAAA,MAAM,KAAA,GAAQ,cAAA,CAAe,IAAA,CAAK,WAAA,EAAa,CAAA;AAC/C,IAAA,OAAO,KAAA,IAAS,KAAA;AAAA,EAClB,CAAC,CAAA;AACH;AAEA,SAAS,UAAU,KAAA,EAAuB;AACxC,EAAA,OAAOL,wBAAAA,CAAO,UAAA,CAAW,QAAQ,CAAA,CAAE,MAAA,CAAO,KAAK,CAAA,CAAE,MAAA,CAAO,KAAK,CAAA,CAAE,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA;AAC5E;AAMA,SAAS,eAAe,KAAA,EAAsE;AAC5F,EAAA,MAAM,EAAA,GAAKM,4BAAW,MAAA,EAAO;AAE7B,EAAA,EAAA,CAAG,eAAe,IAAA,EAAM,CAAC,CAAA,EAAY,CAAA,KAAe,MAAM,CAAC,CAAA;AAC3D,EAAA,EAAA,CAAG,eAAe,IAAA,EAAM,CAAC,CAAA,EAAY,CAAA,KAAe,MAAM,CAAC,CAAA;AAC3D,EAAA,EAAA,CAAG,eAAe,IAAA,EAAM,CAAC,CAAA,EAAQ,CAAA,KAAW,IAAI,CAAC,CAAA;AACjD,EAAA,EAAA,CAAG,eAAe,IAAA,EAAM,CAAC,CAAA,EAAQ,CAAA,KAAW,IAAI,CAAC,CAAA;AACjD,EAAA,EAAA,CAAG,eAAe,KAAA,EAAO,CAAC,CAAA,EAAQ,CAAA,KAAW,KAAK,CAAC,CAAA;AACnD,EAAA,EAAA,CAAG,eAAe,KAAA,EAAO,CAAC,CAAA,EAAQ,CAAA,KAAW,KAAK,CAAC,CAAA;AACnD,EAAA,EAAA,CAAG,cAAA,CAAe,KAAA,EAAO,CAAA,GAAI,IAAA,KAAgB,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA,CAAE,KAAA,CAAM,OAAO,CAAC,CAAA;AAC7E,EAAA,EAAA,CAAG,cAAA,CAAe,IAAA,EAAM,CAAA,GAAI,IAAA,KAAgB,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA,CAAE,IAAA,CAAK,OAAO,CAAC,CAAA;AAC3E,EAAA,EAAA,CAAG,cAAA,CAAe,KAAA,EAAO,CAAC,CAAA,KAAe,CAAC,CAAC,CAAA;AAE3C,EAAA,EAAA,CAAG,cAAA,CAAe,YAAA,EAAc,CAAC,KAAA,EAAgB,GAAA,KAAiB;AAChE,IAAA,IAAI,CAAC,OAAO,OAAO,EAAA;AACnB,IAAA,MAAM,CAAA,GAAI,iBAAiB,IAAA,GAAO,KAAA,GAAQ,IAAI,IAAA,CAAK,MAAA,CAAO,KAAK,CAAC,CAAA;AAChE,IAAA,IAAI,OAAO,KAAA,CAAM,CAAA,CAAE,OAAA,EAAS,GAAG,OAAO,EAAA;AACtC,IAAA,IAAI,GAAA,KAAQ,QAAQ,OAAO,CAAA,CAAE,mBAAmB,OAAA,EAAS,EAAE,SAAA,EAAW,MAAA,EAAQ,CAAA;AAC9E,IAAA,IAAI,GAAA,KAAQ,SAAS,OAAO,CAAA,CAAE,mBAAmB,OAAA,EAAS,EAAE,SAAA,EAAW,OAAA,EAAS,CAAA;AAChF,IAAA,OAAO,CAAA,CAAE,WAAA,EAAY,CAAE,KAAA,CAAM,GAAG,EAAE,CAAA;AAAA,EACpC,CAAC,CAAA;AAED,EAAA,EAAA,CAAG,cAAA,CAAe,cAAA,EAAgB,CAAC,CAAA,KAAe;AAChD,IAAA,MAAM,CAAA,GAAI,OAAO,CAAC,CAAA;AAClB,IAAA,OAAO,OAAO,QAAA,CAAS,CAAC,IAAI,CAAA,CAAE,cAAA,CAAe,OAAO,CAAA,GAAI,EAAA;AAAA,EAC1D,CAAC,CAAA;AAED,EAAA,EAAA,CAAG,cAAA,CAAe,gBAAA,EAAkB,CAAC,KAAA,EAAgB,WAAmB,KAAA,KAAU;AAChF,IAAA,MAAM,CAAA,GAAI,OAAO,KAAK,CAAA;AACtB,IAAA,IAAI,CAAC,MAAA,CAAO,QAAA,CAAS,CAAC,GAAG,OAAO,EAAA;AAChC,IAAA,OAAO,IAAI,IAAA,CAAK,YAAA,CAAa,OAAA,EAAS,EAAE,KAAA,EAAO,UAAA,EAAY,QAAA,EAAU,CAAA,CAAE,MAAA,CAAO,CAAA,GAAI,GAAG,CAAA;AAAA,EACvF,CAAC,CAAA;AAED,EAAA,EAAA,CAAG,cAAA;AAAA,IAAe,WAAA;AAAA,IAAa,CAAC,GAAY,GAAA,EAAa,IAAA,KACvD,OAAO,CAAC,CAAA,KAAM,IAAI,GAAA,GAAM;AAAA,GAC1B;AAEA,EAAA,IAAI,KAAA,EAAO;AACT,IAAA,KAAA,MAAW,CAAC,IAAA,EAAM,EAAE,KAAK,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA,EAAG;AAC9C,MAAA,EAAA,CAAG,cAAA,CAAe,MAAM,EAAE,CAAA;AAAA,IAC5B;AAAA,EACF;AAEA,EAAA,OAAO,EAAA;AACT;;;AC5UA,SAAA,EAAA;;;ACHA,IAAM,cAAA,GAA2D;AAAA,EAC/D,SAAA,EAAW,CAAC,KAAA,EAAO,WAAW,CAAA;AAAA,EAC9B,aAAA,EAAe,CAAC,KAAA,EAAO,eAAe;AACxC,CAAA;AAEA,eAAsB,YAAA,CACpB,WAAA,EACA,KAAA,EACA,IAAA,EAC4B;AAC5B,EAAA,MAAM,UAAA,GAAa,MAAM,WAAA,EAAY;AACrC,EAAA,MAAM,OAAA,GAAU,eAAe,IAAI,CAAA;AAEnC,EAAA,MAAM,OAAA,GAAU,MAAM,WAAA,CAAY,YAAA,CAAa,OAAA,CAAQ;AAAA,IACrD,KAAA,EAAO,UAAA;AAAA,IACP,KAAA,EAAO,EAAE,GAAA,EAAK,OAAA,EAAQ;AAAA,IACtB,GAAA,EAAK,CAAC,EAAE,SAAA,EAAW,MAAK,EAAG,EAAE,SAAA,EAAW,EAAE,GAAA,kBAAK,IAAI,IAAA,EAAK,IAAK;AAAA,GAC9D,CAAA;AACD,EAAA,IAAI,OAAA,EAAS,OAAO,EAAE,UAAA,EAAY,IAAA,EAAM,OAAO,OAAA,CAAQ,KAAA,EAAO,MAAA,EAAQ,OAAA,CAAQ,MAAA,EAAO;AAErF,EAAA,MAAM,MAAA,GAAS,MAAM,WAAA,CAAY,YAAA,CAAa,OAAA,CAAQ;AAAA,IACpD,SAAA,EAAW,UAAU,UAAU,CAAA;AAAA,IAC/B,KAAA,EAAO,EAAE,GAAA,EAAK,OAAA;AAAQ,GACvB,CAAA;AACD,EAAA,IAAI,MAAA,EAAQ,OAAO,EAAE,UAAA,EAAY,IAAA,EAAM,OAAO,MAAA,CAAO,KAAA,EAAO,MAAA,EAAQ,MAAA,CAAO,MAAA,EAAO;AAElF,EAAA,OAAO,EAAE,YAAY,KAAA,EAAM;AAC7B;;;ADlBA,eAAsB,UAAA,CACpB,GAAA,EACA,IAAA,EACA,OAAA,EACA,MACA,GAAA,EACe;AACf,EAAA,MAAM,QAAA,GAAW,MAAM,GAAA,CAAI,WAAA,CAAY,SAAA,CAAU,QAAQ,EAAE,IAAA,EAAM,IAAA,CAAK,YAAA,EAAc,CAAA;AACpF,EAAA,IAAI,CAAC,QAAA,EAAU;AACb,IAAA,MAAM,YAAY,GAAA,EAAK,CAAA,oBAAA,EAAuB,IAAA,CAAK,YAAY,IAAI,GAAG,CAAA;AACtE,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,YAAY,CAAA,QAAA,EAAW,GAAA,CAAI,GAAG,CAAA,KAAA,EAAQ,IAAI,gBAAgB,CAAA,CAAA;AAGhE,EAAA,MAAM,QAAA,GAAW,MAAM,GAAA,CAAI,WAAA,CAAY,MAAM,OAAA,CAAQ,EAAE,WAAW,CAAA;AAClE,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,MAAM,WAAA,CAAY,KAAK,GAAA,EAAK;AAAA,MAC1B,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS,EAAE,SAAA,EAAW,WAAA,EAAa,MAAM,MAAA,EAAQ,MAAA,CAAO,QAAA,CAAS,GAAG,CAAA;AAAE,KACvE,CAAA;AACD,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,YAAA,GAAe,gBAAA,CAAiB,IAAA,CAAK,gBAAA,EAAkB,UAAU,GAAG,CAAA;AAI1E,EAAA,MAAM,SAAA,GAAY,mBAAmB,OAAA,EAAS,GAAA,EAAK,KAAK,IAAA,IAAQ,IAAI,GAAG,CAAA;AACvE,EAAA,IAAI,QAAA;AACJ,EAAA,IAAI;AACF,IAAA,QAAA,GAAW,MAAM,eAAe,QAAA,EAAU,SAAA,EAAW,EAAE,OAAA,EAAS,GAAA,CAAI,mBAAmB,CAAA;AAAA,EACzF,SAAS,GAAA,EAAU;AACjB,IAAA,MAAM,GAAA,CAAI,YAAY,KAAA,CAAM,SAAA;AAAA,MAC1B,UAAA,CAAW;AAAA,QACT,SAAA;AAAA,QACA,GAAA;AAAA,QACA,OAAA;AAAA,QACA,QAAA;AAAA,QAEA,YAAA;AAAA,QACA,iBAAiB,QAAA,CAAS,OAAA;AAAA,QAC1B,QAAA,EAAU,EAAA;AAAA,QACV,MAAA,EAAQ,QAAA;AAAA,QACR,YAAA,EAAc,CAAA,cAAA,EAAiB,GAAA,EAAK,OAAA,IAAW,GAAG,CAAA;AAAA,OACnD;AAAA,KACH;AACA,IAAA,MAAM,WAAA,CAAY,KAAK,GAAA,EAAK;AAAA,MAC1B,MAAA,EAAQ,cAAA;AAAA,MACR,OAAA,EAAS,EAAE,MAAA,EAAQ,cAAA,EAAgB,SAAS,MAAA,CAAO,GAAA,EAAK,OAAA,IAAW,GAAG,CAAA;AAAE,KACzE,CAAA;AACD,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,MAAA,GAAS,IAAIT,gBAAA,EAAS;AAC5B,EAAA,MAAM,GAAA,CAAI,YAAY,KAAA,CAAM,SAAA;AAAA,IAC1B,UAAA,CAAW;AAAA,MACT,GAAA,EAAK,MAAA;AAAA,MACL,SAAA;AAAA,MACA,GAAA;AAAA,MACA,OAAA;AAAA,MACA,QAAA;AAAA,MAEA,YAAA;AAAA,MACA,iBAAiB,QAAA,CAAS,OAAA;AAAA,MAC1B,QAAA,EAAU,MAAA,CAAO,QAAA,CAAS,IAAI,CAAA;AAAA,MAC9B,MAAA,EAAQ,QAAA;AAAA,MACR,YAAA,EAAc,QAAA,CAAS,QAAA,GAAW,EAAE,IAAA,EAAM,SAAS,QAAA,EAAU,KAAA,EAAO,QAAA,CAAS,SAAA,EAAU,GAAI,MAAA;AAAA,MAC3F,IAAA,EAAM,IAAA,CAAK,IAAA,IAAQ;AAAC,KACrB;AAAA,GACH;AAEA,EAAA,MAAM,GAAA,CAAI,OAAO,IAAA,CAAK,GAAA;AAAA,IACpB,MAAA;AAAA,IACA,EAAE,MAAA,EAAQ,MAAA,CAAO,MAAM,CAAA,EAAE;AAAA,IACzB,EAAE,QAAA,EAAU,GAAA,CAAI,MAAA,CAAO,iBAAA,EAAmB,OAAA,EAAS,EAAE,IAAA,EAAM,aAAA,EAAe,KAAA,EAAO,GAAA,EAAO;AAAE,GAC5F;AAEA,EAAA,MAAM,WAAA,CAAY,GAAA,EAAK,GAAA,EAAK,EAAE,QAAQ,MAAA,EAAQ,OAAA,EAAS,EAAE,SAAA,EAAW,MAAA,EAAQ,MAAA,CAAO,MAAM,CAAA,IAAK,CAAA;AAChG;AAMA,eAAsB,YAAA,CAAa,QAAkB,GAAA,EAAmC;AAOtF,EAAA,MAAM,IAAA,GAAO,MAAM,GAAA,CAAI,WAAA,CAAY,KAAA,CAAM,gBAAA;AAAA,IACvC,EAAE,GAAA,EAAK,MAAA,EAAQ,MAAA,EAAQ,EAAE,KAAK,CAAC,QAAA,EAAU,QAAQ,CAAA,EAAE,EAAE;AAAA,IACrD,EAAE,MAAM,EAAE,MAAA,EAAQ,WAAW,SAAA,kBAAW,IAAI,IAAA,EAAK,EAAE;AAAE,GACvD;AACA,EAAA,IAAI,CAAC,IAAA,EAAM;AAEX,EAAA,MAAM,QAAA,GAAW,MAAM,GAAA,CAAI,WAAA,CAAY,SAAA,CAAU,QAAQ,EAAE,GAAA,EAAK,IAAA,CAAK,UAAA,EAAY,CAAA;AACjF,EAAA,IAAI,CAAC,QAAA,EAAU;AACb,IAAA,MAAM,UAAA,CAAW,IAAA,CAAK,GAAA,EAAM,kBAAA,EAAoB,GAAG,CAAA;AACnD,IAAA;AAAA,EACF;AAGA,EAAA,MAAM,IAAA,GAAO,MAAM,YAAA,CAAa,GAAA,CAAI,aAAa,IAAA,CAAK,WAAA,EAAa,KAAK,IAAI,CAAA;AAC5E,EAAA,IAAI,KAAK,UAAA,EAAY;AACnB,IAAA,MAAM,GAAA,CAAI,YAAY,KAAA,CAAM,SAAA;AAAA,MAC1B,EAAE,GAAA,EAAK,IAAA,CAAK,GAAA,EAAI;AAAA,MAChB,EAAE,IAAA,EAAM,EAAE,MAAA,EAAQ,YAAA,EAAc,cAAc,CAAA,YAAA,EAAe,IAAA,CAAK,MAAM,CAAA,CAAA,EAAG;AAAE,KAC/E;AACA,IAAA;AAAA,EACF;AAKA,EAAA,IAAI,IAAA,CAAK,SAAS,WAAA,EAAa;AAC7B,IAAA,MAAM,SAAS,MAAM,eAAA,CAAgB,KAAK,IAAA,CAAK,SAAA,EAAW,KAAK,IAAI,CAAA;AACnE,IAAA,IAAI,MAAA,EAAQ,WAAW,SAAA,EAAW;AAEhC,MAAA,MAAM,GAAA,CAAI,YAAY,KAAA,CAAM,SAAA;AAAA,QAC1B,EAAE,GAAA,EAAK,IAAA,CAAK,GAAA,EAAI;AAAA,QAChB,EAAE,MAAM,EAAE,MAAA,EAAQ,UAAU,SAAA,kBAAW,IAAI,IAAA,EAAK,EAAE;AAAE,OACtD;AACA,MAAA,MAAM,GAAA,CAAI,MAAA,CAAO,IAAA,CAAK,GAAA,CAAI,QAAQ,EAAE,MAAA,EAAQ,MAAA,CAAO,IAAA,CAAK,GAAG,CAAA,EAAE,EAAG,EAAE,KAAA,EAAO,KAAQ,CAAA;AACjF,MAAA;AAAA,IACF;AAAA,EACF;AAGA,EAAA,MAAM,UAAU,MAAM,GAAA,CAAI,OAAA,CAAQ,OAAA,CAAQ,KAAK,UAAU,CAAA;AACzD,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,MAAM,UAAA,CAAW,IAAA,CAAK,GAAA,EAAM,iBAAA,EAAmB,GAAG,CAAA;AAClD,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,SAAA,GAAY,MAAM,GAAA,CAAI,WAAA,CAAY,QAAA,CAAS,OAAA,CAAQ,EAAE,GAAA,EAAK,IAAA,CAAK,SAAA,EAAW,CAAA,GAAI,IAAA;AAK/F,EAAA,IAAI,GAAA,IAAO,IAAI,MAAA,KAAW,QAAA,IAAY,IAAI,UAAA,EAAY,UAAA,CAAW,iBAAiB,CAAA,EAAG;AACnF,IAAA,MAAM,GAAA,CAAI,YAAY,KAAA,CAAM,SAAA;AAAA,MAC1B,EAAE,GAAA,EAAK,IAAA,CAAK,GAAA,EAAI;AAAA,MAChB,EAAE,IAAA,EAAM,EAAE,MAAA,EAAQ,aAAa,YAAA,EAAc,CAAA,WAAA,EAAc,GAAA,CAAI,UAAU,CAAA,CAAA,EAAI,SAAA,kBAAW,IAAI,IAAA,IAAO;AAAE,KACvG;AACA,IAAA;AAAA,EACF;AAKA,EAAA,IAAI,SAAA;AACJ,EAAA,IAAI,QAAA;AACJ,EAAA,IAAI;AACF,IAAA,MAAM,QAAA,GAAW,MAAM,WAAA,CAAY,GAAA,CAAI,aAAa,OAAA,EAAS;AAAA,MAC3D,MAAA,EAAQ,MAAA;AAAA,MACR,cAAc,QAAA,CAAS,IAAA;AAAA,MACvB,UAAU,GAAA,EAAK,QAAA;AAAA,MACf,SAAA,EAAW,KAAK,YAAA,EAAc,IAAA;AAAA,MAC9B,eAAA,EAAiB,KAAK,YAAA,EAAc;AAAA,KACrC,CAAA;AACD,IAAA,SAAA,GAAY,kBAAA,CAAmB,SAAS,GAAA,EAAK,IAAA,CAAK,QAAQ,EAAC,EAAG,KAAK,QAAQ,CAAA;AAC3E,IAAA,QAAA,GAAW,MAAM,eAAe,QAAA,EAAU,SAAA,EAAW,EAAE,OAAA,EAAS,GAAA,CAAI,mBAAmB,CAAA;AAAA,EACzF,SAAS,GAAA,EAAU;AACjB,IAAA,MAAM,UAAA,CAAW,IAAA,CAAK,GAAA,EAAM,CAAA,cAAA,EAAiB,MAAA,CAAO,KAAK,OAAA,IAAW,GAAG,CAAC,CAAA,CAAA,EAAI,GAAG,CAAA;AAC/E,IAAA,MAAM,GAAA;AAAA,EACR;AAQA,EAAA,MAAM,QAAA,GAAW,SAAS,UAAA,KAAe,WAAA;AACzC,EAAA,MAAM,QAAA,GAAW,QAAA,GACb,EAAE,IAAA,EAAM,EAAA,EAAI,KAAA,EAAO,EAAC,EAA4C,GAChE,aAAA,CAAc,QAAA,CAAS,IAAA,EAAM;AAAA,IAC3B,MAAA,EAAQ,MAAA,CAAO,IAAA,CAAK,GAAG,CAAA;AAAA,IACvB,SAAA,EAAW,IAAI,MAAA,CAAO,SAAA;AAAA,IACtB,UAAA,EAAY,QAAA,CAAS,UAAA,IAAc,GAAA,CAAI,MAAA,CAAO,UAAA;AAAA,IAC9C,WAAA,EAAa,QAAA,CAAS,WAAA,IAAe,GAAA,CAAI,MAAA,CAAO,WAAA;AAAA,IAChD,YAAA,EAAc,CAAC,SAAA,CAAU,cAAc,CAAA;AAAA,IACvC,aAAA,EAAe,IAAI,MAAA,CAAO;AAAA,GAC3B,CAAA;AAEL,EAAA,MAAM,GAAA,CAAI,YAAY,KAAA,CAAM,SAAA;AAAA,IAC1B,EAAE,GAAA,EAAK,IAAA,CAAK,GAAA,EAAI;AAAA,IAChB;AAAA,MACE,IAAA,EAAM;AAAA,QACJ,OAAO,QAAA,CAAS,KAAA;AAAA;AAAA;AAAA,QAGhB,UAAU,MAAA,CAAO,QAAA,GAAW,QAAA,CAAS,SAAA,GAAY,SAAS,IAAI,CAAA;AAAA,QAC9D,MAAA,EAAQ,SAAA;AAAA,QACR,UAAU,QAAA,CAAS,QAAA;AAAA,QACnB,WAAW,QAAA,CAAS,SAAA;AAAA,QACpB,SAAS,QAAA,CAAS,OAAA;AAAA,QAClB,SAAA,sBAAe,IAAA;AAAK;AACtB;AACF,GACF;AAoBA,EAAA,MAAM,QAAA,GAAW,eAAA,CAAgB,GAAA,CAAI,SAAA,EAAW,KAAK,QAAQ,CAAA;AAC7D,EAAA,IAAI,CAAC,QAAA,EAAU;AACb,IAAA,MAAM,KAAA,GAAQ,uBAAA,CAAwB,GAAA,CAAI,SAAS,CAAA;AACnD,IAAA,MAAM,UAAA;AAAA,MACJ,IAAA,CAAK,GAAA;AAAA,MACL,CAAA,gDAAA,EAAmD,IAAA,CAAK,QAAQ,CAAA,yBAAA,EACrC,KAAA,CAAM,SAAS,KAAA,CAAM,IAAA,CAAK,IAAI,CAAA,GAAI,QAAQ,CAAA,CAAA,CAAA;AAAA,MACrE;AAAA,KACF;AACA,IAAA;AAAA,EACF;AAMA,EAAA,MAAM,OAAA,GACJ,IAAA,CAAK,IAAA,KAAS,WAAA,GACV;AAAA,IACE,kBAAA,EAAoB,CAAA,CAAA,EAAI,SAAA,CAAU,cAAc,CAAA,CAAA,CAAA;AAAA,IAChD,uBAAA,EAAyB;AAAA,MAE3B,EAAC;AAEP,EAAA,IAAI;AACF,IAAA,MAAM,MAAA,GAAS,MAAM,QAAA,CAAS,IAAA,CAAK;AAAA,MACjC,IAAI,IAAA,CAAK,WAAA;AAAA,MACT,UAAU,QAAA,CAAS,QAAA;AAAA,MACnB,WAAW,QAAA,CAAS,SAAA;AAAA,MACpB,OAAA,EAAS,SAAS,OAAA,IAAW,KAAA,CAAA;AAAA,MAC7B,SAAS,QAAA,CAAS,OAAA;AAAA,MAClB,GAAI,QAAA,GAAW,KAAK,EAAE,IAAA,EAAM,SAAS,IAAA,EAAK;AAAA,MAC1C,MAAM,QAAA,CAAS,SAAA;AAAA,MACf,OAAA;AAAA,MACA,aAAa,EAAE,MAAA,EAAQ,MAAA,CAAO,IAAA,CAAK,GAAG,CAAA;AAAE,KACzC,CAAA;AAED,IAAA,MAAM,GAAA,CAAI,YAAY,KAAA,CAAM,SAAA;AAAA,MAC1B,EAAE,GAAA,EAAK,IAAA,CAAK,GAAA,EAAI;AAAA,MAChB;AAAA,QACE,IAAA,EAAM;AAAA,UACJ,MAAA,EAAQ,MAAA;AAAA,UACR,MAAA,sBAAY,IAAA,EAAK;AAAA,UACjB,mBAAmB,MAAA,CAAO;AAAA;AAC5B;AACF,KACF;AAIA,IAAA,MAAM,mBAAA,CAAoB,GAAA,EAAK,MAAA,EAAQ,EAAE,SAAA,EAAW,KAAK,SAAA,EAAW,IAAA,EAAM,IAAA,CAAK,IAAA,EAAM,CAAA;AAAA,EACvF,SAAS,GAAA,EAAU;AACjB,IAAA,MAAM,GAAA,CAAI,YAAY,KAAA,CAAM,SAAA;AAAA,MAC1B,EAAE,GAAA,EAAK,IAAA,CAAK,GAAA,EAAI;AAAA,MAChB,EAAE,IAAA,EAAM,EAAE,MAAA,EAAQ,QAAA,EAAU,YAAA,EAAc,MAAA,CAAO,GAAA,EAAK,OAAA,IAAW,GAAG,CAAA,EAAE;AAAE,KAC1E;AACA,IAAA,MAAM,mBAAA,CAAoB,GAAA,EAAK,cAAA,EAAgB,EAAE,SAAA,EAAW,KAAK,SAAA,EAAW,IAAA,EAAM,IAAA,CAAK,IAAA,EAAM,CAAA;AAC7F,IAAA,IAAI,GAAA,CAAI,OAAO,aAAA,EAAe;AAC5B,MAAA,IAAI;AACF,QAAA,MAAM,IAAI,MAAA,CAAO,aAAA,CAAc,EAAE,IAAA,EAAM,KAAA,EAAO,KAAK,CAAA;AAAA,MACrD,CAAA,CAAA,MAAQ;AAAA,MAER;AAAA,IACF;AACA,IAAA,MAAM,GAAA;AAAA,EACR;AACF;AAMA,SAAS,gBAAA,CAAiB,YAAA,EAAkC,GAAA,EAAkB,GAAA,EAA4B;AACxG,EAAA,IAAI,cAAc,OAAO,YAAA;AACzB,EAAA,IAAI,GAAA,CAAI,gBAAA,EAAkB,OAAO,GAAA,CAAI,gBAAA;AACrC,EAAA,IAAI,GAAA,CAAI,IAAA,KAAS,eAAA,IAAmB,GAAA,CAAI,OAAO,4BAAA,EAA8B;AAC3E,IAAA,OAAO,IAAI,MAAA,CAAO,4BAAA;AAAA,EACpB;AACA,EAAA,OAAO,IAAI,MAAA,CAAO,eAAA;AACpB;AAEA,SAAS,mBACP,OAAA,EACA,GAAA,EACA,MACA,GAAA,EACA,QAAA,GAAoC,EAAC,EACtB;AACf,EAAA,MAAM,KAAA,GAAQ,WAAA;AACd,EAAA,MAAM,SAAA,GAAY,IAAI,IAAA,CAAK,IAAA,CAAK,GAAA,EAAI,GAAI,GAAA,CAAI,MAAA,CAAO,4BAAA,GAA+B,EAAA,GAAK,EAAA,GAAK,EAAA,GAAK,GAAI,CAAA;AACrG,EAAA,MAAM,KAAA,GAAQ,oBAAA;AAAA,IACZ,EAAE,KAAA,EAAO,OAAA,CAAQ,KAAA,EAAO,OAAO,SAAA,EAAU;AAAA,IACzC,IAAI,MAAA,CAAO;AAAA,GACb;AACA,EAAA,MAAM,iBAAiB,CAAA,EAAG,GAAA,CAAI,MAAA,CAAO,SAAS,YAAY,KAAK,CAAA,CAAA;AAE/D,EAAA,OAAO;AAAA,IACL,GAAG,QAAA;AAAA,IACH,OAAA;AAAA,IACA,IAAA;AAAA,IACA,KAAA,EAAO,GAAA,EAAK,YAAA,EAAc,UAAA,IAAc,EAAC;AAAA,IACzC,cAAA;AAAA,IACA,aAAA,EAAe,IAAI,MAAA,CAAO;AAAA,GAC5B;AACF;AAkBA,SAAS,WAAW,KAAA,EAA8B;AAChD,EAAA,MAAM,GAAA,uBAAU,IAAA,EAAK;AACrB,EAAA,OAAO;AAAA,IACL,KAAK,KAAA,CAAM,GAAA;AAAA,IACX,WAAW,KAAA,CAAM,SAAA;AAAA,IACjB,UAAA,EAAY,MAAM,GAAA,CAAI,UAAA;AAAA,IACtB,WAAA,EAAa,MAAM,OAAA,CAAQ,KAAA;AAAA,IAC3B,UAAA,EAAY,MAAM,QAAA,CAAS,GAAA;AAAA,IAC3B,YAAA,EAAc,MAAM,QAAA,CAAS,IAAA;AAAA,IAC7B,SAAA,EAAW,MAAM,GAAA,CAAI,GAAA;AAAA,IACrB,WAAA,EAAa,IAAA;AAAA,IACb,YAAA,EAAc,IAAA;AAAA,IACd,IAAA,EAAM,MAAM,QAAA,CAAS,IAAA;AAAA,IACrB,UAAU,KAAA,CAAM,YAAA;AAAA,IAChB,iBAAA,EAAmB,IAAA;AAAA,IACnB,QAAA,EAAU,KAAA,CAAM,YAAA,EAAc,IAAA,IAAQ,MAAM,QAAA,CAAS,QAAA;AAAA,IACrD,SAAA,EAAW,KAAA,CAAM,YAAA,EAAc,KAAA,IAAS,MAAM,QAAA,CAAS,SAAA;AAAA,IACvD,SAAS,KAAA,CAAM,eAAA;AAAA,IACf,UAAU,KAAA,CAAM,QAAA;AAAA,IAChB,QAAQ,KAAA,CAAM,MAAA;AAAA,IACd,YAAA,EAAc,MAAM,YAAA,IAAgB,IAAA;AAAA,IACpC,UAAA,EAAY,IAAA;AAAA,IACZ,YAAA,EAAc,IAAA;AAAA,IACd,OAAO,EAAC;AAAA,IACR,IAAA,EAAM,KAAA,CAAM,IAAA,IAAQ,EAAC;AAAA,IACrB,QAAA,EAAU,IAAA;AAAA,IACV,SAAA,EAAW,CAAA;AAAA,IACX,YAAA,EAAc,IAAA;AAAA,IACd,UAAA,EAAY,CAAA;AAAA,IACZ,cAAc,EAAC;AAAA,IACf,cAAA,EAAgB,IAAA;AAAA,IAChB,YAAA,EAAc,IAAA;AAAA,IACd,QAAA,EAAU,GAAA;AAAA,IACV,SAAA,EAAW,GAAA;AAAA,IACX,MAAA,EAAQ,IAAA;AAAA,IACR,WAAA,EAAa;AAAA,GACf;AACF;AAEA,eAAe,UAAA,CAAW,MAAA,EAAkB,MAAA,EAAgB,GAAA,EAAmC;AAC7F,EAAA,MAAM,GAAA,CAAI,YAAY,KAAA,CAAM,SAAA;AAAA,IAC1B,EAAE,KAAK,MAAA,EAAO;AAAA,IACd,EAAE,IAAA,EAAM,EAAE,QAAQ,QAAA,EAAU,YAAA,EAAc,QAAO;AAAE,GACrD;AACF;AAEA,SAAS,OAAO,CAAA,EAAmB;AACjC,EAAA,OAAOG,wBAAAA,CAAO,WAAW,QAAQ,CAAA,CAAE,OAAO,CAAC,CAAA,CAAE,OAAO,KAAK,CAAA;AAC3D;;;AE/YA,IAAM,WAAA,GAAc,GAAA;AAEpB,eAAsB,iBAAA,CAAkB,OAAiB,GAAA,EAAmC;AAC1F,EAAA,MAAM,GAAA,GAAM,MAAM,GAAA,CAAI,WAAA,CAAY,SAAS,OAAA,CAAQ,EAAE,GAAA,EAAK,KAAA,EAAO,CAAA;AACjE,EAAA,IAAI,CAAC,GAAA,IAAO,GAAA,CAAI,MAAA,KAAW,QAAA,EAAU;AAWrC,EAAA,IAAI,GAAA,CAAI,gBAAgB,GAAA,CAAI,YAAA,CAAa,SAAQ,GAAI,IAAA,CAAK,GAAA,EAAI,GAAI,WAAA,EAAa;AAE/E,EAAA,MAAM,IAAA,GAAO,MAAM,GAAA,CAAI,WAAA,CAAY,KAAA,CAAM,QAAQ,EAAE,GAAA,EAAK,GAAA,CAAI,MAAA,EAAQ,CAAA;AACpE,EAAA,IAAI,CAAC,IAAA,EAAM;AACT,IAAA,MAAM,WAAA,CAAY,GAAA,EAAK,cAAA,EAAgB,GAAG,CAAA;AAC1C,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,KAAA,GAAQ,MAAM,eAAA,CAAgB,GAAA,EAAK,MAAM,GAAG,CAAA;AAClD,EAAA,MAAM,OAAO,UAAA,CAAW,KAAA,EAAO,GAAA,CAAI,gBAAA,EAAkB,IAAI,iBAAiB,CAAA;AAC1E,EAAA,IAAI,CAAC,IAAA,EAAM;AACT,IAAA,MAAM,eAAA,CAAgB,GAAA,EAAK,WAAA,EAAa,GAAG,CAAA;AAC3C,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,UAAU,MAAM,GAAA,CAAI,OAAA,CAAQ,OAAA,CAAQ,IAAI,UAAU,CAAA;AACxD,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,MAAM,WAAA,CAAY,GAAA,EAAK,iBAAA,EAAmB,GAAG,CAAA;AAC7C,IAAA;AAAA,EACF;AAOA,EAAA,MAAM,GAAA,GAAM,MAAM,GAAA,CAAI,WAAA,CAAY,aAAA,CAAc,QAAQ,EAAE,UAAA,EAAY,GAAA,CAAI,UAAA,EAAY,CAAA;AACtF,EAAA,IAAI,GAAA,IAAO,GAAA,CAAI,MAAA,KAAW,YAAA,EAAc;AACtC,IAAA,MAAM,WAAA,CAAY,GAAA,EAAK,GAAA,CAAI,MAAA,EAAQ,GAAG,CAAA;AACtC,IAAA;AAAA,EACF;AAEA,EAAA,QAAQ,KAAK,IAAA;AAAM,IACjB,KAAK,MAAA;AACH,MAAA,OAAO,UAAA,CAAW,GAAA,EAAK,IAAA,EAAM,GAAG,CAAA;AAAA,IAClC,KAAK,WAAA;AACH,MAAA,OAAO,eAAA,CAAgB,GAAA,EAAK,IAAA,EAAM,OAAA,EAAS,GAAG,CAAA;AAAA,IAChD,KAAK,QAAA;AACH,MAAA,OAAO,YAAA,CAAa,GAAA,EAAK,IAAA,EAAM,OAAA,EAAS,GAAG,CAAA;AAAA,IAC7C,KAAK,MAAA,EAAQ;AAGX,MAAA,IAAI,KAAK,QAAA,EAAU;AACjB,QAAA,MAAM,SAAA,GAAY,oCAAoB,IAAI,IAAA,IAAQ,IAAA,CAAK,QAAA,EAAU,QAAQ,QAAQ,CAAA;AACjF,QAAA,IAAI,UAAU,OAAA,EAAQ,GAAI,IAAA,CAAK,GAAA,KAAQ,GAAA,EAAQ;AAC7C,UAAA,OAAO,kBAAA,CAAmB,GAAA,EAAK,SAAA,EAAW,GAAG,CAAA;AAAA,QAC/C;AAAA,MACF;AACA,MAAA,OAAO,UAAA,CAAW,GAAA,EAAK,IAAA,EAAM,OAAA,EAAS,MAAM,GAAG,CAAA;AAAA,IACjD;AAAA,IACA,KAAK,KAAA;AACH,MAAA,OAAO,SAAA,CAAU,GAAA,EAAK,IAAA,EAAM,GAAG,CAAA;AAAA,IACjC,KAAK,YAAA;AACH,MAAA,OAAO,eAAA,CAAgB,GAAA,EAAK,IAAA,EAAM,GAAG,CAAA;AAAA,IACvC,KAAK,SAAA;AACH,MAAA,OAAO,iBAAA,CAAkB,GAAA,EAAK,IAAA,EAAM,GAAG,CAAA;AAAA,IACzC,KAAK,MAAA;AACH,MAAA,OAAO,WAAA,CAAY,GAAA,EAAK,IAAA,CAAK,MAAA,IAAU,aAAa,GAAG,CAAA;AAAA;AAE7D;AAMA,eAAe,UAAA,CACb,GAAA,EACA,IAAA,EACA,GAAA,EACe;AACf,EAAA,MAAM,EAAA,GAAK,QAAA,CAAS,IAAA,CAAK,KAAA,EAAO,KAAK,IAAI,CAAA;AACzC,EAAA,MAAM,SAAS,IAAI,IAAA,CAAK,IAAA,CAAK,GAAA,KAAQ,EAAE,CAAA;AAEvC,EAAA,MAAM,OAAA,GAAU,MAAM,GAAA,CAAI,WAAA,CAAY,QAAA,CAAS,gBAAA;AAAA,IAC7C,EAAE,GAAA,EAAK,GAAA,CAAI,GAAA,EAAK,gBAAA,EAAkB,IAAI,gBAAA,EAAiB;AAAA,IACvD;AAAA,MACE,IAAA,EAAM,EAAE,YAAA,EAAc,MAAA,EAAQ,wBAAwB,CAAA,EAAG,SAAA,kBAAW,IAAI,IAAA,EAAK,EAAE;AAAA,MAC/E,IAAA,EAAM,EAAE,gBAAA,EAAkB,CAAA,EAAE;AAAA,MAC5B,KAAA,EAAO;AAAA,QACL,OAAA,EAAS;AAAA,UACP,WAAW,GAAA,CAAI,gBAAA;AAAA,UACf,MAAA,EAAQ,cAAA;AAAA,UACR,EAAA,sBAAQ,IAAA,EAAK;AAAA,UACb,OAAA,EAAS,EAAE,KAAA,EAAO,MAAA;AAAO;AAC3B;AACF,KACF;AAAA,IACA,EAAE,gBAAgB,OAAA;AAAQ,GAC5B;AAEA,EAAA,IAAI,CAAC,OAAA,EAAS;AAEd,EAAA,MAAM,GAAA,CAAI,OAAO,OAAA,CAAQ,GAAA;AAAA,IACvB,SAAA;AAAA,IACA,EAAE,SAAA,EAAW,MAAA,CAAO,GAAA,CAAI,GAAG,CAAA,EAAE;AAAA,IAC7B,EAAE,KAAA,EAAO,EAAA,EAAI,KAAA,EAAO,WAAW,GAAA,CAAI,GAAG,CAAA,CAAA,EAAI,SAAA,CAAU,GAAG,CAAC,CAAA,CAAA,EAAI,GAAA,CAAI,gBAAA,GAAmB,CAAC,CAAA,CAAA;AAAG,GACzF;AACF;AAEA,eAAe,eAAA,CACb,GAAA,EACA,IAAA,EACA,OAAA,EACA,GAAA,EACe;AACf,EAAA,IAAI,CAAC,OAAA,EAAS;AACd,EAAA,MAAM,MAAA,GAAS,MAAM,iBAAA,CAAkB,IAAA,CAAK,MAAM,EAAE,OAAA,EAAS,GAAA,EAAK,WAAA,EAAa,IAAI,WAAA,EAAa,SAAA,EAAW,GAAA,CAAI,MAAA,CAAO,WAAW,CAAA;AAEjI,EAAA,IAAI,MAAA,EAAQ;AACV,IAAA,MAAM,WAAA,CAAY,GAAA,EAAK,GAAA,EAAK,EAAE,MAAA,EAAQ,qBAAA,EAAuB,OAAA,EAAS,EAAE,MAAA,EAAQ,IAAA,EAAK,EAAG,CAAA;AACxF,IAAA;AAAA,EACF;AACA,EAAA,IAAI,IAAA,CAAK,YAAY,UAAA,EAAY;AAC/B,IAAA,MAAM,YAAY,GAAA,EAAK,GAAA,EAAK,EAAE,MAAA,EAAQ,uBAAuB,OAAA,EAAS,EAAE,MAAA,EAAQ,KAAA,EAAO,SAAS,CAAA,EAAE,IAAK,EAAE,OAAA,EAAS,GAAG,CAAA;AACrH,IAAA;AAAA,EACF;AACA,EAAA,MAAM,WAAA,CAAY,GAAA,EAAK,iBAAA,EAAmB,GAAG,CAAA;AAC/C;AAEA,eAAe,YAAA,CACb,GAAA,EACA,IAAA,EACA,OAAA,EACA,GAAA,EACe;AACf,EAAA,IAAI,CAAC,OAAA,EAAS;AACd,EAAA,MAAM,MAAA,GAAS,MAAM,iBAAA,CAAkB,IAAA,CAAK,MAAM,EAAE,OAAA,EAAS,GAAA,EAAK,WAAA,EAAa,IAAI,WAAA,EAAa,SAAA,EAAW,GAAA,CAAI,MAAA,CAAO,WAAW,CAAA;AACjI,EAAA,MAAM,OAAA,GAAU,CAAC,GAAG,GAAA,CAAI,iBAAA,EAAmB,IAAI,gBAAA,EAAkB,MAAA,GAAS,MAAA,GAAS,OAAA,EAAS,CAAC,CAAA;AAE7F,EAAA,MAAM,OAAA,GAAU,MAAM,GAAA,CAAI,WAAA,CAAY,QAAA,CAAS,gBAAA;AAAA,IAC7C,EAAE,GAAA,EAAK,GAAA,CAAI,GAAA,EAAK,gBAAA,EAAkB,IAAI,gBAAA,EAAiB;AAAA,IACvD;AAAA,MACE,IAAA,EAAM;AAAA,QACJ,iBAAA,EAAmB,OAAA;AAAA,QACnB,gBAAA,EAAkB,CAAA;AAAA,QAClB,YAAA,sBAAkB,IAAA,EAAK;AAAA,QACvB,sBAAA,EAAwB,CAAA;AAAA,QACxB,SAAA,sBAAe,IAAA;AAAK,OACtB;AAAA,MACA,KAAA,EAAO;AAAA,QACL,OAAA,EAAS;AAAA,UACP,WAAW,GAAA,CAAI,gBAAA;AAAA,UACf,MAAA,EAAQ,cAAA;AAAA,UACR,EAAA,sBAAQ,IAAA,EAAK;AAAA,UACb,OAAA,EAAS,EAAE,MAAA;AAAO;AACpB;AACF,KACF;AAAA,IACA,EAAE,gBAAgB,OAAA;AAAQ,GAC5B;AAEA,EAAA,IAAI,CAAC,OAAA,EAAS;AACd,EAAA,MAAM,GAAA,CAAI,MAAA,CAAO,OAAA,CAAQ,GAAA,CAAI,SAAA,EAAW,EAAE,SAAA,EAAW,MAAA,CAAO,GAAA,CAAI,GAAG,CAAA,EAAG,CAAA;AACxE;AAEA,eAAe,SAAA,CACb,GAAA,EACA,IAAA,EACA,GAAA,EACe;AACf,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,OAAA,IAAW,EAAC;AAC9B,EAAA,MAAM,OAAA,GAAU,IAAA,CAAK,UAAA,IAAc,EAAC;AAEpC,EAAA,IAAI,GAAA,CAAI,OAAA,CAAQ,OAAA,IAAW,IAAA,CAAK,SAAS,CAAA,EAAG;AAC1C,IAAA,MAAM,GAAA,CAAI,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,YAAY,IAAI,CAAA;AAAA,EAChD,CAAA,MAAA,IAAW,IAAA,CAAK,MAAA,GAAS,CAAA,EAAG;AAC1B,IAAA,MAAM,GAAA,CAAI,YAAY,WAAA,CAAY,SAAA;AAAA,MAChC,IAAA,CAAK,GAAA,CAAI,CAAC,GAAA,MAAS;AAAA,QACjB,SAAA,EAAW;AAAA,UACT,MAAA,EAAQ,EAAE,UAAA,EAAY,GAAA,CAAI,YAAY,GAAA,EAAI;AAAA,UAC1C,MAAA,EAAQ,EAAE,YAAA,EAAc,EAAE,YAAY,GAAA,CAAI,UAAA,EAAY,GAAA,EAAK,SAAA,EAAW,MAAA,EAAQ,SAAA,kBAAW,IAAI,IAAA,IAAO,EAAE;AAAA,UACtG,MAAA,EAAQ;AAAA;AACV,OACF,CAAE;AAAA,KACJ;AAAA,EACF;AAEA,EAAA,IAAI,GAAA,CAAI,OAAA,CAAQ,UAAA,IAAc,OAAA,CAAQ,SAAS,CAAA,EAAG;AAChD,IAAA,MAAM,GAAA,CAAI,OAAA,CAAQ,UAAA,CAAW,GAAA,CAAI,YAAY,OAAO,CAAA;AAAA,EACtD,CAAA,MAAA,IAAW,OAAA,CAAQ,MAAA,GAAS,CAAA,EAAG;AAC7B,IAAA,MAAM,GAAA,CAAI,WAAA,CAAY,WAAA,CAAY,UAAA,CAAW,EAAE,UAAA,EAAY,GAAA,CAAI,UAAA,EAAY,GAAA,EAAK,EAAE,GAAA,EAAK,OAAA,IAAW,CAAA;AAAA,EACpG;AAEA,EAAA,MAAM,WAAA,CAAY,GAAA,EAAK,GAAA,EAAK,EAAE,MAAA,EAAQ,QAAA,EAAU,OAAA,EAAS,EAAE,OAAA,EAAS,IAAA,EAAM,UAAA,EAAY,OAAA,IAAW,CAAA;AACnG;AAEA,eAAe,eAAA,CACb,GAAA,EACA,IAAA,EACA,GAAA,EACe;AACf,EAAA,MAAM,SAAA,GAAY,WAAW,GAAA,CAAI,GAAG,QAAQ,GAAA,CAAI,gBAAgB,CAAA,CAAA,EAAI,IAAA,CAAK,SAAS,CAAA,CAAA;AAClF,EAAA,IAAI;AACF,IAAA,MAAM,GAAA,CAAI,WAAA,CAAY,MAAA,CAAO,SAAA,CAAU;AAAA,MACrC,YAAY,GAAA,CAAI,UAAA;AAAA,MAChB,MAAM,IAAA,CAAK,SAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQX,UAAA,EAAY,EAAE,GAAI,GAAA,CAAI,YAAA,EAAc,UAAA,IAAc,EAAC,EAAI,GAAI,IAAA,CAAK,UAAA,IAAc,EAAC,EAAG;AAAA,MAClF,SAAA;AAAA,MACA,UAAA,sBAAgB,IAAA,EAAK;AAAA,MACrB,SAAA,sBAAe,IAAA;AAAK,KACrB,CAAA;AAAA,EACH,SAAS,GAAA,EAAU;AACjB,IAAA,IAAI,GAAA,EAAK,IAAA,KAAS,IAAA,EAAO,MAAM,GAAA;AAAA,EACjC;AACA,EAAA,MAAM,WAAA,CAAY,GAAA,EAAK,GAAA,EAAK,EAAE,MAAA,EAAQ,aAAA,EAAe,OAAA,EAAS,EAAE,IAAA,EAAM,IAAA,CAAK,SAAA,EAAU,EAAG,CAAA;AAC1F;AAEA,eAAe,iBAAA,CACb,GAAA,EACA,IAAA,EACA,GAAA,EACe;AACf,EAAA,IAAI;AA0BF,IAAA,MAAM,GAAA,GAAM,MAAM,KAAA,CAAM,IAAA,CAAK,GAAA,EAAK;AAAA,MAChC,MAAA,EAAQ,KAAK,MAAA,IAAU,MAAA;AAAA,MACvB,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA,EAAmB;AAAA,MAC9C,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,IAAA,CAAK,WAAW,EAAE,UAAA,EAAY,GAAA,CAAI,UAAA,EAAY,SAAA,EAAW,MAAA,CAAO,GAAA,CAAI,GAAG,GAAG,CAAA;AAAA,MAC/F,MAAA,EAAQ,WAAA,CAAY,OAAA,CAAQ,GAAM;AAAA,KACnC,CAAA;AACD,IAAA,IAAI,CAAC,IAAI,EAAA,EAAI,MAAM,IAAI,KAAA,CAAM,CAAA,sBAAA,EAAyB,GAAA,CAAI,MAAM,CAAA,CAAE,CAAA;AAClE,IAAA,MAAM,WAAA,CAAY,GAAA,EAAK,GAAA,EAAK,EAAE,QAAQ,gBAAA,EAAkB,OAAA,EAAS,EAAE,GAAA,EAAK,KAAK,GAAA,EAAK,MAAA,EAAQ,GAAA,CAAI,MAAA,IAAU,CAAA;AAAA,EAC1G,SAAS,GAAA,EAAU;AACjB,IAAA,MAAM,QAAA,GAAA,CAAY,GAAA,CAAI,sBAAA,IAA0B,CAAA,IAAK,CAAA;AACrD,IAAA,IAAI,QAAA,IAAY,GAAA,CAAI,MAAA,CAAO,oBAAA,EAAsB;AAC/C,MAAA,IAAI,IAAA,CAAK,gBAAgB,UAAA,EAAY;AACnC,QAAA,MAAM,YAAY,GAAA,EAAK,CAAA,gBAAA,EAAmB,GAAA,EAAK,OAAO,IAAI,GAAG,CAAA;AAAA,MAC/D,CAAA,MAAO;AAEL,QAAA,MAAM,WAAA,CAAY,KAAK,GAAA,EAAK;AAAA,UAC1B,MAAA,EAAQ,gBAAA;AAAA,UACR,OAAA,EAAS,EAAE,GAAA,EAAK,IAAA,CAAK,KAAK,KAAA,EAAO,GAAA,EAAK,OAAA,EAAS,SAAA,EAAW,IAAA;AAAK,SAChE,CAAA;AAAA,MACH;AAAA,IACF,CAAA,MAAO;AACL,MAAA,MAAM,GAAA,CAAI,YAAY,QAAA,CAAS,SAAA;AAAA,QAC7B,EAAE,GAAA,EAAK,GAAA,CAAI,GAAA,EAAK,gBAAA,EAAkB,IAAI,gBAAA,EAAiB;AAAA,QACvD,EAAE,IAAA,EAAM,EAAE,sBAAA,EAAwB,CAAA,IAAK,IAAA,EAAM,EAAE,YAAA,EAAc,IAAI,KAAK,IAAA,CAAK,GAAA,EAAI,GAAI,GAAM,GAAE;AAAE,OAC/F;AACA,MAAA,MAAM,GAAA,CAAI,OAAO,OAAA,CAAQ,GAAA;AAAA,QACvB,SAAA;AAAA,QACA,EAAE,SAAA,EAAW,MAAA,CAAO,GAAA,CAAI,GAAG,CAAA,EAAE;AAAA,QAC7B,EAAE,KAAA,EAAO,GAAA,EAAQ,KAAA,EAAO,CAAA,QAAA,EAAW,IAAI,GAAG,CAAA,CAAA,EAAI,SAAA,CAAU,GAAG,CAAC,CAAA,CAAA,EAAI,GAAA,CAAI,gBAAgB,CAAA,OAAA,EAAU,QAAQ,CAAA,CAAA;AAAG,OAC3G;AAAA,IACF;AAAA,EACF;AACF;AAQA,eAAe,kBAAA,CAAmB,GAAA,EAAiB,SAAA,EAAiB,GAAA,EAAmC;AACrG,EAAA,MAAM,OAAA,GAAU,MAAM,GAAA,CAAI,WAAA,CAAY,QAAA,CAAS,gBAAA;AAAA;AAAA;AAAA,IAG7C,EAAE,GAAA,EAAK,GAAA,CAAI,GAAA,EAAK,gBAAA,EAAkB,GAAA,CAAI,gBAAA,EAAkB,YAAA,EAAc,EAAE,GAAA,EAAK,SAAA,EAAU,EAAE;AAAA,IACzF;AAAA,MACE,MAAM,EAAE,YAAA,EAAc,WAAW,SAAA,kBAAW,IAAI,MAAK,EAAE;AAAA,MACvD,KAAA,EAAO;AAAA,QACL,OAAA,EAAS;AAAA,UACP,WAAW,GAAA,CAAI,gBAAA;AAAA,UACf,MAAA,EAAQ,eAAA;AAAA,UACR,EAAA,sBAAQ,IAAA,EAAK;AAAA,UACb,OAAA,EAAS,EAAE,KAAA,EAAO,SAAA;AAAU;AAC9B;AACF,KACF;AAAA,IACA,EAAE,gBAAgB,OAAA;AAAQ,GAC5B;AACA,EAAA,IAAI,CAAC,OAAA,EAAS;AAEd,EAAA,MAAM,GAAA,CAAI,OAAO,OAAA,CAAQ,GAAA;AAAA,IACvB,SAAA;AAAA,IACA,EAAE,SAAA,EAAW,MAAA,CAAO,GAAA,CAAI,GAAG,CAAA,EAAE;AAAA,IAC7B;AAAA,MACE,KAAA,EAAO,KAAK,GAAA,CAAI,CAAA,EAAG,UAAU,OAAA,EAAQ,GAAI,IAAA,CAAK,GAAA,EAAK,CAAA;AAAA,MACnD,KAAA,EAAO,CAAA,QAAA,EAAW,GAAA,CAAI,GAAG,IAAI,SAAA,CAAU,GAAG,CAAC,CAAA,CAAA,EAAI,GAAA,CAAI,gBAAgB,CAAA,QAAA,EAAW,SAAA,CAAU,SAAS,CAAA;AAAA;AACnG,GACF;AACF;AAeA,eAAsB,YACpB,GAAA,EACA,GAAA,EACA,GAAA,EACA,IAAA,GAAuB,EAAC,EACT;AACf,EAAA,MAAM,OAAA,GAAU,KAAK,OAAA,IAAW,CAAA;AAChC,EAAA,MAAM,OAAA,GAAU,MAAM,GAAA,CAAI,WAAA,CAAY,QAAA,CAAS,gBAAA;AAAA,IAC7C,EAAE,GAAA,EAAK,GAAA,CAAI,GAAA,EAAK,gBAAA,EAAkB,IAAI,gBAAA,EAAiB;AAAA,IACvD;AAAA,MACE,IAAA,EAAM,EAAE,YAAA,kBAAc,IAAI,IAAA,EAAK,EAAG,sBAAA,EAAwB,CAAA,EAAG,SAAA,kBAAW,IAAI,IAAA,EAAK,EAAE;AAAA,MACnF,IAAA,EAAM,EAAE,gBAAA,EAAkB,OAAA,EAAQ;AAAA,MAClC,KAAA,EAAO;AAAA,QACL,OAAA,EAAS,EAAE,SAAA,EAAW,GAAA,CAAI,kBAAkB,MAAA,EAAQ,GAAA,CAAI,MAAA,EAAQ,EAAA,kBAAI,IAAI,IAAA,EAAK,EAAG,OAAA,EAAS,IAAI,OAAA;AAAQ;AACvG,KACF;AAAA,IACA,EAAE,gBAAgB,OAAA;AAAQ,GAC5B;AACA,EAAA,IAAI,CAAC,OAAA,EAAS;AACd,EAAA,MAAM,GAAA,CAAI,MAAA,CAAO,OAAA,CAAQ,GAAA,CAAI,SAAA,EAAW,EAAE,SAAA,EAAW,MAAA,CAAO,GAAA,CAAI,GAAG,CAAA,EAAG,CAAA;AACxE;AAEA,eAAsB,WAAA,CAAY,GAAA,EAAiB,MAAA,EAAgB,GAAA,EAAmC;AACpG,EAAA,MAAM,GAAA,CAAI,YAAY,QAAA,CAAS,SAAA;AAAA,IAC7B,EAAE,GAAA,EAAK,GAAA,CAAI,GAAA,EAAK,QAAQ,QAAA,EAAS;AAAA,IACjC;AAAA,MACE,IAAA,EAAM,EAAE,MAAA,EAAQ,QAAA,EAAU,QAAA,kBAAU,IAAI,IAAA,EAAK,EAAG,UAAA,EAAY,MAAA,EAAQ,SAAA,kBAAW,IAAI,MAAK,EAAE;AAAA,MAC1F,OAAO,EAAE,OAAA,EAAS,EAAE,SAAA,EAAW,IAAI,gBAAA,EAAkB,MAAA,EAAQ,QAAA,EAAU,EAAA,sBAAQ,IAAA,EAAK,EAAG,SAAS,EAAE,MAAA,IAAS;AAAE;AAC/G,GACF;AACF;AAEA,eAAsB,eAAA,CAAgB,GAAA,EAAiB,MAAA,EAAgB,GAAA,EAAmC;AACxG,EAAA,MAAM,GAAA,CAAI,YAAY,QAAA,CAAS,SAAA;AAAA,IAC7B,EAAE,GAAA,EAAK,GAAA,CAAI,GAAA,EAAK,QAAQ,QAAA,EAAS;AAAA,IACjC;AAAA,MACE,IAAA,EAAM,EAAE,MAAA,EAAQ,WAAA,EAAa,QAAA,kBAAU,IAAI,IAAA,EAAK,EAAG,UAAA,EAAY,MAAA,EAAQ,SAAA,kBAAW,IAAI,MAAK;AAAE;AAC/F,GACF;AACF;AAEA,eAAsB,WAAA,CAAY,GAAA,EAAiB,MAAA,EAAgB,GAAA,EAAmC;AACpG,EAAA,MAAM,GAAA,CAAI,YAAY,QAAA,CAAS,SAAA;AAAA,IAC7B,EAAE,GAAA,EAAK,GAAA,CAAI,GAAA,EAAK,QAAQ,QAAA,EAAS;AAAA,IACjC;AAAA,MACE,IAAA,EAAM,EAAE,MAAA,EAAQ,QAAA,EAAU,QAAA,kBAAU,IAAI,IAAA,EAAK,EAAG,UAAA,EAAY,MAAA,EAAQ,SAAA,kBAAW,IAAI,MAAK,EAAE;AAAA,MAC1F,OAAO,EAAE,OAAA,EAAS,EAAE,SAAA,EAAW,IAAI,gBAAA,EAAkB,MAAA,EAAQ,QAAA,EAAU,EAAA,sBAAQ,IAAA,EAAK,EAAG,SAAS,EAAE,MAAA,IAAS;AAAE;AAC/G,GACF;AACF;AAEA,eAAsB,eAAA,CACpB,GAAA,EACA,IAAA,EACA,GAAA,EACqB;AACrB,EAAA,IAAI,GAAA,CAAI,WAAA,KAAgB,IAAA,CAAK,OAAA,SAAgB,IAAA,CAAK,KAAA;AAClD,EAAA,MAAM,QAAA,GAAW,MAAM,GAAA,CAAI,WAAA,CAAY,YAAA,CAAa,OAAA,CAAQ,EAAE,MAAA,EAAQ,GAAA,CAAI,MAAA,EAAQ,OAAA,EAAS,GAAA,CAAI,aAAa,CAAA;AAC5G,EAAA,OAAO,QAAA,EAAU,SAAS,IAAA,CAAK,KAAA;AACjC;AAMO,SAAS,UAAA,CACd,KAAA,EACA,gBAAA,EACA,UAAA,EACiB;AACjB,EAAA,IAAI,GAAA,GAAkB,KAAA;AAEtB,EAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,UAAA,CAAW,MAAA,EAAQ,KAAK,CAAA,EAAG;AAC7C,IAAA,MAAM,WAAA,GAAc,WAAW,CAAC,CAAA;AAChC,IAAA,MAAMO,UAAAA,GAAY,UAAA,CAAW,CAAA,GAAI,CAAC,CAAA;AAClC,IAAA,MAAM,MAAA,GAAS,IAAI,WAAW,CAAA;AAC9B,IAAA,IAAI,CAAC,MAAA,IAAU,MAAA,CAAO,IAAA,KAAS,UAAU,OAAO,IAAA;AAChD,IAAA,GAAA,GAAMA,UAAAA,KAAc,MAAA,GAAS,MAAA,CAAO,WAAA,GAAc,MAAA,CAAO,YAAA;AAAA,EAC3D;AAEA,EAAA,OAAO,GAAA,CAAI,gBAAgB,CAAA,IAAK,IAAA;AAClC;AAOA,SAAS,UAAU,GAAA,EAAyB;AAC1C,EAAA,OAAO,GAAA,CAAI,iBAAA,CAAkB,IAAA,CAAK,GAAG,CAAA;AACvC;AAEA,SAAS,QAAA,CAAS,OAAe,IAAA,EAAsD;AACrF,EAAA,MAAM,CAAA,GAAI,GAAA;AACV,EAAA,QAAQ,IAAA;AAAM,IACZ,KAAK,SAAA;AACH,MAAA,OAAO,KAAA,GAAQ,CAAA;AAAA,IACjB,KAAK,OAAA;AACH,MAAA,OAAO,QAAQ,EAAA,GAAK,CAAA;AAAA,IACtB,KAAK,MAAA;AACH,MAAA,OAAO,KAAA,GAAQ,KAAK,EAAA,GAAK,CAAA;AAAA,IAC3B,KAAK,OAAA;AACH,MAAA,OAAO,KAAA,GAAQ,CAAA,GAAI,EAAA,GAAK,EAAA,GAAK,CAAA;AAAA;AAEnC;;;AC1cA,IAAM,WAAA,GAAc,GAAA;AAEpB,eAAsB,sBAAsB,GAAA,EAAmC;AAC7E,EAAA,MAAM,IAAA,GAAO,MAAM,GAAA,CAAI,WAAA,CAAY,QAAA,CAChC,IAAA,CAAK,EAAE,MAAA,EAAQ,QAAA,EAAU,YAAA,EAAc,EAAE,IAAA,kBAAM,IAAI,IAAA,EAAK,EAAE,EAAG,CAAA,CAC7D,IAAA,CAAK,EAAE,YAAA,EAAc,CAAA,EAAG,CAAA,CACxB,KAAA,CAAM,WAAW,CAAA,CACjB,OAAA,EAAQ;AAEX,EAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,IAAA,IAAI;AACF,MAAA,MAAM,iBAAA,CAAkB,GAAA,CAAI,GAAA,EAAM,GAAG,CAAA;AAAA,IACvC,SAAS,GAAA,EAAK;AACZ,MAAA,OAAA,CAAQ,KAAA,CAAM,iCAAiC,EAAE,KAAA,EAAO,OAAO,GAAA,CAAI,GAAG,CAAA,EAAG,GAAA,EAAK,CAAA;AAAA,IAChF;AAAA,EACF;AACF;ACLA,IAAM,8BAAA,GAAiC,KAAK,EAAA,GAAK,GAAA;AAOjD,eAAsB,2BAA2B,GAAA,EAAmC;AAClF,EAAA,MAAM,GAAA,uBAAU,IAAA,EAAK;AACrB,EAAA,MAAM,MAAM,MAAM,GAAA,CAAI,WAAA,CAAY,UAAA,CAC/B,KAAK,EAAE,MAAA,EAAQ,WAAA,EAAa,WAAA,EAAa,EAAE,IAAA,EAAM,GAAA,EAAI,EAAG,EACxD,OAAA,EAAQ;AAEX,EAAA,KAAA,MAAW,KAAK,GAAA,EAAK;AAEnB,IAAA,MAAM,OAAA,GAAU,MAAM,GAAA,CAAI,WAAA,CAAY,UAAA,CAAW,gBAAA;AAAA,MAC/C,EAAE,GAAA,EAAK,CAAA,CAAE,GAAA,EAAK,QAAQ,WAAA,EAAY;AAAA,MAClC,EAAE,MAAM,EAAE,MAAA,EAAQ,WAAW,SAAA,EAAW,GAAA,EAAK,SAAA,EAAW,GAAA,EAAI,EAAE;AAAA,MAC9D,EAAE,gBAAgB,OAAA;AAAQ,KAC5B;AACA,IAAA,IAAI,CAAC,OAAA,EAAS;AACd,IAAA,MAAM,sBAAA,CAAuB,SAAS,GAAG,CAAA;AAAA,EAC3C;AACF;AASA,eAAe,sBAAA,CAAuB,WAAyB,GAAA,EAAmC;AAChG,EAAA,IAAI,GAAA,CAAI,MAAA,CAAO,KAAA,CAAM,MAAA,KAAW,MAAA,EAAQ;AACtC,IAAA,MAAM,oBAAA,CAAqB,WAAW,GAAG,CAAA;AACzC,IAAA;AAAA,EACF;AACA,EAAA,MAAM,GAAA,CAAI,OAAO,OAAA,CAAQ,GAAA;AAAA,IACvB,SAAA;AAAA,IACA,EAAE,WAAA,EAAa,MAAA,CAAO,SAAA,CAAU,GAAG,CAAA,EAAE;AAAA,IACrC;AAAA,MACE,QAAA,EAAU,CAAA;AAAA,MACV,OAAA,EAAS,EAAE,IAAA,EAAM,aAAA,EAAe,OAAO,GAAA,EAAO;AAAA,MAC9C,KAAA,EAAO,CAAA,mBAAA,EAAsB,SAAA,CAAU,GAAG,CAAA;AAAA;AAC5C,GACF;AACF;AAGA,eAAsB,qBAAA,CAAsB,aAAuB,GAAA,EAAmC;AACpG,EAAA,MAAM,SAAA,GAAY,MAAM,GAAA,CAAI,WAAA,CAAY,UAAA,CAAW,OAAA,CAAQ,EAAE,GAAA,EAAK,WAAA,EAAa,MAAA,EAAQ,SAAA,EAAW,CAAA;AAClG,EAAA,IAAI,CAAC,SAAA,EAAW;AAChB,EAAA,MAAM,oBAAA,CAAqB,WAAW,GAAG,CAAA;AAC3C;AAOA,eAAsB,wBAAwB,GAAA,EAAmC;AAC/E,EAAA,MAAM,SAAS,IAAI,IAAA,CAAK,IAAA,CAAK,GAAA,KAAQ,8BAA8B,CAAA;AACnE,EAAA,MAAM,UAAU,MAAM,GAAA,CAAI,WAAA,CAAY,UAAA,CACnC,KAAK,EAAE,MAAA,EAAQ,SAAA,EAAW,SAAA,EAAW,EAAE,GAAA,EAAK,MAAA,EAAO,EAAG,EACtD,OAAA,EAAQ;AAEX,EAAA,KAAA,MAAW,KAAK,OAAA,EAAS;AAEvB,IAAA,MAAM,GAAA,CAAI,YAAY,UAAA,CAAW,SAAA;AAAA,MAC/B,EAAE,GAAA,EAAK,CAAA,CAAE,GAAA,EAAI;AAAA,MACb,EAAE,IAAA,EAAM,EAAE,2BAAW,IAAI,IAAA,IAAO;AAAE,KACpC;AACA,IAAA,MAAM,sBAAA,CAAuB,GAAG,GAAG,CAAA;AAAA,EACrC;AACF;AAEA,eAAe,oBAAA,CAAqB,WAAyB,GAAA,EAAmC;AAC9F,EAAA,IAAI;AACF,IAAA,MAAM,iBAAA,CAAkB,WAAW,GAAG,CAAA;AAAA,EACxC,SAAS,GAAA,EAAK;AACZ,IAAA,OAAA,CAAQ,KAAA,CAAM,sCAAsC,EAAE,EAAA,EAAI,OAAO,SAAA,CAAU,GAAG,CAAA,EAAG,GAAA,EAAK,CAAA;AACtF,IAAA,MAAM,GAAA,CAAI,YAAY,UAAA,CAAW,SAAA;AAAA,MAC/B,EAAE,GAAA,EAAK,SAAA,CAAU,GAAA,EAAI;AAAA,MACrB,EAAE,MAAM,EAAE,MAAA,EAAQ,UAAU,SAAA,kBAAW,IAAI,IAAA,EAAK,EAAE;AAAE,KACtD;AAAA,EACF;AACF;AAEA,eAAe,iBAAA,CAAkB,WAAyB,GAAA,EAAmC;AAC3F,EAAA,MAAM,QAAA,GAAW,MAAM,GAAA,CAAI,WAAA,CAAY,SAAA,CAAU,QAAQ,EAAE,IAAA,EAAM,SAAA,CAAU,YAAA,EAAc,CAAA;AACzF,EAAA,IAAI,CAAC,QAAA,EAAU;AACb,IAAA,MAAM,GAAA,CAAI,YAAY,UAAA,CAAW,SAAA;AAAA,MAC/B,EAAE,GAAA,EAAK,SAAA,CAAU,GAAA,EAAI;AAAA,MACrB,EAAE,MAAM,EAAE,MAAA,EAAQ,UAAU,SAAA,kBAAW,IAAI,IAAA,EAAK,EAAE;AAAE,KACtD;AACA,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,UAAA,GAAa,eAAA,CAAgB,SAAA,CAAU,iBAAiB,CAAA;AAC9D,EAAA,MAAM,WAAA,GAAc,UAAU,iBAAA,CAAkB,OAAA,CAAQ,OAAO,CAAC,CAAA,KAAM,YAAA,CAAa,CAAC,CAAC,CAAA;AAErF,EAAA,IAAI,MAAA,GAA6B,MAAA;AACjC,EAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,EAAA,MAAM,SAAA,GAAY,IAAI,MAAA,CAAO,yBAAA;AAC7B,EAAA,MAAM,UAAA,GAAa,IAAI,MAAA,CAAO,0BAAA;AAC9B,EAAA,MAAM,eAAA,GAAkB,UAAU,wBAAA,KAA6B,IAAA;AAC/D,EAAA,MAAM,cAAc,SAAA,CAAU,WAAA,EAAa,OAAA,EAAQ,IAAK,KAAK,GAAA,EAAI;AAEjE,EAAA,WAAS;AAGP,IAAA,MAAM,GAAA,CAAI,YAAY,UAAA,CAAW,SAAA;AAAA,MAC/B,EAAE,GAAA,EAAK,SAAA,CAAU,GAAA,EAAI;AAAA,MACrB,EAAE,IAAA,EAAM,EAAE,2BAAW,IAAI,IAAA,IAAO;AAAE,KACpC;AAEA,IAAA,MAAM,IAAA,GAAO,MAAM,GAAA,CAAI,OAAA,CAAQ,KAAA,CAAM,YAAY,EAAE,KAAA,EAAO,SAAA,EAAW,MAAA,EAAQ,CAAA;AAC7E,IAAA,IAAI,IAAA,CAAK,QAAA,CAAS,MAAA,KAAW,CAAA,EAAG;AAGhC,IAAA,MAAM,WAAW,MAAM,gBAAA,CAAiB,IAAA,CAAK,QAAA,EAAU,aAAa,GAAG,CAAA;AAEvE,IAAA,IAAI,QAAA,CAAS,SAAS,CAAA,EAAG;AAEvB,MAAA,OAAQ,MAAM,GAAA,CAAI,MAAA,CAAO,IAAA,CAAK,eAAA,KAAqB,UAAA,EAAY;AAC7D,QAAA,MAAM,GAAA,CAAI,YAAY,UAAA,CAAW,SAAA;AAAA,UAC/B,EAAE,GAAA,EAAK,SAAA,CAAU,GAAA,EAAI;AAAA,UACrB,EAAE,IAAA,EAAM,EAAE,2BAAW,IAAI,IAAA,IAAO;AAAE,SACpC;AACA,QAAA,MAAM,MAAM,GAAI,CAAA;AAAA,MAClB;AAEA,MAAA,MAAM,QAAA,GAAW,MAAM,OAAA,CAAQ,GAAA;AAAA,QAC7B,QAAA,CAAS,GAAA,CAAI,OAAO,OAAA,KAAY,YAAA,CAAa,SAAA,EAAW,QAAA,EAAU,OAAA,EAAS,GAAA,EAAK,WAAA,EAAa,eAAe,CAAC;AAAA,OAC/G;AAIA,MAAA,MAAM,WAAyD,EAAC;AAChE,MAAA,KAAA,MAAW,EAAE,GAAA,EAAK,OAAA,EAAQ,IAAK,QAAA,EAAU;AACvC,QAAA,IAAI,CAAC,GAAA,EAAK;AACV,QAAA,IAAI;AACF,UAAA,MAAM,GAAA,CAAI,WAAA,CAAY,KAAA,CAAM,SAAA,CAAU,GAAG,CAAA;AACzC,UAAA,QAAA,CAAS,KAAK,EAAE,MAAA,EAAQ,GAAA,CAAI,GAAA,EAAM,SAAS,CAAA;AAAA,QAC7C,SAAS,GAAA,EAAU;AACjB,UAAA,IAAI,GAAA,EAAK,IAAA,KAAS,IAAA,EAAO,MAAM,GAAA;AAAA,QAEjC;AAAA,MACF;AAGA,MAAA,IAAI,QAAA,CAAS,SAAS,CAAA,EAAG;AACvB,QAAA,MAAM,OAAA,CAAQ,GAAA;AAAA,UACZ,QAAA,CAAS,GAAA;AAAA,YAAI,CAAC,EAAE,MAAA,EAAQ,SAAQ,KAC9B,GAAA,CAAI,OAAO,IAAA,CAAK,GAAA;AAAA,cACd,MAAA;AAAA,cACA,EAAE,MAAA,EAAQ,MAAA,CAAO,MAAM,CAAA,EAAE;AAAA,cACzB;AAAA,gBACE,QAAA,EAAU,IAAI,MAAA,CAAO,iBAAA;AAAA,gBACrB,OAAA,EAAS,EAAE,IAAA,EAAM,aAAA,EAAe,OAAO,GAAA,EAAO;AAAA,gBAC9C,GAAI,OAAA,GAAU,CAAA,GAAI,EAAE,KAAA,EAAO,OAAA,KAAY;AAAC;AAC1C;AACF;AACF,SACF;AAAA,MACF;AAEA,MAAA,KAAA,IAAS,QAAA,CAAS,MAAA;AAAA,IACpB;AAEA,IAAA,IAAI,CAAC,KAAK,UAAA,EAAY;AACtB,IAAA,MAAA,GAAS,IAAA,CAAK,UAAA;AAAA,EAChB;AAEA,EAAA,MAAM,GAAA,CAAI,YAAY,UAAA,CAAW,SAAA;AAAA,IAC/B,EAAE,GAAA,EAAK,SAAA,CAAU,GAAA,EAAI;AAAA,IACrB;AAAA,MACE,IAAA,EAAM;AAAA,QACJ,MAAA,EAAQ,MAAA;AAAA,QACR,WAAA,sBAAiB,IAAA,EAAK;AAAA,QACtB,cAAA,EAAgB,KAAA;AAAA,QAChB,SAAA,sBAAe,IAAA;AAAK;AACtB;AACF,GACF;AACF;AAMA,SAAS,gBAAgB,GAAA,EAAuC;AAC9D,EAAA,MAAM,MAAqB,EAAC;AAC5B,EAAA,KAAA,MAAW,CAAA,IAAK,IAAI,OAAA,EAAS;AAC3B,IAAA,QAAQ,EAAE,IAAA;AAAM,MACd,KAAK,QAAA;AACH,QAAA,GAAA,CAAI,SAAS,CAAA,CAAE,GAAA;AACf,QAAA;AAAA,MACF,KAAK,aAAA;AACH,QAAA,GAAA,CAAI,cAAc,EAAE,KAAA,EAAO,EAAE,KAAA,EAAO,KAAA,EAAO,EAAE,KAAA,EAAM;AACnD,QAAA;AAAA,MACF,KAAK,SAAA;AACH,QAAA,GAAA,CAAI,UAAU,EAAE,KAAA,EAAO,EAAE,KAAA,EAAO,MAAA,EAAQ,EAAE,MAAA,EAAO;AACjD,QAAA;AAAA,MACF,KAAK,aAAA;AACH,QAAA,GAAA,CAAI,cAAc,CAAA,CAAE,KAAA;AACpB,QAAA;AAAA;AAGJ,EACF;AACA,EAAA,OAAO,GAAA;AACT;AAEA,SAAS,aAAa,CAAA,EAA2B;AAC/C,EAAA,OACE,CAAA,CAAE,IAAA,KAAS,oBAAA,IACX,CAAA,CAAE,IAAA,KAAS,YAAA,IACX,CAAA,CAAE,IAAA,KAAS,eAAA,IACX,CAAA,CAAE,IAAA,KAAS,iBAAA,IACX,CAAA,CAAE,IAAA,KAAS,kBAAA,IACX,CAAA,CAAE,IAAA,KAAS,QAAA,IACX,CAAA,CAAE,IAAA,KAAS,WAAA,IACX,CAAA,CAAE,IAAA,KAAS,WAAA,IACX,CAAA,CAAE,IAAA,KAAS,KAAA,IACX,CAAA,CAAE,IAAA,KAAS,KAAA;AAEf;AAEA,eAAe,gBAAA,CAAiB,QAAA,EAAqB,OAAA,EAA0B,GAAA,EAAwC;AACrH,EAAA,IAAI,OAAA,CAAQ,MAAA,KAAW,CAAA,EAAG,OAAO,QAAA;AACjC,EAAA,MAAM,cAAc,QAAA,CAAS,GAAA,CAAI,CAAC,CAAA,KAAM,EAAE,UAAU,CAAA;AAGpD,EAAA,MAAM,QAAqC,EAAC;AAC5C,EAAA,KAAA,MAAW,KAAK,OAAA,EAAS;AACvB,IAAA,IAAI,CAAA,CAAE,SAAS,oBAAA,EAAsB;AACnC,MAAA,MAAM,IAAA,GAAO,MAAM,GAAA,CAAI,WAAA,CAAY,cAChC,IAAA,CAAK,EAAE,UAAA,EAAY,EAAE,GAAA,EAAK,WAAA,IAAe,MAAA,EAAQ,CAAA,CAAE,MAAA,EAAQ,CAAA,CAC3D,OAAA,CAAgC,EAAE,UAAA,EAAY,CAAA,EAAG,CAAA,CACjD,OAAA,EAAQ;AACX,MAAA,KAAA,CAAM,CAAA,IAAA,EAAO,CAAA,CAAE,MAAM,CAAA,CAAE,CAAA,GAAI,IAAI,GAAA,CAAI,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,UAAU,CAAC,CAAA;AAAA,IAClE;AACA,IAAA,IAAI,CAAA,CAAE,IAAA,KAAS,YAAA,IAAgB,CAAA,CAAE,SAAS,eAAA,EAAiB;AACzD,MAAA,MAAM,KAAA,GAAa,EAAE,UAAA,EAAY,EAAE,KAAK,WAAA,EAAY,EAAG,IAAA,EAAM,CAAA,CAAE,SAAA,EAAU;AACzE,MAAA,IAAI,EAAE,UAAA,EAAY;AAChB,QAAA,KAAA,CAAM,UAAA,GAAa,EAAE,GAAA,EAAK,IAAI,IAAA,CAAK,IAAA,CAAK,GAAA,EAAI,GAAI,CAAA,CAAE,UAAA,GAAa,KAAU,CAAA,EAAE;AAAA,MAC7E;AACA,MAAA,MAAM,IAAA,GAAO,MAAM,GAAA,CAAI,WAAA,CAAY,OAChC,IAAA,CAAK,KAAK,CAAA,CACV,OAAA,CAAgC,EAAE,UAAA,EAAY,CAAA,EAAG,EACjD,OAAA,EAAQ;AACX,MAAA,KAAA,CAAM,CAAA,IAAA,EAAO,CAAA,CAAE,SAAS,CAAA,CAAE,CAAA,GAAI,IAAI,GAAA,CAAI,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,UAAU,CAAC,CAAA;AAAA,IACrE;AAAA,EACF;AAEA,EAAA,OAAO,QAAA,CAAS,MAAA,CAAO,CAAC,CAAA,KAAM,OAAA,CAAQ,KAAA,CAAM,CAAC,CAAA,KAAM,aAAA,CAAc,CAAA,EAAG,CAAA,EAAG,KAAK,CAAC,CAAC,CAAA;AAChF;AAEA,SAAS,aAAA,CAAc,CAAA,EAAY,CAAA,EAAkB,KAAA,EAA6C;AAChG,EAAA,QAAQ,EAAE,IAAA;AAAM,IACd,KAAK,oBAAA;AACH,MAAA,OAAO,KAAA,CAAM,OAAO,CAAA,CAAE,MAAM,EAAE,CAAA,EAAG,GAAA,CAAI,CAAA,CAAE,UAAU,CAAA,IAAK,KAAA;AAAA,IACxD,KAAK,YAAA;AACH,MAAA,OAAO,KAAA,CAAM,OAAO,CAAA,CAAE,SAAS,EAAE,CAAA,EAAG,GAAA,CAAI,CAAA,CAAE,UAAU,CAAA,IAAK,KAAA;AAAA,IAC3D,KAAK,eAAA;AACH,MAAA,OAAO,CAAC,MAAM,CAAA,IAAA,EAAO,CAAA,CAAE,SAAS,CAAA,CAAE,CAAA,EAAG,GAAA,CAAI,CAAA,CAAE,UAAU,CAAA;AAAA,IACvD,KAAK,WAAA;AACH,MAAA,OAAO,CAAC,CAAA,CAAE,IAAA,CAAK,QAAA,CAAS,EAAE,GAAG,CAAA;AAAA,IAC/B,KAAK,QAAA;AAAA,IACL,KAAK,WAAA;AAGH,MAAA,OAAO,IAAA;AAAA,IACT,KAAK,iBAAA;AAAA,IACL,KAAK,kBAAA;AACH,MAAA,OAAO,IAAA;AAAA;AAAA,IACT,KAAK,KAAA;AACH,MAAA,OAAO,CAAA,CAAE,QAAQ,IAAA,CAAK,CAAC,QAAQ,aAAA,CAAc,CAAA,EAAG,GAAA,EAAK,KAAK,CAAC,CAAA;AAAA,IAC7D,KAAK,KAAA;AACH,MAAA,OAAO,CAAC,aAAA,CAAc,CAAA,EAAG,CAAA,CAAE,QAAQ,KAAK,CAAA;AAAA,IAC1C;AACE,MAAA,OAAO,IAAA;AAAA;AAEb;AAWA,eAAe,aACb,SAAA,EACA,QAAA,EACA,OAAA,EACA,GAAA,EACA,aACA,eAAA,EACsB;AAEtB,EAAA,MAAM,IAAA,GAAO,MAAM,YAAA,CAAa,GAAA,CAAI,aAAa,OAAA,CAAQ,KAAA,EAAO,SAAS,IAAI,CAAA;AAC7E,EAAA,IAAI,KAAK,UAAA,EAAY,OAAO,EAAE,GAAA,EAAK,IAAA,EAAM,SAAS,CAAA,EAAE;AAEpD,EAAA,MAAM,MAAA,GAAS,IAAIV,gBAAAA,EAAS;AAC5B,EAAA,MAAM,YAAY,CAAA,UAAA,EAAa,SAAA,CAAU,GAAG,CAAA,CAAA,EAAI,QAAQ,UAAU,CAAA,CAAA;AAIlE,EAAA,IAAI,UAAU,IAAA,CAAK,GAAA,CAAI,GAAG,WAAA,GAAc,IAAA,CAAK,KAAK,CAAA;AAClD,EAAA,IAAI,eAAA,IAAmB,QAAQ,QAAA,EAAU;AACvC,IAAA,MAAM,QAAA,GAAW,oBAAA,CAAqB,WAAA,EAAa,OAAA,CAAQ,QAAQ,CAAA;AACnE,IAAA,OAAA,GAAU,KAAK,GAAA,CAAI,CAAA,EAAG,cAAc,QAAA,GAAW,IAAA,CAAK,KAAK,CAAA;AAAA,EAC3D;AAEA,EAAA,MAAM,GAAA,GAAe;AAAA,IACnB,GAAA,EAAK,MAAA;AAAA,IACL,SAAA;AAAA,IACA,YAAY,OAAA,CAAQ,UAAA;AAAA,IACpB,aAAa,OAAA,CAAQ,KAAA;AAAA,IACrB,YAAY,QAAA,CAAS,GAAA;AAAA,IACrB,cAAc,QAAA,CAAS,IAAA;AAAA,IACvB,SAAA,EAAW,IAAA;AAAA,IACX,aAAa,SAAA,CAAU,GAAA;AAAA,IACvB,YAAA,EAAc,IAAA;AAAA,IACd,MAAM,QAAA,CAAS,IAAA;AAAA,IACf,QAAA,EAAU,QAAA,CAAS,gBAAA,IAAoB,GAAA,CAAI,MAAA,CAAO,eAAA;AAAA,IAClD,iBAAA,EAAmB,IAAA;AAAA,IACnB,UAAU,QAAA,CAAS,QAAA;AAAA,IACnB,WAAW,QAAA,CAAS,SAAA;AAAA,IACpB,SAAS,QAAA,CAAS,OAAA;AAAA,IAClB,QAAA,EAAU,EAAA;AAAA,IACV,MAAA,EAAQ,QAAA;AAAA,IACR,YAAA,EAAc,IAAA;AAAA,IACd,UAAA,EAAY,IAAA;AAAA,IACZ,YAAA,EAAc,IAAA;AAAA,IACd,OAAO,EAAC;AAAA,IACR,MAAM,EAAC;AAAA,IACP,QAAA,EAAU,IAAA;AAAA,IACV,SAAA,EAAW,CAAA;AAAA,IACX,YAAA,EAAc,IAAA;AAAA,IACd,UAAA,EAAY,CAAA;AAAA,IACZ,cAAc,EAAC;AAAA,IACf,cAAA,EAAgB,IAAA;AAAA,IAChB,YAAA,EAAc,IAAA;AAAA,IACd,QAAA,sBAAc,IAAA,EAAK;AAAA,IACnB,SAAA,sBAAe,IAAA,EAAK;AAAA,IACpB,MAAA,EAAQ,IAAA;AAAA,IACR,WAAA,EAAa;AAAA,GACf;AAEA,EAAA,OAAO,EAAE,KAAK,OAAA,EAAQ;AACxB;AAeA,SAAS,oBAAA,CAAqB,aAAqB,QAAA,EAA0B;AAC3E,EAAA,MAAMW,OAAAA,GAAS,EAAA,GAAK,EAAA,GAAK,EAAA,GAAK,GAAA;AAC9B,EAAA,IAAI;AAGF,IAAA,MAAM,SAAA,GAAY,IAAI,IAAA,CAAK,WAAW,CAAA;AACtC,IAAA,MAAM,GAAA,GAAM,UAAU,cAAA,CAAe,OAAA,EAAS,EAAE,QAAA,EAAU,KAAA,EAAO,MAAA,EAAQ,KAAA,EAAO,CAAA;AAChF,IAAA,MAAM,KAAA,GAAQ,UAAU,cAAA,CAAe,OAAA,EAAS,EAAE,QAAA,EAAU,QAAA,EAAU,MAAA,EAAQ,KAAA,EAAO,CAAA;AAGrF,IAAA,MAAM,KAAA,GAAQ,CAAC,CAAA,KAAc;AAC3B,MAAA,MAAM,CAAA,GAAI,CAAA,CAAE,KAAA,CAAM,0CAA0C,CAAA;AAC5D,MAAA,IAAI,CAAC,GAAG,OAAO,CAAA;AACf,MAAA,OAAO,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,CAAE,CAAC,CAAA,EAAI,CAAC,CAAA,CAAE,CAAC,CAAA,GAAK,CAAA,EAAG,CAAC,CAAA,CAAE,CAAC,CAAA,EAAI,CAAC,CAAA,CAAE,CAAC,CAAA,EAAI,CAAC,CAAA,CAAE,CAAC,CAAA,EAAI,CAAC,CAAA,CAAE,CAAC,CAAE,CAAA;AAAA,IACpE,CAAA;AACA,IAAA,MAAM,KAAA,GAAQ,MAAM,GAAG,CAAA;AACvB,IAAA,MAAM,OAAA,GAAU,MAAM,KAAK,CAAA;AAC3B,IAAA,MAAM,WAAW,KAAA,GAAQ,OAAA;AAEzB,IAAA,OAAA,CAAS,QAAA,GAAWA,UAAUA,OAAAA,IAAUA,OAAAA;AAAA,EAC1C,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,CAAA;AAAA,EACT;AACF;AAEA,SAAS,MAAM,EAAA,EAA2B;AACxC,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,YAAY,UAAA,CAAW,OAAA,EAAS,EAAE,CAAC,CAAA;AACzD;;;ACjZA,eAAsB,mBAAmB,GAAA,EAAmC;AAC1E,EAAA,MAAM,SAAA,GAAY,IAAI,MAAA,CAAO,4BAAA;AAC7B,EAAA,MAAM,UAAA,GAAa,IAAI,MAAA,CAAO,6BAAA;AAC9B,EAAA,IAAI,SAAA,IAAa,CAAA,IAAK,UAAA,IAAc,CAAA,EAAG;AAEvC,EAAA,MAAM,SAAS,IAAI,IAAA,CAAK,KAAK,GAAA,EAAI,GAAI,aAAa,KAAU,CAAA;AAI5D,EAAA,MAAM,SAAA,GAAY,MAAM,GAAA,CAAI,WAAA,CAAY,MACrC,SAAA,CAAuG;AAAA,IACtG,EAAE,MAAA,EAAQ,EAAE,MAAA,EAAQ,SAAA,EAAW,UAAA,EAAY,MAAA,EAAQ,QAAA,EAAU,EAAE,GAAA,EAAK,MAAA,EAAO,EAAE,EAAE;AAAA,IAC/E,EAAE,KAAA,EAAO,EAAE,QAAA,EAAU,GAAE,EAAE;AAAA,IACzB;AAAA,MACE,MAAA,EAAQ;AAAA,QACN,GAAA,EAAK,cAAA;AAAA,QACL,KAAA,EAAO,EAAE,IAAA,EAAM,CAAA,EAAE;AAAA,QACjB,aAAA,EAAe,EAAE,KAAA,EAAO,YAAA,EAAa;AAAA,QACrC,QAAA,EAAU,EAAE,KAAA,EAAO,OAAA;AAAQ;AAC7B,KACF;AAAA,IACA,EAAE,QAAQ,EAAE,KAAA,EAAO,EAAE,IAAA,EAAM,SAAA,IAAY,EAAE;AAAA,IACzC,EAAE,QAAQ,GAAA;AAAI,GACf,EACA,OAAA,EAAQ;AAEX,EAAA,KAAA,MAAW,KAAK,SAAA,EAAW;AACzB,IAAA,MAAM,QAAQ,MAAA,CAAO,CAAA,CAAE,GAAA,IAAO,EAAE,EAAE,WAAA,EAAY;AAC9C,IAAA,IAAI,CAAC,KAAA,EAAO;AAGZ,IAAA,MAAM,QAAA,GAAW,MAAM,GAAA,CAAI,WAAA,CAAY,aAAa,OAAA,CAAQ;AAAA,MAC1D,KAAA;AAAA,MACA,KAAA,EAAO;AAAA,KACR,CAAA;AACD,IAAA,IAAI,QAAA,EAAU;AAEd,IAAA,MAAM,GAAA,CAAI,YAAY,YAAA,CAAa,SAAA;AAAA,MACjC,EAAE,KAAA,EAAO,KAAA,EAAO,KAAA,EAAM;AAAA,MACtB;AAAA,QACE,YAAA,EAAc;AAAA,UACZ,KAAA;AAAA,UACA,SAAA,EAAW,UAAU,KAAK,CAAA;AAAA,UAC1B,KAAA,EAAO,KAAA;AAAA,UACP,MAAA,EAAQ,aAAA;AAAA,UACR,MAAA,EAAQ,gBAAA;AAAA,UACR,KAAA,EAAO,CAAA,EAAG,CAAA,CAAE,KAAK,yBAAyB,UAAU,CAAA,KAAA,CAAA;AAAA,UACpD,OAAA,sBAAa,IAAA,EAAK;AAAA,UAClB,SAAA,EAAW;AAAA;AACb,OACF;AAAA,MACA,EAAE,QAAQ,IAAA;AAAK,KACjB;AAEA,IAAA,MAAM,GAAA,CAAI,YAAY,aAAA,CAAc,SAAA;AAAA,MAClC,EAAE,kBAAkB,KAAA,EAAM;AAAA,MAC1B,EAAE,MAAM,EAAE,MAAA,EAAQ,WAAW,SAAA,kBAAW,IAAI,IAAA,EAAK,EAAE;AAAE,KACvD;AAEA,IAAA,MAAM,mBAAA;AAAA,MACJ,GAAA;AAAA,MACA,aAAA;AAAA,MACA,CAAA,CAAE,WAAW,EAAE,SAAA,EAAW,EAAE,aAAA,EAAe,IAAA,EAAM,CAAA,CAAE,QAAA,EAAS,GAAI;AAAA,KAClE;AAAA,EACF;AACF;AClDA,IAAM,yCAAyB,IAAI,GAAA,CAAI,CAAC,iBAAA,EAAmB,iBAAiB,CAAC,CAAA;AAG7E,IAAM,eAAA,GAAkB,CAAA;AAMxB,IAAM,eAAA,GAA4B;AAAA,EAChC,QAAA,EAAU,CAAC,QAAA,KAAaC,oBAAA,CAAI,SAAS,QAAQ;AAC/C,CAAA;AAoBA,eAAsB,cAAA,CACpB,GAAA,EACA,IAAA,GAAwB,EAAC,EACA;AACzB,EAAA,MAAM,GAAA,GAAM,GAAA,CAAI,MAAA,CAAO,KAAA,IAAS,EAAC;AACjC,EAAA,MAAM,aAAA,GAAgB,IAAI,aAAA,IAAiB,EAAA;AAE3C,EAAA,IAAI,CAAC,IAAA,CAAK,KAAA,IAAS,aAAA,IAAiB,CAAA,EAAG;AACrC,IAAA,OAAO,EAAE,GAAA,EAAK,KAAA,EAAO,MAAA,EAAQ,UAAA,EAAW;AAAA,EAC1C;AAEA,EAAA,MAAM,OAAA,GAAU,cAAA,CAAe,GAAA,EAAK,GAAG,CAAA;AACvC,EAAA,IAAI,QAAQ,OAAA,CAAQ,MAAA,KAAW,KAAK,OAAA,CAAQ,GAAA,CAAI,WAAW,CAAA,EAAG;AAC5D,IAAA,OAAO,EAAE,GAAA,EAAK,KAAA,EAAO,MAAA,EAAQ,YAAA,EAAa;AAAA,EAC5C;AAEA,EAAA,MAAM,QAAA,GAAW,KAAK,QAAA,IAAY,eAAA;AAClC,EAAA,MAAM,WAAA,GAAc,IAAI,WAAA,IAAe,0BAAA;AACvC,EAAA,MAAM,OAAA,GAAU,IAAI,OAAA,IAAW,sBAAA;AAE/B,EAAA,MAAM,QAID,EAAC;AACN,EAAA,KAAA,MAAW,CAAA,IAAK,QAAQ,OAAA,EAAS;AAC/B,IAAA,KAAA,MAAW,CAAA,IAAK,WAAA,EAAa,KAAA,CAAM,IAAA,CAAK,EAAE,MAAA,EAAQ,CAAA,EAAG,UAAA,EAAY,QAAA,EAAU,IAAA,EAAM,CAAA,EAAG,CAAA;AAAA,EACtF;AACA,EAAA,KAAA,MAAW,EAAA,IAAM,QAAQ,GAAA,EAAK;AAC5B,IAAA,KAAA,MAAW,CAAA,IAAK,OAAA,EAAS,KAAA,CAAM,IAAA,CAAK,EAAE,MAAA,EAAQ,EAAA,EAAI,UAAA,EAAY,IAAA,EAAM,IAAA,EAAM,CAAA,EAAG,CAAA;AAAA,EAC/E;AAMA,EAAA,MAAM,cAAA,GAAiB,KAAK,KAAA,GAAQ,IAAA,GAAO,KAAK,GAAA,EAAI,GAAI,aAAA,GAAgB,EAAA,GAAK,EAAA,GAAK,GAAA;AAClF,EAAA,IAAI,QAAA,GAAW,KAAA;AACf,EAAA,IAAI,kBAAkB,IAAA,EAAM;AAC1B,IAAA,MAAM,QAAA,GAAW,MAAM,GAAA,CAAI,WAAA,CAAY,WAAA,CACpC,IAAA;AAAA,MACC;AAAA,QACE,GAAA,EAAK,KAAA,CAAM,GAAA,CAAI,CAAC,CAAA,MAAO,EAAE,MAAA,EAAQ,CAAA,CAAE,MAAA,EAAQ,IAAA,EAAM,CAAA,CAAE,IAAA,CAAK,MAAK,CAAE;AAAA,OACjE;AAAA,MACA,EAAE,YAAY,EAAE,MAAA,EAAQ,GAAG,IAAA,EAAM,CAAA,EAAG,KAAA,EAAO,CAAA,EAAE;AAAE,MAEhD,OAAA,EAAQ;AACX,IAAA,MAAM,KAAA,uBAAY,GAAA,EAAY;AAC9B,IAAA,KAAA,MAAW,KAAK,QAAA,EAAU;AACxB,MAAA,IAAI,IAAI,IAAA,CAAK,CAAA,CAAE,KAAK,CAAA,CAAE,OAAA,KAAY,cAAA,EAAgB;AAChD,QAAA,KAAA,CAAM,IAAI,CAAA,EAAG,CAAA,CAAE,MAAM,CAAA,CAAA,EAAI,CAAA,CAAE,IAAI,CAAA,CAAE,CAAA;AAAA,MACnC;AAAA,IACF;AACA,IAAA,QAAA,GAAW,KAAA,CAAM,MAAA,CAAO,CAAC,CAAA,KAAM,CAAC,KAAA,CAAM,GAAA,CAAI,CAAA,EAAG,CAAA,CAAE,MAAM,CAAA,CAAA,EAAI,CAAA,CAAE,IAAA,CAAK,IAAI,EAAE,CAAC,CAAA;AACvE,IAAA,IAAI,QAAA,CAAS,WAAW,CAAA,EAAG;AACzB,MAAA,OAAO,EAAE,KAAK,KAAA,EAAO,MAAA,EAAQ,WAAW,WAAA,EAAa,CAAA,EAAG,aAAa,CAAA,EAAE;AAAA,IACzE;AAAA,EACF;AAEA,EAAA,IAAI,WAAA,GAAc,CAAA;AAIlB,EAAA,eAAe,YAAY,CAAA,EAAyB;AAClD,IAAA,MAAM,SAAA,GAAY,eAAe,CAAA,CAAE,MAAA,EAAQ,EAAE,UAAA,EAAY,CAAA,CAAE,KAAK,IAAI,CAAA;AACpE,IAAA,MAAM,MAAA,GAAS,SAAA,GACX,MAAM,UAAA,CAAW,UAAU,SAAS,CAAA,GACpC,EAAE,MAAA,EAAQ,OAAA,EAAwB,WAAA,EAAa,EAAC,EAAG,cAAc,2BAAA,EAA4B;AAGjG,IAAA,IAAI,OAAO,SAAA,EAAW;AACtB,IAAA,IAAI,MAAA,CAAO,WAAW,QAAA,EAAU,WAAA,EAAA;AAChC,IAAA,MAAM,GAAA,CAAI,YAAY,WAAA,CAAY,SAAA;AAAA,MAChC,EAAE,MAAA,EAAQ,CAAA,CAAE,QAAQ,IAAA,EAAM,CAAA,CAAE,KAAK,IAAA,EAAK;AAAA,MACtC;AAAA,QACE,IAAA,EAAM;AAAA,UACJ,QAAQ,CAAA,CAAE,MAAA;AAAA,UACV,YAAY,CAAA,CAAE,UAAA;AAAA,UACd,IAAA,EAAM,EAAE,IAAA,CAAK,IAAA;AAAA,UACb,SAAA,EAAW,EAAE,IAAA,CAAK,KAAA;AAAA,UAClB,QAAQ,MAAA,CAAO,MAAA;AAAA,UACf,aAAa,MAAA,CAAO,WAAA;AAAA,UACpB,cAAc,MAAA,CAAO,YAAA;AAAA,UACrB,KAAA,sBAAW,IAAA;AAAK;AAClB,OACF;AAAA,MACA,EAAE,QAAQ,IAAA;AAAK,KACjB;AAAA,EACF;AAEA,EAAA,IAAI,GAAA,GAAM,CAAA;AACV,EAAA,MAAM,OAAA,CAAQ,GAAA;AAAA,IACZ,KAAA,CAAM,IAAA,CAAK,EAAE,MAAA,EAAQ,IAAA,CAAK,GAAA,CAAI,eAAA,EAAiB,QAAA,CAAS,MAAM,CAAA,EAAE,EAAG,YAAY;AAC7E,MAAA,OAAO,GAAA,GAAM,SAAS,MAAA,EAAQ;AAC5B,QAAA,MAAM,EAAA,GAAK,GAAA,EAAA;AACX,QAAA,MAAM,WAAA,CAAY,QAAA,CAAS,EAAE,CAAE,CAAA;AAAA,MACjC;AAAA,IACF,CAAC;AAAA,GACH;AAEA,EAAA,OAAO,EAAE,GAAA,EAAK,IAAA,EAAM,WAAA,EAAa,QAAA,CAAS,QAAQ,WAAA,EAAY;AAChE;AAQA,SAAS,cAAA,CAAe,KAAoB,GAAA,EAAwD;AAClG,EAAA,MAAM,OAAA,uBAAc,GAAA,EAAY;AAChC,EAAA,MAAM,QAAA,GAAW,IAAI,MAAA,CAAO,aAAA;AAC5B,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,KAAA,MAAW,CAAA,IAAK,OAAO,IAAA,CAAK,QAAQ,GAAG,OAAA,CAAQ,GAAA,CAAI,CAAA,CAAE,WAAA,EAAa,CAAA;AAAA,EACpE;AACA,EAAA,MAAM,UAAA,GAAa,GAAA,CAAI,MAAA,CAAO,YAAA,EAAc,KAAA,GACxC,cAAc,GAAA,CAAI,MAAA,CAAO,YAAA,CAAa,KAAK,CAAA,GAC3C,IAAA;AACJ,EAAA,IAAI,UAAA,EAAY,OAAA,CAAQ,GAAA,CAAI,UAAU,CAAA;AACtC,EAAA,MAAM,SAAA,GAAY,GAAA,CAAI,MAAA,CAAO,yBAAA,EAA2B,KAAA,GACpD,cAAc,GAAA,CAAI,MAAA,CAAO,yBAAA,CAA0B,KAAK,CAAA,GACxD,IAAA;AACJ,EAAA,IAAI,SAAA,EAAW,OAAA,CAAQ,GAAA,CAAI,SAAS,CAAA;AAKpC,EAAA,OAAO;AAAA,IACL,OAAA,EAAS,KAAA,CAAM,IAAA,CAAK,OAAO,CAAA;AAAA,IAC3B,GAAA,EAAA,CAAM,GAAA,CAAI,YAAA,IAAgB,EAAC,EAAG,MAAA,CAAO,CAAC,EAAA,KAAOC,oBAAA,CAAI,IAAA,CAAK,EAAE,CAAA,KAAM,CAAC;AAAA,GACjE;AACF;AAYA,SAAS,cAAA,CAAe,MAAA,EAAgB,IAAA,EAAuB,QAAA,EAAiC;AAC9F,EAAA,IAAI,SAAS,IAAA,EAAM;AACjB,IAAA,MAAM,CAAA,GAAIA,oBAAA,CAAI,IAAA,CAAK,MAAM,CAAA;AACzB,IAAA,IAAI,CAAA,KAAM,GAAG,OAAO,CAAA,EAAG,YAAY,MAAM,CAAC,IAAI,QAAQ,CAAA,CAAA;AACtD,IAAA,IAAI,CAAA,KAAM,GAAG,OAAO,CAAA,EAAG,mBAAmB,MAAM,CAAC,IAAI,QAAQ,CAAA,CAAA;AAC7D,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,MAAM,SAAS,sBAAA,CAAuB,GAAA,CAAI,QAAQ,CAAA,GAAI,iBAAA,CAAkB,MAAM,CAAA,GAAI,MAAA;AAClF,EAAA,OAAO,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,QAAQ,CAAA,CAAA;AAC9B;AAcA,IAAM,mBAAA,mBAAsB,IAAI,GAAA,CAAI,CAAC,WAAA,EAAa,YAAY,UAAA,EAAY,WAAA,EAAa,YAAA,EAAc,cAAc,CAAC,CAAA;AAEpH,eAAe,UAAA,CAAW,UAAoB,KAAA,EAAqC;AACjF,EAAA,IAAI;AACF,IAAA,MAAM,OAAA,GAAU,MAAM,QAAA,CAAS,QAAA,CAAS,KAAK,CAAA;AAC7C,IAAA,OAAO,iBAAiB,OAAO,CAAA;AAAA,EACjC,SAAS,GAAA,EAAU;AACjB,IAAA,MAAM,OAAO,GAAA,EAAK,IAAA;AAElB,IAAA,IAAI,IAAA,KAAS,WAAA,IAAe,IAAA,KAAS,SAAA,EAAW;AAC9C,MAAA,OAAO,EAAE,MAAA,EAAQ,OAAA,EAAS,aAAa,EAAC,EAAG,cAAc,IAAA,EAAK;AAAA,IAChE;AAIA,IAAA,IAAI,IAAA,IAAQ,mBAAA,CAAoB,GAAA,CAAI,IAAI,CAAA,EAAG;AACzC,MAAA,OAAO;AAAA,QACL,SAAA,EAAW,IAAA;AAAA,QACX,MAAA,EAAQ,OAAA;AAAA,QACR,aAAa,EAAC;AAAA,QACd,YAAA,EAAc,MAAA,CAAO,GAAA,EAAK,OAAA,IAAW,GAAG;AAAA,OAC1C;AAAA,IACF;AACA,IAAA,OAAO;AAAA,MACL,MAAA,EAAQ,OAAA;AAAA,MACR,aAAa,EAAC;AAAA,MACd,YAAA,EAAc,MAAA,CAAO,GAAA,EAAK,OAAA,IAAW,GAAG;AAAA,KAC1C;AAAA,EACF;AACF;AAEO,SAAS,iBAAiB,OAAA,EAAgC;AAC/D,EAAA,IAAI,CAAC,OAAA,IAAW,OAAA,CAAQ,MAAA,KAAW,CAAA,EAAG;AACpC,IAAA,OAAO,EAAE,MAAA,EAAQ,OAAA,EAAS,aAAa,EAAC,EAAG,cAAc,IAAA,EAAK;AAAA,EAChE;AAIA,EAAA,MAAM,QAAA,GAAW,QAAQ,MAAA,CAAO,CAAC,MAAM,CAAA,CAAE,UAAA,CAAW,cAAc,CAAC,CAAA;AACnE,EAAA,IAAI,QAAA,CAAS,MAAA,KAAW,OAAA,CAAQ,MAAA,EAAQ;AACtC,IAAA,OAAO;AAAA,MACL,MAAA,EAAQ,OAAA;AAAA,MACR,WAAA,EAAa,OAAA;AAAA,MACb,YAAA,EAAc,CAAA,gCAAA,EAAmC,OAAA,CAAQ,IAAA,CAAK,IAAI,CAAC,CAAA;AAAA,KACrE;AAAA,EACF;AACA,EAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,UAAA,CAAW,MAAM,CAAA,IAAK,CAAC,CAAA,CAAE,UAAA,CAAW,cAAc,CAAC,CAAA;AAC1F,EAAA,IAAI,MAAA,CAAO,SAAS,CAAA,EAAG;AACrB,IAAA,OAAO,EAAE,MAAA,EAAQ,QAAA,EAAU,WAAA,EAAa,OAAA,EAAS,cAAc,IAAA,EAAK;AAAA,EACtE;AACA,EAAA,OAAO,EAAE,MAAA,EAAQ,OAAA,EAAS,WAAA,EAAa,OAAA,EAAS,cAAc,IAAA,EAAK;AACrE;AAEO,SAAS,YAAY,EAAA,EAAoB;AAC9C,EAAA,OAAO,GAAG,KAAA,CAAM,GAAG,EAAE,OAAA,EAAQ,CAAE,KAAK,GAAG,CAAA;AACzC;AAWO,SAAS,mBAAmB,EAAA,EAAoB;AAErD,EAAA,MAAM,OAAA,GAAU,wCAAA,CAAyC,IAAA,CAAK,EAAE,CAAA;AAChE,EAAA,IAAI,UAAA,GAAa,EAAA;AACjB,EAAA,IAAI,OAAA,EAAS;AACX,IAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,CAAC,CAAA,CAAG,KAAA,CAAM,GAAG,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,KAAM,MAAA,CAAO,CAAC,CAAC,CAAA;AAC1D,IAAA,IAAI,MAAA,CAAO,MAAA,KAAW,CAAA,IAAK,MAAA,CAAO,KAAA,CAAM,CAAC,CAAA,KAAM,CAAA,IAAK,CAAA,IAAK,CAAA,IAAK,GAAG,CAAA,EAAG;AAClE,MAAA,MAAM,EAAA,GAAA,CAAO,MAAA,CAAO,CAAC,CAAA,IAAM,CAAA,GAAK,MAAA,CAAO,CAAC,CAAA,EAAI,QAAA,CAAS,EAAE,CAAA,CAAE,QAAA,CAAS,GAAG,GAAG,CAAA;AACxE,MAAA,MAAM,EAAA,GAAA,CAAO,MAAA,CAAO,CAAC,CAAA,IAAM,CAAA,GAAK,MAAA,CAAO,CAAC,CAAA,EAAI,QAAA,CAAS,EAAE,CAAA,CAAE,QAAA,CAAS,GAAG,GAAG,CAAA;AACxE,MAAA,UAAA,GAAa,EAAA,CAAG,MAAM,CAAA,EAAG,OAAA,CAAQ,KAAK,CAAA,GAAI,GAAA,GAAM,KAAK,GAAA,GAAM,EAAA;AAAA,IAC7D;AAAA,EACF;AAGA,EAAA,MAAM,KAAA,GAAQ,UAAA,CAAW,KAAA,CAAM,IAAI,CAAA;AACnC,EAAA,IAAI,MAAA;AACJ,EAAA,IAAI,KAAA,CAAM,WAAW,CAAA,EAAG;AACtB,IAAA,MAAA,GAAS,KAAA,CAAM,CAAC,CAAA,CAAG,KAAA,CAAM,GAAG,CAAA;AAAA,EAC9B,CAAA,MAAO;AACL,IAAA,MAAM,IAAA,GAAO,MAAM,CAAC,CAAA,CAAG,MAAM,GAAG,CAAA,CAAE,OAAO,OAAO,CAAA;AAChD,IAAA,MAAM,KAAA,GAAQ,MAAM,CAAC,CAAA,CAAG,MAAM,GAAG,CAAA,CAAE,OAAO,OAAO,CAAA;AACjD,IAAA,MAAM,OAAA,GAAU,CAAA,GAAI,IAAA,CAAK,MAAA,GAAS,KAAA,CAAM,MAAA;AACxC,IAAA,MAAA,GAAS,CAAC,GAAG,IAAA,EAAM,GAAG,KAAA,CAAM,OAAO,CAAA,CAAE,IAAA,CAAK,GAAG,CAAA,EAAG,GAAG,KAAK,CAAA;AAAA,EAC1D;AACA,EAAA,IAAI,MAAA,CAAO,WAAW,CAAA,EAAG;AACvB,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,gCAAA,EAAmC,EAAE,CAAA,EAAA,EAAK,MAAA,CAAO,MAAM,CAAA,CAAE,CAAA;AAAA,EAC3E;AACA,EAAA,MAAM,MAAA,GAAS,MAAA,CAAO,GAAA,CAAI,CAAC,MAAM,CAAA,CAAE,WAAA,EAAY,CAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAC,CAAA,CAAE,KAAK,EAAE,CAAA;AAC1E,EAAA,OAAO,OAAO,KAAA,CAAM,EAAE,EAAE,OAAA,EAAQ,CAAE,KAAK,GAAG,CAAA;AAC5C;AAQA,SAAS,kBAAkB,MAAA,EAAwB;AACjD,EAAA,MAAM,MAAA,GAASC,oBAAA,CAAI,KAAA,CAAM,MAAM,CAAA;AAC/B,EAAA,IAAI,QAAA,IAAY,MAAA,IAAU,MAAA,CAAO,MAAA,SAAe,MAAA,CAAO,MAAA;AACvD,EAAA,OAAO,MAAA;AACT;;;ACvTA,IAAM,eAAA,GAAkB,qCAAA;AACxB,IAAM,eAAA,GAAkB,gDAAA;AACxB,IAAM,gBAAA,GAAmB,IAAA;AAIzB,eAAe,iBAAiB,OAAA,EAAkB,GAAA,EAAa,OAAoB,EAAC,EAAG,YAAY,gBAAA,EAAqC;AACtI,EAAA,MAAM,GAAA,GAAM,IAAI,eAAA,EAAgB;AAChC,EAAA,MAAM,IAAI,UAAA,CAAW,MAAM,GAAA,CAAI,KAAA,IAAS,SAAS,CAAA;AACjD,EAAA,IAAI;AACF,IAAA,OAAO,MAAM,QAAQ,GAAA,EAAK,EAAE,GAAG,IAAA,EAAM,MAAA,EAAQ,GAAA,CAAI,MAAA,EAAQ,CAAA;AAAA,EAC3D,CAAA,SAAE;AACA,IAAA,YAAA,CAAa,CAAC,CAAA;AAAA,EAChB;AACF;AA6BO,SAAS,sBAAA,CACd,GAAA,EACA,OAAA,GAAmB,UAAA,CAAW,KAAA,EACZ;AAClB,EAAA,IAAI,MAAA,GAA4D,IAAA;AAEhE,EAAA,eAAe,cAAA,GAAkC;AAC/C,IAAA,IAAI,MAAA,IAAU,OAAO,SAAA,GAAY,IAAA,CAAK,KAAI,GAAI,CAAA,GAAI,KAAK,GAAA,EAAM;AAC3D,MAAA,OAAO,MAAA,CAAO,WAAA;AAAA,IAChB;AACA,IAAA,MAAM,IAAA,GAAO,IAAI,eAAA,CAAgB;AAAA,MAC/B,WAAW,GAAA,CAAI,QAAA;AAAA,MACf,eAAe,GAAA,CAAI,YAAA;AAAA,MACnB,eAAe,GAAA,CAAI,YAAA;AAAA,MACnB,UAAA,EAAY;AAAA,KACb,CAAA;AACD,IAAA,MAAM,GAAA,GAAM,MAAM,gBAAA,CAAiB,OAAA,EAAS,eAAA,EAAiB;AAAA,MAC3D,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS,EAAE,cAAA,EAAgB,mCAAA,EAAoC;AAAA,MAC/D,IAAA,EAAM,KAAK,QAAA;AAAS,KACrB,CAAA;AACD,IAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,uCAAA,EAA0C,GAAA,CAAI,MAAM,IAAI,MAAM,QAAA,CAAS,GAAG,CAAC,CAAA,CAAE,CAAA;AAAA,IAC/F;AACA,IAAA,MAAM,IAAA,GAAQ,MAAM,GAAA,CAAI,IAAA,EAAK;AAC7B,IAAA,MAAA,GAAS;AAAA,MACP,aAAa,IAAA,CAAK,YAAA;AAAA,MAClB,SAAA,EAAW,IAAA,CAAK,GAAA,EAAI,GAAI,KAAK,UAAA,GAAa;AAAA,KAC5C;AACA,IAAA,OAAO,MAAA,CAAO,WAAA;AAAA,EAChB;AAEA,EAAA,eAAe,UAAaC,KAAAA,EAA0B;AACpD,IAAA,MAAM,KAAA,GAAQ,MAAM,cAAA,EAAe;AACnC,IAAA,MAAM,GAAA,GAAM,MAAM,gBAAA,CAAiB,OAAA,EAAS,GAAG,eAAe,CAAA,EAAGA,KAAI,CAAA,CAAA,EAAI;AAAA,MACvE,MAAA,EAAQ,KAAA;AAAA,MACR,OAAA,EAAS,EAAE,aAAA,EAAe,CAAA,OAAA,EAAU,KAAK,CAAA,CAAA;AAAG,KAC7C,CAAA;AACD,IAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,eAAA,EAAkBA,KAAI,CAAA,SAAA,EAAY,GAAA,CAAI,MAAM,CAAA,CAAA,EAAI,MAAM,QAAA,CAAS,GAAG,CAAC,CAAA,CAAE,CAAA;AAAA,IACvF;AACA,IAAA,OAAQ,MAAM,IAAI,IAAA,EAAK;AAAA,EACzB;AAEA,EAAA,OAAO;AAAA,IACL,MAAM,WAAA,GAAc;AAClB,MAAA,MAAM,IAAA,GAAO,MAAM,SAAA,CAAsE,UAAU,CAAA;AACnG,MAAA,OAAO,IAAA,CAAK,WAAW,EAAC;AAAA,IAC1B,CAAA;AAAA,IAEA,MAAM,sBAAsB,MAAA,EAAgB;AAI1C,MAAA,MAAM,OAAO,MAAM,SAAA;AAAA,QACjB,CAAA,SAAA,EAAY,kBAAA,CAAmB,MAAM,CAAC,CAAA,wBAAA;AAAA,OACxC;AACA,MAAA,OAAO,IAAA,CAAK,YAAA,GAAe,CAAC,CAAA,IAAK,IAAA;AAAA,IACnC;AAAA,GACF;AACF;AAEA,eAAe,SAAS,GAAA,EAAgC;AACtD,EAAA,IAAI;AACF,IAAA,OAAO,MAAM,IAAI,IAAA,EAAK;AAAA,EACxB,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,WAAA;AAAA,EACT;AACF;AAmBA,eAAsB,iBAAA,CACpB,GAAA,EACA,IAAA,GAA6B,EAAC,EACA;AAC9B,EAAA,MAAM,GAAA,GAAM,IAAI,MAAA,CAAO,UAAA;AACvB,EAAA,IAAI,CAAC,GAAA,EAAK,OAAO,EAAE,GAAA,EAAK,KAAA,EAAO,QAAQ,gBAAA,EAAiB;AAExD,EAAA,MAAM,aAAA,GAAgB,IAAI,aAAA,IAAiB,EAAA;AAC3C,EAAA,IAAI,CAAC,IAAA,CAAK,KAAA,IAAS,aAAA,IAAiB,CAAA,EAAG;AACrC,IAAA,OAAO,EAAE,GAAA,EAAK,KAAA,EAAO,MAAA,EAAQ,UAAA,EAAW;AAAA,EAC1C;AAEA,EAAA,MAAM,SACJ,IAAA,CAAK,MAAA,IAAU,sBAAA,CAAuB,GAAA,EAAK,KAAK,OAAO,CAAA;AACzD,EAAA,MAAM,UAAA,GAAa,cAAA,CAAe,GAAA,EAAK,GAAG,CAAA;AAC1C,EAAA,IAAI,UAAA,CAAW,WAAW,CAAA,EAAG;AAC3B,IAAA,OAAO,EAAE,GAAA,EAAK,KAAA,EAAO,MAAA,EAAQ,YAAA,EAAa;AAAA,EAC5C;AAMA,EAAA,IAAI,OAAA,GAAU,UAAA;AACd,EAAA,IAAI,CAAC,KAAK,KAAA,EAAO;AACf,IAAA,MAAM,SAAS,IAAA,CAAK,GAAA,EAAI,GAAI,aAAA,GAAgB,KAAK,EAAA,GAAK,GAAA;AACtD,IAAA,MAAM,MAAA,GAAS,MAAM,GAAA,CAAI,WAAA,CAAY,oBAClC,IAAA,CAAK,EAAE,MAAA,EAAQ,EAAE,KAAK,UAAA,EAAW,EAAE,EAAG,EAAE,YAAY,EAAE,MAAA,EAAQ,CAAA,EAAG,SAAA,EAAW,CAAA,EAAE,EAAG,CAAA,CACjF,KAAK,EAAE,SAAA,EAAW,EAAA,EAAI,EACtB,KAAA,CAAM,UAAA,CAAW,MAAA,GAAS,CAAC,EAC3B,OAAA,EAAQ;AACX,IAAA,MAAM,YAAA,uBAAmB,GAAA,EAAoB;AAC7C,IAAA,KAAA,MAAW,KAAK,MAAA,EAAQ;AACtB,MAAA,MAAM,KAAK,IAAI,IAAA,CAAK,CAAA,CAAE,SAAS,EAAE,OAAA,EAAQ;AACzC,MAAA,MAAM,GAAA,GAAM,YAAA,CAAa,GAAA,CAAI,CAAA,CAAE,MAAM,CAAA,IAAK,CAAA;AAC1C,MAAA,IAAI,KAAK,GAAA,EAAK,YAAA,CAAa,GAAA,CAAI,CAAA,CAAE,QAAQ,EAAE,CAAA;AAAA,IAC7C;AACA,IAAA,OAAA,GAAU,UAAA,CAAW,OAAO,CAAC,CAAA,KAAA,CAAO,aAAa,GAAA,CAAI,CAAC,CAAA,IAAK,CAAA,IAAK,MAAM,CAAA;AACtE,IAAA,IAAI,OAAA,CAAQ,WAAW,CAAA,EAAG;AACxB,MAAA,OAAO,EAAE,GAAA,EAAK,KAAA,EAAO,MAAA,EAAQ,SAAA,EAAU;AAAA,IACzC;AAAA,EACF;AAIA,EAAA,MAAM,OAAA,GAAU,MAAM,OAAA,CAAQ,GAAA;AAAA,IAC5B,OAAA,CAAQ,GAAA,CAAI,OAAO,MAAA,KAAW;AAC5B,MAAA,IAAI;AACF,QAAA,MAAM,IAAA,GAAO,MAAM,MAAA,CAAO,qBAAA,CAAsB,MAAM,CAAA;AACtD,QAAA,OAAO,EAAE,MAAA,EAAQ,IAAA,EAAM,KAAA,EAAO,IAAA,EAAqB;AAAA,MACrD,SAAS,GAAA,EAAU;AACjB,QAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,qCAAA,EAAwC,MAAM,CAAA,CAAA,EAAI,GAAG,CAAA;AACnE,QAAA,OAAO,EAAE,MAAA,EAAQ,IAAA,EAAM,IAAA,EAAM,OAAO,GAAA,EAAa;AAAA,MACnD;AAAA,IACF,CAAC;AAAA,GACH;AAEA,EAAA,IAAI,OAAA,GAAU,CAAA;AACd,EAAA,MAAM,iBAA2B,EAAC;AAClC,EAAA,KAAA,MAAW,EAAE,MAAA,EAAQ,IAAA,EAAK,IAAK,OAAA,EAAS;AACtC,IAAA,IAAI,CAAC,IAAA,EAAM;AACX,IAAA,MAAM,QAAA,GAAW,UAAA,CAAW,MAAA,EAAQ,IAAI,CAAA;AACxC,IAAA,IAAI,CAAC,QAAA,EAAU;AACf,IAAA,OAAA,EAAA;AAEA,IAAA,MAAM,GAAA,CAAI,YAAY,mBAAA,CAAoB,SAAA;AAAA,MACxC,EAAE,MAAA,EAAQ,QAAA,CAAS,MAAA,EAAQ,IAAA,EAAM,SAAS,IAAA,EAAK;AAAA,MAC/C,EAAE,MAAM,QAAA,EAAS;AAAA,MACjB,EAAE,QAAQ,IAAA;AAAK,KACjB;AAEA,IAAA,IAAI,QAAA,CAAS,qBAAqB,KAAA,EAAO;AAKvC,MAAA,MAAM,WAAA,GAAc,cAAA,CAAe,GAAA,EAAK,MAAM,CAAA;AAC9C,MAAA,KAAA,MAAW,QAAQ,WAAA,EAAa;AAC9B,QAAA,MAAM,UAAU,MAAM,UAAA,CAAW,GAAA,EAAK,MAAA,EAAQ,MAAM,QAAQ,CAAA;AAC5D,QAAA,IAAI,SAAS,cAAA,CAAe,IAAA,CAAK,GAAG,MAAM,CAAA,CAAA,EAAI,IAAI,CAAA,CAAE,CAAA;AAAA,MACtD;AAAA,IACF;AAAA,EACF;AAEA,EAAA,OAAO,EAAE,GAAA,EAAK,IAAA,EAAM,OAAA,EAAS,cAAA,EAAe;AAC9C;AAEA,SAAS,cAAA,CAAe,KAAoB,MAAA,EAAsD;AAChG,EAAA,MAAM,QAAA,GAAW,GAAA,CAAI,MAAA,CAAO,aAAA,IAAiB,EAAC;AAC9C,EAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,MAAA,CAAO,WAAA,EAAa,CAAA;AAC3C,EAAA,IAAI,CAAC,KAAA,EAAO,OAAO,EAAC;AACpB,EAAA,IAAI,MAAM,IAAA,KAAS,MAAA,EAAQ,OAAO,CAAC,aAAa,eAAe,CAAA;AAC/D,EAAA,OAAO,CAAC,MAAM,IAAI,CAAA;AACpB;AAEA,SAAS,cAAA,CAAe,KAAoB,GAAA,EAAiC;AAC3E,EAAA,IAAI,GAAA,CAAI,OAAA,IAAW,GAAA,CAAI,OAAA,CAAQ,SAAS,CAAA,EAAG;AACzC,IAAA,OAAO,IAAI,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,aAAa,CAAA;AAAA,EAC/C;AACA,EAAA,MAAM,GAAA,uBAAU,GAAA,EAAY;AAC5B,EAAA,MAAM,QAAA,GAAW,IAAI,MAAA,CAAO,aAAA;AAC5B,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,KAAA,MAAW,CAAA,IAAK,OAAO,IAAA,CAAK,QAAQ,GAAG,GAAA,CAAI,GAAA,CAAI,CAAA,CAAE,WAAA,EAAa,CAAA;AAAA,EAChE;AACA,EAAA,MAAM,CAAA,GAAI,GAAA,CAAI,MAAA,CAAO,YAAA,EAAc,KAAA,GAAQ,cAAc,GAAA,CAAI,MAAA,CAAO,YAAA,CAAa,KAAK,CAAA,GAAI,IAAA;AAC1F,EAAA,IAAI,CAAA,EAAG,GAAA,CAAI,GAAA,CAAI,CAAC,CAAA;AAChB,EAAA,MAAM,CAAA,GAAI,GAAA,CAAI,MAAA,CAAO,yBAAA,EAA2B,KAAA,GAC5C,cAAc,GAAA,CAAI,MAAA,CAAO,yBAAA,CAA0B,KAAK,CAAA,GACxD,IAAA;AACJ,EAAA,IAAI,CAAA,EAAG,GAAA,CAAI,GAAA,CAAI,CAAC,CAAA;AAChB,EAAA,OAAO,KAAA,CAAM,KAAK,GAAG,CAAA;AACvB;AAEA,SAAS,UAAA,CAAW,QAAgB,IAAA,EAAiD;AAKnF,EAAA,MAAM,CAAA,GAAI,0BAAA,CAA2B,IAAA,CAAK,IAAA,CAAK,QAAQ,EAAE,CAAA;AACzD,EAAA,IAAI,CAAC,CAAA,EAAG;AACN,IAAA,OAAA,CAAQ,MAAM,CAAA,iCAAA,EAAoC,MAAM,CAAA,wBAAA,EAA2B,IAAA,CAAK,IAAI,CAAA,iBAAA,CAAc,CAAA;AAC1G,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,MAAM,QAAA,GAAW,EAAE,CAAC,CAAA;AACpB,EAAA,MAAM,OAAO,CAAA,EAAG,QAAA,CAAS,MAAM,CAAA,EAAG,CAAC,CAAC,CAAA,CAAA,EAAI,QAAA,CAAS,KAAA,CAAM,CAAA,EAAG,CAAC,CAAC,CAAA,CAAA,EAAI,SAAS,KAAA,CAAM,CAAA,EAAG,CAAC,CAAC,CAAA,CAAA;AAEpF,EAAA,OAAO;AAAA,IACL,MAAA;AAAA,IACA,IAAA;AAAA,IACA,gBAAA,EAAkB,KAAK,gBAAA,IAAoB,IAAA;AAAA,IAC3C,eAAe,IAAA,CAAK,aAAA,GAChB,KAAK,aAAA,CAAc,GAAA,CAAI,CAAC,CAAA,MAAO;AAAA,MAC7B,YAAY,CAAA,CAAE,UAAA;AAAA,MACd,OAAA,EAAS,OAAO,CAAA,CAAE,OAAA,KAAY,WAAW,MAAA,CAAO,CAAA,CAAE,OAAO,CAAA,GAAI,CAAA,CAAE;AAAA,MAC/D,CAAA,GACF,IAAA;AAAA,IACJ,qBAAA,EAAuB,KAAK,qBAAA,IAAyB,IAAA;AAAA,IACrD,eAAA,EAAiB,KAAK,eAAA,IAAmB,IAAA;AAAA,IACzC,gBAAA,EAAkB,KAAK,gBAAA,IAAoB,IAAA;AAAA,IAC3C,iBAAA,EAAmB,KAAK,iBAAA,IAAqB,IAAA;AAAA,IAC7C,uBAAA,EAAyB,KAAK,uBAAA,IAA2B,IAAA;AAAA,IACzD,sBAAA,EAAwB,KAAK,sBAAA,IAA0B,IAAA;AAAA,IACvD,cAAA,EAAgB,KAAK,cAAA,IAAkB,IAAA;AAAA,IACvC,mBAAA,EAAqB,KAAK,mBAAA,IAAuB,IAAA;AAAA,IACjD,SAAA,sBAAe,IAAA;AAAK,GACtB;AACF;AAOA,eAAe,UAAA,CACb,GAAA,EACA,MAAA,EACA,IAAA,EACA,QAAA,EACkB;AAClB,EAAA,MAAM,EAAA,GAAK,cAAA,CAAe,MAAA,EAAQ,IAAI,CAAA;AACtC,EAAA,MAAM,MAAA,GAAS,CAAA,yBAAA,EAA4B,MAAM,CAAA,qBAAA,EAAwB,SAAS,IAAI,CAAA,CAAA;AAItF,EAAA,MAAM,KAAA,GAAQ,MAAM,GAAA,CAAI,WAAA,CAAY,OAAO,OAAA,CAAQ,EAAE,GAAA,EAAK,EAAA,EAAI,CAAA;AAC9D,EAAA,IAAI,KAAA,EAAO,WAAW,SAAA,EAAW;AAC/B,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,GAAA,CAAI,YAAY,MAAA,CAAO,SAAA;AAAA,IAC3B,EAAE,KAAK,EAAA,EAAG;AAAA,IACV;AAAA,MACE,IAAA,EAAM;AAAA,QACJ,MAAA,EAAQ,SAAA;AAAA,QACR,SAAA,sBAAe,IAAA,EAAK;AAAA,QACpB,aAAA,EAAe,MAAA;AAAA,QACf,SAAA,sBAAe,IAAA;AAAK,OACtB;AAAA,MACA,YAAA,EAAc;AAAA,QACZ,GAAA,EAAK,EAAA;AAAA,QACL,YAAA,EAAc,MAAA;AAAA,QACd,IAAA;AAAA,QACA,eAAA,sBAAqB,IAAA,EAAK;AAAA,QAC1B,gBAAA,EAAkB,GAAA,CAAI,MAAA,CAAO,cAAA,CAAe,gBAAgB,EAAA,GAAK,GAAA;AAAA,QACjE,iBAAA,EAAmB,IAAA;AAAA,QACnB,QAAA,EAAU,EAAE,IAAA,EAAM,CAAA,EAAG,WAAW,CAAA,EAAG,OAAA,EAAS,CAAA,EAAG,WAAA,EAAa,GAAG,WAAA,EAAa,CAAA,EAAG,UAAA,EAAY,CAAA,EAAG,cAAc,CAAA,EAAE;AAAA,QAC9G,KAAA,EAAO,EAAE,UAAA,EAAY,CAAA,EAAG,gBAAgB,CAAA,EAAG,aAAA,EAAe,CAAA,EAAG,WAAA,EAAa,CAAA;AAAE;AAC9E,KACF;AAAA,IACA,EAAE,QAAQ,IAAA;AAAK,GACjB;AACA,EAAA,IAAI,GAAA,CAAI,OAAO,oBAAA,EAAsB;AACnC,IAAA,IAAI;AACF,MAAA,MAAM,GAAA,CAAI,MAAA,CAAO,oBAAA,CAAqB,EAAE,MAAA,EAAQ,KAAA,EAAO,EAAE,qBAAA,EAAuB,QAAA,CAAS,qBAAA,IAAyB,CAAA,EAAE,EAAG,CAAA;AAAA,IACzH,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF;AACA,EAAA,OAAO,IAAA;AACT;;;AC9UA,IAAM,aAAA,GAAgB,4CAAA;AACtB,IAAMC,iBAAAA,GAAmB,GAAA;AAgBzB,eAAsB,WAAA,CACpB,GAAA,EACA,IAAA,GAAuB,EAAC,EACA;AACxB,EAAA,MAAM,GAAA,GAAM,IAAI,MAAA,CAAO,IAAA;AACvB,EAAA,IAAI,CAAC,KAAK,SAAA,EAAW,OAAO,EAAE,GAAA,EAAK,KAAA,EAAO,QAAQ,gBAAA,EAAiB;AAEnE,EAAA,MAAM,aAAA,GAAgB,IAAI,aAAA,IAAiB,EAAA;AAC3C,EAAA,IAAI,CAAC,IAAA,CAAK,KAAA,IAAS,aAAA,IAAiB,CAAA,SAAU,EAAE,GAAA,EAAK,KAAA,EAAO,MAAA,EAAQ,UAAA,EAAW;AAE/E,EAAA,IAAI,CAAC,KAAK,KAAA,EAAO;AACf,IAAA,MAAM,SAAS,MAAM,GAAA,CAAI,YAAY,aAAA,CAClC,IAAA,CAAK,EAAE,CAAA,CACP,IAAA,CAAK,EAAE,WAAW,EAAA,EAAI,EACtB,KAAA,CAAM,CAAC,EACP,OAAA,EAAQ;AACX,IAAA,IAAI,MAAA,CAAO,CAAC,CAAA,EAAG;AACb,MAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,GAAA,EAAI,GAAI,IAAI,IAAA,CAAK,MAAA,CAAO,CAAC,CAAA,CAAE,SAAS,CAAA,CAAE,OAAA,EAAQ;AACjE,MAAA,IAAI,KAAA,GAAQ,aAAA,GAAgB,EAAA,GAAK,EAAA,GAAK,GAAA,EAAM;AAC1C,QAAA,OAAO,EAAE,GAAA,EAAK,KAAA,EAAO,MAAA,EAAQ,SAAA,EAAU;AAAA,MACzC;AAAA,IACF;AAAA,EACF;AAEA,EAAA,MAAM,OAAA,GAAU,IAAA,CAAK,OAAA,IAAW,UAAA,CAAW,KAAA;AAC3C,EAAA,MAAM,MAAM,CAAA,EAAG,aAAa,QAAQ,kBAAA,CAAmB,GAAA,CAAI,SAAS,CAAC,CAAA,CAAA;AACrE,EAAA,MAAM,GAAA,GAAM,IAAI,eAAA,EAAgB;AAChC,EAAA,MAAM,IAAI,UAAA,CAAW,MAAM,GAAA,CAAI,KAAA,IAASA,iBAAgB,CAAA;AACxD,EAAA,IAAI,GAAA;AACJ,EAAA,IAAI;AACF,IAAA,GAAA,GAAM,MAAM,QAAQ,GAAA,EAAK,EAAE,QAAQ,KAAA,EAAO,MAAA,EAAQ,GAAA,CAAI,MAAA,EAAQ,CAAA;AAAA,EAChE,SAAS,GAAA,EAAU;AAEjB,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,wBAAA,EAA2B,SAAA,CAAU,MAAA,CAAO,GAAA,EAAK,OAAA,IAAW,GAAG,CAAA,EAAG,GAAA,CAAI,SAAS,CAAC,CAAA,CAAE,CAAA;AAAA,EACpG,CAAA,SAAE;AACA,IAAA,YAAA,CAAa,CAAC,CAAA;AAAA,EAChB;AACA,EAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,wBAAA,EAA2B,GAAA,CAAI,MAAM,CAAA,CAAA,EAAI,SAAA,CAAU,MAAMC,SAAAA,CAAS,GAAG,CAAA,EAAG,GAAA,CAAI,SAAS,CAAC,CAAA,CAAE,CAAA;AAAA,EAC1G;AACA,EAAA,MAAM,GAAA,GAAM,MAAM,GAAA,CAAI,IAAA,EAAK;AAC3B,EAAA,MAAM,IAAA,GAAO,aAAa,GAAG,CAAA;AAE7B,EAAA,MAAM,QAAA,GAAW,IAAI,GAAA,EAAK,MAAA,GAAS,IAAI,GAAA,CAAI,GAAA,CAAI,GAAG,CAAA,GAAI,IAAA;AACtD,EAAA,MAAM,GAAA,uBAAU,IAAA,EAAK;AACrB,EAAA,MAAM,GAAA,GAAM,IAAA,CACT,MAAA,CAAO,CAAC,QAAQ,CAAC,QAAA,IAAY,QAAA,CAAS,GAAA,CAAI,IAAI,EAAE,CAAC,CAAA,CACjD,GAAA,CAAI,CAAC,GAAA,MAAS;AAAA,IACb,SAAA,EAAW;AAAA,MACT,QAAQ,EAAE,EAAA,EAAI,IAAI,EAAA,EAAI,aAAA,EAAe,IAAI,aAAA,EAAc;AAAA,MACvD,MAAA,EAAQ,EAAE,IAAA,EAAM,EAAE,GAAG,GAAA,EAAK,SAAA,EAAW,KAAI,EAAE;AAAA,MAC3C,MAAA,EAAQ;AAAA;AACV,GACF,CAAE,CAAA;AACJ,EAAA,IAAI,SAAA,GAAY,CAAA;AAChB,EAAA,IAAI,GAAA,CAAI,SAAS,CAAA,EAAG;AAClB,IAAA,MAAM,CAAA,GAAI,MAAM,GAAA,CAAI,WAAA,CAAY,aAAA,CAAc,UAAU,GAAA,EAAK,EAAE,OAAA,EAAS,KAAA,EAAO,CAAA;AAC/E,IAAA,SAAA,GAAA,CAAa,CAAA,CAAE,aAAA,IAAiB,CAAA,KAAM,CAAA,CAAE,aAAA,IAAiB,CAAA,CAAA;AAAA,EAC3D;AAEA,EAAA,OAAO,EAAE,GAAA,EAAK,IAAA,EAAM,YAAY,IAAA,CAAK,MAAA,EAAQ,eAAe,SAAA,EAAU;AACxE;AAEA,SAAS,SAAA,CAAU,GAAW,GAAA,EAAqB;AACjD,EAAA,IAAI,CAAC,KAAK,OAAO,CAAA;AACjB,EAAA,OAAO,CAAA,CAAE,KAAA,CAAM,GAAG,CAAA,CAAE,IAAA,CAAK,YAAY,CAAA,CAAE,KAAA,CAAM,kBAAA,CAAmB,GAAG,CAAC,CAAA,CAAE,KAAK,YAAY,CAAA;AACzF;AAEA,eAAeA,UAAS,GAAA,EAAgC;AACtD,EAAA,IAAI;AAAE,IAAA,OAAO,MAAM,IAAI,IAAA,EAAK;AAAA,EAAE,CAAA,CAAA,MAAQ;AAAE,IAAA,OAAO,WAAA;AAAA,EAAY;AAC7D;AA6BO,SAAS,aAAa,GAAA,EAA8B;AACzD,EAAA,MAAM,MAAuB,EAAC;AAC9B,EAAA,KAAA,MAAW,GAAA,IAAO,GAAA,CAAI,KAAA,CAAM,OAAO,CAAA,EAAG;AACpC,IAAA,IAAI,CAAC,GAAA,CAAI,IAAA,EAAK,EAAG;AACjB,IAAA,MAAM,MAAA,GAAS,YAAY,GAAG,CAAA;AAC9B,IAAA,IAAI,MAAA,CAAO,SAAS,CAAA,EAAG;AACvB,IAAA,MAAM,MAAA,GAAS,SAAS,MAAM,CAAA;AAC9B,IAAA,IAAI,MAAA,EAAQ,GAAA,CAAI,IAAA,CAAK,MAAM,CAAA;AAAA,EAC7B;AACA,EAAA,OAAO,GAAA;AACT;AAEA,SAAS,YAAY,GAAA,EAAuB;AAC1C,EAAA,MAAM,MAAgB,EAAC;AACvB,EAAA,IAAI,GAAA,GAAM,EAAA;AACV,EAAA,IAAI,QAAA,GAAW,KAAA;AACf,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,GAAA,CAAI,QAAQ,CAAA,EAAA,EAAK;AACnC,IAAA,MAAM,EAAA,GAAK,IAAI,CAAC,CAAA;AAChB,IAAA,IAAI,QAAA,EAAU;AACZ,MAAA,IAAI,OAAO,GAAA,EAAK;AACd,QAAA,IAAI,GAAA,CAAI,CAAA,GAAI,CAAC,CAAA,KAAM,GAAA,EAAK;AACtB,UAAA,GAAA,IAAO,GAAA;AACP,UAAA,CAAA,EAAA;AAAA,QACF,CAAA,MAAO;AACL,UAAA,QAAA,GAAW,KAAA;AAAA,QACb;AAAA,MACF,CAAA,MAAO;AACL,QAAA,GAAA,IAAO,EAAA;AAAA,MACT;AAAA,IACF,CAAA,MAAA,IAAW,OAAO,GAAA,EAAK;AACrB,MAAA,QAAA,GAAW,IAAA;AAAA,IACb,CAAA,MAAA,IAAW,OAAO,GAAA,EAAK;AACrB,MAAA,GAAA,CAAI,KAAK,GAAG,CAAA;AACZ,MAAA,GAAA,GAAM,EAAA;AAAA,IACR,CAAA,MAAO;AACL,MAAA,GAAA,IAAO,EAAA;AAAA,IACT;AAAA,EACF;AACA,EAAA,GAAA,CAAI,KAAK,GAAG,CAAA;AACZ,EAAA,OAAO,IAAI,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,MAAM,CAAA;AAChC;AAEA,SAAS,SAAS,MAAA,EAAwC;AACxD,EAAA,MAAM;AAAA,IACJ,EAAA;AAAA,IACA,aAAA;AAAA,IACA,WAAA;AAAA,IACA,YAAA;AAAA,IACA,YAAA;AAAA,IACA,iBAAA;AAAA,IACA,YAAA;AAAA,IACA,aAAA;AAAA,IACA,gBAAA;AAAA,IACA,UAAA;AAAA,IACA;AAAA,GACF,GAAI,MAAA;AAEJ,EAAA,MAAM,KAAA,GAAQ,aAAA,CAAc,aAAA,IAAiB,EAAE,CAAA;AAC/C,EAAA,MAAM,GAAA,GAAM,aAAA,CAAc,WAAA,IAAe,EAAE,CAAA;AAC3C,EAAA,IAAI,CAAC,EAAA,IAAM,CAAC,KAAA,IAAS,CAAC,KAAK,OAAO,IAAA;AAElC,EAAA,OAAO;AAAA,IACL,EAAA;AAAA,IACA,aAAA,EAAe,KAAA;AAAA,IACf,WAAA,EAAa,GAAA;AAAA,IACb,YAAA,EAAc,MAAM,YAAY,CAAA;AAAA,IAChC,YAAA,EAAc,MAAM,YAAY,CAAA;AAAA,IAChC,iBAAA,EAAmB,MAAM,iBAAiB,CAAA;AAAA,IAC1C,YAAA,EAAc,eAAA,CAAgB,YAAA,IAAgB,EAAE,CAAA;AAAA,IAChD,aAAA,EAAe,kBAAA,CAAmB,aAAA,IAAiB,EAAE,CAAA;AAAA,IACrD,gBAAA,EAAkB,MAAM,gBAAgB,CAAA;AAAA,IACxC,UAAA,EAAY,aAAa,UAAA,GAAa,IAAA;AAAA,IACtC,cAAA,EAAgB,iBAAiB,cAAA,GAAiB;AAAA,GACpD;AACF;AAEA,SAAS,MAAM,CAAA,EAA+B;AAC5C,EAAA,IAAI,CAAC,GAAG,OAAO,CAAA;AACf,EAAA,MAAM,IAAI,MAAA,CAAO,CAAA,CAAE,OAAA,CAAQ,SAAA,EAAW,EAAE,CAAC,CAAA;AACzC,EAAA,OAAO,MAAA,CAAO,QAAA,CAAS,CAAC,CAAA,GAAI,CAAA,GAAI,CAAA;AAClC;AAEA,SAAS,gBAAgB,CAAA,EAA6B;AACpD,EAAA,MAAM,CAAA,GAAI,CAAA,CAAE,WAAA,EAAY,CAAE,IAAA,EAAK;AAC/B,EAAA,IAAI,MAAM,OAAA,IAAW,CAAA,KAAM,QAAA,IAAY,CAAA,KAAM,OAAO,OAAO,CAAA;AAC3D,EAAA,OAAO,SAAA;AACT;AAMO,SAAS,mBAAmB,CAAA,EAA0B;AAC3D,EAAA,MAAM,OAAA,GAAU,EAAE,IAAA,EAAK;AACvB,EAAA,IAAI,CAAC,WAAW,OAAA,KAAY,GAAA,IAAO,SAAS,IAAA,CAAK,OAAO,GAAG,OAAO,IAAA;AAElE,EAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,OAAA,CAAQ,IAAA,EAAM,EAAE,CAAA;AAExC,EAAA,IAAI,CAAA,GAAI,uBAAA,CAAwB,IAAA,CAAK,OAAO,CAAA;AAC5C,EAAA,IAAI,GAAG,OAAO,MAAA,CAAO,CAAA,CAAE,CAAC,CAAC,CAAA,GAAI,GAAA;AAE7B,EAAA,CAAA,GAAI,uBAAA,CAAwB,KAAK,OAAO,CAAA;AACxC,EAAA,IAAI,GAAG,OAAO,MAAA,CAAO,CAAA,CAAE,CAAC,CAAC,CAAA,GAAI,GAAA;AAE7B,EAAA,CAAA,GAAI,yCAAA,CAA0C,KAAK,OAAO,CAAA;AAC1D,EAAA,IAAI,GAAG,OAAO,MAAA,CAAO,CAAA,CAAE,CAAC,CAAC,CAAA,GAAI,GAAA;AAE7B,EAAA,CAAA,GAAI,mBAAA,CAAoB,KAAK,OAAO,CAAA;AACpC,EAAA,IAAI,GAAG,OAAO,MAAA,CAAO,CAAA,CAAE,CAAC,CAAC,CAAA,GAAI,GAAA;AAC7B,EAAA,OAAO,IAAA;AACT;AAYO,SAAS,cAAc,CAAA,EAAwB;AACpD,EAAA,MAAM,OAAA,GAAU,EAAE,IAAA,EAAK;AACvB,EAAA,IAAI,CAAC,SAAS,OAAO,IAAA;AACrB,EAAA,MAAM,CAAA,GAAI,8EAAA,CAA+E,IAAA,CAAK,OAAO,CAAA;AACrG,EAAA,IAAI,CAAA,EAAG;AACL,IAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,CAAA,CAAE,CAAC,CAAC,CAAA,GAAI,CAAA;AAC7B,IAAA,MAAM,GAAA,GAAM,MAAA,CAAO,CAAA,CAAE,CAAC,CAAC,CAAA;AACvB,IAAA,MAAM,IAAA,GAAO,MAAA,CAAO,CAAA,CAAE,CAAC,CAAC,CAAA;AACxB,IAAA,IAAI,IAAA,GAAO,MAAA,CAAO,CAAA,CAAE,CAAC,CAAC,CAAA;AACtB,IAAA,MAAM,MAAA,GAAS,MAAA,CAAO,CAAA,CAAE,CAAC,CAAC,CAAA;AAC1B,IAAA,MAAM,MAAA,GAAS,MAAA,CAAO,CAAA,CAAE,CAAC,KAAK,CAAC,CAAA;AAC/B,IAAA,MAAM,QAAA,GAAW,CAAA,CAAE,CAAC,CAAA,EAAG,WAAA,EAAY;AACnC,IAAA,IAAI,QAAA,KAAa,IAAA,IAAQ,IAAA,GAAO,EAAA,EAAI,IAAA,IAAQ,EAAA;AAC5C,IAAA,IAAI,QAAA,KAAa,IAAA,IAAQ,IAAA,KAAS,EAAA,EAAI,IAAA,GAAO,CAAA;AAG7C,IAAA,MAAM,MAAA,GAAS,KAAK,GAAA,CAAI,IAAA,EAAM,OAAO,GAAA,EAAK,IAAA,EAAM,QAAQ,MAAM,CAAA;AAC9D,IAAA,IAAI,CAAC,MAAA,CAAO,QAAA,CAAS,MAAM,GAAG,OAAO,IAAA;AACrC,IAAA,MAAM,cAAc,cAAA,CAAe,IAAA,EAAM,KAAA,EAAO,GAAG,IAAI,CAAA,GAAI,CAAA;AAC3D,IAAA,OAAO,IAAI,IAAA,CAAK,MAAA,GAAS,WAAA,GAAc,EAAA,GAAK,KAAK,GAAI,CAAA;AAAA,EACvD;AAEA,EAAA,MAAM,CAAA,GAAI,IAAI,IAAA,CAAK,OAAO,CAAA;AAC1B,EAAA,IAAI,CAAC,KAAA,CAAM,CAAA,CAAE,OAAA,EAAS,GAAG,OAAO,CAAA;AAChC,EAAA,OAAO,IAAA;AACT;AAOA,SAAS,cAAA,CAAe,IAAA,EAAc,MAAA,EAAgB,GAAA,EAAsB;AAC1E,EAAA,IAAI,MAAA,GAAS,CAAA,IAAK,MAAA,GAAS,EAAA,EAAI,OAAO,IAAA;AACtC,EAAA,IAAI,MAAA,GAAS,CAAA,IAAK,MAAA,GAAS,EAAA,EAAI,OAAO,KAAA;AAEtC,EAAA,IAAI,WAAW,CAAA,EAAG;AAChB,IAAA,MAAMC,IAAAA,GAAM,gBAAA,CAAiB,IAAA,EAAM,CAAA,EAAG,CAAC,CAAA;AACvC,IAAA,OAAO,GAAA,IAAOA,IAAAA;AAAA,EAChB;AAEA,EAAA,MAAM,GAAA,GAAM,gBAAA,CAAiB,IAAA,EAAM,EAAA,EAAI,CAAC,CAAA;AACxC,EAAA,OAAO,GAAA,GAAM,GAAA;AACf;AAEA,SAAS,gBAAA,CAAiB,IAAA,EAAc,MAAA,EAAgB,CAAA,EAAmB;AACzE,EAAA,MAAM,KAAA,GAAQ,IAAI,IAAA,CAAK,IAAA,CAAK,IAAI,IAAA,EAAM,MAAA,EAAQ,CAAC,CAAC,CAAA;AAChD,EAAA,MAAM,SAAA,GAAY,MAAM,SAAA,EAAU;AAClC,EAAA,MAAM,WAAA,GAAc,CAAA,GAAA,CAAM,CAAA,GAAI,SAAA,IAAa,CAAA;AAC3C,EAAA,OAAO,WAAA,GAAA,CAAe,IAAI,CAAA,IAAK,CAAA;AACjC;AC1QA,IAAM,sBAAA,GAAyB,KAAK,IAAA,GAAO,IAAA;AAQpC,SAAS,uBAAuB,OAAA,EAAuB;AAC5D,EAAA,IAAI,OAAO,OAAA,KAAY,QAAA,IAAY,OAAA,CAAQ,WAAW,CAAA,EAAG;AACvD,IAAA,MAAM,IAAI,MAAM,CAAA,kCAAA,CAAoC,CAAA;AAAA,EACtD;AACA,EAAA,IAAI,OAAA,CAAQ,QAAA,CAAS,IAAI,CAAA,EAAG;AAC1B,IAAA,MAAM,IAAI,MAAM,CAAA,6CAAA,CAA+C,CAAA;AAAA,EACjE;AAEA,EAAA,IAAI,OAAA,CAAQ,UAAA,CAAW,GAAG,CAAA,IAAK,OAAA,CAAQ,UAAA,CAAW,IAAI,CAAA,IAAK,iBAAA,CAAkB,IAAA,CAAK,OAAO,CAAA,EAAG;AAC1F,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,2BAAA,EAA8B,OAAO,CAAA,CAAE,CAAA;AAAA,EACzD;AACA,EAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,KAAA,CAAM,OAAO,CAAA;AACnC,EAAA,IAAI,MAAM,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,KAAM,IAAI,CAAA,EAAG;AACjC,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,2BAAA,EAA8B,OAAO,CAAA,CAAE,CAAA;AAAA,EACzD;AACF;AAiBA,eAAsB,gBAAA,CAAiB,QAAgB,QAAA,EAAqC;AAC1F,EAAA,MAAM,KAAA,GAAA,CAAS,QAAA,IAAY,EAAA,EAAI,WAAA,EAAY;AAC3C,EAAA,MAAM,IAAA,GAAO,MAAM,OAAO,MAAW,CAAA;AAErC,EAAA,IAAI,KAAA,CAAM,QAAA,CAAS,KAAK,CAAA,EAAG;AACzB,IAAA,MAAM,MAAM,MAAM,IAAI,OAAA,CAAgB,CAAC,SAAS,MAAA,KAAW;AACzD,MAAA,MAAM,SAAmB,EAAC;AAC1B,MAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,MAAA,MAAM,MAAA,GAAS,KAAK,YAAA,EAAa;AACjC,MAAA,MAAA,CAAO,EAAA,CAAG,MAAA,EAAQ,CAAC,KAAA,KAAkB;AACnC,QAAA,KAAA,IAAS,KAAA,CAAM,MAAA;AACf,QAAA,IAAI,QAAQ,sBAAA,EAAwB;AAClC,UAAA,MAAA,CAAO,OAAA,EAAQ;AACf,UAAA,MAAA,CAAO,IAAI,KAAA,CAAM,CAAA,mBAAA,EAAsB,sBAAsB,8BAA8B,CAAC,CAAA;AAC5F,UAAA;AAAA,QACF;AACA,QAAA,MAAA,CAAO,KAAK,KAAK,CAAA;AAAA,MACnB,CAAC,CAAA;AACD,MAAA,MAAA,CAAO,EAAA,CAAG,KAAA,EAAO,MAAM,OAAA,CAAQ,MAAA,CAAO,MAAA,CAAO,MAAM,CAAA,CAAE,QAAA,CAAS,MAAM,CAAC,CAAC,CAAA;AACtE,MAAA,MAAA,CAAO,EAAA,CAAG,SAAS,MAAM,CAAA;AACzB,MAAA,MAAA,CAAO,IAAI,MAAM,CAAA;AAAA,IACnB,CAAC,CAAA;AACD,IAAA,OAAO,CAAC,GAAG,CAAA;AAAA,EACb;AAEA,EAAA,IAAI,KAAA,CAAM,QAAA,CAAS,MAAM,CAAA,EAAG;AAC1B,IAAA,MAAM,EAAE,OAAA,EAAS,MAAA,EAAO,GAAI,MAAM,OAAO,SAAS,CAAA;AAClD,IAAA,MAAM,GAAA,GAAM,IAAK,MAAA,CAAwC,MAAM,CAAA;AAC/D,IAAA,MAAM,OAAA,GAAU,IAAI,UAAA,EAAW,CAAE,OAAO,CAAC,CAAA,KAAM,CAAC,CAAA,CAAE,WAAW,CAAA;AAC7D,IAAA,IAAI,QAAQ,MAAA,KAAW,CAAA,EAAG,MAAM,IAAI,MAAM,uBAAuB,CAAA;AAEjE,IAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,IAAA,MAAM,SAAmB,EAAC;AAC1B,IAAA,KAAA,MAAW,SAAS,OAAA,EAAS;AAE3B,MAAA,sBAAA,CAAuB,MAAM,SAAS,CAAA;AAKtC,MAAA,MAAM,YAAA,GAAgB,MAAM,MAAA,EAAgB,IAAA;AAC5C,MAAA,IAAI,OAAO,YAAA,KAAiB,QAAA,IAAY,YAAA,IAAgB,CAAA,EAAG;AACzD,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,UAAA,EAAa,KAAA,CAAM,SAAS,CAAA,8CAAA,CAAgD,CAAA;AAAA,MAC9F;AACA,MAAA,IAAI,YAAA,GAAe,sBAAA,IAA0B,KAAA,GAAQ,YAAA,GAAe,sBAAA,EAAwB;AAC1F,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,kBAAA,EAAqB,sBAAsB,CAAA,4BAAA,CAA8B,CAAA;AAAA,MAC3F;AAKA,MAAA,MAAM,IAAA,GAAO,MAAM,OAAA,EAAQ;AAC3B,MAAA,KAAA,IAAS,IAAA,CAAK,MAAA;AACd,MAAA,IAAI,QAAQ,sBAAA,EAAwB;AAClC,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,uCAAA,EAA0C,sBAAsB,CAAA,uBAAA,CAAyB,CAAA;AAAA,MAC3G;AAIA,MAAA,IAAI,eAAe,EAAA,GAAK,IAAA,IAAQ,KAAK,MAAA,GAAS,YAAA,GAAe,KAAK,IAAA,EAAM;AACtE,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,gBAAA,EAAmB,KAAA,CAAM,SAAS,uBAAuB,IAAA,CAAK,MAAM,CAAA,wBAAA,EAA2B,YAAY,CAAA,CAAA,CAAG,CAAA;AAAA,MAChI;AACA,MAAA,MAAA,CAAO,IAAA,CAAK,IAAA,CAAK,QAAA,CAAS,MAAM,CAAC,CAAA;AAAA,IACnC;AACA,IAAA,OAAO,MAAA;AAAA,EACT;AAGA,EAAA,IAAI,MAAA,CAAO,SAAS,sBAAA,EAAwB;AAC1C,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,sBAAA,EAAyB,sBAAsB,CAAA,MAAA,CAAQ,CAAA;AAAA,EACzE;AACA,EAAA,OAAO,CAAC,MAAA,CAAO,QAAA,CAAS,MAAM,CAAC,CAAA;AACjC;AA0BO,SAAS,iBAAiB,GAAA,EAAgC;AAC/D,EAAA,MAAM,MAAA,GAAS,IAAIC,uBAAA,CAAU;AAAA,IAC3B,gBAAA,EAAkB,KAAA;AAAA,IAClB,mBAAA,EAAqB,KAAA;AAAA,IACrB,aAAA,EAAe,KAAA;AAAA,IACf,UAAA,EAAY,IAAA;AAAA;AAAA;AAAA,IAGZ,gBAAA,EAAkB,CAAC,CAAA,KAAc,CAAA,CAAE,WAAA;AAAY,GAChD,CAAA;AACD,EAAA,MAAM,IAAA,GAAY,MAAA,CAAO,KAAA,CAAM,GAAG,CAAA;AAClC,EAAA,MAAM,KAAK,IAAA,EAAM,QAAA;AACjB,EAAA,IAAI,CAAC,EAAA,EAAI,MAAM,IAAI,MAAM,mCAAmC,CAAA;AAE5D,EAAA,MAAM,IAAA,GAAO,EAAA,CAAG,eAAA,IAAmB,EAAC;AACpC,EAAA,MAAM,MAAA,GAAS,EAAA,CAAG,gBAAA,IAAoB,EAAC;AAEvC,EAAA,MAAM,WAAW,MAAA,CAAO,IAAA,CAAK,SAAA,IAAa,EAAE,EAAE,IAAA,EAAK;AACnD,EAAA,MAAM,UAAU,MAAA,CAAO,IAAA,CAAK,QAAA,IAAY,EAAE,EAAE,IAAA,EAAK;AACjD,EAAA,MAAM,QAAQ,MAAA,CAAO,IAAA,CAAK,KAAA,IAAS,EAAE,EAAE,IAAA,EAAK;AAC5C,EAAA,MAAM,MAAA,GAAS,OAAO,MAAA,CAAO,MAAA,IAAU,EAAE,CAAA,CAAE,IAAA,GAAO,WAAA,EAAY;AAC9D,EAAA,MAAM,OAAA,GAAW,OAAO,CAAA,IAAK,MAAA;AAC7B,EAAA,MAAM,MAAA,GAAS,MAAA,CAAO,MAAA,CAAO,GAAA,IAAO,GAAG,CAAA;AAEvC,EAAA,MAAM,SAAA,GAAY,MAAA,CAAO,QAAA,CAAS,MAAM,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,GAAA,CAAI,GAAA,EAAK,MAAM,CAAC,CAAA,GAAI,GAAA;AAEjF,EAAA,IAAI,CAAC,QAAA,EAAU,MAAM,IAAI,MAAM,6BAA6B,CAAA;AAC5D,EAAA,IAAI,CAAC,MAAA,EAAQ,MAAM,IAAI,MAAM,2CAA2C,CAAA;AAExE,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,UAAA,IAAc,EAAC;AAClC,EAAA,MAAM,KAAA,GAAQ,aAAA,CAAc,KAAA,CAAM,KAAK,CAAA;AACvC,EAAA,MAAM,GAAA,GAAM,aAAA,CAAc,KAAA,CAAM,GAAG,CAAA;AACnC,EAAA,IAAI,CAAC,KAAA,IAAS,CAAC,KAAK,MAAM,IAAI,MAAM,8BAA8B,CAAA;AAElE,EAAA,MAAM,OAAA,GAAU,OAAA,CAAa,EAAA,CAAG,MAAM,CAAA;AACtC,EAAA,MAAM,WAA0C,EAAC;AACjD,EAAA,IAAI,aAAA,GAAgB,CAAA;AACpB,EAAA,IAAI,SAAA,GAAY,CAAA;AAChB,EAAA,IAAI,SAAA,GAAY,CAAA;AAGhB,EAAA,MAAM,KAAA,GAAQ,KAAK,KAAA,CAAA,CAAO,KAAA,CAAM,SAAQ,GAAI,GAAA,CAAI,OAAA,EAAQ,IAAK,CAAC,CAAA;AAC9D,EAAA,MAAM,GAAA,GAAM,IAAI,IAAA,CAAK,KAAK,EAAE,WAAA,EAAY,CAAE,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA;AAErD,EAAA,KAAA,MAAW,OAAO,OAAA,EAAS;AACzB,IAAA,MAAM,GAAA,GAAM,GAAA,EAAK,GAAA,IAAO,EAAC;AACzB,IAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,GAAA,CAAI,KAAA,IAAS,CAAC,CAAA,IAAK,CAAA;AACxC,IAAA,aAAA,IAAiB,KAAA;AAEjB,IAAA,MAAM,KAAA,GAAQ,GAAA,CAAI,gBAAA,IAAoB,EAAC;AACvC,IAAA,MAAM,IAAA,GAAQ,MAAM,IAAA,IAAQ,MAAA;AAC5B,IAAA,MAAM,GAAA,GAAO,MAAM,GAAA,IAAO,MAAA;AAC1B,IAAA,MAAM,OAAA,GAAU,IAAA,KAAS,MAAA,IAAU,GAAA,KAAQ,MAAA;AAE3C,IAAA,IAAI,OAAA,EAAS;AACX,MAAA,SAAA,IAAa,KAAA;AACb,MAAA;AAAA,IACF;AACA,IAAA,SAAA,IAAa,KAAA;AAEb,IAAA,MAAM,WAAW,MAAA,CAAO,GAAA,CAAI,SAAA,IAAa,EAAE,EAAE,IAAA,EAAK;AAClD,IAAA,IAAI,CAAC,QAAA,EAAU;AACf,IAAA,MAAM,aAAa,MAAA,CAAO,GAAA,EAAK,aAAa,WAAA,IAAe,EAAE,EAAE,WAAA,EAAY;AAC3E,IAAA,MAAM,kBAAA,GAAqB,MAAA,CAAO,KAAA,CAAM,WAAA,IAAe,MAAM,CAAA;AAE7D,IAAA,QAAA,CAAS,IAAA,CAAK;AAAA,MACZ,QAAA;AAAA,MACA,MAAA;AAAA,MACA,QAAA;AAAA,MACA,KAAA;AAAA,MACA,UAAA;AAAA,MACA,UAAA,EAAY,IAAA;AAAA,MACZ,SAAA,EAAW,GAAA;AAAA,MACX,kBAAA;AAAA,MACA;AAAA,KACD,CAAA;AAAA,EACH;AAEA,EAAA,OAAO;AAAA,IACL,MAAA,EAAQ;AAAA,MACN,QAAA;AAAA,MACA,OAAA;AAAA,MACA,KAAA;AAAA,MACA,MAAA;AAAA,MACA,OAAA;AAAA,MACA,SAAA;AAAA,MACA,UAAA,EAAY,KAAA;AAAA,MACZ,QAAA,EAAU,GAAA;AAAA,MACV,aAAA;AAAA,MACA,SAAA;AAAA,MACA;AAAA,KACF;AAAA,IACA;AAAA,GACF;AACF;AAEA,SAAS,cAAc,CAAA,EAAyB;AAC9C,EAAA,IAAI,CAAA,KAAM,MAAA,IAAa,CAAA,KAAM,IAAA,EAAM,OAAO,IAAA;AAC1C,EAAA,MAAM,CAAA,GAAI,OAAO,CAAA,KAAM,QAAA,GAAW,IAAI,MAAA,CAAO,MAAA,CAAO,CAAC,CAAC,CAAA;AACtD,EAAA,IAAI,CAAC,MAAA,CAAO,QAAA,CAAS,CAAC,CAAA,IAAK,CAAA,IAAK,GAAG,OAAO,IAAA;AAC1C,EAAA,OAAO,IAAI,IAAA,CAAK,CAAA,GAAI,GAAI,CAAA;AAC1B;AAEA,SAAS,QAAW,CAAA,EAAoC;AACtD,EAAA,IAAI,CAAA,KAAM,MAAA,IAAa,CAAA,KAAM,IAAA,SAAa,EAAC;AAC3C,EAAA,OAAO,MAAM,OAAA,CAAQ,CAAC,CAAA,GAAI,CAAA,GAAI,CAAC,CAAC,CAAA;AAClC;AAwCA,eAAsB,sBACpB,GAAA,EACA,MAAA,EACA,QAAA,EACA,IAAA,GAAsB,EAAC,EACiC;AACxD,EAAA,MAAM,IAAA,GAAO,MAAM,gBAAA,CAAiB,MAAA,EAAQ,QAAQ,CAAA;AACpD,EAAA,IAAI,KAAK,MAAA,KAAW,CAAA,EAAG,MAAM,IAAI,MAAM,qCAAqC,CAAA;AAC5E,EAAA,MAAM,UAA0B,EAAC;AACjC,EAAA,IAAI,UAAA,GAAsB,IAAA;AAC1B,EAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,IAAA,IAAI;AACF,MAAA,MAAM,MAAA,GAAS,iBAAiB,GAAG,CAAA;AACnC,MAAA,IAAI,IAAA,CAAK,eAAe,CAAC,IAAA,CAAK,YAAY,MAAA,CAAO,MAAA,CAAO,MAAM,CAAA,EAAG;AAC/D,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,4BAAA,EAA+B,MAAA,CAAO,MAAA,CAAO,MAAM,CAAA,2CAAA,CAA6C,CAAA;AAAA,MAClH;AACA,MAAA,OAAA,CAAQ,IAAA,CAAK,MAAM,uBAAA,CAAwB,GAAA,EAAK,MAAM,CAAC,CAAA;AAAA,IACzD,SAAS,GAAA,EAAK;AACZ,MAAA,IAAI,CAAC,YAAY,UAAA,GAAa,GAAA;AAAA,IAGhC;AAAA,EACF;AACA,EAAA,IAAI,OAAA,CAAQ,WAAW,CAAA,EAAG;AACxB,IAAA,MAAM,UAAA,IAAc,IAAI,KAAA,CAAM,0CAA0C,CAAA;AAAA,EAC1E;AACA,EAAA,OAAO,EAAE,GAAG,OAAA,CAAQ,CAAC,GAAI,iBAAA,EAAmB,OAAA,CAAQ,SAAS,CAAA,EAAE;AACjE;AAEA,eAAsB,uBAAA,CACpB,KACA,MAAA,EACuB;AACvB,EAAA,MAAM,GAAA,uBAAU,IAAA,EAAK;AACrB,EAAA,MAAM,EAAE,MAAA,EAAQ,QAAA,EAAS,GAAI,MAAA;AAM7B,EAAA,IAAI,SAAA,GAAY,KAAA;AAChB,EAAA,IAAI;AACF,IAAA,MAAM,GAAA,CAAI,YAAY,YAAA,CAAa,SAAA,CAAU,EAAE,GAAG,MAAA,EAAQ,UAAA,EAAY,GAAA,EAAK,CAAA;AAAA,EAC7E,SAAS,GAAA,EAAU;AACjB,IAAA,IAAI,GAAA,EAAK,SAAS,IAAA,EAAO;AACvB,MAAA,SAAA,GAAY,IAAA;AAAA,IACd,CAAA,MAAO;AACL,MAAA,MAAM,GAAA;AAAA,IACR;AAAA,EACF;AAEA,EAAA,IAAI,CAAC,SAAA,IAAa,QAAA,CAAS,MAAA,GAAS,CAAA,EAAG;AAIrC,IAAA,IAAI;AACF,MAAA,MAAM,GAAA,CAAI,YAAY,aAAA,CAAc,UAAA;AAAA,QAClC,QAAA,CAAS,IAAI,CAAC,CAAA,MAAO,EAAE,GAAG,CAAA,EAAG,UAAA,EAAY,GAAA,EAAI,CAAE,CAAA;AAAA,QAC/C,EAAE,SAAS,KAAA;AAAM,OACnB;AAAA,IACF,SAAS,GAAA,EAAU;AACjB,MAAA,MAAM,cAAoD,GAAA,EAAK,WAAA;AAC/D,MAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,WAAW,CAAA,EAAG;AAC9B,QAAA,MAAM,SAAS,WAAA,CAAY,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,EAAG,SAAS,IAAK,CAAA;AACxD,QAAA,IAAI,QAAQ,MAAM,GAAA;AAAA,MACpB,CAAA,MAAA,IAAW,GAAA,EAAK,IAAA,KAAS,IAAA,EAAO;AAC9B,QAAA,MAAM,GAAA;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,EAAA,OAAO;AAAA,IACL,EAAA,EAAI,IAAA;AAAA,IACJ,UAAU,MAAA,CAAO,QAAA;AAAA,IACjB,QAAQ,MAAA,CAAO,MAAA;AAAA,IACf,YAAY,MAAA,CAAO,UAAA;AAAA,IACnB,UAAU,MAAA,CAAO,QAAA;AAAA,IACjB,eAAe,MAAA,CAAO,aAAA;AAAA,IACtB,WAAW,MAAA,CAAO,SAAA;AAAA,IAClB,WAAW,MAAA,CAAO,SAAA;AAAA,IAClB;AAAA,GACF;AACF;AAQA,IAAI,YAAA,GAAe,CAAA;AACnB,IAAM,iBAAA,GAAoB,KAAK,EAAA,GAAK,GAAA;AAEpC,eAAsB,kBAAA,CAAmB,GAAA,EAAoB,IAAA,GAA4B,EAAC,EAAoB;AAC5G,EAAA,MAAM,GAAA,GAAM,IAAI,MAAA,CAAO,KAAA;AACvB,EAAA,MAAM,IAAA,GAAO,KAAK,aAAA,IAAiB,EAAA;AACnC,EAAA,IAAI,IAAA,IAAQ,GAAG,OAAO,CAAA;AACtB,EAAA,IAAI,CAAC,KAAK,KAAA,IAAS,IAAA,CAAK,KAAI,GAAI,YAAA,GAAe,mBAAmB,OAAO,CAAA;AACzE,EAAA,YAAA,GAAe,KAAK,GAAA,EAAI;AACxB,EAAA,MAAM,SAAS,IAAI,IAAA,CAAK,KAAK,GAAA,EAAI,GAAI,OAAO,KAAU,CAAA;AACtD,EAAA,MAAM,CAAA,GAAI,MAAM,GAAA,CAAI,WAAA,CAAY,aAAA,CAAc,UAAA,CAAW,EAAE,UAAA,EAAY,EAAE,GAAA,EAAK,MAAA,EAAO,EAAG,CAAA;AACxF,EAAA,OAAO,EAAE,YAAA,IAAgB,CAAA;AAC3B;AAcA,eAAsB,kBAAkB,GAAA,EAA6D;AACnG,EAAA,MAAM,GAAA,uBAAU,GAAA,EAA+B;AAC/C,EAAA,KAAA,MAAW,KAAK,GAAA,CAAI,MAAA,CAAO,KAAA,EAAO,YAAA,IAAgB,EAAC,EAAG;AACpD,IAAA,GAAA,CAAI,IAAI,CAAA,CAAE,EAAA,EAAI,EAAE,EAAA,EAAI,EAAE,EAAA,EAAI,KAAA,EAAO,CAAA,CAAE,KAAA,EAAO,SAAS,CAAC,CAAC,EAAE,OAAA,EAAS,MAAA,EAAQ,UAAU,CAAA;AAAA,EACpF;AAEA,EAAA,MAAM,MAAA,GAAS,MAAM,GAAA,CAAI,WAAA,CAAY,gBAAgB,IAAA,CAAK,EAAE,CAAA,CAAE,OAAA,EAAQ;AACtE,EAAA,KAAA,MAAW,KAAK,MAAA,EAAQ;AACtB,IAAA,GAAA,CAAI,GAAA,CAAI,CAAA,CAAE,EAAA,EAAI,EAAE,IAAI,CAAA,CAAE,EAAA,EAAI,KAAA,EAAO,CAAA,CAAE,OAAO,OAAA,EAAS,CAAA,CAAE,OAAA,EAAS,MAAA,EAAQ,MAAM,CAAA;AAAA,EAC9E;AACA,EAAA,OAAO,GAAA;AACT;AAiCO,SAAS,yBAAyB,KAAA,EAAyD;AAChG,EAAA,MAAM,EAAE,OAAA,EAAS,QAAA,EAAU,gBAAgB,gBAAA,EAAkB,aAAA,EAAe,YAAW,GAAI,KAAA;AAE3F,EAAA,IAAI,aAAA,KAAkB,UAAU,OAAO,IAAA;AAEvC,EAAA,MAAM,OAAA,GAAU,IAAA,CAAK,GAAA,EAAI,GAAI,EAAA,GAAK,KAAA;AAClC,EAAA,MAAM,aAAA,GAAgB,QAAQ,MAAA,CAAO,CAAC,MAAM,CAAA,CAAE,QAAA,CAAS,OAAA,EAAQ,IAAK,OAAO,CAAA;AAC3E,EAAA,MAAM,SAAA,GAAY,aAAA,CAAc,MAAA,CAAO,CAAC,GAAA,EAAK,CAAA,KAAM,GAAA,GAAM,CAAA,CAAE,SAAA,GAAY,CAAA,CAAE,SAAA,EAAW,CAAC,CAAA;AACrF,EAAA,MAAM,SAAA,GAAY,cAAc,MAAA,CAAO,CAAC,KAAK,CAAA,KAAM,GAAA,GAAM,CAAA,CAAE,SAAA,EAAW,CAAC,CAAA;AAEvE,EAAA,IAAI,aAAA,CAAc,MAAA,GAAS,EAAA,EAAI,OAAO,IAAA;AACtC,EAAA,IAAI,SAAA,GAAY,KAAM,OAAO,IAAA;AAI7B,EAAA,MAAM,mBAAmB,QAAA,CAAS,MAAA;AAAA,IAChC,CAAC,CAAA,KAAM,CAAA,CAAE,UAAA,CAAW,OAAA,MAAa,OAAA,IAAW,CAAC,cAAA,CAAe,GAAA,CAAI,EAAE,QAAQ,CAAA,IAAK,CAAC,gBAAA,CAAiB,GAAA,CAAI,EAAE,QAAQ;AAAA,GACjH;AACA,EAAA,IAAI,gBAAA,CAAiB,MAAA,GAAS,CAAA,EAAG,OAAO,IAAA;AAExC,EAAA,MAAM,aAAA,GAAgB,SAAA,KAAc,CAAA,GAAI,CAAA,GAAI,SAAA,GAAY,SAAA;AAExD,EAAA,IAAI,aAAA,KAAkB,IAAA,IAAQ,aAAA,KAAkB,MAAA,EAAQ;AACtD,IAAA,IAAI,iBAAiB,IAAA,EAAM;AACzB,MAAA,OAAO;AAAA,QACL,MAAA,EAAQ,YAAA;AAAA,QACR,GAAA,EAAK,EAAA;AAAA,QACL,MAAA,EAAQ,CAAA,EAAA,CAAI,aAAA,GAAgB,GAAA,EAAK,OAAA,CAAQ,CAAC,CAAC,CAAA,iBAAA,EAAoB,aAAA,CAAc,MAAM,CAAA,WAAA,EAAc,SAAA,CAAU,gBAAgB,CAAA,oCAAA;AAAA,OAC7H;AAAA,IACF;AACA,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,IAAI,kBAAkB,YAAA,EAAc;AAClC,IAAA,MAAM,MAAM,UAAA,IAAc,GAAA;AAC1B,IAAA,IAAI,aAAA,GAAgB,OAAO,OAAO,IAAA;AAClC,IAAA,IAAI,MAAM,EAAA,EAAI,OAAO,EAAE,MAAA,EAAQ,cAAc,GAAA,EAAK,EAAA,EAAI,MAAA,EAAQ,CAAA,kBAAA,EAAA,CAAsB,gBAAgB,GAAA,EAAK,OAAA,CAAQ,CAAC,CAAC,CAAA,+BAAA,EAA6B,GAAG,CAAA,OAAA,CAAA,EAAU;AAC7J,IAAA,IAAI,MAAM,EAAA,EAAI,OAAO,EAAE,MAAA,EAAQ,cAAc,GAAA,EAAK,EAAA,EAAI,MAAA,EAAQ,CAAA,kBAAA,EAAA,CAAsB,gBAAgB,GAAA,EAAK,OAAA,CAAQ,CAAC,CAAC,CAAA,+BAAA,EAA6B,GAAG,CAAA,OAAA,CAAA,EAAU;AAC7J,IAAA,IAAI,MAAM,GAAA,EAAK,OAAO,EAAE,MAAA,EAAQ,cAAc,GAAA,EAAK,GAAA,EAAK,MAAA,EAAQ,CAAA,kBAAA,EAAA,CAAsB,gBAAgB,GAAA,EAAK,OAAA,CAAQ,CAAC,CAAC,CAAA,+BAAA,EAA6B,GAAG,CAAA,QAAA,CAAA,EAAW;AAGhK,IAAA,IAAI,iBAAiB,KAAA,EAAO;AAC1B,MAAA,OAAO,EAAE,MAAA,EAAQ,QAAA,EAAU,GAAA,EAAK,GAAA,EAAK,MAAA,EAAQ,CAAA,aAAA,EAAA,CAAiB,aAAA,GAAgB,GAAA,EAAK,OAAA,CAAQ,CAAC,CAAC,CAAA,iEAAA,CAAA,EAA+D;AAAA,IAC9J;AAAA,EACF;AAEA,EAAA,OAAO,IAAA;AACT;ACldA,IAAM,cAAA,GAAiB,YAAA;AAOhB,IAAM,cAAA,GAAiB,IAAI,EAAA,GAAK,GAAA;AAGhC,IAAM,kBAAA,GAAqB,IAAI,IAAA,GAAO,IAAA;AAO7C,IAAM,UAAA,GAAcC,mBAAA,CAAG,SAAA,CAAsC,UAAA,IAAc,CAAA;AAE3E,IAAM,YAAA,GACJA,oBAAG,SAAA,CAAU,QAAA,GAAWA,oBAAG,SAAA,CAAU,OAAA,GAAUA,mBAAA,CAAG,SAAA,CAAU,QAAA,GAAW,UAAA;AAoBlE,SAAS,kBAAA,CAAmB,aAAqB,KAAA,EAAgC;AACtF,EAAAA,mBAAA,CAAG,SAAA,CAAUL,qBAAA,CAAK,OAAA,CAAQ,WAAW,CAAA,EAAG,EAAE,SAAA,EAAW,IAAA,EAAM,IAAA,EAAM,GAAA,EAAO,CAAA;AAExE,EAAA,MAAM,EAAA,GAAKK,mBAAA,CAAG,QAAA,CAAS,WAAA,EAAa,cAAc,GAAK,CAAA;AACvD,EAAA,IAAI;AACF,IAAA,wBAAA,CAAyB,IAAI,WAAW,CAAA;AACxC,IAAAA,mBAAA,CAAG,SAAA,CAAU,EAAA,EAAI,cAAA,CAAe,KAAK,CAAC,CAAA;AAAA,EACxC,CAAA,SAAE;AACA,IAAAA,mBAAA,CAAG,UAAU,EAAE,CAAA;AAAA,EACjB;AACF;AAWA,SAAS,wBAAA,CAAyB,IAAY,WAAA,EAA2B;AACvE,EAAA,MAAM,EAAA,GAAKA,mBAAA,CAAG,SAAA,CAAU,EAAE,CAAA;AAC1B,EAAA,IAAI,CAAC,EAAA,CAAG,MAAA,EAAO,EAAG;AAChB,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,mDAAA,EAAsD,WAAW,CAAA,CAAE,CAAA;AAAA,EACrF;AACA,EAAA,IAAI,EAAA,CAAG,QAAQ,CAAA,EAAG;AAChB,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,gCAAA,EAAmC,GAAG,KAAK,CAAA,aAAA,EAAgB,WAAW,CAAA,CAAE,CAAA;AAAA,EAC1F;AACA,EAAA,IAAA,CAAK,GAAG,IAAA,GAAO,EAAA,MAAW,GAAGA,mBAAA,CAAG,UAAA,CAAW,IAAI,GAAK,CAAA;AACtD;AAEO,SAAS,eAAe,KAAA,EAAkC;AAC/D,EAAA,OAAO,IAAA,CAAK,SAAA,CAAU,KAAK,CAAA,GAAI,IAAA;AACjC;AAMA,SAAS,UAAA,GAAqB;AAC5B,EAAA,OAAO,CAAA,EAAG,IAAA,CAAK,GAAA,EAAI,CAAE,QAAA,CAAS,EAAE,CAAC,CAAA,CAAA,EAAIC,mBAAA,CAAY,CAAC,CAAA,CAAE,QAAA,CAAS,KAAK,CAAC,CAAA,CAAA;AACrE;AAOO,SAAS,aAAa,WAAA,EAAoC;AAC/D,EAAA,MAAM,UAAU,CAAA,EAAG,WAAW,GAAG,cAAc,CAAA,EAAG,YAAY,CAAA,CAAA;AAC9D,EAAA,IAAI;AACF,IAAAD,mBAAA,CAAG,UAAA,CAAW,aAAa,OAAO,CAAA;AAAA,EACpC,SAAS,GAAA,EAAK;AACZ,IAAA,IAAI,SAAA,CAAU,GAAG,CAAA,EAAG,OAAO,IAAA;AAC3B,IAAA,MAAM,GAAA;AAAA,EACR;AACA,EAAA,eAAA,CAAgB,OAAO,CAAA;AACvB,EAAA,OAAO,OAAA;AACT;AAWA,SAAS,gBAAgB,SAAA,EAAyB;AAChD,EAAA,MAAM,GAAA,uBAAU,IAAA,EAAK;AACrB,EAAA,IAAI;AACF,IAAAA,mBAAA,CAAG,UAAA,CAAW,SAAA,EAAW,GAAA,EAAK,GAAG,CAAA;AAAA,EACnC,SAAS,GAAA,EAAK;AAGZ,IAAA,IAAI,CAAC,SAAA,CAAU,GAAG,CAAA,EAAG,MAAM,GAAA;AAAA,EAC7B;AACF;AASO,SAAS,oBAAA,CACd,WAAA,EACA,IAAA,GAA+C,EAAC,EACtC;AACV,EAAA,MAAM,WAAA,GAAc,KAAK,WAAA,IAAe,cAAA;AACxC,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,GAAA,IAAO,IAAA,CAAK,GAAA,EAAI;AACjC,EAAA,MAAM,GAAA,GAAML,qBAAA,CAAK,OAAA,CAAQ,WAAW,CAAA;AACpC,EAAA,MAAM,MAAA,GAASA,qBAAA,CAAK,QAAA,CAAS,WAAW,CAAA,GAAI,cAAA;AAE5C,EAAA,IAAI,KAAA;AACJ,EAAA,IAAI;AACF,IAAA,KAAA,GAAQK,mBAAA,CAAG,YAAY,GAAG,CAAA;AAAA,EAC5B,SAAS,GAAA,EAAK;AACZ,IAAA,IAAI,SAAA,CAAU,GAAG,CAAA,EAAG,OAAO,EAAC;AAC5B,IAAA,MAAM,GAAA;AAAA,EACR;AAEA,EAAA,MAAM,UAAoB,EAAC;AAC3B,EAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,IAAA,IAAI,CAAC,IAAA,CAAK,UAAA,CAAW,MAAM,CAAA,EAAG;AAC9B,IAAA,MAAM,IAAA,GAAOL,qBAAA,CAAK,IAAA,CAAK,GAAA,EAAK,IAAI,CAAA;AAChC,IAAA,IAAI,EAAA;AACJ,IAAA,IAAI;AACF,MAAA,EAAA,GAAKK,mBAAA,CAAG,SAAS,IAAI,CAAA;AAAA,IACvB,SAAS,GAAA,EAAK;AACZ,MAAA,IAAI,SAAA,CAAU,GAAG,CAAA,EAAG;AACpB,MAAA,MAAM,GAAA;AAAA,IACR;AACA,IAAA,IAAI,CAAC,EAAA,CAAG,MAAA,EAAO,EAAG;AAClB,IAAA,IAAI,GAAA,GAAM,EAAA,CAAG,OAAA,GAAU,WAAA,EAAa;AAEpC,IAAA,MAAM,OAAO,CAAA,EAAG,WAAW,GAAG,cAAc,CAAA,EAAG,YAAY,CAAA,CAAA;AAC3D,IAAA,IAAI;AACF,MAAAA,mBAAA,CAAG,UAAA,CAAW,MAAM,IAAI,CAAA;AACxB,MAAA,eAAA,CAAgB,IAAI,CAAA;AACpB,MAAA,OAAA,CAAQ,KAAK,IAAI,CAAA;AAAA,IACnB,SAAS,GAAA,EAAK;AAEZ,MAAA,IAAI,CAAC,SAAA,CAAU,GAAG,CAAA,EAAG,MAAM,GAAA;AAAA,IAC7B;AAAA,EACF;AACA,EAAA,OAAO,OAAA;AACT;AA6BO,SAAS,UAAU,SAAA,EAA+B;AACvD,EAAA,IAAI,GAAA;AACJ,EAAA,IAAI;AACF,IAAA,GAAA,GAAMA,mBAAA,CAAG,YAAA,CAAa,SAAA,EAAW,MAAM,CAAA;AAAA,EACzC,SAAS,GAAA,EAAK;AACZ,IAAA,IAAI,SAAA,CAAU,GAAG,CAAA,EAAG,OAAO,EAAE,OAAA,EAAS,EAAC,EAAG,SAAA,EAAW,EAAC,EAAG,KAAA,EAAO,CAAA,EAAE;AAClE,IAAA,MAAM,GAAA;AAAA,EACR;AAEA,EAAA,MAAM,UAA+B,EAAC;AACtC,EAAA,MAAM,YAAqC,EAAC;AAE5C,EAAA,MAAM,KAAA,GAAQ,GAAA,CAAI,KAAA,CAAM,IAAI,CAAA;AAC5B,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,CAAM,QAAQ,CAAA,EAAA,EAAK;AACrC,IAAA,MAAM,IAAA,GAAO,MAAM,CAAC,CAAA;AACpB,IAAA,IAAI,IAAA,CAAK,IAAA,EAAK,KAAM,EAAA,EAAI;AACxB,IAAA,MAAM,MAAA,GAAS,WAAW,IAAI,CAAA;AAC9B,IAAA,IAAI,MAAA,EAAQ,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAA;AAAA,SAC1B,SAAA,CAAU,IAAA,CAAK,EAAE,UAAA,EAAY,CAAA,GAAI,CAAA,EAAG,OAAA,EAAS,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,GAAG,CAAA,EAAG,CAAA;AAAA,EACxE;AAEA,EAAA,OAAO,EAAE,OAAA,EAAS,SAAA,EAAW,OAAO,MAAA,CAAO,UAAA,CAAW,GAAG,CAAA,EAAE;AAC7D;AAMO,SAAS,WAAW,IAAA,EAAwC;AACjE,EAAA,IAAI,GAAA;AACJ,EAAA,IAAI;AACF,IAAA,GAAA,GAAM,IAAA,CAAK,MAAM,IAAI,CAAA;AAAA,EACvB,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,IAAI,CAAC,OAAO,OAAO,GAAA,KAAQ,YAAY,KAAA,CAAM,OAAA,CAAQ,GAAG,CAAA,EAAG,OAAO,IAAA;AAClE,EAAA,MAAM,CAAA,GAAI,GAAA;AAIV,EAAA,MAAM,KAAA,GAAQ,uBAAuB,SAAA,CAAU;AAAA,IAC7C,OAAO,CAAA,CAAE,KAAA;AAAA,IACT,OAAO,CAAA,CAAE,KAAA;AAAA,IACT,MAAA,EAAQ,cAAA;AAAA,IACR,MAAA,EAAQ;AAAA,GACT,CAAA;AACD,EAAA,IAAI,CAAC,KAAA,CAAM,OAAA,EAAS,OAAO,IAAA;AAE3B,EAAA,MAAM,EAAA,GAAK,OAAO,CAAA,CAAE,EAAA,KAAO,QAAA,IAAY,MAAA,CAAO,QAAA,CAAS,CAAA,CAAE,EAAE,CAAA,GAAI,CAAA,CAAE,EAAA,GAAK,KAAK,GAAA,EAAI;AAC/E,EAAA,MAAM,WACJ,OAAO,CAAA,CAAE,QAAA,KAAa,QAAA,IAAY,OAAO,QAAA,CAAS,CAAA,CAAE,QAAQ,CAAA,IAAK,EAAE,QAAA,GAAW,CAAA,GAC1E,KAAK,KAAA,CAAM,CAAA,CAAE,QAAQ,CAAA,GACrB,MAAA;AAEN,EAAA,OAAO;AAAA,IACL,KAAA,EAAO,MAAM,IAAA,CAAK,KAAA;AAAA,IAClB,KAAA,EAAO,MAAM,IAAA,CAAK,KAAA;AAAA,IAClB,EAAA;AAAA,IACA,GAAI,QAAA,KAAa,MAAA,GAAY,EAAC,GAAI,EAAE,QAAA;AAAS,GAC/C;AACF;AAGO,SAAS,aAAa,KAAA,EAA4C;AACvE,EAAA,OAAO,uBAAuB,KAAA,CAAM;AAAA,IAClC,OAAO,KAAA,CAAM,KAAA;AAAA,IACb,OAAO,KAAA,CAAM,KAAA;AAAA,IACb,MAAA,EAAQ,cAAA;AAAA;AAAA;AAAA;AAAA,IAIR,MAAA,EAAQ;AAAA,GACT,CAAA;AACH;AAgBO,SAAS,YAAA,CACd,WAAA,EACA,SAAA,EACA,SAAA,EACM;AACN,EAAA,IAAI,SAAA,CAAU,SAAS,CAAA,EAAG;AACxB,IAAAA,mBAAA,CAAG,SAAA,CAAUL,qBAAA,CAAK,OAAA,CAAQ,WAAW,CAAA,EAAG,EAAE,SAAA,EAAW,IAAA,EAAM,IAAA,EAAM,GAAA,EAAO,CAAA;AACxE,IAAA,MAAM,EAAA,GAAKK,mBAAA,CAAG,QAAA,CAAS,WAAA,EAAa,cAAc,GAAK,CAAA;AACvD,IAAA,IAAI;AACF,MAAA,wBAAA,CAAyB,IAAI,WAAW,CAAA;AACxC,MAAAA,mBAAA,CAAG,SAAA;AAAA,QACD,EAAA;AAAA,QACA,UAAU,GAAA,CAAI,CAAC,CAAA,KAAM,cAAA,CAAe,EAAE,GAAG,CAAA,EAAG,QAAA,EAAA,CAAW,CAAA,CAAE,YAAY,CAAA,IAAK,CAAA,EAAG,CAAC,CAAA,CAAE,KAAK,EAAE;AAAA,OACzF;AAAA,IACF,CAAA,SAAE;AACA,MAAAA,mBAAA,CAAG,UAAU,EAAE,CAAA;AAAA,IACjB;AAAA,EACF;AACA,EAAA,IAAI;AACF,IAAAA,mBAAA,CAAG,WAAW,SAAS,CAAA;AAAA,EACzB,SAAS,GAAA,EAAK;AACZ,IAAA,IAAI,CAAC,SAAA,CAAU,GAAG,CAAA,EAAG,MAAM,GAAA;AAAA,EAC7B;AACF;AAGO,SAAS,cAAc,WAAA,EAA8B;AAC1D,EAAA,IAAI;AACF,IAAA,OAAOA,mBAAA,CAAG,QAAA,CAAS,WAAW,CAAA,CAAE,MAAA,EAAO;AAAA,EACzC,SAAS,GAAA,EAAK;AACZ,IAAA,IAAI,SAAA,CAAU,GAAG,CAAA,EAAG,OAAO,KAAA;AAC3B,IAAA,MAAM,GAAA;AAAA,EACR;AACF;AAEA,SAAS,UAAU,GAAA,EAAuB;AACxC,EAAA,MAAM,OAAQ,GAAA,EAA2C,IAAA;AACzD,EAAA,OAAO,IAAA,KAAS,YAAY,IAAA,KAAS,SAAA;AACvC;;;ACjVA,IAAM,oBAAA,GAAuB,GAAA;AAO7B,IAAM,oBAAA,GAAuB,EAAA;AAyB7B,IAAM,UAAA,GAAa;AAAA,EACjB,IAAA,EAAM,CAAC,MAAA,EAAiC,GAAA,KAAiB,QAAQ,IAAA,CAAK,GAAA,IAAO,WAAW,MAAM,CAAA;AAAA,EAC9F,KAAA,EAAO,CAAC,MAAA,EAAiC,GAAA,KAAiB,QAAQ,KAAA,CAAM,GAAA,IAAO,WAAW,MAAM;AAClG,CAAA;AAEA,eAAsB,wBAAA,CACpB,GAAA,EACA,IAAA,GAAkC,EAAC,EACA;AACnC,EAAA,MAAM,WAAA,GAAc,IAAA,CAAK,IAAA,IAAQ,GAAA,CAAI,MAAA,CAAO,iBAAA;AAC5C,EAAA,MAAM,MAAA,GAAmC;AAAA,IACvC,OAAA,EAAS,QAAQ,WAAW,CAAA;AAAA,IAC5B,OAAA,EAAS,CAAA;AAAA,IACT,QAAA,EAAU,CAAA;AAAA,IACV,SAAA,EAAW,CAAA;AAAA,IACX,OAAA,EAAS;AAAA,GACX;AACA,EAAA,IAAI,CAAC,aAAa,OAAO,MAAA;AAEzB,EAAA,MAAM,GAAA,GAAM,KAAK,GAAA,IAAO,UAAA;AACxB,EAAA,MAAM,MAAA,GAAS,KAAK,UAAA,IAAc,oBAAA;AAIlC,EAAA,MAAM,SAAmB,EAAC;AAC1B,EAAA,IAAI;AACF,IAAA,MAAA,CAAO,IAAA,CAAK,GAAG,oBAAA,CAAqB,WAAW,CAAC,CAAA;AAAA,EAClD,SAAS,GAAA,EAAK;AACZ,IAAA,GAAA,CAAI,QAAQ,EAAE,GAAA,EAAK,IAAA,EAAM,WAAA,IAAe,8CAA8C,CAAA;AAAA,EACxF;AAEA,EAAA,IAAI,aAAA,CAAc,WAAW,CAAA,EAAG;AAC9B,IAAA,MAAM,OAAA,GAAU,aAAa,WAAW,CAAA;AACxC,IAAA,IAAI,OAAA,EAAS,MAAA,CAAO,IAAA,CAAK,OAAO,CAAA;AAAA,EAClC;AACA,EAAA,IAAI,MAAA,CAAO,MAAA,KAAW,CAAA,EAAG,OAAO,MAAA;AAEhC,EAAA,IAAI,eAAA,GAAkB,MAAA;AAEtB,EAAA,KAAA,MAAW,aAAa,MAAA,EAAQ;AAC9B,IAAA,MAAA,CAAO,OAAA,EAAA;AACP,IAAA,MAAM,KAAA,GAAQ,UAAU,SAAS,CAAA;AAEjC,IAAA,IAAI,KAAA,CAAM,QAAQ,kBAAA,EAAoB;AACpC,MAAA,GAAA,CAAI,IAAA;AAAA,QACF,EAAE,MAAM,SAAA,EAAW,KAAA,EAAO,MAAM,KAAA,EAAO,OAAA,EAAS,KAAA,CAAM,OAAA,CAAQ,MAAA,EAAO;AAAA,QACrE;AAAA,OACF;AAAA,IACF;AACA,IAAA,KAAA,MAAW,GAAA,IAAO,MAAM,SAAA,EAAW;AACjC,MAAA,MAAA,CAAO,SAAA,EAAA;AACP,MAAA,GAAA,CAAI,IAAA;AAAA,QACF,EAAE,MAAM,SAAA,EAAW,UAAA,EAAY,IAAI,UAAA,EAAY,OAAA,EAAS,IAAI,OAAA,EAAQ;AAAA,QACpE;AAAA,OACF;AAAA,IACF;AAEA,IAAA,MAAM,WAAgC,EAAC;AACvC,IAAA,IAAI,IAAA,GAAO,KAAA;AAEX,IAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,KAAA,CAAM,OAAA,CAAQ,QAAQ,CAAA,EAAA,EAAK;AAC7C,MAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAA;AAC7B,MAAA,IAAI,IAAA,IAAQ,mBAAmB,CAAA,EAAG;AAChC,QAAA,QAAA,CAAS,KAAK,KAAK,CAAA;AACnB,QAAA;AAAA,MACF;AACA,MAAA,IAAI;AACF,QAAA,MAAM,gBAAA,CAAiB,GAAA,CAAI,WAAA,EAAa,YAAA,CAAa,KAAK,CAAC,CAAA;AAC3D,QAAA,MAAA,CAAO,OAAA,EAAA;AACP,QAAA,eAAA,EAAA;AAAA,MACF,SAAS,GAAA,EAAK;AAGZ,QAAA,IAAA,GAAO,IAAA;AACP,QAAA,QAAA,CAAS,KAAK,KAAK,CAAA;AACnB,QAAA,MAAM,QAAA,GAAA,CAAY,KAAA,CAAM,QAAA,IAAY,CAAA,IAAK,CAAA;AACzC,QAAA,MAAM,MAAA,GAAS,EAAE,GAAA,EAAK,IAAA,EAAM,SAAA,EAAW,UAAU,OAAA,EAAS,KAAA,CAAM,OAAA,CAAQ,MAAA,GAAS,CAAA,EAAE;AACnF,QAAA,IAAI,YAAY,oBAAA,EAAsB;AACpC,UAAA,GAAA,CAAI,KAAA;AAAA,YACF,MAAA;AAAA,YACA;AAAA,WACF;AAAA,QACF,CAAA,MAAO;AACL,UAAA,GAAA,CAAI,IAAA,GAAO,QAAQ,yEAAoE,CAAA;AAAA,QACzF;AAAA,MACF;AAAA,IACF;AAEA,IAAA,MAAA,CAAO,YAAY,QAAA,CAAS,MAAA;AAI5B,IAAA,YAAA,CAAa,WAAA,EAAa,WAAW,QAAQ,CAAA;AAAA,EAC/C;AAEA,EAAA,OAAO,MAAA;AACT;;;AC7JA,IAAM,0BAAA,GAA6B,IAAI,EAAA,GAAK,GAAA;AAO5C,IAAM,6BAAA,GAAgC,IAAI,EAAA,GAAK,GAAA;AAE/C,eAAsB,QAAQ,GAAA,EAAmC;AAI/D,EAAA,IAAI;AACF,IAAA,MAAM,GAAA,CAAI,YAAY,MAAA,CAAO,SAAA;AAAA,MAC3B,EAAE,KAAK,aAAA,EAAc;AAAA,MACrB;AAAA,QACE,IAAA,EAAM,EAAE,SAAA,kBAAW,IAAI,MAAK,EAAE;AAAA,QAC9B,YAAA,EAAc;AAAA,UACZ,GAAA,EAAK,aAAA;AAAA,UACL,YAAA,EAAc,IAAA;AAAA,UACd,IAAA,EAAM,IAAA;AAAA,UACN,eAAA,sBAAqB,IAAA,EAAK;AAAA,UAC1B,gBAAA,EAAkB,GAAA,CAAI,MAAA,CAAO,cAAA,CAAe,gBAAgB,EAAA,GAAK,GAAA;AAAA,UACjE,MAAA,EAAQ,SAAA;AAAA,UACR,SAAA,EAAW,IAAA;AAAA,UACX,aAAA,EAAe,IAAA;AAAA,UACf,iBAAA,EAAmB,IAAA;AAAA,UACnB,QAAA,EAAU,EAAE,IAAA,EAAM,CAAA,EAAG,WAAW,CAAA,EAAG,OAAA,EAAS,CAAA,EAAG,WAAA,EAAa,GAAG,WAAA,EAAa,CAAA,EAAG,UAAA,EAAY,CAAA,EAAG,cAAc,CAAA,EAAE;AAAA,UAC9G,KAAA,EAAO,EAAE,UAAA,EAAY,CAAA,EAAG,gBAAgB,CAAA,EAAG,aAAA,EAAe,CAAA,EAAG,WAAA,EAAa,CAAA;AAAE;AAC9E,OACF;AAAA,MACA,EAAE,QAAQ,IAAA;AAAK,KACjB;AAAA,EACF,SAAS,GAAA,EAAK;AACZ,IAAA,OAAA,CAAQ,KAAA,CAAM,mCAAmC,GAAG,CAAA;AAAA,EACtD;AAIA,EAAA,MAAM,8BAAA,CAA+B,GAAG,CAAA,CAAE,KAAA,CAAM,CAAC,GAAA,KAAQ;AACvD,IAAA,OAAA,CAAQ,KAAA,CAAM,iCAAiC,GAAG,CAAA;AAAA,EACpD,CAAC,CAAA;AACD,EAAA,MAAM,qBAAA,CAAsB,GAAG,CAAA,CAAE,KAAA,CAAM,CAAC,GAAA,KAAQ;AAC9C,IAAA,OAAA,CAAQ,KAAA,CAAM,yBAAyB,GAAG,CAAA;AAAA,EAC5C,CAAC,CAAA;AACD,EAAA,MAAM,kBAAA,CAAmB,GAAG,CAAA,CAAE,KAAA,CAAM,CAAC,GAAA,KAAQ;AAC3C,IAAA,OAAA,CAAQ,KAAA,CAAM,uCAAuC,GAAG,CAAA;AAAA,EAC1D,CAAC,CAAA;AACD,EAAA,MAAM,WAAA,CAAY,GAAG,CAAA,CAAE,KAAA,CAAM,CAAC,GAAA,KAAQ;AACpC,IAAA,OAAA,CAAQ,KAAA,CAAM,gCAAgC,GAAG,CAAA;AAAA,EACnD,CAAC,CAAA;AAMD,EAAA,MAAM,wBAAA,CAAyB,GAAG,CAAA,CAAE,KAAA,CAAM,CAAC,GAAA,KAAQ;AACjD,IAAA,OAAA,CAAQ,KAAA,CAAM,6CAA6C,GAAG,CAAA;AAAA,EAChE,CAAC,CAAA;AACD,EAAA,MAAME,2BAAAA,CAA2B,GAAG,CAAA,CAAE,KAAA,CAAM,CAAC,GAAA,KAAQ;AACnD,IAAA,OAAA,CAAQ,KAAA,CAAM,sCAAsC,GAAG,CAAA;AAAA,EACzD,CAAC,CAAA;AACD,EAAA,MAAM,uBAAA,CAAwB,GAAG,CAAA,CAAE,KAAA,CAAM,CAAC,GAAA,KAAQ;AAChD,IAAA,OAAA,CAAQ,KAAA,CAAM,4CAA4C,GAAG,CAAA;AAAA,EAC/D,CAAC,CAAA;AACD,EAAA,MAAM,cAAA,CAAe,GAAG,CAAA,CAAE,KAAA,CAAM,CAAC,GAAA,KAAQ;AACvC,IAAA,OAAA,CAAQ,KAAA,CAAM,qCAAqC,GAAG,CAAA;AAAA,EACxD,CAAC,CAAA;AACD,EAAA,MAAM,kBAAA,CAAmB,GAAG,CAAA,CAAE,KAAA,CAAM,CAAC,GAAA,KAAQ;AAC3C,IAAA,OAAA,CAAQ,KAAA,CAAM,yCAAyC,GAAG,CAAA;AAAA,EAC5D,CAAC,CAAA;AACD,EAAA,MAAM,qBAAA,CAAsB,KAAK,EAAE,WAAA,EAAa,+BAA+B,CAAA,CAAE,KAAA,CAAM,CAAC,GAAA,KAAQ;AAC9F,IAAA,OAAA,CAAQ,KAAA,CAAM,0CAA0C,GAAG,CAAA;AAAA,EAC7D,CAAC,CAAA;AAKD,EAAA,MAAM,QAAQ,GAAA,CAAI;AAAA,IAChB,cAAA,CAAe,GAAG,CAAA,CAAE,KAAA,CAAM,CAAC,GAAA,KAAQ;AACjC,MAAA,OAAA,CAAQ,KAAA,CAAM,gCAAgC,GAAG,CAAA;AAAA,IACnD,CAAC,CAAA;AAAA,IACD,iBAAA,CAAkB,GAAG,CAAA,CAAE,KAAA,CAAM,CAAC,GAAA,KAAQ;AACpC,MAAA,OAAA,CAAQ,KAAA,CAAM,mCAAmC,GAAG,CAAA;AAAA,IACtD,CAAC,CAAA;AAAA,IACD,WAAA,CAAY,GAAG,CAAA,CAAE,KAAA,CAAM,CAAC,GAAA,KAAQ;AAC9B,MAAA,OAAA,CAAQ,KAAA,CAAM,6BAA6B,GAAG,CAAA;AAAA,IAChD,CAAC,CAAA;AAAA,IACD,kBAAA,CAAmB,GAAG,CAAA,CAAE,KAAA,CAAM,CAAC,GAAA,KAAQ;AACrC,MAAA,OAAA,CAAQ,KAAA,CAAM,+BAA+B,GAAG,CAAA;AAAA,IAClD,CAAC;AAAA,GACF,CAAA;AACH;AAMA,eAAe,mBAAmB,GAAA,EAAmC;AACnE,EAAA,MAAM,SAAS,IAAI,IAAA,CAAK,IAAA,CAAK,GAAA,KAAQ,0BAA0B,CAAA;AAC/D,EAAA,MAAM,MAAA,GAAS,GAAA,CAAI,WAAA,CAAY,KAAA,CAAM,IAAA;AAAA,IACnC,EAAE,MAAA,EAAQ,SAAA,EAAW,WAAW,EAAE,GAAA,EAAK,QAAO,EAAE;AAAA,IAChD,EAAE,UAAA,EAAY,EAAE,GAAA,EAAK,GAAE;AAAE,GAC3B,CAAE,MAAM,GAAG,CAAA;AACX,EAAA,WAAA,MAAiB,OAAO,MAAA,EAAQ;AAC9B,IAAA,MAAM,KAAA,GAAQ,MAAM,GAAA,CAAI,WAAA,CAAY,KAAA,CAAM,SAAA;AAAA,MACxC,EAAE,GAAA,EAAK,GAAA,CAAI,GAAA,EAAK,MAAA,EAAQ,WAAW,SAAA,EAAW,EAAE,GAAA,EAAK,MAAA,EAAO,EAAE;AAAA,MAC9D,EAAE,MAAM,EAAE,MAAA,EAAQ,UAAU,SAAA,kBAAW,IAAI,IAAA,EAAK,EAAE;AAAE,KACtD;AACA,IAAA,IAAI,KAAA,CAAM,kBAAkB,CAAA,EAAG;AAC/B,IAAA,MAAM,GAAA,CAAI,MAAA,CAAO,IAAA,CAAK,GAAA,CAAI,MAAA,EAAQ,EAAE,MAAA,EAAQ,MAAA,CAAO,GAAA,CAAI,GAAG,CAAA,EAAE,EAAG;AAAA,MAC7D,QAAA,EAAU,IAAI,MAAA,CAAO,iBAAA;AAAA,MACrB,OAAA,EAAS,EAAE,IAAA,EAAM,aAAA,EAAe,OAAO,GAAA;AAAO,KAC/C,CAAA;AAAA,EACH;AACF;AAMA,eAAe,YAAY,GAAA,EAAmC;AAC5D,EAAA,MAAM,KAAA,GAAQ,MAAM,GAAA,CAAI,WAAA,CAAY,OACjC,IAAA,CAAK,EAAE,QAAQ,SAAA,EAAW,EAC1B,IAAA,CAAK,EAAE,YAAY,CAAA,EAAG,EACtB,KAAA,CAAM,GAAG,EACT,OAAA,EAAQ;AAEX,EAAA,KAAA,MAAW,OAAO,KAAA,EAAO;AACvB,IAAA,IAAI;AACF,MAAA,IAAI,GAAA,CAAI,OAAA,CAAQ,IAAA,KAAS,OAAA,EAAS;AAChC,QAAA,IAAI;AACF,UAAA,MAAM,GAAA,CAAI,WAAA,CAAY,MAAA,CAAO,SAAA,CAAU;AAAA,YACrC,UAAA,EAAY,GAAA,CAAI,OAAA,CAAQ,IAAA,CAAK,UAAA;AAAA,YAC7B,IAAA,EAAM,GAAA,CAAI,OAAA,CAAQ,IAAA,CAAK,IAAA;AAAA,YACvB,UAAA,EAAa,GAAA,CAAI,OAAA,CAAQ,IAAA,CAAK,cAA0C,EAAC;AAAA,YACzE,SAAA,EAAW,IAAI,OAAA,CAAQ,SAAA;AAAA,YACvB,YAAa,GAAA,CAAI,OAAA,CAAQ,IAAA,CAAK,UAAA,wBAAuC,IAAA,EAAK;AAAA,YAC1E,SAAA,sBAAe,IAAA;AAAK,WACrB,CAAA;AAAA,QACH,SAAS,GAAA,EAAU;AACjB,UAAA,IAAI,GAAA,EAAK,IAAA,KAAS,IAAA,EAAO,MAAM,GAAA;AAAA,QACjC;AAAA,MACF;AACA,MAAA,MAAM,GAAA,CAAI,YAAY,MAAA,CAAO,SAAA;AAAA,QAC3B,EAAE,GAAA,EAAK,GAAA,CAAI,GAAA,EAAI;AAAA,QACf,EAAE,MAAM,EAAE,MAAA,EAAQ,aAAa,WAAA,kBAAa,IAAI,IAAA,EAAK,EAAE;AAAE,OAC3D;AAAA,IACF,SAAS,GAAA,EAAU;AACjB,MAAA,MAAM,GAAA,CAAI,YAAY,MAAA,CAAO,SAAA;AAAA,QAC3B,EAAE,GAAA,EAAK,GAAA,CAAI,GAAA,EAAI;AAAA,QACf;AAAA,UACE,IAAA,EAAM,EAAE,aAAA,kBAAe,IAAI,IAAA,EAAK,EAAG,SAAA,EAAW,MAAA,CAAO,GAAA,EAAK,OAAA,IAAW,GAAG,CAAA,EAAE;AAAA,UAC1E,IAAA,EAAM,EAAE,QAAA,EAAU,CAAA;AAAE;AACtB,OACF;AAAA,IACF;AAAA,EACF;AACF;AASA,eAAeA,4BAA2B,GAAA,EAAmC;AAC3E,EAAA,MAAM,2BAAkB,GAAG,CAAA;AAC7B;;;AC3IO,IAAM,MAAA,GAAN,MAAM,OAAA,CAAO;AAAA,EACT,EAAA;AAAA,EACA,WAAA;AAAA,EACA,OAAA;AAAA,EACA,SAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EAED,WAAA;AAAA,EACA,cAAA,GAAiB,KAAA;AAAA,EACjB,aAAA;AAAA,EAEA,YAAY,IAAA,EAQjB;AACD,IAAA,IAAA,CAAK,SAAS,IAAA,CAAK,MAAA;AACnB,IAAA,IAAA,CAAK,KAAK,IAAA,CAAK,EAAA;AACf,IAAA,IAAA,CAAK,cAAc,IAAA,CAAK,WAAA;AACxB,IAAA,IAAA,CAAK,UAAU,IAAA,CAAK,OAAA;AACpB,IAAA,IAAA,CAAK,YAAY,IAAA,CAAK,SAAA;AACtB,IAAA,IAAA,CAAK,cAAc,IAAA,CAAK,WAAA;AACxB,IAAA,IAAA,CAAK,MAAA,GAAS,KAAK,WAAA,CAAY,MAAA;AAC/B,IAAA,IAAA,CAAK,SAAS,IAAA,CAAK,MAAA;AAEnB,IAAA,IAAA,CAAK,aAAA,GAAgB;AAAA,MACnB,IAAI,IAAA,CAAK,EAAA;AAAA,MACT,aAAa,IAAA,CAAK,WAAA;AAAA,MAClB,SAAS,IAAA,CAAK,OAAA;AAAA,MACd,WAAA,EAAa,KAAK,MAAA,CAAO,WAAA;AAAA,MACzB,WAAW,IAAA,CAAK,SAAA;AAAA,MAChB,QAAQ,IAAA,CAAK,MAAA;AAAA,MACb,QAAQ,IAAA,CAAK,MAAA;AAAA,MACb,iBAAA,EAAmB,KAAK,MAAA,CAAO,iBAAA;AAAA,MAC/B,KAAA,EAAO,CAAC,KAAA,KAAU,IAAA,CAAK,MAAM,KAAK;AAAA,KACpC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA6BA,aAAa,OAAA,GAA2B;AACtC,IAAA,MAAM,MAAM,OAAA,CAAQ,GAAA;AACpB,IAAA,MAAM,QAAA,GAAW,CAAC,CAAA,KAAc;AAC9B,MAAA,MAAM,CAAA,GAAI,IAAI,CAAC,CAAA;AACf,MAAA,IAAI,CAAC,CAAA,EAAG,MAAM,IAAI,KAAA,CAAM,CAAA,gCAAA,EAAmC,CAAC,CAAA,CAAE,CAAA;AAC9D,MAAA,OAAO,CAAA;AAAA,IACT,CAAA;AAEA,IAAA,MAAM,EAAE,WAAA,EAAY,GAAI,MAAM,OAAO,SAAS,CAAA;AAC9C,IAAA,MAAM,cAAc,MAAM,WAAA,CAAY,OAAA,CAAQ,QAAA,CAAS,oBAAoB,CAAC,CAAA;AAC5E,IAAA,MAAM,EAAA,GAAK,IAAI,iBAAA,GAAoB,WAAA,CAAY,GAAG,GAAA,CAAI,iBAAiB,CAAA,GAAI,WAAA,CAAY,EAAA,EAAG;AAE1F,IAAA,MAAM,EAAE,mBAAA,EAAAvB,oBAAAA,EAAoB,GAAI,MAAM,OAAA,CAAA,OAAA,EAAA,CAAA,IAAA,CAAA,OAAA,UAAA,EAAA,EAAA,aAAA,CAAA,CAAA;AACtC,IAAA,MAAM,OAAA,GAAU,IAAIA,oBAAAA,CAAoB;AAAA,MACtC,EAAA;AAAA,MACA,UAAA,EAAY,IAAI,4BAAA,IAAgC,OAAA;AAAA,MAChD,UAAA,EAAY,IAAI,6BAAA,IAAiC,OAAA;AAAA,MACjD,OAAA,EAAS,IAAI,0BAAA,IAA8B,KAAA;AAAA,MAC3C,WAAW,GAAA,CAAI,4BAAA;AAAA,MACf,YAAA,EACE,GAAA,CAAI,+BAAA,KAAoC,GAAA,IAAO,IAAI,+BAAA,KAAoC;AAAA,KAC1F,CAAA;AAED,IAAA,MAAM,YAA0C,EAAC;AACjD,IAAA,IAAI,IAAI,uBAAA,EAAyB;AAC/B,MAAA,MAAM,EAAE,gBAAA,EAAAE,iBAAAA,EAAiB,GAAI,MAAM,OAAA,CAAA,OAAA,EAAA,CAAA,IAAA,CAAA,OAAA,aAAA,EAAA,EAAA,gBAAA,CAAA,CAAA;AACnC,MAAA,SAAA,CAAU,QAAA,GAAW,IAAIA,iBAAAA,CAAiB;AAAA,QACxC,QAAQ,GAAA,CAAI,uBAAA;AAAA,QACZ,wBAAwB,GAAA,CAAI,2BAAA;AAAA;AAAA;AAAA;AAAA,QAI5B,yBAAyB,GAAA,CAAI,iCAAA,GACzB,MAAA,CAAO,GAAA,CAAI,iCAAiC,CAAA,GAC5C,MAAA;AAAA,QACJ,OAAA,EAAS,IAAI,QAAA,KAAa;AAAA,OAC3B,CAAA;AAAA,IACH;AACA,IAAA,IAAI,MAAA,CAAO,IAAA,CAAK,SAAS,CAAA,CAAE,WAAW,CAAA,EAAG;AACvC,MAAA,MAAM,IAAI,MAAM,2EAA2E,CAAA;AAAA,IAC7F;AAEA,IAAA,MAAM,kBAAkB,GAAA,CAAI,uBAAA,IAA2B,OAAO,IAAA,CAAK,SAAS,EAAE,CAAC,CAAA;AAE/E,IAAA,MAAM,SAAA,GAAY,IAAI,mBAAA,IAAuB,MAAA;AAC7C,IAAA,MAAM,KAAA,GACJ,SAAA,KAAc,QAAA,GACT,EAAE,QAAQ,QAAA,EAAmB,MAAA,EAAQ,GAAA,CAAI,mBAAA,KAC1C,SAAA,KAAc,MAAA,GACb,EAAE,MAAA,EAAQ,QAAgB,GAC1B;AAAA,MACC,MAAA,EAAQ,MAAA;AAAA,MACR,KAAA,EAAO,EAAE,GAAA,EAAK,QAAA,CAAS,kBAAkB,CAAA,EAAE;AAAA,MAC3C,QAAQ,GAAA,CAAI;AAAA,KACd;AAEN,IAAA,OAAO,QAAO,IAAA,CAAK;AAAA,MACjB,EAAA;AAAA,MACA,OAAA;AAAA,MACA,KAAA;AAAA,MACA,SAAA;AAAA,MACA,eAAA;AAAA,MACA,SAAA,EAAW,SAAS,mBAAmB,CAAA;AAAA,MACvC,iBAAA,EAAmB,SAAS,2BAA2B,CAAA;AAAA,MACvD,eAAe,GAAA,CAAI,qBAAA;AAAA,MACnB,YAAA,EACE,GAAA,CAAI,gBAAA,IAAoB,GAAA,CAAI,iBAAA,GACxB,EAAE,IAAA,EAAM,GAAA,CAAI,gBAAA,EAAkB,KAAA,EAAO,GAAA,CAAI,iBAAA,EAAkB,GAC3D;AAAA,KACP,CAAA;AAAA,EACH;AAAA,EAEA,aAAa,KAAK,KAAA,EAAsC;AACtD,IAAA,MAAM,MAAA,GAAS,cAAc,KAAK,CAAA;AAMlC,IAAA,IAAI,CAAC,eAAA,CAAgB,MAAA,CAAO,SAAA,EAAW,MAAA,CAAO,eAAe,CAAA,EAAG;AAC9D,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,CAAA,iBAAA,EAAoB,MAAA,CAAO,eAAe,CAAA,4CAAA,EACvB,uBAAA,CAAwB,MAAA,CAAO,SAAS,CAAA,CAAE,IAAA,CAAK,IAAI,CAAA,IAAK,QAAQ,CAAA;AAAA,OACrF;AAAA,IACF;AACA,IAAA,IACE,MAAA,CAAO,gCAAgC,IAAA,IACpC,CAAC,gBAAgB,MAAA,CAAO,SAAA,EAAW,MAAA,CAAO,4BAA4B,CAAA,EACzE;AACA,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,CAAA,8BAAA,EAAiC,MAAA,CAAO,4BAA4B,CAAA,4CAAA,EAEjD,uBAAA,CAAwB,MAAA,CAAO,SAAS,CAAA,CAAE,IAAA,CAAK,IAAI,CAAA,IAAK,QAAQ,CAAA;AAAA,OACrF;AAAA,IACF;AACA,IAAA,IAAI,OAAO,WAAA,EAAa;AACtB,MAAA,MAAM,EAAE,uBAAA,EAAAsB,wBAAAA,EAAwB,GAAI,MAAM,OAAA,CAAA,OAAA,EAAA,CAAA,IAAA,CAAA,OAAA,SAAA,EAAA,EAAA,YAAA,CAAA,CAAA;AAC1C,MAAAA,wBAAAA,CAAwB,OAAO,WAAW,CAAA;AAAA,IAC5C;AAEA,IAAA,MAAM,WAAA,GAAc,cAAA,CAAe,MAAA,CAAO,EAAA,EAAI,OAAO,gBAAgB,CAAA;AACrE,IAAA,MAAM,aAAA,CAAc,MAAA,CAAO,EAAA,EAAI,MAAA,CAAO,gBAAgB,CAAA;AAEtD,IAAA,MAAM,cAAc,MAAM,iBAAA,CAAkB,MAAA,CAAO,KAAA,EAAO,OAAO,EAAE,CAAA;AACnE,IAAA,IAAI,CAAC,MAAA,CAAO,UAAA,IAAc,MAAA,CAAO,KAAA,CAAM,WAAW,MAAA,EAAQ;AACxD,MAAA,MAAM,WAAA,CAAY,qBAAA,CAAsB,MAAA,CAAO,mBAAmB,CAAA;AAAA,IACpE;AAEA,IAAA,OAAO,IAAI,OAAA,CAAO;AAAA,MAChB,MAAA;AAAA,MACA,IAAI,MAAA,CAAO,EAAA;AAAA,MACX,WAAA;AAAA,MACA,SAAS,MAAA,CAAO,OAAA;AAAA,MAChB,WAAW,MAAA,CAAO,SAAA;AAAA,MAClB,WAAA;AAAA,MACA,MAAA,EAAQ,IAAI,aAAA;AAAc,KAC3B,CAAA;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAMA,cAAc,GAAA,EAA+B;AAC3C,IAAA,MAAM,MAAA,GAAS,mBAAA,CAAoB,KAAA,CAAM,GAAG,CAAA;AAC5C,IAAA,IAAA,CAAK,MAAA,CAAO,SAAS,MAAM,CAAA;AAAA,EAC7B;AAAA,EAEA,MAAM,IAAA,CACJ,SAAA,EACA,YACA,UAAA,GAAsC,IACtC,SAAA,EACe;AACf,IAAA,MAAM,KAAA,GAAQ,gBAAgB,KAAA,CAAM,EAAE,WAAW,UAAA,EAAY,UAAA,EAAY,WAAW,CAAA;AACpF,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,MAAA,CAAO,SAAA,CAAU,KAAA,CAAM,SAAA,EAAW,KAAA,CAAM,UAAA,EAAY,KAAA,CAAM,SAAA,kBAAW,IAAI,IAAA,EAAM,CAAA;AAChG,IAAA,IAAI,CAAC,GAAA,EAAK;AACR,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,CAAA,MAAA,EAAS,KAAA,CAAM,SAAS,CAAA,0EAAA,EACQ,MAAM,SAAS,CAAA,8CAAA;AAAA,OACjD;AAAA,IACF;AACA,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,CAAK,WAAA,CAAY,MAAA,CAAO,SAAA,CAAU;AAAA,QACtC,YAAY,KAAA,CAAM,UAAA;AAAA,QAClB,MAAM,KAAA,CAAM,SAAA;AAAA,QACZ,UAAA,EAAY,KAAA,CAAM,UAAA,IAAc,EAAC;AAAA,QACjC,SAAA,EAAW,GAAA;AAAA,QACX,UAAA,sBAAgB,IAAA,EAAK;AAAA,QACrB,SAAA,sBAAe,IAAA;AAAK,OACrB,CAAA;AAAA,IACH,SAAS,GAAA,EAAU;AACjB,MAAA,IAAI,GAAA,EAAK,IAAA,KAAS,IAAA,EAAO,MAAM,GAAA;AAAA,IAEjC;AAAA,EACF;AAAA,EAEA,MAAM,gBACJ,OAAA,EACA,SAAA,EACA,YACA,UAAA,GAAsC,IACtC,SAAA,EACe;AACf,IAAA,MAAM,KAAA,GAAQ,gBAAgB,KAAA,CAAM,EAAE,WAAW,UAAA,EAAY,UAAA,EAAY,WAAW,CAAA;AACpF,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,MAAA,CAAO,SAAA,CAAU,KAAA,CAAM,SAAA,EAAW,KAAA,CAAM,UAAA,EAAY,KAAA,CAAM,SAAA,kBAAW,IAAI,IAAA,EAAM,CAAA;AAChG,IAAA,IAAI,CAAC,GAAA,EAAK;AACR,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,iBAAA,EAAoB,KAAA,CAAM,SAAS,CAAA,8CAAA,CAAgD,CAAA;AAAA,IACrG;AACA,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,CAAK,YAAY,MAAA,CAAO,SAAA;AAAA,QAC5B;AAAA,UACE,OAAA,EAAS;AAAA,YACP,IAAA,EAAM,OAAA;AAAA,YACN,IAAA,EAAM;AAAA,cACJ,YAAY,KAAA,CAAM,UAAA;AAAA,cAClB,MAAM,KAAA,CAAM,SAAA;AAAA,cACZ,UAAA,EAAY,KAAA,CAAM,UAAA,IAAc,EAAC;AAAA,cACjC,UAAA,sBAAgB,IAAA;AAAK,aACvB;AAAA,YACA,SAAA,EAAW;AAAA,WACb;AAAA,UACA,MAAA,EAAQ,SAAA;AAAA,UACR,QAAA,EAAU,CAAA;AAAA,UACV,aAAA,EAAe,IAAA;AAAA,UACf,SAAA,EAAW,IAAA;AAAA,UACX,UAAA,sBAAgB,IAAA,EAAK;AAAA,UACrB,WAAA,EAAa;AAAA,SACf;AAAA,QACA,EAAE,OAAA;AAAQ,OACZ;AAAA,IACF,SAAS,GAAA,EAAU;AACjB,MAAA,IAAI,GAAA,EAAK,IAAA,KAAS,IAAA,EAAO,MAAM,GAAA;AAAA,IACjC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,mBAAmB,KAAA,EAA+C;AACtE,IAAA,MAAM,MAAA,GAAS,wBAAA,CAAyB,KAAA,CAAM,KAAK,CAAA;AACnD,IAAA,MAAM,UAAU,MAAM,IAAA,CAAK,OAAA,CAAQ,OAAA,CAAQ,OAAO,UAAU,CAAA;AAC5D,IAAA,IAAI,CAAC,SAAS,MAAM,IAAI,MAAM,CAAA,sCAAA,EAAyC,MAAA,CAAO,UAAU,CAAA,CAAE,CAAA;AAE1F,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,MAAA,CAAO,kBAAA,GAAqB,aAAA,GAAgB,YAAA;AAChE,IAAA,MAAM,GAAA,uBAAU,IAAA,EAAK;AAIrB,IAAA,IAAI,QAAA,GAA0B,IAAA;AAC9B,IAAA,IAAI,YAAA,GAA8B,IAAA;AAClC,IAAA,IAAI,WAAW,aAAA,EAAe;AAC5B,MAAA,MAAM,SAAA,GAAY,IAAI,IAAA,CAAK,GAAA,CAAI,SAAQ,GAAI,IAAA,CAAK,MAAA,CAAO,oBAAA,GAAuB,KAAU,CAAA;AACxF,MAAA,QAAA,GAAW,YAAA,CAAa,EAAE,UAAA,EAAY,MAAA,CAAO,YAAY,SAAA,EAAU,EAAG,IAAA,CAAK,MAAA,CAAO,iBAAiB,CAAA;AACnG,MAAA,YAAA,GAAe,UAAU,QAAQ,CAAA;AAAA,IACnC;AAEA,IAAA,MAAM,IAAA,CAAK,YAAY,aAAA,CAAc,SAAA;AAAA,MACnC,EAAE,UAAA,EAAY,MAAA,CAAO,UAAA,EAAW;AAAA,MAChC;AAAA,QACE,IAAA,EAAM;AAAA,UACJ,MAAA;AAAA,UACA,QAAQ,MAAA,CAAO,MAAA;AAAA,UACf,kBAAkB,OAAA,CAAQ,KAAA;AAAA,UAC1B,YAAA,EAAc,MAAA,KAAW,YAAA,GAAgB,MAAA,CAAO,oBAAoB,GAAA,GAAO,IAAA;AAAA,UAC3E,SAAA,EAAW,GAAA;AAAA,UACX,GAAI,YAAA,GAAe,EAAE,cAAc,cAAA,EAAgB,GAAA,KAAQ;AAAC,SAC9D;AAAA,QACA,YAAA,EAAc;AAAA,UACZ,YAAY,MAAA,CAAO,UAAA;AAAA,UACnB,SAAA,EAAW,GAAA;AAAA,UACX,cAAA,EAAgB,IAAA;AAAA,UAChB,iBAAA,EAAmB,IAAA;AAAA,UACnB,YAAA,EAAc,IAAA;AAAA,UACd,cAAA,EAAgB,IAAA;AAAA,UAChB,cAAA,EAAgB,IAAA;AAAA,UAChB,KAAA,EAAO,OAAO,SAAA,IAAa,IAAA;AAAA,UAC3B,YAAA,EAAc,OAAO,gBAAA,IAAoB;AAAA;AAC3C,OACF;AAAA,MACA,EAAE,QAAQ,IAAA;AAAK,KACjB;AAIA,IAAA,IAAI,MAAA,KAAW,iBAAiB,QAAA,EAAU;AACxC,MAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,WAAA,CAAY,SAAA,CAAU,OAAA,CAAQ,EAAE,IAAA,EAAM,IAAA,CAAK,MAAA,CAAO,eAAA,EAAiB,CAAA;AAC1F,MAAA,IAAI,CAAC,GAAA,EAAK;AACR,QAAA,OAAA,CAAQ,IAAA,CAAK,CAAA,oCAAA,EAAuC,IAAA,CAAK,MAAA,CAAO,eAAe,CAAA,8CAAA,CAA2C,CAAA;AAC1H,QAAA;AAAA,MACF;AACA,MAAA,MAAM,SAAA,GAAY,CAAA,IAAA,EAAO,MAAA,CAAO,UAAU,CAAA,CAAA,EAAI,GAAA,CAAI,WAAA,EAAY,CAAE,KAAA,CAAM,CAAA,EAAG,EAAE,CAAC,CAAA,CAAA;AAC5E,MAAA,IAAI;AACF,QAAA,MAAM,KAAK,UAAA,CAAW;AAAA,UACpB,cAAc,GAAA,CAAI,IAAA;AAAA,UAClB,YAAY,MAAA,CAAO,UAAA;AAAA,UACnB,IAAA,EAAM,EAAE,aAAA,EAAe,CAAA,EAAG,KAAK,MAAA,CAAO,SAAS,CAAA,eAAA,EAAkB,QAAQ,CAAA,CAAA,EAAG;AAAA,UAC5E;AAAA,SACD,CAAA;AAAA,MACH,SAAS,GAAA,EAAK;AACZ,QAAA,OAAA,CAAQ,KAAA,CAAM,yCAAyC,GAAG,CAAA;AAAA,MAC5D;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,WAAA,CAAY,KAAA,EAAe,IAAA,EAAsD;AACrF,IAAA,MAAM,SAAS,sBAAA,CAAuB,KAAA,CAAM,EAAE,KAAA,EAAO,GAAG,MAAM,CAAA;AAC9D,IAAA,MAAM,gBAAA,CAAiB,IAAA,CAAK,WAAA,EAAa,MAAM,CAAA;AAAA,EACjD;AAAA,EAEA,MAAM,QAAA,CAAS,KAAA,EAAe,IAAA,EAAmD;AAC/E,IAAA,MAAM,SAAS,mBAAA,CAAoB,KAAA,CAAM,EAAE,KAAA,EAAO,GAAG,MAAM,CAAA;AAC3D,IAAA,MAAM,IAAA,CAAK,YAAY,YAAA,CAAa,SAAA;AAAA,MAClC,EAAE,KAAA,EAAO,MAAA,CAAO,KAAA,EAAO,KAAA,EAAO,OAAO,KAAA,EAAM;AAAA,MAC3C;AAAA,QACE,YAAA,EAAc;AAAA,UACZ,OAAO,MAAA,CAAO,KAAA;AAAA,UACd,SAAA,EAAW,SAAA,CAAU,MAAA,CAAO,KAAK,CAAA;AAAA,UACjC,OAAO,MAAA,CAAO,KAAA;AAAA,UACd,QAAQ,MAAA,CAAO,MAAA;AAAA,UACf,QAAQ,MAAA,CAAO,MAAA;AAAA,UACf,KAAA,EAAO,OAAO,KAAA,IAAS,IAAA;AAAA,UACvB,OAAA,sBAAa,IAAA,EAAK;AAAA,UAClB,SAAA,EAAW,OAAO,SAAA,IAAa;AAAA;AACjC,OACF;AAAA,MACA,EAAE,QAAQ,IAAA;AAAK,KACjB;AAAA,EACF;AAAA,EAEA,MAAM,GAAA,CAAI,UAAA,EAAoB,GAAA,EAA4B;AACxD,IAAA,MAAM,SAAS,cAAA,CAAe,KAAA,CAAM,EAAE,UAAA,EAAY,KAAK,CAAA;AACvD,IAAA,IAAI,IAAA,CAAK,QAAQ,OAAA,EAAS;AACxB,MAAA,MAAM,IAAA,CAAK,QAAQ,OAAA,CAAQ,MAAA,CAAO,YAAY,CAAC,MAAA,CAAO,GAAG,CAAC,CAAA;AAAA,IAC5D,CAAA,MAAO;AACL,MAAA,MAAM,IAAA,CAAK,YAAY,WAAA,CAAY,SAAA;AAAA,QACjC,EAAE,UAAA,EAAY,MAAA,CAAO,UAAA,EAAY,GAAA,EAAK,OAAO,GAAA,EAAI;AAAA,QACjD;AAAA,UACE,YAAA,EAAc;AAAA,YACZ,YAAY,MAAA,CAAO,UAAA;AAAA,YACnB,KAAK,MAAA,CAAO,GAAA;AAAA,YACZ,SAAA,EAAW,OAAA;AAAA,YACX,SAAA,sBAAe,IAAA;AAAK;AACtB,SACF;AAAA,QACA,EAAE,QAAQ,IAAA;AAAK,OACjB;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,KAAA,CAAM,UAAA,EAAoB,GAAA,EAA4B;AAC1D,IAAA,MAAM,SAAS,cAAA,CAAe,KAAA,CAAM,EAAE,UAAA,EAAY,KAAK,CAAA;AACvD,IAAA,IAAI,IAAA,CAAK,QAAQ,UAAA,EAAY;AAC3B,MAAA,MAAM,IAAA,CAAK,QAAQ,UAAA,CAAW,MAAA,CAAO,YAAY,CAAC,MAAA,CAAO,GAAG,CAAC,CAAA;AAAA,IAC/D,CAAA,MAAO;AACL,MAAA,MAAM,IAAA,CAAK,WAAA,CAAY,WAAA,CAAY,SAAA,CAAU,EAAE,UAAA,EAAY,MAAA,CAAO,UAAA,EAAY,GAAA,EAAK,MAAA,CAAO,GAAA,EAAK,CAAA;AAAA,IACjG;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,MAAM,SAAA,CACJ,QAAA,EACA,UAAA,EACA,IAAA,GAA8E,EAAC,EACrB;AAC1D,IAAA,MAAM,MAAA,GAAS,qBAAqB,KAAA,CAAM;AAAA,MACxC,QAAA;AAAA,MACA,UAAA;AAAA,MACA,QAAQ,IAAA,CAAK,MAAA;AAAA,MACb,wBAAwB,IAAA,CAAK;AAAA,KAC9B,CAAA;AACD,IAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,WAAA,CAAY,KAAA,CAAM,OAAA;AAAA,MACxC,EAAE,IAAA,EAAM,MAAA,CAAO,QAAA,EAAS;AAAA,MACxB,EAAE,UAAA,EAAY,EAAE,GAAA,EAAK,GAAE;AAAE,KAC3B;AACA,IAAA,IAAI,CAAC,MAAM,MAAM,IAAI,MAAM,CAAA,8BAAA,EAAiC,MAAA,CAAO,QAAQ,CAAA,CAAA,CAAG,CAAA;AAI9E,IAAA,MAAM,eAAe,MAAA,CAAO,WAAA;AAAA,MAC1B,MAAA,CAAO,OAAA,CAAQ,MAAA,CAAO,sBAAA,IAA0B,EAAE,CAAA,CAAE,GAAA,CAAI,CAAC,CAAC,CAAA,EAAG,CAAC,CAAA,KAAM;AAAA,QAClE,2BAA2B,CAAC,CAAA,CAAA;AAAA,QAC5B;AAAA,OACD;AAAA,KACH;AAEA,IAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,eAAA;AAAA,MACxB,EAAE,YAAY,MAAA,CAAO,UAAA,EAAY,QAAQ,IAAA,CAAK,GAAA,EAAM,GAAG,YAAA,EAAa;AAAA,MACpE,MAAA,CAAO,MAAA,GAAS,CAAA,gBAAA,EAAmB,MAAA,CAAO,MAAM,CAAA,CAAA,GAAK;AAAA,KACvD;AACA,IAAA,IAAI,MAAA,CAAO,WAAA,GAAc,CAAA,IAAK,MAAA,CAAO,iBAAiB,CAAA,EAAG;AACvD,MAAA,MAAM,KAAK,KAAA,CAAM;AAAA,QACf,KAAA,EAAO,MAAA;AAAA,QACP,MAAA,EAAQ,YAAA;AAAA,QACR,UAAU,EAAE,UAAA,EAAY,kBAAA,EAAoB,IAAA,EAAM,OAAO,QAAA,EAAS;AAAA;AAAA;AAAA,QAGlE,WAAA,EAAa,CAAA,eAAA,EAAkB,MAAA,CAAO,QAAQ,CAAA,YAAA,EAAe,MAAA,CAAO,UAAU,CAAA,OAAA,EAC5E,MAAA,CAAO,sBAAA,GAAyB,IAAA,CAAK,SAAA,CAAU,MAAA,CAAO,sBAAsB,CAAA,GAAI,KAClF,CAAA,MAAA,EAAS,MAAA,CAAO,WAAW,CAAA,OAAA,EAAU,MAAA,CAAO,cAAc,CAAA,EAAG,MAAA,CAAO,MAAA,GAAS,CAAA,QAAA,EAAW,MAAA,CAAO,MAAM,KAAK,EAAE,CAAA;AAAA,OAC7G,CAAA;AAAA,IACH;AACA,IAAA,OAAO,MAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,aAAA,CACJ,UAAA,EACA,IAAA,GAA4B,EAAC,EAC6B;AAC1D,IAAA,MAAM,MAAA,GAAS,yBAAyB,KAAA,CAAM,EAAE,YAAY,MAAA,EAAQ,IAAA,CAAK,QAAQ,CAAA;AAEjF,IAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,eAAA;AAAA,MACxB,EAAE,UAAA,EAAY,MAAA,CAAO,UAAA,EAAW;AAAA,MAChC,MAAA,CAAO,MAAA,GAAS,CAAA,gBAAA,EAAmB,MAAA,CAAO,MAAM,CAAA,CAAA,GAAK;AAAA,KACvD;AACA,IAAA,IAAI,MAAA,CAAO,WAAA,GAAc,CAAA,IAAK,MAAA,CAAO,iBAAiB,CAAA,EAAG;AACvD,MAAA,MAAM,KAAK,KAAA,CAAM;AAAA,QACf,KAAA,EAAO,MAAA;AAAA,QACP,MAAA,EAAQ,gBAAA;AAAA,QACR,QAAA,EAAU,EAAE,UAAA,EAAY,kBAAA,EAAmB;AAAA,QAC3C,aAAa,CAAA,yBAAA,EAA4B,MAAA,CAAO,UAAU,CAAA,MAAA,EAAS,OAAO,WAAW,CAAA,OAAA,EAAU,MAAA,CAAO,cAAc,GAAG,MAAA,CAAO,MAAA,GAAS,WAAW,MAAA,CAAO,MAAM,KAAK,EAAE,CAAA;AAAA,OACvK,CAAA;AAAA,IACH;AACA,IAAA,OAAO,MAAA;AAAA,EACT;AAAA,EAEA,MAAc,eAAA,CAGZ,MAAA,EACA,UAAA,EAC0D;AAC1D,IAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,WAAA,CAAY,QAAA,CACjC,IAAA,CAAK,EAAE,GAAG,MAAA,EAAQ,MAAA,EAAQ,QAAA,EAAU,EACpC,OAAA,EAAQ;AACX,IAAA,IAAI,IAAA,CAAK,WAAW,CAAA,EAAG,OAAO,EAAE,WAAA,EAAa,CAAA,EAAG,gBAAgB,CAAA,EAAE;AAElE,IAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,MAAA,MAAM,WAAA,CAAY,GAAA,EAAK,UAAA,EAAY,IAAA,CAAK,aAAa,CAAA;AAAA,IACvD;AAMA,IAAA,MAAM,SAAA,GAAY,MAAM,IAAA,CAAK,WAAA,CAAY,KAAA,CAAM,UAAA;AAAA,MAC7C,EAAE,SAAA,EAAW,EAAE,KAAK,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,GAAI,CAAA,EAAE,EAAG,QAAQ,EAAE,GAAA,EAAK,CAAC,QAAA,EAAU,QAAQ,GAAE,EAAE;AAAA,MACrF,EAAE,IAAA,EAAM,EAAE,MAAA,EAAQ,WAAA,EAAa,YAAA,EAAc,CAAA,WAAA,EAAc,UAAU,CAAA,CAAA,EAAI,SAAA,kBAAW,IAAI,IAAA,IAAO;AAAE,KACnG;AAEA,IAAA,OAAO,EAAE,WAAA,EAAa,IAAA,CAAK,MAAA,EAAQ,cAAA,EAAgB,UAAU,aAAA,EAAc;AAAA,EAC7E;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,OAAO,UAAA,EAAmC;AAC9C,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,WAAA,CAAY,cAAc,OAAA,CAAQ,EAAE,YAAY,CAAA;AACvE,IAAA,MAAM,KAAA,GAAQ,GAAA,EAAK,gBAAA,EAAkB,WAAA,EAAY;AAEjD,IAAA,MAAM,SAAA,GAAY,MAAM,OAAA,CAAQ,GAAA,CAAI;AAAA,MAClC,IAAA,CAAK,WAAA,CAAY,KAAA,CAAM,IAAA,CAAK,EAAE,UAAA,EAAY,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,WAAW,EAAE,OAAA;AAAQ,KAC/E,CAAA;AACD,IAAA,MAAM,MAAA,uBAAa,GAAA,EAAY;AAC/B,IAAA,IAAI,KAAA,EAAO,MAAA,CAAO,GAAA,CAAI,KAAK,CAAA;AAC3B,IAAA,KAAA,MAAW,CAAA,IAAK,SAAA,CAAU,CAAC,CAAA,EAAG,IAAI,GAAG,MAAA,CAAO,GAAA,CAAI,CAAA,CAAE,WAAA,EAAa,CAAA;AAE/D,IAAA,MAAM,QAAQ,GAAA,CAAI;AAAA,MAChB,KAAK,WAAA,CAAY,MAAA,CAAO,UAAA,CAAW,EAAE,YAAY,CAAA;AAAA,MACjD,KAAK,WAAA,CAAY,QAAA,CAAS,UAAA,CAAW,EAAE,YAAY,CAAA;AAAA,MACnD,KAAK,WAAA,CAAY,KAAA,CAAM,UAAA,CAAW,EAAE,YAAY,CAAA;AAAA,MAChD,KAAK,WAAA,CAAY,aAAA,CAAc,UAAA,CAAW,EAAE,YAAY,CAAA;AAAA,MACxD,KAAK,WAAA,CAAY,WAAA,CAAY,UAAA,CAAW,EAAE,YAAY;AAAA,KACvD,CAAA;AACD,IAAA,IAAI,KAAA,EAAO;AACT,MAAA,MAAM,KAAK,WAAA,CAAY,KAAA,CAAM,UAAA,CAAW,EAAE,OAAO,CAAA;AAAA,IACnD;AAEA,IAAA,KAAA,MAAW,KAAK,MAAA,EAAQ;AACtB,MAAA,MAAM,IAAA,CAAK,YAAY,YAAA,CAAa,SAAA;AAAA,QAClC,EAAE,SAAA,EAAW,SAAA,CAAU,CAAC,CAAA,EAAG,OAAO,KAAA,EAAM;AAAA,QACxC;AAAA,UACE,YAAA,EAAc;AAAA,YACZ,KAAA,EAAO,IAAA;AAAA,YACP,SAAA,EAAW,UAAU,CAAC,CAAA;AAAA,YACtB,KAAA,EAAO,KAAA;AAAA,YACP,MAAA,EAAQ,aAAA;AAAA,YACR,MAAA,EAAQ,cAAA;AAAA,YACR,KAAA,EAAO,IAAA;AAAA,YACP,OAAA,sBAAa,IAAA,EAAK;AAAA,YAClB,SAAA,EAAW;AAAA;AACb,SACF;AAAA,QACA,EAAE,QAAQ,IAAA;AAAK,OACjB;AAAA,IACF;AAEA,IAAA,MAAM,KAAK,KAAA,CAAM;AAAA,MACf,KAAA,EAAO,aAAA;AAAA,MACP,MAAA,EAAQ,aAAA;AAAA,MACR,UAAU,EAAE,UAAA,EAAY,sBAAA,EAAwB,EAAA,EAAI,KAAK,GAAA,EAAI;AAAA,MAC7D,WAAA,EAAa,qBAAqB,UAAU,CAAA;AAAA,KAC7C,CAAA;AAAA,EACH;AAAA;AAAA,EAGA,MAAM,kBAAkB,UAAA,EAAsD;AAC5E,IAAA,MAAM,YAAA,GAAe,MAAM,IAAA,CAAK,WAAA,CAAY,cAAc,OAAA,CAAQ,EAAE,YAAY,CAAA;AAChF,IAAA,MAAM,CAAC,QAAQ,QAAA,EAAU,KAAA,EAAO,cAAc,IAAI,CAAA,GAAI,MAAM,OAAA,CAAQ,GAAA,CAAI;AAAA,MACtE,IAAA,CAAK,YAAY,MAAA,CAAO,IAAA,CAAK,EAAE,UAAA,EAAY,EAAE,OAAA,EAAQ;AAAA,MACrD,IAAA,CAAK,YAAY,QAAA,CAAS,IAAA,CAAK,EAAE,UAAA,EAAY,EAAE,OAAA,EAAQ;AAAA,MACvD,IAAA,CAAK,YAAY,KAAA,CAAM,IAAA,CAAK,EAAE,UAAA,EAAY,EAAE,OAAA,EAAQ;AAAA,MACpD,cAAc,gBAAA,GACV,IAAA,CAAK,WAAA,CAAY,YAAA,CAAa,KAAK,EAAE,KAAA,EAAO,YAAA,CAAa,gBAAA,EAAkB,CAAA,CAAE,OAAA,KAC7E,OAAA,CAAQ,OAAA,CAAQ,EAAE,CAAA;AAAA,MACtB,IAAA,CAAK,YAAY,WAAA,CAAY,IAAA,CAAK,EAAE,UAAA,EAAY,EAAE,OAAA;AAAQ,KAC3D,CAAA;AACD,IAAA,OAAO,EAAE,YAAA,EAAc,MAAA,EAAQ,QAAA,EAAU,KAAA,EAAO,cAAc,IAAA,EAAK;AAAA,EACrE;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,WAAW,KAAA,EAAqD;AACpE,IAAA,MAAM,MAAA,GAAS,qBAAA,CAAsB,KAAA,CAAM,KAAK,CAAA;AAChD,IAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,WAAA,CAAY,SAAA,CAAU,QAAQ,EAAE,IAAA,EAAM,MAAA,CAAO,YAAA,EAAc,CAAA;AACvF,IAAA,IAAI,CAAC,UAAU,MAAM,IAAI,MAAM,CAAA,oBAAA,EAAuB,MAAA,CAAO,YAAY,CAAA,CAAE,CAAA;AAE3E,IAAA,MAAM,UAAU,MAAM,IAAA,CAAK,OAAA,CAAQ,OAAA,CAAQ,OAAO,UAAU,CAAA;AAC5D,IAAA,IAAI,CAAC,SAAS,MAAM,IAAI,MAAM,CAAA,mBAAA,EAAsB,MAAA,CAAO,UAAU,CAAA,CAAE,CAAA;AAEvE,IAAA,MAAM,SAAA,GAAY,CAAA,OAAA,EAAU,MAAA,CAAO,SAAS,CAAA,CAAA;AAC5C,IAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,WAAA,CAAY,MAAM,OAAA,CAAQ,EAAE,WAAW,CAAA;AACnE,IAAA,IAAI,UAAU,OAAO,EAAE,QAAQ,MAAA,CAAO,QAAA,CAAS,GAAG,CAAA,EAAE;AAEpD,IAAA,MAAM,YAAA,GACJ,MAAA,CAAO,gBAAA,IACJ,QAAA,CAAS,gBAAA,KACR,QAAA,CAAS,IAAA,KAAS,eAAA,GAAkB,IAAA,CAAK,MAAA,CAAO,4BAAA,GAA+B,IAAA,CAAA,IAChF,KAAK,MAAA,CAAO,eAAA;AAEjB,IAAA,MAAM,MAAA,GAAS,IAAIC,gBAAA,EAAa;AAChC,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,CAAK,WAAA,CAAY,KAAA,CAAM,SAAA,CAAU;AAAA,QACvC,GAAA,EAAK,MAAA;AAAA,QACL,SAAA;AAAA,QACA,YAAY,MAAA,CAAO,UAAA;AAAA,QACnB,aAAa,OAAA,CAAQ,KAAA;AAAA,QACrB,YAAY,QAAA,CAAS,GAAA;AAAA,QACrB,cAAc,QAAA,CAAS,IAAA;AAAA,QACvB,SAAA,EAAW,IAAA;AAAA,QACX,WAAA,EAAa,IAAA;AAAA,QACb,YAAA,EAAc,YAAA;AAAA,QACd,MAAM,QAAA,CAAS,IAAA;AAAA,QACf,QAAA,EAAU,YAAA;AAAA,QACV,iBAAA,EAAmB,IAAA;AAAA,QACnB,UAAU,QAAA,CAAS,QAAA;AAAA,QACnB,WAAW,QAAA,CAAS,SAAA;AAAA,QACpB,SAAS,QAAA,CAAS,OAAA;AAAA,QAClB,QAAA,EAAU,EAAA;AAAA,QACV,MAAA,EAAQ,QAAA;AAAA,QACR,YAAA,EAAc,IAAA;AAAA,QACd,UAAA,EAAY,IAAA;AAAA,QACZ,YAAA,EAAc,IAAA;AAAA,QACd,OAAO,EAAC;AAAA,QACR,IAAA,EAAM,MAAA,CAAO,IAAA,IAAQ,EAAC;AAAA,QACtB,QAAA,EAAU,IAAA;AAAA,QACV,SAAA,EAAW,CAAA;AAAA,QACX,YAAA,EAAc,IAAA;AAAA,QACd,UAAA,EAAY,CAAA;AAAA,QACZ,cAAc,EAAC;AAAA,QACf,cAAA,EAAgB,IAAA;AAAA,QAChB,YAAA,EAAc,IAAA;AAAA,QACd,QAAA,sBAAc,IAAA,EAAK;AAAA,QACnB,SAAA,sBAAe,IAAA,EAAK;AAAA,QACpB,MAAA,EAAQ,IAAA;AAAA,QACR,WAAA,EAAa;AAAA,OACZ,CAAA;AAAA,IACH,SAAS,GAAA,EAAU;AAEjB,MAAA,IAAI,GAAA,EAAK,IAAA,KAAS,IAAA,EAAO,MAAM,GAAA;AAC/B,MAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,WAAA,CAAY,MAAM,OAAA,CAAQ,EAAE,WAAW,CAAA;AACjE,MAAA,IAAI,QAAQ,OAAO,EAAE,QAAQ,MAAA,CAAO,MAAA,CAAO,GAAG,CAAA,EAAE;AAChD,MAAA,MAAM,GAAA;AAAA,IACR;AAEA,IAAA,MAAM,IAAA,CAAK,OAAO,IAAA,CAAK,GAAA;AAAA,MACrB,MAAA;AAAA,MACA,EAAE,MAAA,EAAQ,MAAA,CAAO,MAAM,CAAA,EAAE;AAAA,MACzB,EAAE,QAAA,EAAU,IAAA,CAAK,MAAA,CAAO,iBAAA,EAAmB,OAAA,EAAS,EAAE,IAAA,EAAM,aAAA,EAAe,KAAA,EAAO,GAAA,EAAO;AAAE,KAC7F;AAEA,IAAA,OAAO,EAAE,MAAA,EAAQ,MAAA,CAAO,MAAM,CAAA,EAAE;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,MAAM,KAAA,EAUM;AAChB,IAAA,MAAM,IAAA,CAAK,WAAA,CAAY,QAAA,CAAS,SAAA,CAAU;AAAA,MACxC,OAAO,KAAA,CAAM,KAAA;AAAA,MACb,QAAQ,KAAA,CAAM,MAAA;AAAA,MACd,UAAU,KAAA,CAAM,QAAA;AAAA,MAChB,MAAA,EAAQ,MAAM,MAAA,IAAU,IAAA;AAAA,MACxB,KAAA,EAAO,MAAM,KAAA,IAAS,IAAA;AAAA,MACtB,WAAA,EAAa,MAAM,WAAA,IAAe,IAAA;AAAA,MAClC,EAAA,EAAI,MAAM,EAAA,IAAM,IAAA;AAAA,MAChB,SAAA,EAAW,MAAM,SAAA,IAAa,IAAA;AAAA,MAC9B,SAAA,EAAW,MAAM,SAAA,IAAa,IAAA;AAAA,MAC9B,UAAA,sBAAgB,IAAA;AAAK,KACtB,CAAA;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,YAAA,GAA8B;AAClC,IAAA,IAAI,KAAK,cAAA,EAAgB;AACzB,IAAA,IAAI,IAAA,CAAK,MAAA,CAAO,KAAA,CAAM,MAAA,KAAW,MAAA,EAAQ;AACvC,MAAA,MAAM,IAAI,MAAM,+CAA+C,CAAA;AAAA,IACjE;AACA,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,SAAA,CAAU,IAAA,CAAK,OAAO,eAAe,CAAA;AAC3D,IAAA,MAAM,QAAA,GAAW,QAAA,EAAU,iBAAA,IAAqB,IAAA,CAAK,MAAA,CAAO,iBAAA;AAE5D,IAAA,MAAM,IAAA,CAAK,YAAY,YAAA,CAAa;AAAA,MAClC,WAAA,EAAa,EAAE,IAAA,EAAM,IAAA,CAAK,OAAO,eAAA,EAAgB;AAAA,MACjD,aAAA,EAAe,EAAE,GAAA,EAAK,QAAA,EAAU,YAAY,GAAA,EAAM;AAAA,MAClD,aAAA,EAAe,KAAK,MAAA,CAAO,iBAAA;AAAA,MAC3B,QAAA,EAAU;AAAA,QACR,MAAM,YAAY;AAChB,UAAA,MAAM,OAAA,CAAQ,KAAK,aAAa,CAAA;AAAA,QAClC,CAAA;AAAA,QACA,OAAA,EAAS,OAAO,IAAA,KAAS;AACvB,UAAA,IAAI,KAAK,WAAA,EAAa;AACpB,YAAA,IAAI,CAACA,gBAAA,CAAa,OAAA,CAAQ,IAAA,CAAK,WAAW,CAAA,EAAG;AAC7C,YAAA,MAAM,sBAAsB,IAAIA,gBAAA,CAAa,KAAK,WAAW,CAAA,EAAG,KAAK,aAAa,CAAA;AAClF,YAAA;AAAA,UACF;AACA,UAAA,IAAI,CAAC,KAAK,SAAA,IAAa,CAACA,iBAAa,OAAA,CAAQ,IAAA,CAAK,SAAS,CAAA,EAAG;AAC9D,UAAA,MAAM,kBAAkB,IAAIA,gBAAA,CAAa,KAAK,SAAS,CAAA,EAAG,KAAK,aAAa,CAAA;AAAA,QAC9E,CAAA;AAAA,QACA,IAAA,EAAM,OAAO,IAAA,KAAS;AACpB,UAAA,IAAI,CAACA,gBAAA,CAAa,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAA,EAAG;AACxC,UAAA,MAAM,aAAa,IAAIA,gBAAA,CAAa,KAAK,MAAM,CAAA,EAAG,KAAK,aAAa,CAAA;AAAA,QACtE,CAAA;AAAA,QACA,SAAS,YAAY;AACnB,UAAA,MAAM,KAAK,qBAAA,EAAsB;AAAA,QACnC;AAAA;AACF,KACD,CAAA;AACD,IAAA,IAAA,CAAK,cAAA,GAAiB,IAAA;AAAA,EACxB;AAAA;AAAA,EAGA,MAAc,qBAAA,GAAuC;AACnD,IAAA,MAAM,qBAAA,CAAsB,KAAK,aAAa,CAAA;AAAA,EAChD;AAAA,EAEA,MAAM,IAAA,GAAsB;AAC1B,IAAA,MAAM,IAAA,CAAK,YAAY,KAAA,EAAM;AAC7B,IAAA,IAAA,CAAK,cAAA,GAAiB,KAAA;AAAA,EACxB;AAAA;AAAA,EAGA,gBAAA,GAAkC;AAChC,IAAA,OAAO,IAAA,CAAK,aAAA;AAAA,EACd;AACF;;;ACtwBA,UAAA,EAAA;AAEA,SAAA,EAAA;;;ACbA,IAAI,OAAA,GAAU,CAAA;AAEP,IAAM,eAAN,MAA2C;AAAA,EACvC,IAAA,GAAO,MAAA;AAAA,EACP,iBAAA,GAAoB,GAAA;AAAA,EACb,OAAmB,EAAC;AAAA,EAEpC,MAAM,KAAK,IAAA,EAAqC;AAC9C,IAAA,IAAA,CAAK,IAAA,CAAK,KAAK,IAAI,CAAA;AACnB,IAAA,OAAO;AAAA,MACL,YAAY,CAAA,KAAA,EAAQ,IAAA,CAAK,KAAK,CAAA,CAAA,EAAI,EAAE,OAAO,CAAA,CAAA;AAAA,MAC3C,MAAA,EAAQ;AAAA,KACV;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,MAAM,aAAA,GAAkC;AACtC,IAAA,OAAO,KAAA;AAAA,EACT;AAAA,EAEA,kBAAA,GAAwC;AACtC,IAAA,OAAO,EAAC;AAAA,EACV;AAAA,EAEA,KAAA,GAAc;AACZ,IAAA,IAAA,CAAK,KAAK,MAAA,GAAS,CAAA;AAAA,EACrB;AACF;;;ADpBA,aAAA,EAAA;;;AEkCA,IAAM,iBAAiB,CAAC,QAAA,EAAU,MAAA,EAAQ,aAAA,EAAe,UAAU,OAAO,CAAA;AAE1E,IAAM,YAAA,GAA2D;AAAA,EAC/D,EAAE,OAAA,EAAS,UAAA,EAAY,MAAA,EAAQ,MAAA,EAAO;AAAA,EACtC,EAAE,OAAA,EAAS,cAAA,EAAgB,MAAA,EAAQ,SAAA,EAAU;AAAA,EAC7C,EAAE,OAAA,EAAS,wBAAA,EAA0B,MAAA,EAAQ,iBAAA;AAC/C,CAAA;AAEA,IAAM,yBAAA,GAA4B,8BAAA;AAE3B,SAAS,YAAA,CAAa,QAAA,EAAqB,MAAA,GAAqB,EAAC,EAAe;AAKrF,EAAA,MAAM,KAAA,GAAmB;AAAA,IACvB,SAAS,OAAO,QAAA,CAAS,OAAA,KAAY,QAAA,GAAW,SAAS,OAAA,GAAU,EAAA;AAAA,IACnE,WAAW,OAAO,QAAA,CAAS,SAAA,KAAc,QAAA,GAAW,SAAS,SAAA,GAAY,EAAA;AAAA,IACzE,MAAM,OAAO,QAAA,CAAS,IAAA,KAAS,QAAA,GAAW,SAAS,IAAA,GAAO,EAAA;AAAA,IAC1D,YAAY,QAAA,CAAS,UAAA;AAAA,IACrB,MAAM,OAAO,QAAA,CAAS,IAAA,KAAS,QAAA,GAAW,SAAS,IAAA,GAAO,EAAA;AAAA,IAC1D,WAAW,OAAO,QAAA,CAAS,SAAA,KAAc,QAAA,GAAW,SAAS,SAAA,GAAY,EAAA;AAAA,IACzE,IAAA,EAAM,SAAS,IAAA,KAAS,WAAA,IAAe,SAAS,IAAA,KAAS,eAAA,GAAkB,SAAS,IAAA,GAAO,eAAA;AAAA,IAC3F,WAAW,OAAO,QAAA,CAAS,SAAA,KAAc,QAAA,GAAW,SAAS,SAAA,GAAY;AAAA,GAC3E;AACA,EAAA,MAAM,SAAsB,EAAC;AAG7B,EAAA,IAAI,CAAC,MAAM,SAAA,IAAa,KAAA,CAAM,UAAU,IAAA,EAAK,CAAE,WAAW,CAAA,EAAG;AAC3D,IAAA,MAAA,CAAO,IAAA,CAAK;AAAA,MACV,IAAA,EAAM,oBAAA;AAAA,MACN,QAAA,EAAU,OAAA;AAAA,MACV,OAAA,EAAS,kCAAA;AAAA,MACT,IAAA,EAAM;AAAA,KACP,CAAA;AAAA,EACH;AAGA,EAAA,MAAM,UAAA,GAAa,YAAA,CAAa,KAAA,CAAM,IAAA,EAAM,UAAU,CAAA;AACtD,EAAA,MAAM,OAAA,GAAU,KAAA,CAAM,SAAA,CAAU,IAAA,EAAK,CAAE,MAAA;AACvC,EAAA,IAAI,UAAA,IAAc,CAAA,IAAK,OAAA,GAAU,EAAA,EAAI;AACnC,IAAA,MAAA,CAAO,IAAA,CAAK;AAAA,MACV,IAAA,EAAM,iBAAA;AAAA,MACN,QAAA,EAAU,OAAA;AAAA,MACV,OAAA,EAAS,+CAAA;AAAA,MACT,IAAA,EAAM;AAAA,KACP,CAAA;AAAA,EACH;AAGA,EAAA,MAAM,cAAA,GAAiB,kBAAA,CAAmB,KAAA,CAAM,IAAI,CAAA;AACpD,EAAA,IAAI,cAAA,CAAe,SAAS,CAAA,EAAG;AAC7B,IAAA,MAAA,CAAO,IAAA,CAAK;AAAA,MACV,IAAA,EAAM,eAAA;AAAA,MACN,QAAA,EAAU,OAAA;AAAA,MACV,OAAA,EAAS,CAAA,2BAAA,EAA8B,cAAA,CAAe,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA,CAAA;AAAA,MAChE,IAAA,EAAM;AAAA,KACP,CAAA;AAAA,EACH;AAGA,EAAA,IAAI,uBAAA,CAAwB,KAAA,CAAM,IAAI,CAAA,EAAG;AACvC,IAAA,MAAA,CAAO,IAAA,CAAK;AAAA,MACV,IAAA,EAAM,UAAA;AAAA,MACN,QAAA,EAAU,SAAA;AAAA,MACV,OAAA,EAAS,iEAAA;AAAA,MACT,IAAA,EAAM;AAAA,KACP,CAAA;AAAA,EACH;AAGA,EAAA,MAAM,IAAA,GAAO,eAAA,CAAgB,CAAA,EAAG,KAAA,CAAM,OAAO;AAAA,EAAK,KAAA,CAAM,SAAS,CAAA,CAAE,CAAA;AACnE,EAAA,IAAI,IAAA,CAAK,SAAS,CAAA,EAAG;AACnB,IAAA,MAAA,CAAO,IAAA,CAAK;AAAA,MACV,IAAA,EAAM,cAAA;AAAA,MACN,QAAA,EAAU,SAAA;AAAA,MACV,OAAA,EAAS,CAAA,uCAAA,EAA0C,IAAA,CAAK,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA,CAAA;AAAA,MAClE,IAAA,EAAM;AAAA,KACP,CAAA;AAAA,EACH;AAGA,EAAA,IAAI,SAAA,CAAU,KAAA,CAAM,OAAO,CAAA,EAAG;AAC5B,IAAA,MAAA,CAAO,IAAA,CAAK;AAAA,MACV,IAAA,EAAM,kBAAA;AAAA,MACN,QAAA,EAAU,SAAA;AAAA,MACV,OAAA,EAAS,mCAAA;AAAA,MACT,IAAA,EAAM;AAAA,KACP,CAAA;AAAA,EACH;AAOA,EAAA,IAAI,KAAA,CAAM,SAAS,WAAA,EAAa;AAC9B,IAAA,MAAM,OAAA,GAAU,CAAC,KAAA,CAAM,IAAA,IAAQ,EAAA,EAAI,KAAA,CAAM,IAAA,IAAQ,EAAA,EAAI,IAAA,CAAK,SAAA,CAAU,KAAA,CAAM,UAAA,IAAc,IAAI,CAAC,CAAA;AAC7F,IAAA,MAAM,MAAA,GAAS,QAAQ,IAAA,CAAK,CAAC,MAAM,yBAAA,CAA0B,IAAA,CAAK,CAAC,CAAC,CAAA;AACpE,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA,MAAA,CAAO,IAAA,CAAK;AAAA,QACV,IAAA,EAAM,yBAAA;AAAA,QACN,QAAA,EAAU,OAAA;AAAA,QACV,OAAA,EAAS,iEAAA;AAAA,QACT,IAAA,EAAM;AAAA,OACP,CAAA;AAAA,IACH;AAAA,EACF;AAGA,EAAA,MAAM,cAAc,oBAAA,CAAqB,KAAA,CAAM,WAAW,KAAA,CAAM,IAAA,EAAM,OAAO,aAAa,CAAA;AAC1F,EAAA,IAAI,CAAC,YAAY,EAAA,EAAI;AACnB,IAAA,MAAA,CAAO,IAAA,CAAK;AAAA,MACV,IAAA,EAAM,uBAAA;AAAA,MACN,QAAA,EAAU,OAAA;AAAA,MACV,SAAS,WAAA,CAAY,MAAA;AAAA,MACrB,IAAA,EAAM;AAAA,KACP,CAAA;AAAA,EACH;AAGA,EAAA,IAAI,CAAC,MAAM,SAAA,IAAa,KAAA,CAAM,UAAU,IAAA,EAAK,CAAE,WAAW,CAAA,EAAG;AAC3D,IAAA,MAAA,CAAO,IAAA,CAAK;AAAA,MACV,IAAA,EAAM,iBAAA;AAAA,MACN,QAAA,EAAU,MAAA;AAAA,MACV,OAAA,EAAS,mBAAA;AAAA,MACT,IAAA,EAAM;AAAA,KACP,CAAA;AAAA,EACH;AAGA,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,MAAA,GAAS,EAAA,EAAI;AAC7B,IAAA,MAAA,CAAO,IAAA,CAAK;AAAA,MACV,IAAA,EAAM,kBAAA;AAAA,MACN,QAAA,EAAU,SAAA;AAAA,MACV,OAAA,EAAS,CAAA,WAAA,EAAc,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,+CAAA,CAAA;AAAA,MAC3C,IAAA,EAAM;AAAA,KACP,CAAA;AAAA,EACH;AAGA,EAAA,IAAI,OAAO,cAAA,EAAgB;AACzB,IAAA,MAAM,OAAA,GAAU,CAAC,KAAA,CAAM,OAAA,EAAS,KAAA,CAAM,SAAA,EAAW,KAAA,CAAM,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,KAAA,CAAM,UAAA,IAAc,IAAI,CAAC,CAAA;AACrG,IAAA,MAAM,UAAU,oBAAA,CAAqB,OAAA,CAAQ,KAAK,IAAI,CAAA,EAAG,OAAO,cAAc,CAAA;AAC9E,IAAA,IAAI,OAAA,CAAQ,SAAS,CAAA,EAAG;AACtB,MAAA,MAAA,CAAO,IAAA,CAAK;AAAA,QACV,IAAA,EAAM,kBAAA;AAAA,QACN,QAAA,EAAU,SAAA;AAAA,QACV,OAAA,EAAS,CAAA,wDAAA,EAA2D,OAAA,CAAQ,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA,CAAA;AAAA,QACtF,IAAA,EAAM;AAAA,OACP,CAAA;AAAA,IACH;AAAA,EACF;AAMA,EAAA,MAAM,SAAA,GAAY,sBAAA,CAAuB,KAAA,CAAM,IAAA,EAAM,MAAM,SAAS,CAAA;AACpE,EAAA,IAAI,SAAA,CAAU,QAAA,IAAY,SAAA,CAAU,KAAA,CAAM,SAAS,CAAA,EAAG;AACpD,IAAA,MAAA,CAAO,IAAA,CAAK;AAAA,MACV,IAAA,EAAM,iBAAA;AAAA,MACN,QAAA,EAAU,SAAA;AAAA,MACV,SAAS,CAAA,4CAAA,EAA+C,SAAA,CAAU,KAAA,CAAM,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA,CAAA;AAAA,MAClF,IAAA,EAAM;AAAA,KACP,CAAA;AAAA,EACH;AAKA,EAAA,MAAM,QAAA,GAAW,qBAAA,CAAsB,KAAA,CAAM,IAAI,CAAA;AACjD,EAAA,IAAI,QAAA,CAAS,SAAS,CAAA,EAAG;AACvB,IAAA,MAAA,CAAO,IAAA,CAAK;AAAA,MACV,IAAA,EAAM,eAAA;AAAA,MACN,QAAA,EAAU,SAAA;AAAA,MACV,OAAA,EAAS,CAAA,yBAAA,EAA4B,QAAA,CAAS,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA,CAAA;AAAA,MACxD,IAAA,EAAM;AAAA,KACP,CAAA;AAAA,EACH;AAGA,EAAA,IAAI,qBAAA,CAAsB,KAAA,CAAM,IAAI,CAAA,GAAI,CAAA,EAAG;AACzC,IAAA,MAAA,CAAO,IAAA,CAAK;AAAA,MACV,IAAA,EAAM,mBAAA;AAAA,MACN,QAAA,EAAU,SAAA;AAAA,MACV,OAAA,EAAS,sCAAA;AAAA,MACT,IAAA,EAAM;AAAA,KACP,CAAA;AAAA,EACH;AAGA,EAAA,IAAI,gBAAA,CAAiB,KAAA,CAAM,IAAI,CAAA,EAAG;AAChC,IAAA,MAAA,CAAO,IAAA,CAAK;AAAA,MACV,IAAA,EAAM,iBAAA;AAAA,MACN,QAAA,EAAU,SAAA;AAAA,MACV,OAAA,EAAS,kDAAA;AAAA,MACT,IAAA,EAAM;AAAA,KACP,CAAA;AAAA,EACH;AAKA,EAAA,MAAM,SAAA,GAAY,YAAA,CAAa,KAAA,CAAM,IAAA,EAAM,uBAAuB,CAAA;AAClE,EAAA,IAAI,YAAY,EAAA,EAAI;AAClB,IAAA,MAAA,CAAO,IAAA,CAAK;AAAA,MACV,IAAA,EAAM,gBAAA;AAAA,MACN,QAAA,EAAU,SAAA;AAAA,MACV,OAAA,EAAS,GAAG,SAAS,CAAA,kFAAA,CAAA;AAAA,MACrB,IAAA,EAAM;AAAA,KACP,CAAA;AAAA,EACH;AAEA,EAAA,OAAO,gBAAgB,MAAM,CAAA;AAC/B;AAMA,SAAS,gBAAgB,MAAA,EAAiC;AACxD,EAAA,MAAM,GAAA,GAAkB,EAAE,MAAA,EAAQ,EAAC,EAAG,UAAU,EAAC,EAAG,KAAA,EAAO,EAAC,EAAE;AAC9D,EAAA,KAAA,MAAW,KAAK,MAAA,EAAQ;AACtB,IAAA,IAAI,EAAE,QAAA,KAAa,OAAA,EAAS,GAAA,CAAI,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,SAAA,IACpC,EAAE,QAAA,KAAa,SAAA,EAAW,GAAA,CAAI,QAAA,CAAS,KAAK,CAAC,CAAA;AAAA,SACjD,GAAA,CAAI,KAAA,CAAM,IAAA,CAAK,CAAC,CAAA;AAAA,EACvB;AACA,EAAA,OAAO,GAAA;AACT;AAEA,SAAS,YAAA,CAAa,GAAW,EAAA,EAAoB;AACnD,EAAA,OAAA,CAAQ,CAAA,CAAE,KAAA,CAAM,EAAE,CAAA,IAAK,EAAC,EAAG,MAAA;AAC7B;AAEA,SAAS,mBAAmB,IAAA,EAAwB;AAClD,EAAA,MAAM,KAAA,GAAQ,aAAa,IAAI,CAAA;AAC/B,EAAA,MAAM,IAAA,uBAAW,GAAA,EAAY;AAC7B,EAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,IAAA,MAAM,MAAA,GAAS,WAAW,IAAI,CAAA;AAC9B,IAAA,IAAI,CAAC,MAAA,EAAQ;AACb,IAAA,IAAI,eAAe,QAAA,CAAS,MAAM,CAAA,EAAG,IAAA,CAAK,IAAI,MAAM,CAAA;AAAA,EACtD;AACA,EAAA,OAAO,KAAA,CAAM,KAAK,IAAI,CAAA;AACxB;AAEA,SAAS,aAAa,IAAA,EAAwB;AAC5C,EAAA,MAAM,MAAgB,EAAC;AAIvB,EAAA,MAAM,EAAA,GAAK,2DAAA;AACX,EAAA,IAAI,CAAA;AACJ,EAAA,OAAQ,CAAA,GAAI,EAAA,CAAG,IAAA,CAAK,IAAI,CAAA,EAAI;AAC1B,IAAA,MAAM,IAAA,GAAO,EAAE,CAAC,CAAA,IAAK,EAAE,CAAC,CAAA,IAAK,EAAE,CAAC,CAAA;AAChC,IAAA,IAAI,IAAA,EAAM,GAAA,CAAI,IAAA,CAAK,IAAI,CAAA;AAAA,EACzB;AACA,EAAA,OAAO,GAAA;AACT;AAEA,SAAS,WAAW,GAAA,EAA4B;AAC9C,EAAA,IAAI;AACF,IAAA,OAAO,IAAI,GAAA,CAAI,GAAG,CAAA,CAAE,SAAS,WAAA,EAAY;AAAA,EAC3C,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAOA,SAAS,wBAAwB,IAAA,EAAuB;AACtD,EAAA,MAAM,WAAW,IAAA,CACd,OAAA,CAAQ,uBAAA,EAAyB,GAAG,EACpC,OAAA,CAAQ,+BAAA,EAAiC,GAAG,CAAA,CAC5C,QAAQ,iCAAA,EAAmC,GAAG,CAAA,CAC9C,OAAA,CAAQ,+BAA+B,GAAG,CAAA;AAC7C,EAAA,OAAO,wBAAA,CAAyB,KAAK,QAAQ,CAAA;AAC/C;AAQA,SAAS,sBAAA,CAAuB,MAAc,SAAA,EAA2D;AACvG,EAAA,MAAM,aAAa,SAAA,CAAU,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,GAAG,WAAA,EAAY;AACxD,EAAA,IAAI,CAAC,YAAY,OAAO,EAAE,OAAO,EAAC,EAAG,UAAU,KAAA,EAAM;AAErD,EAAA,MAAM,KAAA,uBAAY,GAAA,EAAY;AAC9B,EAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,EAAA,IAAI,GAAA,GAAM,CAAA;AACV,EAAA,KAAA,MAAW,IAAA,IAAQ,YAAA,CAAa,IAAI,CAAA,EAAG;AACrC,IAAA,IAAI,IAAA,CAAK,QAAA,CAAS,IAAI,CAAA,EAAG;AACzB,IAAA,MAAM,IAAA,GAAO,WAAW,IAAI,CAAA;AAC5B,IAAA,IAAI,CAAC,IAAA,EAAM;AACX,IAAA,KAAA,EAAA;AACA,IAAA,IAAI,QAAA,CAAS,IAAA,EAAM,UAAU,CAAA,EAAG;AAChC,IAAA,GAAA,EAAA;AACA,IAAA,KAAA,CAAM,IAAI,IAAI,CAAA;AAAA,EAChB;AACA,EAAA,OAAO,EAAE,KAAA,EAAO,KAAA,CAAM,IAAA,CAAK,KAAK,CAAA,EAAG,QAAA,EAAU,KAAA,GAAQ,CAAA,IAAK,GAAA,GAAM,CAAA,GAAI,KAAA,EAAM;AAC5E;AAQA,SAAS,QAAA,CAAS,GAAW,CAAA,EAAoB;AAC/C,EAAA,IAAI,CAAA,KAAM,GAAG,OAAO,IAAA;AACpB,EAAA,IAAI,CAAA,CAAE,QAAA,CAAS,CAAA,CAAA,EAAI,CAAC,CAAA,CAAE,CAAA,IAAK,CAAA,CAAE,QAAA,CAAS,CAAA,CAAA,EAAI,CAAC,CAAA,CAAE,CAAA,EAAG,OAAO,IAAA;AACvD,EAAA,OAAO,UAAA,CAAW,CAAC,CAAA,KAAM,UAAA,CAAW,CAAC,CAAA;AACvC;AAEA,SAAS,WAAW,IAAA,EAAsB;AACxC,EAAA,OAAO,IAAA,CAAK,MAAM,GAAG,CAAA,CAAE,MAAM,EAAE,CAAA,CAAE,KAAK,GAAG,CAAA;AAC3C;AAEA,SAAS,sBAAsB,IAAA,EAAwB;AACrD,EAAA,MAAM,IAAA,uBAAW,GAAA,EAAY;AAC7B,EAAA,KAAA,MAAW,IAAA,IAAQ,YAAA,CAAa,IAAI,CAAA,EAAG;AACrC,IAAA,IAAI,CAAC,aAAA,CAAc,IAAA,CAAK,IAAI,CAAA,EAAG;AAC/B,IAAA,MAAM,IAAA,GAAO,WAAW,IAAI,CAAA;AAC5B,IAAA,IAAI,IAAA,EAAM,IAAA,CAAK,GAAA,CAAI,IAAI,CAAA;AAAA,EACzB;AACA,EAAA,OAAO,KAAA,CAAM,KAAK,IAAI,CAAA;AACxB;AAEA,SAAS,sBAAsB,IAAA,EAAsB;AACnD,EAAA,IAAI,OAAA,GAAU,CAAA;AACd,EAAA,MAAM,EAAA,GAAK,gBAAA;AACX,EAAA,IAAI,CAAA;AACJ,EAAA,OAAQ,CAAA,GAAI,EAAA,CAAG,IAAA,CAAK,IAAI,CAAA,EAAI;AAC1B,IAAA,MAAM,GAAA,GAAM,EAAE,CAAC,CAAA;AACf,IAAA,MAAM,GAAA,GAAM,gDAAA,CAAiD,IAAA,CAAK,GAAG,CAAA;AACrE,IAAA,MAAM,KAAA,GAAQ,GAAA,GAAO,GAAA,CAAI,CAAC,CAAA,IAAK,GAAA,CAAI,CAAC,CAAA,IAAK,GAAA,CAAI,CAAC,CAAA,IAAK,EAAA,GAAM,EAAA;AACzD,IAAA,IAAI,KAAA,CAAM,IAAA,EAAK,CAAE,MAAA,KAAW,CAAA,EAAG,OAAA,EAAA;AAAA,EACjC;AACA,EAAA,OAAO,OAAA;AACT;AAGA,SAAS,iBAAiB,IAAA,EAAuB;AAC/C,EAAA,MAAM,EAAA,GAAK,yBAAA;AACX,EAAA,IAAI,CAAA;AACJ,EAAA,OAAQ,CAAA,GAAI,EAAA,CAAG,IAAA,CAAK,IAAI,CAAA,EAAI;AAC1B,IAAA,MAAM,KAAA,GAAQ,EAAE,CAAC,CAAA;AACjB,IAAA,IAAI,CAAC,SAAA,CAAU,IAAA,CAAK,KAAK,CAAA,EAAG;AAC5B,IAAA,MAAM,IAAA,GAAO,KAAA,CACV,OAAA,CAAQ,UAAA,EAAY,EAAE,EACtB,OAAA,CAAQ,UAAA,EAAY,GAAG,CAAA,CACvB,IAAA,EAAK;AACR,IAAA,IAAI,IAAA,CAAK,MAAA,KAAW,CAAA,EAAG,OAAO,IAAA;AAAA,EAChC;AACA,EAAA,OAAO,KAAA;AACT;AAEA,SAAS,gBAAgB,IAAA,EAAwB;AAC/C,EAAA,MAAM,GAAA,uBAAU,GAAA,EAAY;AAC5B,EAAA,KAAA,MAAW,EAAE,OAAA,EAAS,MAAA,EAAO,IAAK,YAAA,EAAc;AAC9C,IAAA,IAAI,QAAQ,IAAA,CAAK,IAAI,CAAA,EAAG,GAAA,CAAI,IAAI,MAAM,CAAA;AAAA,EACxC;AACA,EAAA,IAAI,QAAQ,IAAA,CAAK,IAAI,CAAA,EAAG,GAAA,CAAI,IAAI,iBAAiB,CAAA;AACjD,EAAA,OAAO,KAAA,CAAM,KAAK,GAAG,CAAA;AACvB;AAKA,IAAM,iBAAA,uBAAwB,GAAA,CAAI;AAAA,EAChC,SAAA;AAAA,EACA,MAAA;AAAA,EACA,OAAA;AAAA,EACA,gBAAA;AAAA,EACA,kBAAA;AAAA,EACA,qBAAA;AAAA,EACA,eAAA;AAAA,EACA;AACF,CAAC,CAAA;AAED,IAAM,UAAA,GAAa,yCAAA;AASZ,SAAS,oBAAA,CAAqB,QAAgB,MAAA,EAA2C;AAG9F,EAAA,MAAM,cAAA,GAAiB,0BAAA,CAA2B,IAAA,CAAK,MAAM,CAAA;AAE7D,EAAA,MAAM,OAAA,uBAAc,GAAA,EAAY;AAChC,EAAA,MAAM,EAAA,GAAK,gCAAA;AACX,EAAA,IAAI,CAAA;AACJ,EAAA,OAAQ,CAAA,GAAI,EAAA,CAAG,IAAA,CAAK,MAAM,CAAA,EAAI;AAC5B,IAAA,MAAM,IAAA,GAAO,CAAA,CAAE,CAAC,CAAA,CAAG,IAAA,EAAK;AACxB,IAAA,IAAI,CAAC,IAAA,IAAQ,UAAA,CAAW,KAAK,IAAI,CAAA,IAAK,SAAS,MAAA,EAAQ;AACvD,IAAA,IAAI,IAAA,CAAK,QAAA,CAAS,GAAG,CAAA,EAAG;AAIxB,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,KAAK,CAAA;AAC9B,IAAA,MAAM,aAAa,KAAA,CAAM,MAAA,GAAS,IAAI,KAAA,CAAM,KAAA,CAAM,CAAC,CAAA,GAAI,KAAA;AACvD,IAAA,KAAA,MAAW,OAAO,UAAA,EAAY;AAC5B,MAAA,IAAI,CAAC,UAAA,CAAW,IAAA,CAAK,GAAG,CAAA,EAAG;AAC3B,MAAA,IAAI,GAAA,CAAI,UAAA,CAAW,GAAG,CAAA,EAAG;AACzB,MAAA,MAAM,QAAA,GAAW,GAAA,CAAI,KAAA,CAAM,GAAG,CAAA;AAC9B,MAAA,IAAI,iBAAA,CAAkB,GAAA,CAAI,QAAA,CAAS,CAAC,CAAE,CAAA,EAAG;AACzC,MAAA,IAAI,cAAA,IAAkB,QAAA,CAAS,MAAA,KAAW,CAAA,EAAG;AAC7C,MAAA,IAAI,CAAC,aAAA,CAAc,MAAA,EAAQ,QAAQ,CAAA,EAAG,OAAA,CAAQ,IAAI,GAAG,CAAA;AAAA,IACvD;AAAA,EACF;AACA,EAAA,OAAO,KAAA,CAAM,KAAK,OAAO,CAAA;AAC3B;AAOA,SAAS,aAAA,CAAc,MAAe,QAAA,EAA6B;AACjE,EAAA,IAAI,QAAA,CAAS,MAAA,KAAW,CAAA,EAAG,OAAO,IAAA;AAClC,EAAA,IAAI,CAAC,IAAA,IAAQ,OAAO,IAAA,KAAS,UAAU,OAAO,IAAA;AAC9C,EAAA,MAAM,CAAA,GAAI,IAAA;AAGV,EAAA,KAAA,MAAW,GAAA,IAAO,CAAC,OAAA,EAAS,OAAA,EAAS,OAAO,CAAA,EAAG;AAC7C,IAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,CAAA,CAAE,GAAG,CAAC,CAAA,EAAG;AACzB,MAAA,OAAQ,CAAA,CAAE,GAAG,CAAA,CAAgB,IAAA,CAAK,CAAC,MAAA,KAAW,aAAA,CAAc,MAAA,EAAQ,QAAQ,CAAC,CAAA;AAAA,IAC/E;AAAA,EACF;AAEA,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,CAAA,CAAE,IAAI,CAAA,IAAK,CAAA,CAAE,IAAA,CAAK,QAAA,CAAS,QAAQ,CAAA,IAAK,CAAC,CAAA,CAAE,YAAY,OAAO,IAAA;AAChF,EAAA,IAAI,CAAA,CAAE,SAAS,OAAA,EAAS;AACtB,IAAA,IAAI,QAAA,CAAS,CAAC,CAAA,KAAM,QAAA,EAAU,OAAO,IAAA;AACrC,IAAA,OAAO,aAAA,CAAc,CAAA,CAAE,KAAA,EAAO,QAAQ,CAAA;AAAA,EACxC;AAEA,EAAA,MAAM,QAAQ,CAAA,CAAE,UAAA;AAChB,EAAA,IAAI,CAAC,KAAA,IAAS,OAAO,KAAA,KAAU,UAAU,OAAO,IAAA;AAEhD,EAAA,MAAM,CAAC,IAAA,EAAM,GAAG,IAAI,CAAA,GAAI,QAAA;AACxB,EAAA,IAAI,QAAS,KAAA,EAAO,OAAO,cAAc,KAAA,CAAM,IAAK,GAAG,IAAI,CAAA;AAE3D,EAAA,IAAI,EAAE,oBAAA,KAAyB,MAAA,IAAa,CAAA,CAAE,oBAAA,KAAyB,OAAO,OAAO,KAAA;AACrF,EAAA,OAAO,IAAA;AACT;AAEA,SAAS,UAAU,OAAA,EAA0B;AAC3C,EAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,OAAA,CAAQ,YAAA,EAAc,EAAE,CAAA;AAChD,EAAA,IAAI,OAAA,CAAQ,MAAA,GAAS,CAAA,EAAG,OAAO,KAAA;AAC/B,EAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,OAAA,CAAQ,SAAA,EAAW,EAAE,CAAA,CAAE,MAAA;AAC7C,EAAA,OAAO,KAAA,GAAQ,QAAQ,MAAA,GAAS,GAAA;AAClC;;;AChfA,SAAA,EAAA;;;ACSO,IAAM,qBAAA,GAAuD,CAAC,WAAA,EAAa,WAAW,CAAA;;;ACD7F,eAAsB,eAAe,MAAA,EAAsC;AACzE,EAAA,MAAM,SAAuB,EAAC;AAE9B,EAAA,MAAA,CAAO,IAAA,CAAK,MAAM,UAAA,CAAW,MAAM,CAAC,CAAA;AACpC,EAAA,MAAA,CAAO,IAAA,CAAK,MAAM,UAAA,CAAW,MAAM,CAAC,CAAA;AAMpC,EAAA,IAAI,MAAA,CAAO,MAAA,CAAO,KAAA,CAAM,MAAA,KAAW,MAAA,EAAQ;AACzC,IAAA,MAAA,CAAO,IAAA,CAAK,MAAM,qBAAA,CAAsB,MAAM,CAAC,CAAA;AAAA,EACjD;AACA,EAAA,MAAA,CAAO,IAAA,CAAK,MAAM,mBAAA,CAAoB,MAAM,CAAC,CAAA;AAC7C,EAAA,MAAA,CAAO,IAAA,CAAK,MAAM,UAAA,CAAW,MAAM,CAAC,CAAA;AACpC,EAAA,MAAA,CAAO,IAAA,CAAK,MAAM,eAAA,CAAgB,MAAM,CAAC,CAAA;AACzC,EAAA,MAAA,CAAO,IAAA,CAAK,MAAM,SAAA,CAAU,MAAM,CAAC,CAAA;AACnC,EAAA,MAAM,IAAA,GAAO,UAAU,MAAM,CAAA;AAC7B,EAAA,IAAI,IAAA,EAAM,MAAA,CAAO,IAAA,CAAK,IAAI,CAAA;AAC1B,EAAA,MAAA,CAAO,IAAA,CAAK,MAAM,UAAA,CAAW,MAAM,CAAC,CAAA;AACpC,EAAA,MAAA,CAAO,IAAA,CAAK,GAAG,gCAAA,CAAiC,MAAM,CAAC,CAAA;AACvD,EAAA,MAAA,CAAO,IAAA,CAAK,GAAI,MAAM,uBAAA,CAAwB,MAAM,CAAE,CAAA;AACtD,EAAA,MAAA,CAAO,IAAA,CAAK,MAAM,kBAAA,CAAmB,MAAM,CAAC,CAAA;AAC5C,EAAA,MAAA,CAAO,IAAA,CAAK,MAAM,gBAAA,CAAiB,MAAM,CAAC,CAAA;AAE1C,EAAA,MAAM,UAAyB,MAAA,CAAO,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,aAAa,OAAO,CAAA,GACpE,OAAA,GACA,MAAA,CAAO,KAAK,CAAC,CAAA,KAAM,EAAE,QAAA,KAAa,MAAM,IACxC,MAAA,GACA,IAAA;AAEJ,EAAA,OAAO;AAAA,IACL,OAAA;AAAA,IACA,WAAA,EAAA,iBAAa,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAAA,IACpC;AAAA,GACF;AACF;AAEA,eAAe,WAAW,MAAA,EAAqC;AAC7D,EAAA,IAAI;AACF,IAAA,MAAM,MAAA,CAAO,EAAA,CAAG,KAAA,EAAM,CAAE,IAAA,EAAK;AAC7B,IAAA,OAAO,EAAE,MAAM,OAAA,EAAS,KAAA,EAAO,sBAAsB,QAAA,EAAU,IAAA,EAAM,SAAS,WAAA,EAAY;AAAA,EAC5F,SAAS,GAAA,EAAK;AACZ,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,OAAA;AAAA,MACN,KAAA,EAAO,oBAAA;AAAA,MACP,QAAA,EAAU,OAAA;AAAA,MACV,OAAA,EAAS,CAAA,qBAAA,EAAyB,GAAA,EAAe,OAAA,IAAW,GAAG,CAAA,CAAA;AAAA,MAC/D,IAAA,EAAM;AAAA,KACR;AAAA,EACF;AACF;AAEA,eAAe,WAAW,MAAA,EAAqC;AAC7D,EAAA,MAAM,MAAA,GAAS,MAAA,CAAO,MAAA,CAAO,KAAA,CAAM,MAAA;AACnC,EAAA,IAAI,WAAW,MAAA,EAAQ;AACrB,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,OAAA;AAAA,MACN,KAAA,EAAO,cAAA;AAAA,MACP,QAAA,EAAU,IAAA;AAAA,MACV,OAAA,EAAS;AAAA,KACX;AAAA,EACF;AACA,EAAA,IAAI;AACF,IAAA,MAAM,MAAA,CAAO,MAAA,CAAO,IAAA,CAAK,eAAA,EAAgB;AACzC,IAAA,OAAO,EAAE,IAAA,EAAM,OAAA,EAAS,KAAA,EAAO,cAAA,EAAgB,UAAU,IAAA,EAAM,OAAA,EAAS,CAAA,QAAA,EAAW,MAAM,CAAA,CAAA,EAAG;AAAA,EAC9F,SAAS,GAAA,EAAK;AACZ,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,OAAA;AAAA,MACN,KAAA,EAAO,cAAA;AAAA,MACP,QAAA,EAAU,OAAA;AAAA,MACV,SAAS,CAAA,EAAG,MAAM,CAAA,0BAAA,EAA8B,GAAA,EAAe,WAAW,GAAG,CAAA,CAAA;AAAA,MAC7E,IAAA,EACE,MAAA,KAAW,MAAA,GACP,6CAAA,GACA;AAAA,KACR;AAAA,EACF;AACF;AAEA,eAAe,sBAAsB,MAAA,EAAqC;AAGxE,EAAA,MAAM,CAAA,GAAI,MAAM,MAAA,CAAO,WAAA,CAAY,MAAA,CAAO,OAAA;AAAA,IACxC,EAAC;AAAA,IACD,EAAE,IAAA,EAAM,EAAE,SAAA,EAAW,IAAG;AAAE,GAC5B;AACA,EAAA,MAAM,cAAA,GAAiB,MAAA,CAAO,MAAA,CAAO,mBAAA,GAAsB,GAAA;AAC3D,EAAA,MAAM,YAAA,GAAe,IAAA,CAAK,GAAA,CAAI,cAAA,GAAiB,GAAG,GAAM,CAAA;AAIxD,EAAA,MAAM,UAAA,GAAa,OAAO,MAAA,CAAO,UAAA;AAEjC,EAAA,IAAI,CAAC,CAAA,EAAG;AACN,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,mBAAA;AAAA,MACN,KAAA,EAAO,oBAAA;AAAA,MACP,QAAA,EAAU,MAAA;AAAA,MACV,OAAA,EAAS,aAAa,sDAAA,GAAyD,qBAAA;AAAA,MAC/E,IAAA,EAAM,aACF,qNAAA,GACA;AAAA,KACN;AAAA,EACF;AAEA,EAAA,MAAM,KAAA,GAAQ,KAAK,GAAA,EAAI,GAAI,IAAI,IAAA,CAAK,CAAA,CAAE,SAAS,CAAA,CAAE,OAAA,EAAQ;AACzD,EAAA,IAAI,QAAQ,YAAA,EAAc;AACxB,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,mBAAA;AAAA,MACN,KAAA,EAAO,oBAAA;AAAA,MACP,QAAA,EAAU,OAAA;AAAA,MACV,OAAA,EAAS,aAAa,aAAA,CAAc,KAAK,CAAC,CAAA,sBAAA,EAAyB,aAAA,CAAc,cAAc,CAAC,CAAA,CAAA,CAAA;AAAA,MAChG,IAAA,EAAM,aACF,qKAAA,GACA;AAAA,KACN;AAAA,EACF;AACA,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,mBAAA;AAAA,IACN,KAAA,EAAO,oBAAA;AAAA,IACP,QAAA,EAAU,IAAA;AAAA,IACV,OAAA,EAAS,aAAa,aAAA,CAAc,KAAK,CAAC,CAAA,IAAA,EAAO,UAAA,GAAa,sBAAsB,EAAE,CAAA;AAAA,GACxF;AACF;AAEA,eAAe,oBAAoB,MAAA,EAAqC;AACtE,EAAA,MAAM,IAAA,GAAO,MAAM,MAAA,CAAO,WAAA,CAAY,OAAO,IAAA,CAAK,EAAE,CAAA,CAAE,OAAA,EAAQ;AAC9D,EAAA,MAAM,UAAU,IAAA,CAAK,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,QAAQ,aAAa,CAAA;AAE1D,EAAA,IAAI,OAAA,CAAQ,WAAW,CAAA,EAAG;AAGxB,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,iBAAA;AAAA,MACN,KAAA,EAAO,iBAAA;AAAA,MACP,QAAA,EAAU,IAAA;AAAA,MACV,OAAA,EAAS,kBAAA;AAAA,MACT,IAAA,EAAM;AAAA,KACR;AAAA,EACF;AAEA,EAAA,MAAM,UAAU,OAAA,CAAQ,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,WAAW,SAAS,CAAA;AAC5D,EAAA,IAAI,OAAA,CAAQ,SAAS,CAAA,EAAG;AACtB,IAAA,MAAM,OAAA,GAAU,OAAA,CACb,GAAA,CAAI,CAAC,MAAM,CAAA,EAAG,CAAA,CAAE,YAAA,IAAgB,UAAU,IAAI,CAAA,CAAE,IAAI,CAAA,CAAE,CAAA,CACtD,KAAK,IAAI,CAAA;AACZ,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,iBAAA;AAAA,MACN,KAAA,EAAO,iBAAA;AAAA,MACP,QAAA,EAAU,OAAA;AAAA,MACV,OAAA,EAAS,YAAY,OAAO,CAAA,CAAA;AAAA,MAC5B,IAAA,EAAM;AAAA,KACR;AAAA,EACF;AAEA,EAAA,MAAM,WAAW,OAAA,CAAQ,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,WAAW,UAAU,CAAA;AAC9D,EAAA,IAAI,QAAA,CAAS,SAAS,CAAA,EAAG;AACvB,IAAA,MAAM,OAAA,GAAU,QAAA,CACb,GAAA,CAAI,CAAC,MAAM,CAAA,EAAG,CAAA,CAAE,YAAA,IAAgB,UAAU,IAAI,CAAA,CAAE,IAAI,CAAA,CAAE,CAAA,CACtD,KAAK,IAAI,CAAA;AACZ,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,iBAAA;AAAA,MACN,KAAA,EAAO,iBAAA;AAAA,MACP,QAAA,EAAU,MAAA;AAAA,MACV,OAAA,EAAS,aAAa,OAAO,CAAA,CAAA;AAAA,MAC7B,IAAA,EAAM;AAAA,KACR;AAAA,EACF;AAEA,EAAA,OAAO,EAAE,MAAM,iBAAA,EAAmB,KAAA,EAAO,mBAAmB,QAAA,EAAU,IAAA,EAAM,SAAS,SAAA,EAAU;AACjG;AAEA,eAAe,WAAW,MAAA,EAAqC;AAC7D,EAAA,MAAM,IAAA,GAAO,MAAM,MAAA,CAAO,WAAA,CAAY,YAAY,IAAA,CAAK,EAAE,CAAA,CAAE,OAAA,EAAQ;AACnE,EAAA,IAAI,IAAA,CAAK,WAAW,CAAA,EAAG;AACrB,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,OAAA;AAAA,MACN,KAAA,EAAO,uBAAA;AAAA,MACP,QAAA,EAAU,IAAA;AAAA,MACV,OAAA,EAAS,mBAAA;AAAA,MACT,IAAA,EAAM;AAAA,KACR;AAAA,EACF;AACA,EAAA,MAAM,SAAS,IAAA,CAAK,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,WAAW,QAAQ,CAAA;AACvD,EAAA,IAAI,MAAA,CAAO,SAAS,CAAA,EAAG;AACrB,IAAA,MAAM,UAAU,MAAA,CACb,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,EAAG,EAAE,MAAM,CAAA,IAAA,EAAO,CAAA,CAAE,SAAS,EAAE,CAAA,CAC1C,KAAA,CAAM,GAAG,CAAC,CAAA,CACV,KAAK,IAAI,CAAA;AACZ,IAAA,MAAM,IAAA,GAAO,OAAO,MAAA,GAAS,CAAA,GAAI,MAAM,MAAA,CAAO,MAAA,GAAS,CAAC,CAAA,MAAA,CAAA,GAAW,EAAA;AACnE,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,OAAA;AAAA,MACN,KAAA,EAAO,uBAAA;AAAA,MACP,QAAA,EAAU,OAAA;AAAA,MACV,SAAS,CAAA,EAAG,MAAA,CAAO,MAAM,CAAA,aAAA,EAAgB,OAAO,GAAG,IAAI,CAAA,CAAA;AAAA,MACvD,IAAA,EAAM;AAAA,KACR;AAAA,EACF;AACA,EAAA,MAAM,UAAU,IAAA,CAAK,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,WAAW,OAAO,CAAA;AACvD,EAAA,IAAI,OAAA,CAAQ,MAAA,KAAW,IAAA,CAAK,MAAA,EAAQ;AAClC,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,OAAA;AAAA,MACN,KAAA,EAAO,uBAAA;AAAA,MACP,QAAA,EAAU,MAAA;AAAA,MACV,OAAA,EAAS,CAAA,IAAA,EAAO,IAAA,CAAK,MAAM,CAAA,eAAA,CAAA;AAAA,MAC3B,IAAA,EAAM;AAAA,KACR;AAAA,EACF;AACA,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,OAAA;AAAA,IACN,KAAA,EAAO,uBAAA;AAAA,IACP,QAAA,EAAU,IAAA;AAAA,IACV,OAAA,EAAS,CAAA,OAAA,EAAU,IAAA,CAAK,MAAM,CAAA,QAAA;AAAA,GAChC;AACF;AAEA,eAAe,gBAAgB,MAAA,EAAqC;AAClE,EAAA,MAAM,GAAA,GAAM,OAAO,MAAA,CAAO,UAAA;AAC1B,EAAA,IAAI,CAAC,KAAK,QAAA,IAAY,CAAC,KAAK,YAAA,IAAgB,CAAC,KAAK,YAAA,EAAc;AAI9D,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,YAAA;AAAA,MACN,KAAA,EAAO,yBAAA;AAAA,MACP,QAAA,EAAU,IAAA;AAAA,MACV,OAAA,EAAS,2BAAA;AAAA,MACT,IAAA,EAAM;AAAA,KACR;AAAA,EACF;AAEA,EAAA,MAAM,SAAA,GAAY,MAAM,MAAA,CAAO,WAAA,CAAY,oBAAoB,IAAA,CAAK,EAAE,CAAA,CAAE,KAAK,EAAE,SAAA,EAAW,EAAA,EAAI,EAAE,OAAA,EAAQ;AACxG,EAAA,IAAI,SAAA,CAAU,WAAW,CAAA,EAAG;AAC1B,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,YAAA;AAAA,MACN,KAAA,EAAO,yBAAA;AAAA,MACP,QAAA,EAAU,MAAA;AAAA,MACV,OAAA,EAAS,4BAAA;AAAA,MACT,IAAA,EAAM;AAAA,KACR;AAAA,EACF;AAGA,EAAA,MAAM,cAAA,uBAAqB,GAAA,EAAsC;AACjE,EAAA,KAAA,MAAW,KAAK,SAAA,EAAW;AACzB,IAAA,IAAI,CAAC,cAAA,CAAe,GAAA,CAAI,CAAA,CAAE,MAAM,GAAG,cAAA,CAAe,GAAA,CAAI,CAAA,CAAE,MAAA,EAAQ,CAAC,CAAA;AAAA,EACnE;AACA,EAAA,MAAM,MAAgB,EAAC;AACvB,EAAA,MAAM,MAAgB,EAAC;AACvB,EAAA,KAAA,MAAW,CAAA,IAAK,cAAA,CAAe,MAAA,EAAO,EAAG;AACvC,IAAA,IAAI,EAAE,gBAAA,KAAqB,KAAA,EAAO,GAAA,CAAI,IAAA,CAAK,EAAE,MAAM,CAAA;AAAA,SAAA,IAC1C,EAAE,gBAAA,KAAqB,KAAA,EAAO,GAAA,CAAI,IAAA,CAAK,EAAE,MAAM,CAAA;AAAA,EAC1D;AAEA,EAAA,IAAI,GAAA,CAAI,SAAS,CAAA,EAAG;AAClB,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,YAAA;AAAA,MACN,KAAA,EAAO,yBAAA;AAAA,MACP,QAAA,EAAU,OAAA;AAAA,MACV,OAAA,EAAS,CAAA,kBAAA,EAAqB,GAAA,CAAI,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA;AAAA,MAC5C,IAAA,EAAM;AAAA,KACR;AAAA,EACF;AACA,EAAA,IAAI,GAAA,CAAI,SAAS,CAAA,EAAG;AAClB,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,YAAA;AAAA,MACN,KAAA,EAAO,yBAAA;AAAA,MACP,QAAA,EAAU,MAAA;AAAA,MACV,OAAA,EAAS,CAAA,kBAAA,EAAqB,GAAA,CAAI,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA;AAAA,MAC5C,IAAA,EAAM;AAAA,KACR;AAAA,EACF;AACA,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,YAAA;AAAA,IACN,KAAA,EAAO,yBAAA;AAAA,IACP,QAAA,EAAU,IAAA;AAAA;AAAA;AAAA,IAGV,UAAU,MAAM;AACd,MAAA,MAAM,KAAA,GAAQ,IAAI,GAAA,CAAI,KAAA,CAAM,KAAK,cAAA,CAAe,MAAA,EAAQ,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,gBAAgB,CAAC,CAAA;AACxF,MAAA,MAAM,SAAA,GAAY,KAAA,CAAM,GAAA,CAAI,iCAAwC,CAAA;AACpE,MAAA,OAAO,GAAG,cAAA,CAAe,IAAI,CAAA,kBAAA,EAAqB,SAAA,GAAY,wCAAwC,mBAAmB,CAAA,CAAA;AAAA,IAC3H,CAAA;AAAG,GACL;AACF;AAUA,SAAS,UAAU,MAAA,EAAmC;AACpD,EAAA,MAAM,kBAAkB,MAAA,CAAO,MAAA,CAAO,KAAA,EAAO,YAAA,EAAc,UAAU,CAAA,IAAK,CAAA;AAC1E,EAAA,IAAI,CAAC,gBAAgB,OAAO,IAAA;AAC5B,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,WAAA;AAAA,IACN,KAAA,EAAO,0BAAA;AAAA,IACP,QAAA,EAAU,IAAA;AAAA,IACV,OAAA,EAAS,6CAAA;AAAA,IACT,IAAA,EAAM;AAAA,GACR;AACF;AAEA,eAAe,UAAU,MAAA,EAAqC;AAC5D,EAAA,MAAM,GAAA,GAAM,OAAO,MAAA,CAAO,IAAA;AAC1B,EAAA,MAAM,kBAAkB,MAAA,CAAO,MAAA,CAAO,KAAA,EAAO,YAAA,EAAc,UAAU,CAAA,IAAK,CAAA;AAE1E,EAAA,IAAI,CAAC,KAAK,SAAA,EAAW;AACnB,IAAA,IAAI,CAAC,cAAA,EAAgB;AACnB,MAAA,OAAO;AAAA,QACL,IAAA,EAAM,MAAA;AAAA,QACN,KAAA,EAAO,gBAAA;AAAA,QACP,QAAA,EAAU,IAAA;AAAA,QACV,OAAA,EAAS,kCAAA;AAAA,QACT,IAAA,EAAM;AAAA,OACR;AAAA,IACF;AACA,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,MAAA;AAAA,MACN,KAAA,EAAO,gBAAA;AAAA,MACP,QAAA,EAAU,MAAA;AAAA,MACV,OAAA,EAAS,qDAAA;AAAA,MACT,IAAA,EAAM;AAAA,KACR;AAAA,EACF;AAEA,EAAA,MAAM,SAAA,GAAY,MAAM,MAAA,CAAO,WAAA,CAAY,cAAc,IAAA,CAAK,EAAE,CAAA,CAAE,KAAK,EAAE,SAAA,EAAW,EAAA,EAAI,EAAE,OAAA,EAAQ;AAClG,EAAA,IAAI,SAAA,CAAU,WAAW,CAAA,EAAG;AAC1B,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,MAAA;AAAA,MACN,KAAA,EAAO,gBAAA;AAAA,MACP,QAAA,EAAU,MAAA;AAAA,MACV,OAAA,EAAS,4BAAA;AAAA,MACT,IAAA,EAAM;AAAA,KACR;AAAA,EACF;AAEA,EAAA,MAAM,UAAA,uBAAiB,GAAA,EAAsC;AAC7D,EAAA,KAAA,MAAW,KAAK,SAAA,EAAW;AACzB,IAAA,IAAI,CAAC,UAAA,CAAW,GAAA,CAAI,CAAA,CAAE,EAAE,GAAG,UAAA,CAAW,GAAA,CAAI,CAAA,CAAE,EAAA,EAAI,CAAC,CAAA;AAAA,EACnD;AACA,EAAA,MAAM,MAAgB,EAAC;AACvB,EAAA,MAAM,SAAmB,EAAC;AAC1B,EAAA,KAAA,MAAW,CAAA,IAAK,UAAA,CAAW,MAAA,EAAO,EAAG;AACnC,IAAA,IAAI,EAAE,YAAA,KAAiB,KAAA,EAAO,GAAA,CAAI,IAAA,CAAK,EAAE,EAAE,CAAA;AAAA,SAAA,IAClC,EAAE,YAAA,KAAiB,QAAA,EAAU,MAAA,CAAO,IAAA,CAAK,EAAE,EAAE,CAAA;AAAA,EACxD;AAEA,EAAA,IAAI,GAAA,CAAI,SAAS,CAAA,EAAG;AAClB,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,MAAA;AAAA,MACN,KAAA,EAAO,gBAAA;AAAA,MACP,QAAA,EAAU,OAAA;AAAA,MACV,OAAA,EAAS,CAAA,cAAA,EAAiB,GAAA,CAAI,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA;AAAA,MACxC,IAAA,EAAM;AAAA,KACR;AAAA,EACF;AACA,EAAA,IAAI,MAAA,CAAO,SAAS,CAAA,EAAG;AACrB,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,MAAA;AAAA,MACN,KAAA,EAAO,gBAAA;AAAA,MACP,QAAA,EAAU,MAAA;AAAA,MACV,OAAA,EAAS,CAAA,iBAAA,EAAoB,MAAA,CAAO,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA;AAAA,MAC9C,IAAA,EAAM;AAAA,KACR;AAAA,EACF;AACA,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,MAAA;AAAA,IACN,KAAA,EAAO,gBAAA;AAAA,IACP,QAAA,EAAU,IAAA;AAAA,IACV,OAAA,EAAS,CAAA,EAAG,UAAA,CAAW,IAAI,CAAA,yBAAA;AAAA,GAC7B;AACF;AAEA,eAAe,WAAW,MAAA,EAAqC;AAC7D,EAAA,MAAM,WAAA,GAAc,MAAM,MAAA,CAAO,WAAA,CAAY,aAAa,sBAAA,EAAuB;AACjF,EAAA,IAAI,gBAAgB,CAAA,EAAG;AACrB,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,OAAA;AAAA,MACN,KAAA,EAAO,mBAAA;AAAA,MACP,QAAA,EAAU,IAAA;AAAA,MACV,OAAA,EAAS,yBAAA;AAAA,MACT,IAAA,EAAM;AAAA,KACR;AAAA,EACF;AAEA,EAAA,MAAM,QAAQ,IAAI,IAAA,CAAK,KAAK,GAAA,EAAI,GAAI,IAAI,KAAU,CAAA;AAClD,EAAA,MAAM,MAAA,GAAS,MAAM,MAAA,CAAO,WAAA,CAAY,aAAa,IAAA,CAAK,EAAE,QAAA,EAAU,EAAE,IAAA,EAAM,KAAA,EAAM,EAAG,EAAE,OAAA,EAAQ;AACjG,EAAA,IAAI,MAAA,CAAO,WAAW,CAAA,EAAG;AACvB,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,OAAA;AAAA,MACN,KAAA,EAAO,mBAAA;AAAA,MACP,QAAA,EAAU,MAAA;AAAA,MACV,OAAA,EAAS,kCAAkC,WAAW,CAAA,OAAA,CAAA;AAAA,MACtD,IAAA,EAAM;AAAA,KACR;AAAA,EACF;AAKA,EAAA,MAAM,MAAA,GAAS,MAAM,iBAAA,CAAkB,MAAA,CAAO,kBAAkB,CAAA;AAChE,EAAA,MAAM,KAAA,GAAQ,IAAI,GAAA,CAAI,KAAA,CAAM,KAAK,MAAA,CAAO,IAAA,EAAM,CAAC,CAAA;AAC/C,EAAA,MAAM,UAAU,IAAI,IAAA,CAAK,KAAK,GAAA,EAAI,GAAI,KAAK,KAAU,CAAA;AACrD,EAAA,MAAM,QAAA,GAAW,MAAM,MAAA,CAAO,WAAA,CAAY,cAAc,IAAA,CAAK,EAAE,UAAA,EAAY,EAAE,IAAA,EAAM,OAAA,EAAQ,EAAG,EAAE,OAAA,EAAQ;AACxG,EAAA,MAAM,cAAA,GAAiB,QAAA,CAAS,MAAA,CAAO,CAAC,CAAA,KAAM,CAAC,KAAA,CAAM,GAAA,CAAI,CAAA,CAAE,QAAQ,CAAC,CAAA;AAEpE,EAAA,IAAI,cAAA,CAAe,WAAW,CAAA,EAAG;AAC/B,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,OAAA;AAAA,MACN,KAAA,EAAO,mBAAA;AAAA,MACP,QAAA,EAAU,IAAA;AAAA,MACV,OAAA,EAAS,CAAA,EAAG,MAAA,CAAO,MAAM,CAAA,gDAAA;AAAA,KAC3B;AAAA,EACF;AAEA,EAAA,MAAM,YAAA,GAAe,eAAe,MAAA,CAAO,CAAC,KAAK,CAAA,KAAM,GAAA,GAAM,CAAA,CAAE,KAAA,EAAO,CAAC,CAAA;AACvE,EAAA,MAAM,MAAM,KAAA,CAAM,IAAA,CAAK,IAAI,GAAA,CAAI,eAAe,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,QAAQ,CAAC,CAAC,CAAA,CAAE,KAAA,CAAM,GAAG,CAAC,CAAA;AACjF,EAAA,MAAM,IAAA,GAAO,eAAe,MAAA,GAAS,CAAA,GAAI,MAAM,cAAA,CAAe,MAAA,GAAS,CAAC,CAAA,MAAA,CAAA,GAAW,EAAA;AACnF,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,OAAA;AAAA,IACN,KAAA,EAAO,mBAAA;AAAA,IACP,QAAA,EAAU,MAAA;AAAA,IACV,OAAA,EAAS,GAAG,YAAY,CAAA,yBAAA,EAA4B,IAAI,IAAA,CAAK,IAAI,CAAC,CAAA,EAAG,IAAI,CAAA,CAAA;AAAA,IACzE,IAAA,EAAM;AAAA,GACR;AACF;AAEA,SAAS,iCAAiC,MAAA,EAA8B;AACtE,EAAA,MAAM,QAAA,GAAW,OAAO,MAAA,CAAO,aAAA;AAC/B,EAAA,IAAI,CAAC,YAAY,MAAA,CAAO,IAAA,CAAK,QAAQ,CAAA,CAAE,MAAA,KAAW,CAAA,EAAG,OAAO,EAAC;AAE7D,EAAA,MAAM,MAAoB,EAAC;AAC3B,EAAA,MAAM,IAAA,GAAO,MAAA,CAAO,MAAA,CAAO,YAAA,EAAc,KAAA;AACzC,EAAA,MAAM,EAAA,GAAK,MAAA,CAAO,MAAA,CAAO,yBAAA,EAA2B,KAAA;AAEpD,EAAA,IAAI,IAAA,EAAM;AACR,IAAA,MAAM,CAAA,GAAI,oBAAA,CAAqB,IAAA,EAAM,WAAA,EAAa,QAAQ,CAAA;AAC1D,IAAA,IAAI,CAAC,EAAE,EAAA,EAAI;AACT,MAAA,GAAA,CAAI,IAAA,CAAK;AAAA,QACP,IAAA,EAAM,yBAAA;AAAA,QACN,KAAA,EAAO,+BAAA;AAAA,QACP,QAAA,EAAU,OAAA;AAAA,QACV,SAAS,CAAA,CAAE,MAAA;AAAA,QACX,IAAA,EAAM;AAAA,OACP,CAAA;AAAA,IACH;AAAA,EACF;AAEA,EAAA,IAAI,EAAA,EAAI;AACN,IAAA,MAAM,CAAA,GAAI,oBAAA,CAAqB,EAAA,EAAI,eAAA,EAAiB,QAAQ,CAAA;AAC5D,IAAA,IAAI,CAAC,EAAE,EAAA,EAAI;AACT,MAAA,GAAA,CAAI,IAAA,CAAK;AAAA,QACP,IAAA,EAAM,6BAAA;AAAA,QACN,KAAA,EAAO,4CAAA;AAAA,QACP,QAAA,EAAU,OAAA;AAAA,QACV,SAAS,CAAA,CAAE,MAAA;AAAA,QACX,IAAA,EAAM;AAAA,OACP,CAAA;AAAA,IACH;AAAA,EACF,WAAW,IAAA,EAAM;AAGf,IAAA,MAAM,CAAA,GAAI,oBAAA,CAAqB,IAAA,EAAM,eAAA,EAAiB,QAAQ,CAAA;AAC9D,IAAA,IAAI,CAAC,EAAE,EAAA,EAAI;AACT,MAAA,GAAA,CAAI,IAAA,CAAK;AAAA,QACP,IAAA,EAAM,wBAAA;AAAA,QACN,KAAA,EAAO,wBAAA;AAAA,QACP,QAAA,EAAU,MAAA;AAAA,QACV,OAAA,EAAS,wDAAwD,IAAI,CAAA,wCAAA,CAAA;AAAA,QACrE,IAAA,EAAM;AAAA,OACP,CAAA;AAAA,IACH;AAAA,EACF;AAEA,EAAA,OAAO,GAAA;AACT;AAEA,eAAe,wBAAwB,MAAA,EAAuC;AAC5E,EAAA,MAAM,QAAA,GAAW,OAAO,MAAA,CAAO,aAAA;AAC/B,EAAA,IAAI,CAAC,YAAY,MAAA,CAAO,IAAA,CAAK,QAAQ,CAAA,CAAE,MAAA,KAAW,CAAA,EAAG,OAAO,EAAC;AAE7D,EAAA,MAAM,SAAA,GAAY,MAAM,MAAA,CAAO,WAAA,CAAY,SAAA,CACxC,KAAK,EAAE,WAAA,EAAa,EAAE,GAAA,EAAK,IAAA,EAAK,IAAK,EAAE,UAAA,EAAY,EAAE,IAAA,EAAM,CAAA,EAAG,IAAA,EAAM,CAAA,EAAG,SAAA,EAAW,CAAA,EAAE,EAAG,CAAA,CACvF,OAAA,EAAQ;AAEX,EAAA,MAAM,SAAkD,EAAC;AACzD,EAAA,KAAA,MAAW,OAAO,SAAA,EAAW;AAC3B,IAAA,MAAM,IAAI,oBAAA,CAAqB,GAAA,CAAI,SAAA,EAAW,GAAA,CAAI,MAAM,QAAQ,CAAA;AAChE,IAAA,IAAI,CAAC,CAAA,CAAE,EAAA,EAAI,MAAA,CAAO,IAAA,CAAK,EAAE,IAAA,EAAM,GAAA,CAAI,IAAA,EAAM,MAAA,EAAQ,CAAA,CAAE,MAAA,EAAQ,CAAA;AAAA,EAC7D;AAEA,EAAA,IAAI,MAAA,CAAO,MAAA,KAAW,CAAA,EAAG,OAAO,EAAC;AACjC,EAAA,MAAM,OAAO,MAAA,CAAO,KAAA,CAAM,GAAG,CAAC,CAAA,CAAE,IAAI,CAAC,CAAA,KAAM,CAAA,EAAG,CAAA,CAAE,IAAI,CAAA,EAAA,EAAK,CAAA,CAAE,MAAM,CAAA,CAAA,CAAG,CAAA,CAAE,KAAK,IAAI,CAAA;AAC/E,EAAA,MAAM,IAAA,GAAO,OAAO,MAAA,GAAS,CAAA,GAAI,cAAS,MAAA,CAAO,MAAA,GAAS,CAAC,CAAA,KAAA,CAAA,GAAU,EAAA;AACrE,EAAA,OAAO;AAAA,IACL;AAAA,MACE,IAAA,EAAM,4BAAA;AAAA,MACN,KAAA,EAAO,qBAAA;AAAA,MACP,QAAA,EAAU,OAAA;AAAA,MACV,OAAA,EAAS,CAAA,EAAG,MAAA,CAAO,MAAM,CAAA,mBAAA,EAAsB,MAAA,CAAO,MAAA,KAAW,CAAA,GAAI,EAAA,GAAK,GAAG,CAAA,uDAAA,EAA0D,IAAI,GAAG,IAAI,CAAA,CAAA;AAAA,MAClJ,IAAA,EAAM;AAAA;AACR,GACF;AACF;AAEA,eAAe,mBAAmB,MAAA,EAAqC;AACrE,EAAA,IAAI,MAAA,CAAO,OAAO,aAAA,EAAe;AAC/B,IAAA,OAAO,EAAE,MAAM,gBAAA,EAAkB,KAAA,EAAO,2BAA2B,QAAA,EAAU,IAAA,EAAM,SAAS,KAAA,EAAM;AAAA,EACpG;AACA,EAAA,MAAM,cAAA,GAAiB,MAAM,MAAA,CAAO,WAAA,CAAY,UAAU,cAAA,CAAe;AAAA,IACvE,IAAA,EAAM,WAAA;AAAA,IACN,WAAA,EAAa,EAAE,GAAA,EAAK,IAAA;AAAK,GAC1B,CAAA;AACD,EAAA,IAAI,mBAAmB,CAAA,EAAG;AACxB,IAAA,OAAO,EAAE,MAAM,gBAAA,EAAkB,KAAA,EAAO,2BAA2B,QAAA,EAAU,IAAA,EAAM,SAAS,sCAAA,EAAuC;AAAA,EACrI;AACA,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,gBAAA;AAAA,IACN,KAAA,EAAO,yBAAA;AAAA,IACP,QAAA,EAAU,MAAA;AAAA,IACV,SAAS,CAAA,EAAG,cAAc,gCAAgC,cAAA,KAAmB,CAAA,GAAI,KAAK,GAAG,CAAA,2BAAA,CAAA;AAAA,IACzF,IAAA,EAAM;AAAA,GACR;AACF;AAEA,eAAe,iBAAiB,MAAA,EAAqC;AACnE,EAAA,IAAI,CAAC,MAAA,CAAO,MAAA,CAAO,kBAAA,EAAoB;AACrC,IAAA,OAAO,EAAE,MAAM,cAAA,EAAgB,KAAA,EAAO,gBAAgB,QAAA,EAAU,IAAA,EAAM,SAAS,kBAAA,EAAmB;AAAA,EACpG;AACA,EAAA,MAAM,GAAA,GAAM,MAAM,MAAA,CAAO,WAAA,CAAY,UAAU,OAAA,CAAQ;AAAA,IACrD,IAAA,EAAM,OAAO,MAAA,CAAO,eAAA;AAAA,IACpB,WAAA,EAAa,EAAE,GAAA,EAAK,IAAA;AAAK,GAC1B,CAAA;AACD,EAAA,IAAI,GAAA,EAAK;AACP,IAAA,OAAO,EAAE,IAAA,EAAM,cAAA,EAAgB,KAAA,EAAO,cAAA,EAAgB,QAAA,EAAU,IAAA,EAAM,OAAA,EAAS,CAAA,UAAA,EAAa,GAAA,CAAI,IAAI,CAAA,WAAA,CAAA,EAAc;AAAA,EACpH;AACA,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,cAAA;AAAA,IACN,KAAA,EAAO,cAAA;AAAA,IACP,QAAA,EAAU,OAAA;AAAA,IACV,OAAA,EAAS,CAAA,gEAAA,EAAmE,MAAA,CAAO,MAAA,CAAO,eAAe,CAAA,CAAA,CAAA;AAAA,IACzG,IAAA,EAAM;AAAA,GACR;AACF;AAEA,SAAS,cAAc,EAAA,EAAoB;AACzC,EAAA,IAAI,EAAA,GAAK,GAAA,EAAM,OAAO,CAAA,EAAG,EAAE,CAAA,EAAA,CAAA;AAC3B,EAAA,IAAI,EAAA,GAAK,KAAQ,OAAO,CAAA,EAAG,KAAK,KAAA,CAAM,EAAA,GAAK,GAAI,CAAC,CAAA,CAAA,CAAA;AAChD,EAAA,IAAI,EAAA,GAAK,MAAW,OAAO,CAAA,EAAG,KAAK,KAAA,CAAM,EAAA,GAAK,GAAM,CAAC,CAAA,CAAA,CAAA;AACrD,EAAA,OAAO,CAAA,EAAG,IAAA,CAAK,KAAA,CAAM,EAAA,GAAK,IAAS,CAAC,CAAA,CAAA,CAAA;AACtC;;;ACjkBA,IAAM,MAAA,GAAS,KAAA;AAER,IAAM,eAAA,GAAkB;AAAA,EAC7B,EAAE,KAAA,EAAO,wBAAA,EAA0B,OAAA,EAAS,EAAA,EAAG;AAAA,EAC/C,EAAE,KAAA,EAAO,sBAAA,EAAwB,OAAA,EAAS,EAAA,EAAI,SAAS,EAAA,EAAG;AAAA,EAC1D,EAAE,KAAA,EAAO,sBAAA,EAAwB,OAAA,EAAS,EAAA,EAAI,SAAS,EAAA,EAAG;AAAA,EAC1D,EAAE,KAAA,EAAO,uBAAA,EAAyB,OAAA,EAAS,EAAA,EAAI,SAAS,GAAA,EAAI;AAAA,EAC5D,EAAE,KAAA,EAAO,sBAAA,EAAwB,OAAA,EAAS,GAAA,EAAI;AAAA,EAC9C,EAAE,KAAA,EAAO,eAAA,EAAiB,YAAA,EAAc,IAAA;AAC1C,CAAA;AAuDA,eAAsB,kBAAA,CACpB,GAAA,EACA,IAAA,GAA8B,EAAC,EACP;AACxB,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,GAAA,IAAO,IAAA,CAAK,GAAA,EAAI;AACjC,EAAA,MAAM,UAAA,GAAa,KAAK,mBAAA,IAAuB,GAAA;AAC/C,EAAA,MAAM,UAAA,GAAa,KAAK,gBAAA,IAAoB,EAAA;AAC5C,EAAA,MAAM,YAAA,GAAe,IAAI,IAAA,CAAK,GAAA,GAAM,aAAa,MAAM,CAAA;AAEvD,EAAA,MAAM,gBAAA,GAAmB,MAAM,GAAA,CAAI,WAAA,CAAY,cAAc,cAAA,CAAe,EAAE,MAAA,EAAQ,YAAA,EAAc,CAAA;AAQpG,EAAA,MAAM,aAAA,uBAAoB,GAAA,EAAY;AACtC,EAAA;AACE,IAAA,MAAMC,OAAAA,GAAS,GAAA,CAAI,WAAA,CAAY,aAAA,CAC5B,KAAK,EAAE,MAAA,EAAQ,YAAA,EAAa,EAAG,EAAE,UAAA,EAAY,EAAE,UAAA,EAAY,CAAA,IAAK,CAAA;AACnE,IAAA,WAAA,MAAiB,CAAA,IAAKA,OAAAA,EAAQ,aAAA,CAAc,GAAA,CAAI,EAAE,UAAU,CAAA;AAAA,EAC9D;AAoBA,EAAA,MAAM,MAAA,GAAS,GAAA,CAAI,WAAA,CAAY,KAAA,CAAM,SAAA;AAAA,IACnC;AAAA,MACE;AAAA,QACE,MAAA,EAAQ;AAAA,UACN,GAAA,EAAK,aAAA;AAAA,UACL,UAAA,EAAY,EAAE,IAAA,EAAM,WAAA,EAAY;AAAA,UAChC,WAAA,EAAa,EAAE,IAAA,EAAM,eAAA,EAAgB;AAAA,UACrC,SAAA,EAAW,EAAE,IAAA,EAAM,WAAA,EAAY;AAAA,UAC/B,UAAA,EAAY,EAAE,IAAA,EAAM,CAAA,EAAE;AAAA,UACtB,SAAS,EAAE,IAAA,EAAM,EAAE,KAAA,EAAO,CAAC,EAAE,GAAA,EAAK,CAAC,SAAA,EAAW,SAAS,CAAA,EAAE,EAAG,CAAA,EAAG,CAAC,GAAE,EAAE;AAAA,UACpE,WAAA,EAAa;AAAA,YACX,IAAA,EAAM;AAAA,cACJ,KAAA,EAAO;AAAA,gBACL,EAAE,IAAA,EAAM,CAAC,EAAE,GAAA,EAAK,CAAC,SAAA,EAAW,SAAS,CAAA,EAAE,EAAG,EAAE,GAAA,EAAK,CAAC,eAAe,MAAM,CAAA,EAAG,CAAA,EAAE;AAAA,gBAC5E,CAAA;AAAA,gBACA;AAAA;AACF;AACF,WACF;AAAA,UACA,YAAY,EAAE,IAAA,EAAM,EAAE,KAAA,EAAO,CAAC,EAAE,GAAA,EAAK,CAAC,eAAA,EAAiB,IAAI,CAAA,EAAE,EAAG,CAAA,EAAG,CAAC,GAAE,EAAE;AAAA,UACxE,aAAa,EAAE,IAAA,EAAM,EAAE,KAAA,EAAO,CAAC,EAAE,IAAA,EAAM,CAAC,WAAA,EAAa,YAAY,CAAA,EAAE,EAAG,CAAA,EAAG,CAAC,GAAE,EAAE;AAAA,UAC9E,aAAA,EAAe;AAAA,YACb,IAAA,EAAM;AAAA,cACJ,KAAA,EAAO;AAAA,gBACL,EAAE,IAAA,EAAM,CAAC,EAAE,GAAA,EAAK,CAAC,SAAA,EAAW,SAAS,CAAA,EAAE,EAAG,EAAE,IAAA,EAAM,CAAC,aAAa,YAAY,CAAA,EAAG,CAAA,EAAE;AAAA,gBACjF,CAAA;AAAA,gBACA;AAAA;AACF;AACF,WACF;AAAA,UACA,gBAAA,EAAkB;AAAA,YAChB,IAAA,EAAM;AAAA,cACJ,KAAA,EAAO;AAAA,gBACL,EAAE,IAAA,EAAM,CAAC,EAAE,GAAA,EAAK,CAAC,eAAA,EAAiB,IAAI,CAAA,EAAE,EAAG,EAAE,IAAA,EAAM,CAAC,aAAa,YAAY,CAAA,EAAG,CAAA,EAAE;AAAA,gBAClF,CAAA;AAAA,gBACA;AAAA;AACF;AACF;AACF;AACF;AACF,KACF;AAAA,IACA,EAAE,cAAc,IAAA;AAAK,GACvB;AAEA,EAAA,MAAM,OAAA,GAA2B,eAAA,CAAgB,GAAA,CAAI,CAAC,CAAA,MAAO;AAAA,IAC3D,OAAO,CAAA,CAAE,KAAA;AAAA,IACT,OAAA,EAAS,SAAA,IAAa,CAAA,GAAI,CAAA,CAAE,OAAA,GAAU,IAAA;AAAA,IACtC,OAAA,EAAS,SAAA,IAAa,CAAA,GAAI,CAAA,CAAE,OAAA,GAAU,IAAA;AAAA,IACtC,YAAA,EAAc,cAAA,IAAkB,CAAA,IAAK,CAAA,CAAE,YAAA;AAAA,IACvC,KAAA,EAAO,CAAA;AAAA,IACP,UAAA,EAAY;AAAA,GACd,CAAE,CAAA;AAEF,EAAA,IAAI,cAAA,GAAiB,CAAA;AACrB,EAAA,IAAI,WAAA,GAAc,CAAA;AAElB,EAAA,MAAM,iBAAA,GAAoB,EAAE,UAAA,EAAY,CAAA,EAAG,SAAS,CAAA,EAAG,WAAA,EAAa,CAAA,EAAG,UAAA,EAAY,CAAA,EAAE;AACrF,EAAA,MAAM,kBAAkB,EAAE,UAAA,EAAY,GAAG,OAAA,EAAS,CAAA,EAAG,YAAY,CAAA,EAAE;AAEnE,EAAA,WAAA,MAAiB,OAAO,MAAA,EAAQ;AAC9B,IAAA,IAAI,CAAC,aAAA,CAAc,GAAA,CAAI,GAAA,CAAI,GAAG,CAAA,EAAG;AACjC,IAAA,cAAA,EAAA;AAEA,IAAA,MAAM,UAAA,GAAa,IAAI,UAAA,GAAa,IAAI,KAAK,GAAA,CAAI,UAAU,CAAA,CAAE,OAAA,EAAQ,GAAI,IAAA;AACzE,IAAA,MAAM,WAAA,GAAc,IAAI,WAAA,GAAc,IAAI,KAAK,GAAA,CAAI,WAAW,CAAA,CAAE,OAAA,EAAQ,GAAI,IAAA;AAC5E,IAAA,MAAM,WAAA,GAAc,UAAA,IAAc,IAAA,IAAQ,WAAA,IAAe,IAAA,GACrD,IAAA,GACA,IAAA,CAAK,GAAA,CAAI,UAAA,IAAc,CAAA,EAAG,WAAA,IAAe,CAAC,CAAA;AAE9C,IAAA,IAAI,QAAA,GAAW,KAAA;AACf,IAAA,IAAI,eAAe,IAAA,EAAM;AACvB,MAAA,MAAM,SAAA,GAAY,IAAI,SAAA,GAAY,IAAI,KAAK,GAAA,CAAI,SAAS,CAAA,CAAE,OAAA,EAAQ,GAAI,IAAA;AACtE,MAAA,OAAA,CAAQ,CAAC,CAAA,CAAG,KAAA,EAAA;AACZ,MAAA,IAAI,SAAA,IAAa,IAAA,IAAQ,GAAA,GAAM,SAAA,GAAY,aAAa,MAAA,EAAQ;AAC9D,QAAA,QAAA,GAAW,IAAA;AAAA,MACb;AAAA,IACF,CAAA,MAAO;AACL,MAAA,MAAM,SAAA,GAAA,CAAa,MAAM,WAAA,IAAe,MAAA;AACxC,MAAA,IAAI,SAAA,IAAa,EAAA,EAAI,OAAA,CAAQ,CAAC,CAAA,CAAG,KAAA,EAAA;AAAA,WAAA,IACxB,SAAA,IAAa,EAAA,EAAI,OAAA,CAAQ,CAAC,CAAA,CAAG,KAAA,EAAA;AAAA,WAAA,IAC7B,SAAA,IAAa,EAAA,EAAI,OAAA,CAAQ,CAAC,CAAA,CAAG,KAAA,EAAA;AAAA,WAAA,IAC7B,SAAA,IAAa,GAAA,EAAK,OAAA,CAAQ,CAAC,CAAA,CAAG,KAAA,EAAA;AAAA,WAClC;AACH,QAAA,OAAA,CAAQ,CAAC,CAAA,CAAG,KAAA,EAAA;AACZ,QAAA,QAAA,GAAW,IAAA;AAAA,MACb;AAAA,IACF;AAEA,IAAA,IAAI,QAAA,EAAU;AACZ,MAAA,WAAA,EAAA;AACA,MAAA,iBAAA,CAAkB,cAAc,GAAA,CAAI,UAAA;AACpC,MAAA,iBAAA,CAAkB,WAAW,GAAA,CAAI,OAAA;AACjC,MAAA,iBAAA,CAAkB,eAAe,GAAA,CAAI,WAAA;AACrC,MAAA,iBAAA,CAAkB,cAAc,GAAA,CAAI,UAAA;AACpC,MAAA,eAAA,CAAgB,cAAc,GAAA,CAAI,WAAA;AAClC,MAAA,eAAA,CAAgB,WAAW,GAAA,CAAI,aAAA;AAC/B,MAAA,eAAA,CAAgB,cAAc,GAAA,CAAI,gBAAA;AAAA,IACpC;AAAA,EACF;AAEA,EAAA,KAAA,MAAW,KAAK,OAAA,EAAS;AACvB,IAAA,CAAA,CAAE,UAAA,GAAa,gBAAA,KAAqB,CAAA,GAAI,CAAA,GAAI,EAAE,KAAA,GAAQ,gBAAA;AAAA,EACxD;AAEA,EAAA,MAAM,cAAA,GACJ,iBAAA,CAAkB,UAAA,GAAa,CAAA,GAC3B;AAAA,IACE,YAAY,iBAAA,CAAkB,UAAA;AAAA,IAC9B,WAAA,EAAa,iBAAA,CAAkB,OAAA,GAAU,iBAAA,CAAkB,UAAA;AAAA,IAC3D,eAAA,EAAiB,iBAAA,CAAkB,WAAA,GAAc,iBAAA,CAAkB,UAAA;AAAA,IACnE,aAAA,EAAe,iBAAA,CAAkB,UAAA,GAAa,iBAAA,CAAkB;AAAA,GAClE,GACA,IAAA;AAIN,EAAA,IAAI,eAAA,GAAuE,IAAA;AAC3E,EAAA,MAAM,SAAA,GAAY,MAAM,GAAA,CAAI,WAAA,CAAY,MACrC,SAAA,CAAuE;AAAA,IACtE,EAAE,QAAQ,EAAE,QAAA,EAAU,EAAE,IAAA,EAAM,YAAA,IAAe,EAAE;AAAA,IAC/C;AAAA,MACE,MAAA,EAAQ;AAAA,QACN,GAAA,EAAK,IAAA;AAAA,QACL,UAAA,EAAY,EAAE,IAAA,EAAM,CAAA,EAAE;AAAA,QACtB,SAAS,EAAE,IAAA,EAAM,EAAE,KAAA,EAAO,CAAC,EAAE,GAAA,EAAK,CAAC,SAAA,EAAW,SAAS,CAAA,EAAE,EAAG,CAAA,EAAG,CAAC,GAAE,EAAE;AAAA,QACpE,YAAY,EAAE,IAAA,EAAM,EAAE,KAAA,EAAO,CAAC,EAAE,GAAA,EAAK,CAAC,eAAA,EAAiB,IAAI,CAAA,EAAE,EAAG,CAAA,EAAG,CAAC,GAAE;AAAE;AAC1E;AACF,GACD,EACA,OAAA,EAAQ;AAEX,EAAA,IAAI,UAAU,CAAC,CAAA,IAAK,UAAU,CAAC,CAAA,CAAE,aAAa,CAAA,EAAG;AAC/C,IAAA,MAAM,GAAA,GAAM,UAAU,CAAC,CAAA;AACvB,IAAA,MAAM,MAAA,GAAS,eAAA;AACf,IAAA,MAAM,iBAAA,GAAoB,GAAA,CAAI,OAAA,GAAU,GAAA,CAAI,UAAA;AAC5C,IAAA,MAAM,oBAAA,GAAuB,GAAA,CAAI,UAAA,GAAa,GAAA,CAAI,UAAA;AAClD,IAAA,MAAM,cAAA,GAAiB,GAAA,CAAI,UAAA,GAAa,MAAA,CAAO,UAAA;AAC/C,IAAA,MAAM,gBAAA,GAAmB,GAAA,CAAI,OAAA,GAAU,MAAA,CAAO,OAAA;AAC9C,IAAA,MAAM,mBAAA,GAAsB,GAAA,CAAI,UAAA,GAAa,MAAA,CAAO,UAAA;AACpD,IAAA,MAAM,mBAAA,GAAsB,cAAA,GAAiB,CAAA,GAAI,gBAAA,GAAmB,cAAA,GAAiB,CAAA;AACrF,IAAA,MAAM,sBAAA,GAAyB,cAAA,GAAiB,CAAA,GAAI,mBAAA,GAAsB,cAAA,GAAiB,CAAA;AAE3F,IAAA,eAAA,GAAkB;AAAA,MAChB,kBAAkB,GAAA,CAAI,UAAA;AAAA,MACtB,eAAe,GAAA,CAAI,OAAA;AAAA,MACnB,kBAAkB,GAAA,CAAI,UAAA;AAAA,MACtB,mBAAmB,MAAA,CAAO,UAAA;AAAA,MAC1B,qBAAqB,MAAA,CAAO,OAAA;AAAA,MAC5B,wBAAwB,MAAA,CAAO,UAAA;AAAA,MAC/B,wBAAA,EAA0B,iBAAA;AAAA,MAC1B,mBAAA;AAAA,MACA,2BAAA,EAA6B,oBAAA;AAAA,MAC7B;AAAA,KACF;AAAA,EACF;AAEA,EAAA,OAAO;AAAA,IACL,gBAAA;AAAA,IACA,cAAA;AAAA,IACA,OAAA;AAAA,IACA,eAAA,EAAiB;AAAA,MACf,KAAA,EAAO,WAAA;AAAA,MACP,UAAA,EAAY,gBAAA,KAAqB,CAAA,GAAI,CAAA,GAAI,WAAA,GAAc,gBAAA;AAAA,MACvD,cAAA;AAAA,MACA;AAAA,KACF;AAAA,IACA,UAAA,EAAY,IAAI,IAAA,CAAK,GAAG,EAAE,WAAA;AAAY,GACxC;AACF;ACrPA,IAAMT,iBAAAA,GAAmB,IAAA;AAElB,SAAS,sBAAA,CACd,GAAA,EACA,OAAA,GAAmB,UAAA,CAAW,KAAA,EACZ;AAClB,EAAA,MAAM,IAAA,GAAO,IAAI,OAAA,IAAW,6BAAA;AAE5B,EAAA,SAAS,SAAS,CAAA,EAAmB;AACnC,IAAA,IAAI,CAAC,GAAA,CAAI,MAAA,EAAQ,OAAO,CAAA;AACxB,IAAA,OAAO,CAAA,CAAE,KAAA,CAAM,GAAA,CAAI,MAAM,EAAE,IAAA,CAAK,YAAY,CAAA,CAAE,KAAA,CAAM,mBAAmB,GAAA,CAAI,MAAM,CAAC,CAAA,CAAE,KAAK,YAAY,CAAA;AAAA,EACvG;AAEA,EAAA,eAAe,IAAA,CAAK,MAAA,EAAgBD,KAAAA,EAAc,IAAA,EAA8B;AAC9E,IAAA,MAAM,GAAA,GAAM,IAAI,eAAA,EAAgB;AAChC,IAAA,MAAM,IAAI,UAAA,CAAW,MAAM,GAAA,CAAI,KAAA,IAASC,iBAAgB,CAAA;AACxD,IAAA,IAAI,GAAA;AACJ,IAAA,IAAI;AACF,MAAA,GAAA,GAAM,MAAM,OAAA,CAAQ,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,kBAAA,CAAmB,GAAA,CAAI,MAAM,CAAC,CAAA,EAAGD,KAAI,CAAA,CAAA,EAAI;AAAA,QACtE,MAAA;AAAA,QACA,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA,EAAmB;AAAA,QAC9C,IAAA,EAAM,IAAA,GAAO,IAAA,CAAK,SAAA,CAAU,IAAI,CAAA,GAAI,KAAA,CAAA;AAAA,QACpC,QAAQ,GAAA,CAAI;AAAA,OACb,CAAA;AAAA,IACH,SAAS,GAAA,EAAU;AACjB,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,YAAA,EAAe,MAAM,CAAA,CAAA,EAAI,SAASA,KAAI,CAAC,CAAA,SAAA,EAAY,QAAA,CAAS,OAAO,GAAA,EAAK,OAAA,IAAW,GAAG,CAAC,CAAC,CAAA,CAAE,CAAA;AAAA,IAC5G,CAAA,SAAE;AACA,MAAA,YAAA,CAAa,CAAC,CAAA;AAAA,IAChB;AACA,IAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,MAAA,MAAM,IAAA,GAAO,MAAME,SAAAA,CAAS,GAAG,CAAA;AAC/B,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,YAAA,EAAe,MAAM,IAAI,QAAA,CAASF,KAAI,CAAC,CAAA,QAAA,EAAM,IAAI,MAAM,CAAA,EAAA,EAAK,QAAA,CAAS,IAAI,CAAC,CAAA,CAAE,CAAA;AAAA,IAC9F;AACA,IAAA,OAAO,IAAI,IAAA,EAAK;AAAA,EAClB;AAEA,EAAA,OAAO;AAAA,IACL,MAAM,cAAA,GAAiB;AACrB,MAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,MAAA,EAAQ,MAAM,CAAA;AACtC,MAAA,MAAM,UAAU,MAAA,CAAO,IAAA,CAAK,QAAA,IAAY,IAAA,CAAK,WAAW,EAAE,CAAA;AAC1D,MAAA,MAAM,eAAe,MAAA,CAAO,IAAA,CAAK,aAAA,IAAiB,IAAA,CAAK,SAAS,EAAE,CAAA;AAClE,MAAA,IAAI,CAAC,OAAA,IAAW,CAAC,cAAc,MAAM,IAAI,MAAM,+CAA+C,CAAA;AAC9F,MAAA,OAAO,EAAE,SAAS,YAAA,EAAa;AAAA,IACjC,CAAA;AAAA,IACA,MAAM,YAAY,OAAA,EAAS;AACzB,MAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,KAAA,EAAO,IAAI,kBAAA,CAAmB,OAAO,CAAC,CAAA,CAAE,CAAA;AAIhE,MAAA,MAAM,KAAA,GAAQ,QAAQ,IAAA,CAAK,KAAA,IAAS,KAAK,QAAA,IAAY,IAAA,CAAK,SAAS,IAAI,CAAA;AACvE,MAAA,MAAM,QAAA,GAAW,MAAA,CAAO,IAAA,CAAK,KAAK,CAAA;AAClC,MAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,QAAA,CAAS,QAAQ,IAAI,QAAA,GAAW,CAAA;AACrD,MAAA,MAAM,QAAA,GAAiC,KAAA,CAAM,OAAA,CAAQ,IAAA,CAAK,QAAQ,CAAA,GAC9D,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,iBAAiB,CAAA,GACnC,EAAC;AACL,MAAA,MAAM,aAAa,OAAO,IAAA,CAAK,OAAA,KAAY,QAAA,GAAW,KAAK,OAAA,GAAU,IAAA;AACrE,MAAA,OAAO,EAAE,OAAO,KAAA,IAAS,MAAA,CAAO,SAAS,QAAQ,CAAA,EAAG,KAAA,EAAO,QAAA,EAAU,UAAA,EAAW;AAAA,IAClF;AAAA,GACF;AACF;AAEA,SAAS,kBAAkB,GAAA,EAA8B;AACvD,EAAA,MAAM,WAAW,MAAA,CAAO,GAAA,CAAI,QAAA,IAAY,MAAM,EAAE,WAAA,EAAY;AAC5D,EAAA,OAAO;AAAA,IACL,QAAA,EAAU,MAAA,CAAO,GAAA,CAAI,QAAA,IAAY,OAAO,CAAA;AAAA,IACxC,UAAU,QAAA,KAAa,OAAA,IAAW,aAAa,SAAA,IAAa,QAAA,KAAa,SAAS,QAAA,GAAW,MAAA;AAAA,IAC7F,OAAA,EAAS,MAAA,CAAO,GAAA,CAAI,OAAA,IAAW,EAAE;AAAA,GACnC;AACF;AAEA,eAAeE,UAAS,GAAA,EAAgC;AACtD,EAAA,IAAI;AAAE,IAAA,OAAO,MAAM,IAAI,IAAA,EAAK;AAAA,EAAE,CAAA,CAAA,MAAQ;AAAE,IAAA,OAAO,WAAA;AAAA,EAAY;AAC7D;AAMO,SAAS,qBAAqB,KAAA,EAAyE;AAC5G,EAAA,OAAOd,yBACJ,UAAA,CAAW,QAAQ,CAAA,CACnB,MAAA,CAAO,GAAG,KAAA,CAAM,QAAQ,CAAA,CAAA,EAAI,KAAA,CAAM,OAAO,CAAA,CAAA,EAAI,KAAA,CAAM,SAAS,CAAA,CAAE,CAAA,CAC9D,OAAO,KAAK,CAAA;AACjB;AAEA,eAAsB,eAAA,CACpB,KACA,UAAA,EACoC;AACpC,EAAA,MAAM,GAAA,GAAM,MAAM,GAAA,CAAI,WAAA,CAAY,iBAAiB,OAAA,CAAQ,EAAE,YAAY,CAAA;AACzE,EAAA,IAAI,CAAC,KAAK,OAAO,IAAA;AACjB,EAAA,IAAI,IAAI,IAAA,CAAK,GAAA,CAAI,SAAS,CAAA,CAAE,SAAQ,GAAI,IAAA,CAAK,GAAA,EAAI,EAAG,OAAO,IAAA;AAC3D,EAAA,OAAO,GAAA;AACT;AAEA,eAAsB,YAAA,CACpB,KACA,KAAA,EAM6B;AAC7B,EAAA,MAAM,GAAA,GAAM,IAAI,MAAA,CAAO,UAAA;AACvB,EAAA,MAAM,KAAA,GAAQ,KAAK,UAAA,IAAc,EAAA;AACjC,EAAA,MAAM,GAAA,uBAAU,IAAA,EAAK;AACrB,EAAA,MAAM,SAAA,GAAY,IAAI,IAAA,CAAK,GAAA,CAAI,SAAQ,GAAI,KAAA,GAAQ,EAAA,GAAK,EAAA,GAAK,GAAI,CAAA;AACjE,EAAA,MAAM,GAAA,GAA0B;AAAA,IAC9B,cAAc,KAAA,CAAM,YAAA;AAAA,IACpB,YAAY,KAAA,CAAM,UAAA;AAAA,IAClB,SAAS,KAAA,CAAM,OAAA;AAAA,IACf,KAAA,EAAO,MAAM,MAAA,CAAO,KAAA;AAAA,IACpB,QAAA,EAAU,MAAM,MAAA,CAAO,QAAA;AAAA,IACvB,UAAA,EAAY,MAAM,MAAA,CAAO,UAAA;AAAA,IACzB,SAAA,EAAW,GAAA;AAAA,IACX;AAAA,GACF;AACA,EAAA,MAAM,GAAA,CAAI,YAAY,gBAAA,CAAiB,SAAA;AAAA,IACrC,EAAE,UAAA,EAAY,KAAA,CAAM,UAAA,EAAW;AAAA,IAC/B,EAAE,MAAM,GAAA,EAAI;AAAA,IACZ,EAAE,QAAQ,IAAA;AAAK,GACjB;AACA,EAAA,OAAO,GAAA;AACT;AAsCA,eAAsB,sBAAA,CACpB,KACA,KAAA,EAC+B;AAC/B,EAAA,MAAM,GAAA,GAAM,IAAI,MAAA,CAAO,UAAA;AACvB,EAAA,IAAI,CAAC,GAAA,EAAK,MAAA,EAAQ,OAAO,EAAE,OAAA,EAAS,IAAA,EAAM,MAAA,EAAQ,IAAA,EAAM,KAAA,EAAO,IAAA,EAAM,IAAA,EAAM,IAAA,EAAK;AAEhF,EAAA,MAAM,QAAA,GAAW,IAAI,QAAA,IAAY,CAAA;AACjC,EAAA,MAAM,GAAA,GAAM,qBAAqB,KAAK,CAAA;AACtC,EAAA,MAAM,MAAA,GAAS,MAAM,eAAA,CAAgB,GAAA,EAAK,GAAG,CAAA;AAE7C,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,IAAI,IAAI,YAAA,EAAc;AACpB,MAAA,OAAO;AAAA,QACL,OAAA,EAAS,KAAA;AAAA,QACT,MAAA,EACE,4FAAA;AAAA,QACF,KAAA,EAAO,IAAA;AAAA,QACP,IAAA,EAAM;AAAA,OACR;AAAA,IACF;AACA,IAAA,OAAO,EAAE,SAAS,IAAA,EAAM,MAAA,EAAQ,MAAM,KAAA,EAAO,IAAA,EAAM,MAAM,IAAA,EAAK;AAAA,EAChE;AAEA,EAAA,IAAI,MAAA,CAAO,QAAQ,QAAA,EAAU;AAC3B,IAAA,OAAO;AAAA,MACL,OAAA,EAAS,KAAA;AAAA,MACT,MAAA,EAAQ,CAAA,kBAAA,EAAqB,MAAA,CAAO,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAC,CAAA,kBAAA,EAAqB,QAAA,CAAS,OAAA,CAAQ,CAAC,CAAC,CAAA,CAAA;AAAA,MAC5F,KAAA,EAAO,MAAA;AAAA,MACP,IAAA,EAAM;AAAA,KACR;AAAA,EACF;AACA,EAAA,OAAO,EAAE,SAAS,IAAA,EAAM,MAAA,EAAQ,MAAM,KAAA,EAAO,MAAA,EAAQ,MAAM,IAAA,EAAK;AAClE;;;AJ7LA,IAAMuB,YAAA,GAAaC,iBAAA,CAAc,2PAAe,CAAA;AAChD,IAAMC,WAAA,GAAYb,qBAAAA,CAAK,OAAA,CAAQW,YAAU,CAAA;AAEzC,SAAS,aAAA,GAAwB;AAE/B,EAAA,OAAOX,qBAAAA,CAAK,OAAA,CAAQa,WAAA,EAAW,WAAW,CAAA;AAC5C;AAcO,SAAS,iBAAA,CAAkB,MAAA,EAAgB,IAAA,GAA2B,EAAC,EAAW;AACvF,EAAA,MAAM,SAASC,cAAA,EAAO;AACtB,EAAA,MAAM,MAAA,GAAS,IAAA,CAAK,MAAA,IAAU,aAAA,EAAc;AAC5C,EAAA,MAAM,QAAA,GACJ,KAAK,QAAA,KAAa,CAAC,QAAiB,CAAA,MAAA,EAAU,GAAA,CAAY,IAAA,EAAM,KAAA,IAAS,WAAW,CAAA,CAAA,CAAA;AAGtF,EAAA,MAAA,CAAO,GAAA;AAAA,IACL,UAAA;AAAA,IACAC,wBAAA,CAAQ,OAAO,MAAA,EAAQ;AAAA,MACrB,MAAA,EAAQ,IAAA;AAAA,MACR,SAAA,EAAW,IAAA;AAAA,MACX,KAAA,EAAO;AAAA,KACR;AAAA,GACH;AAGA,EAAA,MAAA,CAAO,GAAA,CAAI,QAAQA,wBAAA,CAAQ,IAAA,CAAK,EAAE,KAAA,EAAO,KAAA,EAAO,CAAC,CAAA;AAGjD,EAAA,MAAA,CAAO,GAAA,CAAI,MAAA,EAAQ,CAAC,GAAA,EAAc,MAAM,IAAA,KAAuB;AAC5D,IAAC,GAAA,CAAY,KAAA,GAAQ,QAAA,CAAS,GAAG,CAAA;AAClC,IAAA,IAAA,EAAK;AAAA,EACP,CAAC,CAAA;AAED,EAAA,MAAA,CAAO,GAAA,CAAI,MAAA,EAAQ,SAAA,CAAU,MAAA,EAAQ,IAAI,CAAC,CAAA;AAI1C,EAAA,MAAA,CAAO,GAAA,CAAI,IAAA,EAAM,CAAC,IAAA,EAAe,GAAA,KAAkB;AACjD,IAAA,GAAA,CAAI,QAAA,CAASf,qBAAAA,CAAK,IAAA,CAAK,MAAA,EAAQ,YAAY,CAAC,CAAA;AAAA,EAC9C,CAAC,CAAA;AAED,EAAA,OAAO,MAAA;AACT;AAMA,SAAS,SAAA,CAAU,MAAA,EAAgB,IAAA,GAA2B,EAAC,EAAW;AACxE,EAAA,MAAM,IAAIc,cAAA,EAAO;AACjB,EAAA,MAAM,IAAI,MAAA,CAAO,WAAA;AAGjB,EAAA,MAAM,UAAA,GAAa,OAAO,MAAA,CAAO,WAAA,GAAc,eAAe,MAAA,CAAO,MAAA,CAAO,WAAW,CAAA,GAAI,IAAA;AAE3F,EAAA,SAAS,mBAAA,GAA+C;AACtD,IAAA,IAAI,IAAA,CAAK,gBAAA,EAAkB,OAAO,IAAA,CAAK,gBAAA;AACvC,IAAA,MAAM,GAAA,GAAM,OAAO,MAAA,CAAO,UAAA;AAC1B,IAAA,IAAI,CAAC,GAAA,EAAK,MAAA,EAAQ,OAAO,IAAA;AACzB,IAAA,OAAO,uBAAuB,GAAG,CAAA;AAAA,EACnC;AAKA,EAAA,CAAA,CAAE,GAAA;AAAA,IACA,cAAA;AAAA,IACA,YAAA,CAAa,OAAO,IAAA,EAAM,GAAA,KAAQ;AAChC,MAAA,GAAA,CAAI,KAAK,EAAE,MAAA,EAAQ,UAAA,EAAY,QAAA,EAAUhC,2BAAmB,CAAA;AAAA,IAC9D,CAAC;AAAA,GACH;AAEA,EAAA,CAAA,CAAE,GAAA;AAAA,IACA,KAAA;AAAA,IACA,YAAA,CAAa,OAAO,GAAA,EAAK,GAAA,KAAQ;AAC/B,MAAA,MAAM,CAAC,KAAA,EAAO,SAAA,EAAW,UAAA,EAAY,QAAA,EAAU,cAAc,UAAU,CAAA,GAAI,MAAM,OAAA,CAAQ,GAAA,CAAI;AAAA,QAC3F,CAAA,CAAE,MAAM,sBAAA,EAAuB;AAAA,QAC/B,CAAA,CAAE,UAAU,sBAAA,EAAuB;AAAA,QACnC,CAAA,CAAE,WAAW,sBAAA,EAAuB;AAAA,QACpC,EAAE,aAAA,CAAc,cAAA,CAAe,EAAE,MAAA,EAAQ,cAAc,CAAA;AAAA,QACvD,CAAA,CAAE,aAAa,sBAAA,EAAuB;AAAA,QACtC,CAAA,CAAE,OAAO,IAAA,CAAK,EAAE,CAAA,CAAE,KAAA,CAAM,GAAG,CAAA,CAAE,OAAA;AAAQ,OACtC,CAAA;AACD,MAAA,GAAA,CAAI,IAAA,CAAK;AAAA,QACP,OAAQ,GAAA,CAAY,KAAA;AAAA,QACpB,QAAQ,EAAE,KAAA,EAAO,SAAA,EAAW,UAAA,EAAY,UAAU,YAAA,EAAa;AAAA,QAC/D,MAAA,EAAQ,EAAE,MAAA,EAAQ,sBAAA,CAAuB,UAAU,CAAA,EAAE;AAAA,QACrD,SAAA,EAAW;AAAA,UACT,KAAA,EAAO,MAAA,CAAO,IAAA,CAAK,MAAA,CAAO,OAAO,SAAS,CAAA;AAAA,UAC1C,OAAA,EAAS,OAAO,MAAA,CAAO;AAAA,SACzB;AAAA,QACA,8BAAA,EAAgC,OAAO,MAAA,CAAO;AAAA,OAC/C,CAAA;AAAA,IACH,CAAC;AAAA,GACH;AAGA,EAAA,CAAA,CAAE,GAAA;AAAA,IACA,YAAA;AAAA,IACA,YAAA,CAAa,OAAO,IAAA,EAAM,GAAA,KAAQ;AAChC,MAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,MAAA,MAAM,IAAA,GAAO,KAAK,EAAA,GAAK,GAAA;AACvB,MAAA,MAAM,QAAA,GAAW,IAAI,IAAA,CAAK,GAAA,GAAM,KAAK,IAAI,CAAA;AACzC,MAAA,MAAM,QAAA,GAAW,IAAI,IAAA,CAAK,GAAA,GAAM,KAAK,IAAI,CAAA;AAEzC,MAAA,MAAM;AAAA,QACJ,SAAA;AAAA,QAAW,cAAA;AAAA,QAAgB,YAAA;AAAA,QAAc,WAAA;AAAA,QAAa,YAAA;AAAA,QACtD,QAAA;AAAA,QAAU,aAAA;AAAA,QAAe,UAAA;AAAA,QAAY,WAAA;AAAA,QACrC;AAAA,OACF,GAAI,MAAM,OAAA,CAAQ,GAAA,CAAI;AAAA,QACpB,CAAA,CAAE,MAAM,cAAA,CAAe,EAAE,UAAU,EAAE,GAAA,EAAK,QAAA,EAAS,EAAG,CAAA;AAAA,QACtD,CAAA,CAAE,KAAA,CAAM,cAAA,CAAe,EAAE,QAAA,EAAU,EAAE,GAAA,EAAK,QAAA,EAAS,EAAG,MAAA,EAAQ,WAAA,EAAa,CAAA;AAAA,QAC3E,CAAA,CAAE,KAAA,CAAM,cAAA,CAAe,EAAE,QAAA,EAAU,EAAE,GAAA,EAAK,QAAA,EAAS,EAAG,MAAA,EAAQ,SAAA,EAAW,CAAA;AAAA,QACzE,CAAA,CAAE,KAAA,CAAM,cAAA,CAAe,EAAE,UAAU,EAAE,GAAA,EAAK,QAAA,EAAS,EAAG,QAAA,EAAU,EAAE,GAAA,EAAK,IAAA,IAAQ,CAAA;AAAA,QAC/E,CAAA,CAAE,KAAA,CAAM,cAAA,CAAe,EAAE,UAAU,EAAE,GAAA,EAAK,QAAA,EAAS,EAAG,YAAA,EAAc,EAAE,GAAA,EAAK,IAAA,IAAQ,CAAA;AAAA,QACnF,CAAA,CAAE,KAAA,CAAM,cAAA,CAAe,EAAE,QAAA,EAAU,EAAE,GAAA,EAAK,QAAA,EAAU,IAAA,EAAM,QAAA,EAAS,EAAG,CAAA;AAAA,QACtE,CAAA,CAAE,KAAA,CAAM,cAAA,CAAe,EAAE,QAAA,EAAU,EAAE,GAAA,EAAK,QAAA,EAAU,IAAA,EAAM,QAAA,EAAS,EAAG,MAAA,EAAQ,aAAa,CAAA;AAAA,QAC3F,EAAE,KAAA,CAAM,cAAA,CAAe,EAAE,QAAA,EAAU,EAAE,GAAA,EAAK,QAAA,EAAU,IAAA,EAAM,QAAA,IAAY,QAAA,EAAU,EAAE,GAAA,EAAK,IAAA,IAAQ,CAAA;AAAA,QAC/F,EAAE,KAAA,CAAM,cAAA,CAAe,EAAE,QAAA,EAAU,EAAE,GAAA,EAAK,QAAA,EAAU,IAAA,EAAM,QAAA,IAAY,YAAA,EAAc,EAAE,GAAA,EAAK,IAAA,IAAQ,CAAA;AAAA,QACnG,CAAA,CAAE,MACC,SAAA,CAAyD;AAAA,UACxD,EAAE,QAAQ,EAAE,QAAA,EAAU,EAAE,GAAA,EAAK,QAAA,IAAW,EAAE;AAAA,UAC1C;AAAA,YACE,QAAA,EAAU;AAAA,cACR,IAAA,EAAM;AAAA,gBACJ,MAAA,EAAQ;AAAA,kBACN,OAAA,EAAS,CAAC,EAAE,SAAA,EAAW,CAAC,GAAA,EAAK,EAAE,OAAA,EAAS,WAAA,EAAa,CAAA,EAAE,EAAG,IAAI;AAAA;AAChE,eACF;AAAA,cACA,MAAA,EAAQ,EAAE,KAAA,EAAO,CAAC,EAAE,OAAA,EAAS,CAAC,WAAA,EAAa,KAAK,CAAA,EAAE,EAAG,CAAA,EAAG,CAAC,CAAA;AAAE;AAC7D,WACF;AAAA,UACA,EAAE,MAAA,EAAQ,EAAE,GAAA,EAAK,SAAS,KAAA,EAAO,EAAE,IAAA,EAAM,CAAA,IAAK,KAAA,EAAO,EAAE,IAAA,EAAM,SAAA,IAAY;AAAE,SAC5E,EACA,OAAA;AAAQ,OACZ,CAAA;AAED,MAAA,MAAM,aAAa,IAAI,KAAA,CAAM,EAAE,CAAA,CAAE,KAAK,CAAC,CAAA;AACvC,MAAA,MAAM,aAAa,IAAI,KAAA,CAAM,EAAE,CAAA,CAAE,KAAK,CAAC,CAAA;AACvC,MAAA,KAAA,MAAW,OAAO,MAAA,EAAQ;AACxB,QAAA,MAAM,GAAA,GAAM,EAAA,GAAK,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,KAAK,GAAA,CAAI,EAAA,EAAI,GAAA,CAAI,GAAG,CAAC,CAAA;AAClD,QAAA,UAAA,CAAW,GAAG,IAAI,GAAA,CAAI,KAAA;AACtB,QAAA,UAAA,CAAW,GAAG,IAAI,GAAA,CAAI,KAAA;AAAA,MACxB;AAEA,MAAA,MAAM,KAAA,GAAQ,CAAC,GAAA,EAAa,IAAA,KAAgC;AAC1D,QAAA,IAAI,IAAA,KAAS,GAAG,OAAO,IAAA;AACvB,QAAA,OAAA,CAAQ,MAAM,IAAA,IAAQ,IAAA;AAAA,MACxB,CAAA;AACA,MAAA,MAAM,SAAA,GAAY,CAAC,IAAA,EAAc,IAAA,EAAc,OAAe,KAAA,KAAiC;AAC7F,QAAA,IAAI,KAAA,KAAU,CAAA,IAAK,IAAA,KAAS,CAAA,EAAG,OAAO,IAAA;AACtC,QAAA,OAAO,IAAA,GAAO,OAAO,KAAA,GAAQ,KAAA;AAAA,MAC/B,CAAA;AAEA,MAAA,MAAM,UAAA,GAAa,MAAM,CAAA,CAAE,MAAA,CAAO,IAAA,CAAK,EAAE,CAAA,CAAE,KAAA,CAAM,GAAG,CAAA,CAAE,OAAA,EAAQ;AAC9D,MAAA,MAAM,SAAA,GAAY,WAAW,IAAA,CAAK,CAAC,MAAM,CAAA,CAAE,GAAA,KAAQ,aAAa,CAAA,IAAK,IAAA;AACrE,MAAA,MAAM,cAAA,GAAiB,MAAM,CAAA,CAAE,KAAA,CAAM,IAAA,CAAK,EAAE,OAAA,EAAS,IAAA,EAAM,CAAA,CAAE,KAAA,CAAM,CAAC,EAAE,OAAA,EAAQ;AAC9E,MAAA,MAAM,YAAA,GAAe,MAAM,gBAAA,CAAiB,MAAM,CAAA;AAClD,MAAA,MAAM,cAAc,cAAA,CAAe,GAAA,CAAI,CAAC,CAAA,MAAO,EAAE,GAAG,CAAA,EAAG,KAAA,EAAO,YAAA,CAAa,IAAI,CAAA,CAAE,IAAI,CAAA,IAAK,cAAA,IAAiB,CAAE,CAAA;AAC7G,MAAA,MAAM,WAAA,GAAc,MAAM,CAAA,CAAE,KAAA,CAAM,MAAK,CAAE,IAAA,CAAK,EAAE,QAAA,EAAU,IAAI,CAAA,CAAE,KAAA,CAAM,CAAC,EAAE,OAAA,EAAQ;AACjF,MAAA,MAAM,WAAA,GAAc,MAAM,CAAA,CAAE,QAAA,CAAS,MAAK,CAAE,IAAA,CAAK,EAAE,UAAA,EAAY,IAAI,CAAA,CAAE,KAAA,CAAM,CAAC,EAAE,OAAA,EAAQ;AAEtF,MAAA,MAAM,WAAA,GAAc,MAAM,kBAAA,CAAmB,MAAM,CAAA;AACnD,MAAA,MAAM,aAAA,GAAgB,MAAM,CAAA,CAAE,KAAA,CAC3B,QAAQ,EAAE,MAAA,EAAQ,EAAE,GAAA,EAAK,CAAC,WAAW,QAAQ,CAAA,IAAI,EAAG,EAAE,MAAM,EAAE,QAAA,EAAU,EAAA,EAAG,EAAG,CAAA;AACjF,MAAA,MAAM,UAAA,GAAa,MAAM,CAAA,CAAE,KAAA,CACxB,QAAQ,EAAE,MAAA,EAAQ,WAAA,EAAY,EAAG,EAAE,IAAA,EAAM,EAAE,QAAA,EAAU,EAAA,IAAM,CAAA;AAC9D,MAAA,MAAM,UAAA,GACJ,cAAc,aAAA,GACV,IAAI,KAAK,UAAA,CAAW,QAAgB,EAAE,OAAA,EAAQ,IAAK,IAAI,IAAA,CAAK,aAAA,CAAc,QAAgB,CAAA,CAAE,OAAA,KAC5F,UAAA,GACA,IAAA,GACA,gBACA,KAAA,GACA,IAAA;AAEN,MAAA,GAAA,CAAI,IAAA,CAAK;AAAA,QACP,IAAA,EAAM;AAAA,UACJ,KAAA,EAAO,EAAE,KAAA,EAAO,SAAA,EAAW,OAAO,KAAA,CAAM,SAAA,EAAW,QAAQ,CAAA,EAAE;AAAA,UAC7D,aAAA,EAAe;AAAA,YACb,KAAA,EAAO,SAAA,KAAc,CAAA,GAAI,IAAA,GAAO,cAAA,GAAiB,SAAA;AAAA,YACjD,KAAA,EAAO,SAAA,CAAU,cAAA,EAAgB,SAAA,EAAW,eAAe,QAAQ,CAAA;AAAA,YACnE,OAAA,EAAS;AAAA,WACX;AAAA,UACA,QAAA,EAAU;AAAA,YACR,KAAA,EAAO,SAAA,KAAc,CAAA,GAAI,IAAA,GAAO,WAAA,GAAc,SAAA;AAAA,YAC9C,KAAA,EAAO,SAAA,CAAU,WAAA,EAAa,SAAA,EAAW,YAAY,QAAQ;AAAA,WAC/D;AAAA,UACA,SAAA,EAAW;AAAA,YACT,KAAA,EAAO,SAAA,KAAc,CAAA,GAAI,IAAA,GAAO,YAAA,GAAe,SAAA;AAAA,YAC/C,KAAA,EAAO,SAAA,CAAU,YAAA,EAAc,SAAA,EAAW,aAAa,QAAQ;AAAA;AACjE,SACF;AAAA,QACA,MAAA,EAAQ,EAAE,MAAA,EAAQ,EAAE,OAAO,UAAA,EAAY,KAAA,EAAO,YAAW,EAAE;AAAA,QAC3D,MAAA,EAAQ;AAAA,UACN,MAAA,EAAQ,uBAAuB,UAAU,CAAA;AAAA,UACzC,KAAA,EAAO,WAAW,KAAA,IAAS,IAAA;AAAA,UAC3B,UAAA,EAAY;AAAA,YACV,qBAAA,EAAuB,MAAA,CAAO,MAAA,CAAO,cAAA,CAAe,qBAAA;AAAA,YACpD,oBAAA,EAAsB,MAAA,CAAO,MAAA,CAAO,cAAA,CAAe,oBAAA;AAAA,YACnD,yBAAA,EAA2B,MAAA,CAAO,MAAA,CAAO,cAAA,CAAe,yBAAA;AAAA,YACxD,0BAAA,EAA4B,MAAA,CAAO,MAAA,CAAO,cAAA,CAAe;AAAA;AAC3D,SACF;AAAA,QACA,KAAA,EAAO;AAAA,UACL,QAAA,EAAU,aAAa,QAAA,IAAY,IAAA;AAAA,UACnC,OAAA,EAAS,aAAa,OAAA,IAAW,IAAA;AAAA,UACjC,UAAA;AAAA,UACA,YAAA,EAAc,OAAO,MAAA,CAAO;AAAA,SAC9B;AAAA,QACA,WAAA;AAAA,QACA,WAAA;AAAA,QACA;AAAA,OACD,CAAA;AAAA,IACH,CAAC;AAAA,GACH;AAGA,EAAA,CAAA,CAAE,GAAA;AAAA,IACA,SAAA;AAAA,IACA,YAAA,CAAa,OAAO,IAAA,EAAM,GAAA,KAAQ;AAChC,MAAA,MAAM,UAAA,GAAa,MAAA,CAAO,MAAA,CAAO,IAAA,EAAK;AACtC,MAAA,MAAM,SAAA,GAAY,MAAM,CAAA,CAAE,MAAA,CAAO,SAAS,MAAM,CAAA;AAChD,MAAA,MAAM,KAAA,GAAQ,IAAI,GAAA,CAAI,UAAA,CAAW,IAAI,CAACkC,EAAAA,KAAMA,EAAAA,CAAE,IAAI,CAAC,CAAA;AACnD,MAAA,MAAM,YAAA,GAAgB,SAAA,CAAuB,MAAA,CAAO,CAAC,CAAA,KAAM,KAAK,CAAC,KAAA,CAAM,GAAA,CAAI,CAAC,CAAC,CAAA;AAC7E,MAAA,GAAA,CAAI,IAAA,CAAK;AAAA,QACP,UAAA,EAAY,UAAA,CAAW,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,CAAE,IAAA,CAAK,aAAA,CAAc,CAAA,CAAE,IAAI,CAAC,CAAA;AAAA,QAClE,IAAA,EAAM,aAAa,IAAA;AAAK,OACzB,CAAA;AAAA,IACH,CAAC;AAAA,GACH;AAGA,EAAA,CAAA,CAAE,GAAA;AAAA,IACA,QAAA;AAAA,IACA,YAAA,CAAa,OAAO,IAAA,EAAM,GAAA,KAAQ;AAChC,MAAA,MAAM,KAAA,GAAQ,MAAM,CAAA,CAAE,KAAA,CAAM,IAAA,EAAK,CAAE,IAAA,CAAK,EAAE,SAAA,EAAW,EAAA,EAAI,CAAA,CAAE,OAAA,EAAQ;AACnE,MAAA,MAAM,KAAA,GAAQ,MAAM,gBAAA,CAAiB,MAAM,CAAA;AAC3C,MAAA,GAAA,CAAI,KAAK,KAAA,CAAM,GAAA,CAAI,CAAC,CAAA,MAAO,EAAE,GAAG,CAAA,EAAG,KAAA,EAAO,KAAA,CAAM,IAAI,CAAA,CAAE,IAAI,KAAK,cAAA,EAAe,GAAI,CAAC,CAAA;AAAA,IACrF,CAAC;AAAA,GACH;AAEA,EAAA,CAAA,CAAE,GAAA;AAAA,IACA,cAAA;AAAA,IACA,YAAA,CAAa,OAAO,GAAA,EAAK,GAAA,KAAQ;AAC/B,MAAA,MAAM,IAAA,GAAO,MAAM,CAAA,CAAE,KAAA,CAAM,OAAA,CAAQ,EAAE,IAAA,EAAM,GAAA,CAAI,MAAA,CAAO,IAAA,EAAM,CAAA;AAC5D,MAAA,IAAI,CAAC,IAAA,EAAM,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,WAAA,EAAa,CAAA;AAC7D,MAAA,MAAM,KAAA,GAAA,CAAS,MAAM,gBAAA,CAAiB,MAAA,EAAQ,IAAA,CAAK,IAAI,CAAA,EAAG,GAAA,CAAI,IAAA,CAAK,IAAI,CAAA,IAAK,cAAA,EAAe;AAC3F,MAAA,OAAO,IAAI,IAAA,CAAK,EAAE,GAAG,IAAA,EAAM,OAAO,CAAA;AAAA,IACpC,CAAC;AAAA,GACH;AAEA,EAAA,CAAA,CAAE,IAAA;AAAA,IACA,oBAAA;AAAA,IACA,YAAA,CAAa,OAAO,GAAA,EAAK,GAAA,KAAQ;AAC/B,MAAA,MAAM,MAAA,GAAS,MAAM,CAAA,CAAE,KAAA,CAAM,OAAA,CAAQ,EAAE,IAAA,EAAM,GAAA,CAAI,MAAA,CAAO,IAAA,EAAM,CAAA;AAC9D,MAAA,IAAI,CAAC,MAAA,EAAQ,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,WAAA,EAAa,CAAA;AAC/D,MAAA,MAAM,EAAE,KAAA,CAAM,SAAA,CAAU,EAAE,GAAA,EAAK,MAAA,CAAO,KAAI,EAAG,EAAE,IAAA,EAAM,EAAE,SAAS,KAAA,EAAO,SAAA,sBAAe,IAAA,EAAK,IAAK,CAAA;AAChG,MAAA,MAAM,OAAO,KAAA,CAAM;AAAA,QACjB,OAAQ,GAAA,CAAY,KAAA;AAAA,QACpB,MAAA,EAAQ,YAAA;AAAA,QACR,QAAA,EAAU,EAAE,UAAA,EAAY,cAAA,EAAgB,IAAI,MAAA,CAAO,GAAA,EAAK,IAAA,EAAM,MAAA,CAAO,IAAA;AAAK,OAC3E,CAAA;AACD,MAAA,OAAO,GAAA,CAAI,IAAA,CAAK,EAAE,EAAA,EAAI,MAAM,CAAA;AAAA,IAC9B,CAAC;AAAA,GACH;AAEA,EAAA,CAAA,CAAE,IAAA;AAAA,IACA,qBAAA;AAAA,IACA,YAAA,CAAa,OAAO,GAAA,EAAK,GAAA,KAAQ;AAC/B,MAAA,MAAM,MAAA,GAAS,MAAM,CAAA,CAAE,KAAA,CAAM,OAAA,CAAQ,EAAE,IAAA,EAAM,GAAA,CAAI,MAAA,CAAO,IAAA,EAAM,CAAA;AAC9D,MAAA,IAAI,CAAC,MAAA,EAAQ,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,WAAA,EAAa,CAAA;AAC/D,MAAA,MAAM,EAAE,KAAA,CAAM,SAAA,CAAU,EAAE,GAAA,EAAK,MAAA,CAAO,KAAI,EAAG,EAAE,IAAA,EAAM,EAAE,SAAS,IAAA,EAAM,SAAA,sBAAe,IAAA,EAAK,IAAK,CAAA;AAC/F,MAAA,MAAM,OAAO,KAAA,CAAM;AAAA,QACjB,OAAQ,GAAA,CAAY,KAAA;AAAA,QACpB,MAAA,EAAQ,aAAA;AAAA,QACR,QAAA,EAAU,EAAE,UAAA,EAAY,cAAA,EAAgB,IAAI,MAAA,CAAO,GAAA,EAAK,IAAA,EAAM,MAAA,CAAO,IAAA;AAAK,OAC3E,CAAA;AACD,MAAA,OAAO,GAAA,CAAI,IAAA,CAAK,EAAE,EAAA,EAAI,MAAM,CAAA;AAAA,IAC9B,CAAC;AAAA,GACH;AAGA,EAAA,CAAA,CAAE,GAAA;AAAA,IACA,YAAA;AAAA,IACA,YAAA,CAAa,OAAO,IAAA,EAAM,GAAA,KAAQ;AAChC,MAAA,MAAM,SAAA,GAAY,MAAM,CAAA,CAAE,SAAA,CAAU,IAAA,EAAK,CAAE,IAAA,CAAK,EAAE,SAAA,EAAW,EAAA,EAAI,CAAA,CAAE,OAAA,EAAQ;AAC3E,MAAA,MAAM,KAAA,GAAQ,MAAM,oBAAA,CAAqB,MAAM,CAAA;AAC/C,MAAA,GAAA,CAAI,KAAK,SAAA,CAAU,GAAA,CAAI,CAAC,CAAA,MAAO,EAAE,GAAG,CAAA,EAAG,KAAA,EAAO,KAAA,CAAM,IAAI,CAAA,CAAE,IAAI,KAAK,kBAAA,EAAmB,GAAI,CAAC,CAAA;AAAA,IAC7F,CAAC;AAAA,GACH;AAEA,EAAA,CAAA,CAAE,GAAA;AAAA,IACA,kBAAA;AAAA,IACA,YAAA,CAAa,OAAO,GAAA,EAAK,GAAA,KAAQ;AAC/B,MAAA,MAAM,QAAA,GAAW,MAAM,CAAA,CAAE,SAAA,CAAU,OAAA,CAAQ,EAAE,IAAA,EAAM,GAAA,CAAI,MAAA,CAAO,IAAA,EAAM,CAAA;AACpE,MAAA,IAAI,CAAC,QAAA,EAAU,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,WAAA,EAAa,CAAA;AACjE,MAAA,MAAM,KAAA,GAAA,CAAS,MAAM,oBAAA,CAAqB,MAAA,EAAQ,QAAA,CAAS,IAAI,CAAA,EAAG,GAAA,CAAI,QAAA,CAAS,IAAI,CAAA,IAAK,kBAAA,EAAmB;AAC3G,MAAA,OAAO,IAAI,IAAA,CAAK,EAAE,GAAG,QAAA,EAAU,OAAO,CAAA;AAAA,IACxC,CAAC;AAAA,GACH;AAGA,EAAA,CAAA,CAAE,GAAA;AAAA,IACA,aAAA;AAAA,IACA,YAAA,CAAa,OAAO,IAAA,EAAM,GAAA,KAAQ;AAChC,MAAA,MAAM,UAAA,GAAa,MAAM,CAAA,CAAE,UAAA,CAAW,IAAA,EAAK,CAAE,IAAA,CAAK,EAAE,SAAA,EAAW,EAAA,EAAI,CAAA,CAAE,OAAA,EAAQ;AAC7E,MAAA,MAAM,KAAA,GAAQ,MAAM,qBAAA,CAAsB,MAAM,CAAA;AAChD,MAAA,GAAA,CAAI,KAAK,UAAA,CAAW,GAAA,CAAI,CAAC,CAAA,MAAO,EAAE,GAAG,CAAA,EAAG,KAAA,EAAO,MAAM,GAAA,CAAI,MAAA,CAAO,EAAE,GAAG,CAAC,KAAK,mBAAA,EAAoB,GAAI,CAAC,CAAA;AAAA,IACtG,CAAC;AAAA,GACH;AAEA,EAAA,CAAA,CAAE,GAAA;AAAA,IACA,mBAAA;AAAA,IACA,YAAA,CAAa,OAAO,GAAA,EAAK,GAAA,KAAQ;AAC/B,MAAA,MAAM,SAAA,GAAY,MAAM,CAAA,CAAE,UAAA,CAAW,OAAA,CAAQ,EAAE,IAAA,EAAM,GAAA,CAAI,MAAA,CAAO,IAAA,EAAM,CAAA;AACtE,MAAA,IAAI,CAAC,SAAA,EAAW,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,WAAA,EAAa,CAAA;AAClE,MAAA,MAAM,KAAA,GAAA,CAAS,MAAM,qBAAA,CAAsB,MAAA,EAAQ,SAAA,CAAU,GAAG,CAAA,EAAG,GAAA,CAAI,MAAA,CAAO,SAAA,CAAU,GAAG,CAAC,KAAK,mBAAA,EAAoB;AACrH,MAAA,OAAO,IAAI,IAAA,CAAK,EAAE,GAAG,SAAA,EAAW,OAAO,CAAA;AAAA,IACzC,CAAC;AAAA,GACH;AAGA,EAAA,CAAA,CAAE,GAAA;AAAA,IACA,WAAA;AAAA,IACA,YAAA,CAAa,OAAO,GAAA,EAAK,GAAA,KAAQ;AAC/B,MAAA,MAAM,MAAA,GAAS,OAAO,GAAA,CAAI,KAAA,CAAM,WAAW,QAAA,GAAW,GAAA,CAAI,MAAM,MAAA,GAAS,MAAA;AACzE,MAAA,MAAM,KAAA,GAAQ,KAAK,GAAA,CAAI,MAAA,CAAO,IAAI,KAAA,CAAM,KAAA,IAAS,EAAE,CAAA,EAAG,GAAG,CAAA;AACzD,MAAA,MAAM,CAAC,EAAE,QAAA,EAAU,UAAA,IAAc,MAAM,CAAA,GAAI,MAAM,OAAA,CAAQ,GAAA,CAAI;AAAA,QAC3D,MAAA,CAAO,QAAQ,KAAA,CAAM,IAAI,EAAE,KAAA,EAAO,QAAQ,CAAA;AAAA,QAAA,CACzC,YAAY;AACX,UAAA,MAAM,IAAA,GAAO,MAAM,CAAA,CAAE,aAAA,CAClB,UAAsC,CAAC,EAAE,QAAQ,EAAE,GAAA,EAAK,WAAW,CAAA,EAAG,EAAE,MAAM,CAAA,EAAE,IAAK,CAAC,EACtF,OAAA,EAAQ;AACX,UAAA,MAAM,GAAA,GAA8B,EAAE,UAAA,EAAY,CAAA,EAAG,WAAA,EAAa,CAAA,EAAG,YAAA,EAAc,CAAA,EAAG,OAAA,EAAS,CAAA,EAAG,UAAA,EAAY,CAAA,EAAE;AAChH,UAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,UAAA,KAAA,MAAWA,MAAK,IAAA,EAAM;AACpB,YAAA,IAAIA,GAAE,GAAA,EAAK,GAAA,CAAIA,EAAAA,CAAE,GAAG,IAAIA,EAAAA,CAAE,CAAA;AAC1B,YAAA,KAAA,IAASA,EAAAA,CAAE,CAAA;AAAA,UACb;AACA,UAAA,OAAO,EAAE,GAAG,GAAA,EAAK,KAAA,EAAM;AAAA,QACzB,CAAA;AAAG,OACJ,CAAA;AACD,MAAA,GAAA,CAAI,IAAA,CAAK,EAAE,QAAA,EAAU,UAAA,EAAY,QAAQ,CAAA;AAAA,IAC3C,CAAC;AAAA,GACH;AAEA,EAAA,CAAA,CAAE,GAAA;AAAA,IACA,uBAAA;AAAA,IACA,YAAA,CAAa,OAAO,GAAA,EAAK,GAAA,KAAQ;AAC/B,MAAA,MAAM,UAAA,GAAa,MAAA,CAAO,GAAA,CAAI,MAAA,CAAO,UAAU,CAAA;AAC/C,MAAA,MAAM,CAAC,SAAS,YAAA,EAAc,YAAA,EAAc,aAAa,UAAU,CAAA,GAAI,MAAM,OAAA,CAAQ,GAAA,CAAI;AAAA,QACvF,MAAA,CAAO,OAAA,CAAQ,OAAA,CAAQ,UAAU,CAAA;AAAA,QACjC,CAAA,CAAE,aAAA,CAAc,OAAA,CAAQ,EAAE,YAAY,CAAA;AAAA,QACtC,EAAE,MAAA,CAAO,IAAA,CAAK,EAAE,UAAA,EAAY,CAAA,CAAE,IAAA,CAAK,EAAE,UAAA,EAAY,IAAI,CAAA,CAAE,KAAA,CAAM,EAAE,EAAE,OAAA,EAAQ;AAAA,QACzE,EAAE,KAAA,CAAM,IAAA,CAAK,EAAE,UAAA,EAAY,CAAA,CAAE,IAAA,CAAK,EAAE,QAAA,EAAU,IAAI,CAAA,CAAE,KAAA,CAAM,EAAE,EAAE,OAAA,EAAQ;AAAA,QACtE,EAAE,QAAA,CAAS,IAAA,CAAK,EAAE,UAAA,EAAY,MAAA,EAAQ,UAAU,CAAA,CAAE,IAAA,CAAK,EAAE,cAAc,CAAA,EAAG,EAAE,KAAA,CAAM,EAAE,EAAE,OAAA;AAAQ,OAC/F,CAAA;AACD,MAAA,IAAI,CAAC,OAAA,EAAS,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,WAAA,EAAa,CAAA;AAChE,MAAA,OAAO,GAAA,CAAI,KAAK,EAAE,OAAA,EAAS,cAAc,YAAA,EAAc,WAAA,EAAa,YAAY,CAAA;AAAA,IAClF,CAAC;AAAA,GACH;AAGA,EAAA,CAAA,CAAE,GAAA;AAAA,IACA,QAAA;AAAA,IACA,YAAA,CAAa,OAAO,GAAA,EAAK,GAAA,KAAQ;AAC/B,MAAA,MAAM,KAAA,GAAQ,KAAK,GAAA,CAAI,MAAA,CAAO,IAAI,KAAA,CAAM,KAAA,IAAS,GAAG,CAAA,EAAG,GAAG,CAAA;AAC1D,MAAA,MAAM,MAAA,GAAS,OAAO,GAAA,CAAI,KAAA,CAAM,WAAW,QAAA,GAAW,GAAA,CAAI,MAAM,MAAA,GAAS,MAAA;AACzE,MAAA,MAAM,SAAc,EAAC;AACrB,MAAA,IAAI,MAAA,SAAe,MAAA,GAAS,MAAA;AAC5B,MAAA,MAAM,QAAQ,MAAM,CAAA,CAAE,KAAA,CAAM,IAAA,CAAK,MAAM,CAAA,CAAE,IAAA,CAAK,EAAE,QAAA,EAAU,IAAI,CAAA,CAAE,KAAA,CAAM,KAAK,EAAE,OAAA,EAAQ;AACrF,MAAA,GAAA,CAAI,KAAK,KAAK,CAAA;AAAA,IAChB,CAAC;AAAA,GACH;AAEA,EAAA,CAAA,CAAE,GAAA;AAAA,IACA,YAAA;AAAA,IACA,YAAA,CAAa,OAAO,GAAA,EAAK,GAAA,KAAQ;AAC/B,MAAA,MAAM,EAAA,GAAK,MAAA,CAAO,GAAA,CAAI,MAAA,CAAO,EAAE,CAAA;AAC/B,MAAA,IAAI,CAAC/B,gBAAAA,CAAS,OAAA,CAAQ,EAAE,GAAG,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,UAAU,CAAA;AAC1E,MAAA,MAAM,IAAA,GAAO,MAAM,CAAA,CAAE,KAAA,CAAM,OAAA,CAAQ,EAAE,GAAA,EAAK,IAAIA,gBAAAA,CAAS,EAAE,CAAA,EAAG,CAAA;AAC5D,MAAA,IAAI,CAAC,IAAA,EAAM,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,WAAA,EAAa,CAAA;AAC7D,MAAA,MAAM,MAAA,GAAS,IAAA,CAAK,iBAAA,GAChB,MAAM,CAAA,CAAE,cACL,IAAA,CAAK,EAAE,iBAAA,EAAmB,IAAA,CAAK,iBAAA,EAAmB,EAClD,IAAA,CAAK,EAAE,UAAA,EAAY,EAAA,EAAI,CAAA,CACvB,MAAM,GAAG,CAAA,CACT,OAAA,EAAQ,GACX,EAAC;AACL,MAAA,OAAO,IAAI,IAAA,CAAK,EAAE,IAAA,EAAM,aAAA,EAAe,QAAQ,CAAA;AAAA,IACjD,CAAC;AAAA,GACH;AAGA,EAAA,CAAA,CAAE,GAAA;AAAA,IACA,eAAA;AAAA,IACA,YAAA,CAAa,OAAO,IAAA,EAAM,GAAA,KAAQ;AAChC,MAAA,MAAM,IAAA,GAAO,MAAM,CAAA,CAAE,YAAA,CAAa,MAAK,CAAE,IAAA,CAAK,EAAE,OAAA,EAAS,IAAI,CAAA,CAAE,KAAA,CAAM,GAAG,EAAE,OAAA,EAAQ;AAClF,MAAA,GAAA,CAAI,KAAK,IAAI,CAAA;AAAA,IACf,CAAC;AAAA,GACH;AAEA,EAAA,CAAA,CAAE,IAAA;AAAA,IACA,eAAA;AAAA,IACA,YAAA,CAAa,OAAO,GAAA,EAAK,GAAA,KAAQ;AAC/B,MAAA,MAAM,EAAE,OAAO,KAAA,EAAO,MAAA,EAAQ,QAAQ,KAAA,EAAM,GAAI,GAAA,CAAI,IAAA,IAAQ,EAAC;AAC7D,MAAA,MAAM,MAAA,CAAO,SAAS,KAAA,EAAO,EAAE,OAAO,MAAA,EAAQ,MAAA,EAAQ,OAAO,CAAA;AAC7D,MAAA,MAAM,OAAO,KAAA,CAAM;AAAA,QACjB,OAAQ,GAAA,CAAY,KAAA;AAAA,QACpB,MAAA,EAAQ,iBAAA;AAAA,QACR,QAAA,EAAU,EAAE,UAAA,EAAY,qBAAA,EAAsB;AAAA,QAC9C,aAAa,CAAA,EAAG,KAAK,CAAA,QAAA,EAAM,KAAK,IAAI,MAAM,CAAA;AAAA,OAC3C,CAAA;AACD,MAAA,GAAA,CAAI,IAAA,CAAK,EAAE,EAAA,EAAI,IAAA,EAAM,CAAA;AAAA,IACvB,CAAC;AAAA,GACH;AAGA,EAAA,CAAA,CAAE,GAAA;AAAA,IACA,QAAA;AAAA,IACA,YAAA,CAAa,OAAO,IAAA,EAAM,GAAA,KAAQ;AAChC,MAAA,MAAM,IAAA,GAAO,MAAM,CAAA,CAAE,QAAA,CAAS,MAAK,CAAE,IAAA,CAAK,EAAE,UAAA,EAAY,IAAI,CAAA,CAAE,KAAA,CAAM,GAAG,EAAE,OAAA,EAAQ;AACjF,MAAA,GAAA,CAAI,KAAK,IAAI,CAAA;AAAA,IACf,CAAC;AAAA,GACH;AAGA,EAAA,CAAA,CAAE,GAAA;AAAA,IACA,eAAA;AAAA,IACA,YAAA,CAAa,OAAO,IAAA,EAAM,GAAA,KAAQ;AAChC,MAAA,MAAM,MAAA,GAAS,MAAM,cAAA,CAAe,MAAM,CAAA;AAC1C,MAAA,GAAA,CAAI,KAAK,MAAM,CAAA;AAAA,IACjB,CAAC;AAAA,GACH;AAGA,EAAA,CAAA,CAAE,GAAA;AAAA,IACA,SAAA;AAAA,IACA,YAAA,CAAa,OAAO,IAAA,EAAM,GAAA,KAAQ;AAChC,MAAA,MAAM,EAAA,GAAK,OAAO,MAAA,CAAO,cAAA;AACzB,MAAA,MAAM,UAAA,GAAa;AAAA,QACjB,uBAAuB,EAAA,CAAG,qBAAA;AAAA,QAC1B,sBAAsB,EAAA,CAAG,oBAAA;AAAA,QACzB,2BAA2B,EAAA,CAAG,yBAAA;AAAA,QAC9B,4BAA4B,EAAA,CAAG;AAAA,OACjC;AACA,MAAA,MAAM,IAAA,GAAO,MAAM,CAAA,CAAE,MAAA,CAAO,IAAA,CAAK,EAAE,CAAA,CAAE,KAAA,CAAM,GAAG,CAAA,CAAE,OAAA,EAAQ;AACxD,MAAA,MAAM,SAAA,GAAY,KAAK,IAAA,CAAK,CAAC,MAAM,CAAA,CAAE,GAAA,KAAQ,aAAa,CAAA,IAAK,IAAA;AAC/D,MAAA,MAAM,UAAU,IAAA,CAAK,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,QAAQ,aAAa,CAAA;AAC1D,MAAA,MAAM,OAAA,GAAU,uBAAuB,IAAI,CAAA;AAC3C,MAAA,IAAI,IAAA,CAAK,WAAW,CAAA,EAAG;AAErB,QAAA,GAAA,CAAI,IAAA,CAAK,EAAE,MAAA,EAAQ,IAAA,EAAM,OAAO,IAAA,EAAM,QAAA,EAAU,IAAA,EAAM,SAAA,EAAW,IAAA,EAAM,OAAA,EAAS,EAAC,EAAG,YAAY,CAAA;AAChG,QAAA;AAAA,MACF;AAGA,MAAA,GAAA,CAAI,IAAA,CAAK;AAAA,QACP,MAAA,EAAQ,OAAA;AAAA,QACR,KAAA,EAAO,WAAW,KAAA,IAAS,IAAA;AAAA,QAC3B,QAAA,EAAU,WAAW,QAAA,IAAY,IAAA;AAAA,QACjC,SAAA;AAAA,QACA,OAAA;AAAA,QACA;AAAA,OACD,CAAA;AAAA,IACH,CAAC;AAAA,GACH;AAEA,EAAA,CAAA,CAAE,GAAA;AAAA,IACA,eAAA;AAAA,IACA,YAAA,CAAa,OAAO,IAAA,EAAM,GAAA,KAAQ;AAChC,MAAA,MAAM,IAAA,GAAO,MAAM,CAAA,CAAE,QAAA,CAClB,IAAA,CAAK,EAAE,MAAA,EAAQ,EAAE,GAAA,EAAK,CAAC,aAAA,EAAe,eAAe,GAAE,EAAG,CAAA,CAC1D,IAAA,CAAK,EAAE,UAAA,EAAY,EAAA,EAAI,CAAA,CACvB,KAAA,CAAM,EAAE,CAAA,CACR,OAAA,EAAQ;AACX,MAAA,GAAA,CAAI,KAAK,IAAI,CAAA;AAAA,IACf,CAAC;AAAA,GACH;AAEA,EAAA,CAAA,CAAE,IAAA;AAAA,IACA,gBAAA;AAAA,IACA,YAAA,CAAa,OAAO,GAAA,EAAK,GAAA,KAAQ;AAC/B,MAAA,MAAM,IAAA,GAAQ,GAAA,CAAI,IAAA,IAAQ,EAAC;AAI3B,MAAA,IAAK,IAAA,CAAK,YAAA,IAAgB,IAAA,MAAW,IAAA,CAAK,QAAQ,IAAA,CAAA,EAAO;AACvD,QAAA,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK;AAAA,UAC1B,KAAA,EAAO,mBAAA;AAAA,UACP,OAAA,EAAS;AAAA,SACV,CAAA;AAAA,MACH;AACA,MAAA,IAAI,IAAA,CAAK,IAAA,IAAQ,CAAC,CAAC,WAAA,EAAa,eAAe,CAAA,CAAE,QAAA,CAAS,IAAA,CAAK,IAAI,CAAA,EAAG;AACpE,QAAA,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,mBAAA,EAAqB,OAAA,EAAS,6CAAA,EAA+C,CAAA;AAAA,MACpH;AACA,MAAA,MAAM,MAAA,GAAS,KAAK,YAAA,IAAgB,IAAA,CAAK,OACrC,EAAE,GAAA,EAAK,cAAA,CAAe,IAAA,CAAK,YAAA,CAAa,WAAA,IAAe,IAAA,CAAK,IAAI,CAAA,EAAE,GAGlE,EAAE,MAAA,EAAQ,WAAoB,GAAA,EAAK,EAAE,GAAA,EAAK,aAAA,EAAc,EAAE;AAE9D,MAAA,MAAM,MAAA,GAAS,MAAM,CAAA,CAAE,MAAA,CAAO,UAAA;AAAA,QAC5B,MAAA;AAAA,QACA,EAAE,IAAA,EAAM,EAAE,MAAA,EAAQ,SAAA,EAAW,iBAAA,kBAAmB,IAAI,IAAA,EAAK,EAAG,SAAA,kBAAW,IAAI,IAAA,IAAO;AAAE,OACtF;AACA,MAAA,MAAM,OAAO,KAAA,CAAM;AAAA,QACjB,OAAQ,GAAA,CAAY,KAAA;AAAA,QACpB,MAAA,EAAQ,eAAA;AAAA,QACR,QAAA,EAAU;AAAA,UACR,UAAA,EAAY,eAAA;AAAA,UACZ,EAAA,EAAI,IAAA,CAAK,YAAA,IAAgB,IAAA,CAAK,IAAA,GAAO,CAAA,EAAG,IAAA,CAAK,YAAY,CAAA,CAAA,EAAI,IAAA,CAAK,IAAI,CAAA,CAAA,GAAK;AAAA;AAC7E,OACD,CAAA;AACD,MAAA,GAAA,CAAI,KAAK,EAAE,EAAA,EAAI,MAAM,OAAA,EAAS,MAAA,CAAO,eAAe,CAAA;AAAA,IACtD,CAAC;AAAA,GACH;AAGA,EAAA,CAAA,CAAE,GAAA;AAAA,IACA,QAAA;AAAA,IACA,YAAA,CAAa,OAAO,IAAA,EAAM,GAAA,KAAQ;AAChC,MAAA,MAAM,MAAA,GAAS,MAAM,CAAA,CAAE,WAAA,CAAY,KAAK,EAAE,EAAE,IAAA,CAAK,EAAE,QAAQ,CAAA,EAAG,MAAA,EAAQ,GAAG,IAAA,EAAM,CAAA,EAAG,CAAA,CAAE,KAAA,CAAM,GAAG,CAAA,CAAE,OAAA,EAAQ;AACvG,MAAA,MAAM,WAAA,GAAc,MAAA,CAAO,MAAA,CAAoB,CAAC,KAAK,CAAA,KAAM;AACzD,QAAA,MAAM,CAAA,GAAI,IAAI,IAAA,CAAK,CAAA,CAAE,KAAK,CAAA;AAC1B,QAAA,OAAO,OAAO,GAAA,CAAI,OAAA,MAAa,CAAA,CAAE,OAAA,KAAY,GAAA,GAAM,CAAA;AAAA,MACrD,GAAG,IAAI,CAAA;AACP,MAAA,GAAA,CAAI,IAAA,CAAK;AAAA,QACP,MAAA;AAAA,QACA,WAAA,EAAa,WAAA,GAAc,WAAA,CAAY,WAAA,EAAY,GAAI,IAAA;AAAA,QACvD,aAAA,EAAe,MAAA,CAAO,MAAA,CAAO,KAAA,EAAO,aAAA,IAAiB;AAAA,OACtD,CAAA;AAAA,IACH,CAAC;AAAA,GACH;AAEA,EAAA,CAAA,CAAE,IAAA;AAAA,IACA,gBAAA;AAAA,IACA,YAAA,CAAa,OAAO,GAAA,EAAK,GAAA,KAAQ;AAC/B,MAAA,MAAM,MAAA,GAAS,MAAM,cAAA,CAAe,MAAA,CAAO,kBAAiB,EAAG,EAAE,KAAA,EAAO,IAAA,EAAM,CAAA;AAC9E,MAAA,MAAM,OAAO,KAAA,CAAM;AAAA,QACjB,OAAQ,GAAA,CAAY,KAAA;AAAA,QACpB,MAAA,EAAQ,eAAA;AAAA,QACR,QAAA,EAAU,EAAE,UAAA,EAAY,qBAAA,EAAsB;AAAA,QAC9C,WAAA,EAAa,MAAA,CAAO,GAAA,GAChB,CAAA,EAAG,MAAA,CAAO,WAAW,CAAA,SAAA,EAAY,MAAA,CAAO,WAAW,CAAA,OAAA,CAAA,GACnD,CAAA,SAAA,EAAY,MAAA,CAAO,MAAM,CAAA;AAAA,OAC9B,CAAA;AACD,MAAA,GAAA,CAAI,KAAK,MAAM,CAAA;AAAA,IACjB,CAAC;AAAA,GACH;AAGA,EAAA,CAAA,CAAE,GAAA;AAAA,IACA,aAAA;AAAA,IACA,YAAA,CAAa,OAAO,IAAA,EAAM,GAAA,KAAQ;AAChC,MAAA,MAAM,GAAA,GAAM,OAAO,MAAA,CAAO,UAAA;AAC1B,MAAA,MAAM,UAAA,GAAa,CAAC,CAAC,GAAA,EAAK,QAAA,IAAY,CAAC,CAAC,GAAA,EAAK,YAAA,IAAgB,CAAC,CAAC,GAAA,EAAK,YAAA;AACpE,MAAA,MAAM,MAAM,MAAM,CAAA,CAAE,oBAAoB,IAAA,CAAK,EAAE,CAAA,CAAE,IAAA,CAAK,EAAE,MAAA,EAAQ,CAAA,EAAG,MAAM,EAAA,EAAI,EAAE,KAAA,CAAM,GAAI,EAAE,OAAA,EAAQ;AAEnG,MAAA,MAAM,QAAA,uBAAe,GAAA,EAAwB;AAC7C,MAAA,KAAA,MAAW,KAAK,GAAA,EAAK;AACnB,QAAA,MAAM,MAAM,QAAA,CAAS,GAAA,CAAI,CAAA,CAAE,MAAM,KAAK,EAAC;AACvC,QAAA,IAAI,GAAA,CAAI,MAAA,GAAS,EAAA,EAAI,GAAA,CAAI,KAAK,CAAC,CAAA;AAC/B,QAAA,QAAA,CAAS,GAAA,CAAI,CAAA,CAAE,MAAA,EAAQ,GAAG,CAAA;AAAA,MAC5B;AACA,MAAA,MAAM,OAAA,GAAU,KAAA,CAAM,IAAA,CAAK,QAAA,CAAS,OAAA,EAAS,CAAA,CAAE,GAAA,CAAI,CAAC,CAAC,MAAA,EAAQ,SAAS,CAAA,MAAO;AAAA,QAC3E,MAAA;AAAA,QACA,MAAA,EAAQ,SAAA,CAAU,CAAC,CAAA,IAAK,IAAA;AAAA,QACxB,OAAA,EAAS;AAAA,OACX,CAAE,CAAA;AACF,MAAA,GAAA,CAAI,IAAA,CAAK;AAAA,QACP,UAAA;AAAA,QACA,aAAA,EAAe,KAAK,aAAA,IAAiB,EAAA;AAAA,QACrC;AAAA,OACD,CAAA;AAAA,IACH,CAAC;AAAA,GACH;AAEA,EAAA,CAAA,CAAE,IAAA;AAAA,IACA,qBAAA;AAAA,IACA,YAAA,CAAa,OAAO,GAAA,EAAK,GAAA,KAAQ;AAC/B,MAAA,MAAM,MAAA,GAAS,MAAM,iBAAA,CAAkB,MAAA,CAAO,kBAAiB,EAAG,EAAE,KAAA,EAAO,IAAA,EAAM,CAAA;AACjF,MAAA,MAAM,OAAO,KAAA,CAAM;AAAA,QACjB,OAAQ,GAAA,CAAY,KAAA;AAAA,QACpB,MAAA,EAAQ,oBAAA;AAAA,QACR,QAAA,EAAU,EAAE,UAAA,EAAY,6BAAA,EAA8B;AAAA,QACtD,aAAa,MAAA,CAAO,GAAA,GAChB,CAAA,QAAA,EAAW,MAAA,CAAO,WAAW,CAAC,CAAA,UAAA,EAAA,CAAc,MAAA,CAAO,cAAA,IAAkB,EAAC,EAAG,MAAM,CAAA,CAAA,GAC/E,CAAA,SAAA,EAAY,OAAO,MAAM,CAAA;AAAA,OAC9B,CAAA;AACD,MAAA,GAAA,CAAI,KAAK,MAAM,CAAA;AAAA,IACjB,CAAC;AAAA,GACH;AAMA,EAAA,IAAI,YAAA,GAAsG,IAAA;AAC1G,EAAA,IAAI,eAAA,GAAkF,IAAA;AACtF,EAAA,MAAM,gBAAA,GAAmB,GAAA;AAEzB,EAAA,CAAA,CAAE,GAAA;AAAA,IACA,UAAA;AAAA,IACA,YAAA,CAAa,OAAO,GAAA,EAAK,GAAA,KAAQ;AAC/B,MAAA,MAAM,QAAQ,GAAA,CAAI,KAAA,CAAM,YAAY,GAAA,IAAO,GAAA,CAAI,MAAM,OAAA,KAAY,MAAA;AACjE,MAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,MAAA,IAAI,CAAC,KAAA,IAAS,YAAA,IAAgB,GAAA,GAAM,YAAA,CAAa,aAAa,gBAAA,EAAkB;AAC9E,QAAA,OAAO,GAAA,CAAI,IAAA,CAAK,YAAA,CAAa,MAAM,CAAA;AAAA,MACrC;AACA,MAAA,IAAI,CAAC,eAAA,EAAiB;AACpB,QAAA,eAAA,GAAA,CAAmB,YAAY;AAC7B,UAAA,IAAI;AACF,YAAA,MAAMgC,OAAAA,GAAS,MAAM,kBAAA,CAAmB,MAAA,CAAO,kBAAkB,CAAA;AACjE,YAAA,YAAA,GAAe,EAAE,UAAA,EAAY,IAAA,CAAK,GAAA,EAAI,EAAG,QAAAA,OAAAA,EAAO;AAChD,YAAA,OAAOA,OAAAA;AAAA,UACT,CAAA,SAAE;AACA,YAAA,eAAA,GAAkB,IAAA;AAAA,UACpB;AAAA,QACF,CAAA,GAAG;AAAA,MACL;AACA,MAAA,MAAM,SAAS,MAAM,eAAA;AACrB,MAAA,GAAA,CAAI,KAAK,MAAM,CAAA;AAAA,IACjB,CAAC;AAAA,GACH;AAGA,EAAA,MAAM,cAAcC,uBAAA,CAAO;AAAA,IACzB,OAAA,EAASA,wBAAO,aAAA,EAAc;AAAA,IAC9B,MAAA,EAAQ,EAAE,QAAA,EAAU,EAAA,GAAK,OAAO,IAAA;AAAK;AAAA,GACtC,CAAA;AAED,EAAA,CAAA,CAAE,IAAA;AAAA,IACA,eAAA;AAAA,IACA,WAAA,CAAY,OAAO,MAAM,CAAA;AAAA,IACzB,YAAA,CAAa,OAAO,GAAA,EAAK,GAAA,KAAQ;AAC/B,MAAA,MAAM,OAAQ,GAAA,CAAY,IAAA;AAC1B,MAAA,IAAI,CAAC,IAAA,EAAM,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,SAAA,EAAW,OAAA,EAAS,2BAA2B,CAAA;AAE/F,MAAA,IAAI;AACF,QAAA,MAAM,MAAA,GAAS,MAAM,qBAAA,CAAsB,MAAA,CAAO,kBAAiB,EAAG,IAAA,CAAK,MAAA,EAAQ,IAAA,CAAK,YAAY,CAAA;AACpG,QAAA,MAAM,OAAO,KAAA,CAAM;AAAA,UACjB,OAAQ,GAAA,CAAY,KAAA;AAAA,UACpB,MAAA,EAAQ,cAAA;AAAA,UACR,UAAU,EAAE,UAAA,EAAY,sBAAA,EAAwB,EAAA,EAAI,OAAO,QAAA,EAAS;AAAA,UACpE,aAAa,MAAA,CAAO,SAAA,GAChB,oBAAoB,MAAA,CAAO,QAAQ,KACnC,CAAA,SAAA,EAAY,MAAA,CAAO,aAAa,CAAA,OAAA,EAAU,OAAO,SAAS,CAAA,QAAA,EAAW,OAAO,SAAS,CAAA,WAAA,EAAc,OAAO,MAAM,CAAA;AAAA,SACrH,CAAA;AACD,QAAA,OAAO,GAAA,CAAI,KAAK,MAAM,CAAA;AAAA,MACxB,SAAS,GAAA,EAAU;AACjB,QAAA,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,KAAK,EAAE,KAAA,EAAO,eAAA,EAAiB,OAAA,EAAS,MAAA,CAAO,GAAA,EAAK,OAAA,IAAW,GAAG,GAAG,CAAA;AAAA,MAC9F;AAAA,IACF,CAAC;AAAA,GACH;AAEA,EAAA,CAAA,CAAE,GAAA;AAAA,IACA,QAAA;AAAA,IACA,YAAA,CAAa,OAAO,IAAA,EAAM,GAAA,KAAQ;AAChC,MAAA,MAAM,GAAA,GAAM,OAAO,gBAAA,EAAiB;AACpC,MAAA,MAAM,MAAA,GAAS,MAAM,iBAAA,CAAkB,GAAG,CAAA;AAC1C,MAAA,MAAM,UAAU,MAAM,CAAA,CAAE,YAAA,CAAa,IAAA,CAAK,EAAE,CAAA,CAAE,IAAA,CAAK,EAAE,UAAU,EAAA,EAAI,EAAE,KAAA,CAAM,GAAG,EAAE,OAAA,EAAQ;AACxF,MAAA,MAAM,UAAU,IAAI,IAAA,CAAK,KAAK,GAAA,EAAI,GAAI,KAAK,KAAU,CAAA;AAIrD,MAAA,MAAM,cAAA,GAAiB,MAAM,CAAA,CAAE,aAAA,CAC5B,KAAK,EAAE,UAAA,EAAY,EAAE,IAAA,EAAM,OAAA,EAAQ,EAAG,CAAA,CACtC,IAAA,CAAK,EAAE,UAAA,EAAY,EAAA,EAAI,CAAA,CACvB,KAAA,CAAM,GAAI,CAAA,CACV,OAAA,EAAQ;AAEX,MAAA,MAAM,QAAA,uBAAe,GAAA,EAAyO;AAC9P,MAAA,KAAA,MAAWF,MAAK,OAAA,EAAS;AACvB,QAAA,MAAM,GAAA,GAAM,SAAS,GAAA,CAAIA,EAAAA,CAAE,MAAM,CAAA,IAAK,EAAE,SAAA,EAAW,CAAA,EAAG,SAAA,EAAW,CAAA,EAAG,eAAe,CAAA,EAAG,WAAA,EAAa,CAAA,EAAG,cAAA,EAAgB,IAAA,EAAM,YAAA,EAAc,MAAM,SAAA,EAAW,IAAA,EAAM,OAAA,EAAS,EAAC,EAAE;AAC7K,QAAA,GAAA,CAAI,aAAaA,EAAAA,CAAE,SAAA;AACnB,QAAA,GAAA,CAAI,aAAaA,EAAAA,CAAE,SAAA;AACnB,QAAA,GAAA,CAAI,iBAAiBA,EAAAA,CAAE,aAAA;AACvB,QAAA,GAAA,CAAI,WAAA,IAAe,CAAA;AACnB,QAAA,MAAM,EAAA,GAAK,IAAI,IAAA,CAAKA,EAAAA,CAAE,QAAQ,CAAA;AAC9B,QAAA,IAAI,CAAC,GAAA,CAAI,cAAA,IAAkB,EAAA,GAAK,IAAI,cAAA,EAAgB;AAClD,UAAA,GAAA,CAAI,cAAA,GAAiB,EAAA;AACrB,UAAA,GAAA,CAAI,eAAeA,EAAAA,CAAE,OAAA;AACrB,UAAA,GAAA,CAAI,YAAYA,EAAAA,CAAE,SAAA;AAAA,QACpB;AACA,QAAA,GAAA,CAAI,OAAA,CAAQ,KAAKA,EAAC,CAAA;AAClB,QAAA,QAAA,CAAS,GAAA,CAAIA,EAAAA,CAAE,MAAA,EAAQ,GAAG,CAAA;AAAA,MAC5B;AAGA,MAAA,MAAM,OAAA,GAAU,IAAA,CAAK,GAAA,EAAI,GAAI,EAAA,GAAK,KAAA;AAElC,MAAA,MAAM,OAAA,GAAU,KAAA,CAAM,IAAA,CAAK,QAAA,CAAS,OAAA,EAAS,CAAA,CAAE,GAAA,CAAI,CAAC,CAAC,MAAA,EAAQ,CAAC,CAAA,KAAM;AAElE,QAAA,MAAM,SAAA,uBAAgB,GAAA,EAA6C;AACnE,QAAA,KAAA,MAAWA,EAAAA,IAAK,EAAE,OAAA,EAAS;AACzB,UAAA,IAAI,IAAI,IAAA,CAAKA,EAAAA,CAAE,QAAQ,CAAA,CAAE,OAAA,KAAY,OAAA,EAAS;AAC9C,UAAA,MAAM,GAAA,GAAM,IAAI,IAAA,CAAKA,EAAAA,CAAE,QAAQ,EAAE,WAAA,EAAY,CAAE,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA;AAC1D,UAAA,MAAM,CAAA,GAAI,UAAU,GAAA,CAAI,GAAG,KAAK,EAAE,IAAA,EAAM,CAAA,EAAG,KAAA,EAAO,CAAA,EAAE;AACpD,UAAA,CAAA,CAAE,QAAQA,EAAAA,CAAE,SAAA;AACZ,UAAA,CAAA,CAAE,KAAA,IAASA,EAAAA,CAAE,SAAA,GAAYA,EAAAA,CAAE,SAAA;AAC3B,UAAA,SAAA,CAAU,GAAA,CAAI,KAAK,CAAC,CAAA;AAAA,QACtB;AACA,QAAA,MAAM,SAAS,KAAA,CAAM,IAAA,CAAK,SAAA,CAAU,OAAA,EAAS,CAAA,CAC1C,IAAA,CAAK,CAAC,CAAA,EAAG,MAAM,CAAA,CAAE,CAAC,CAAA,CAAE,aAAA,CAAc,EAAE,CAAC,CAAC,CAAC,CAAA,CACvC,IAAI,CAAC,CAAC,GAAA,EAAK,CAAC,OAAO,EAAE,GAAA,EAAK,aAAA,EAAe,CAAA,CAAE,UAAU,CAAA,GAAI,IAAA,GAAO,EAAE,IAAA,GAAO,CAAA,CAAE,OAAM,CAAE,CAAA;AAGtF,QAAA,MAAM,QAAA,GAAW,IAAI,GAAA,CAAI,KAAA,CAAM,KAAK,MAAA,CAAO,MAAA,EAAQ,CAAA,CAAE,MAAA,CAAO,CAAC,CAAA,KAAM,CAAC,EAAE,OAAO,CAAA,CAAE,IAAI,CAAC,CAAA,KAAM,CAAA,CAAE,EAAE,CAAC,CAAA;AAC/F,QAAA,MAAM,UAAA,GAAa,IAAI,GAAA,CAAI,KAAA,CAAM,KAAK,MAAA,CAAO,MAAA,EAAQ,CAAA,CAAE,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,EAAE,CAAC,CAAA;AAChG,QAAA,MAAM,YAAY,wBAAA,CAAyB;AAAA,UACzC,SAAS,CAAA,CAAE,OAAA,CAAQ,IAAI,CAACA,EAAAA,MAAO,EAAE,QAAA,EAAU,IAAI,KAAKA,EAAAA,CAAE,QAAQ,GAAG,SAAA,EAAWA,EAAAA,CAAE,WAAW,SAAA,EAAWA,EAAAA,CAAE,WAAU,CAAE,CAAA;AAAA,UAClH,QAAA,EAAU,cAAA,CAAe,MAAA,CAAO,CAAC,CAAA,KAAM,EAAE,MAAA,KAAW,MAAM,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,MAAO,EAAE,QAAA,EAAU,CAAA,CAAE,QAAA,EAAU,KAAA,EAAO,CAAA,CAAE,KAAA,EAAO,UAAA,EAAY,IAAI,IAAA,CAAK,CAAA,CAAE,UAAU,CAAA,EAAE,CAAE,CAAA;AAAA,UACrJ,cAAA,EAAgB,QAAA;AAAA,UAChB,gBAAA,EAAkB,UAAA;AAAA,UAClB,eAAe,CAAA,CAAE,YAAA;AAAA,UACjB,YAAY,CAAA,CAAE;AAAA,SACf,CAAA;AAED,QAAA,OAAO;AAAA,UACL,MAAA;AAAA,UACA,WAAW,CAAA,CAAE,SAAA;AAAA,UACb,WAAW,CAAA,CAAE,SAAA;AAAA,UACb,eAAe,CAAA,CAAE,aAAA;AAAA,UACjB,aAAa,CAAA,CAAE,WAAA;AAAA,UACf,gBAAgB,CAAA,CAAE,cAAA;AAAA,UAClB,eAAe,CAAA,CAAE,aAAA,KAAkB,IAAI,IAAA,GAAO,CAAA,CAAE,YAAY,CAAA,CAAE,aAAA;AAAA,UAC9D,eAAe,CAAA,CAAE,YAAA;AAAA,UACjB,YAAY,CAAA,CAAE,SAAA;AAAA,UACd,WAAA,EAAa,SAAA,GACT,EAAE,GAAG,WAAW,OAAA,EAAS,EAAE,MAAA,EAAQ,CAAA,CAAE,YAAA,EAAc,GAAA,EAAK,CAAA,CAAE,SAAA,IAAY,GACtE,IAAA;AAAA,UACJ;AAAA,SACF;AAAA,MACF,CAAC,CAAA;AAED,MAAA,MAAM,WAAA,GAAc,MAAM,CAAA,CAAE,aAAA,CACzB,SAAA,CAAmH;AAAA,QAClH,EAAE,QAAQ,EAAE,UAAA,EAAY,EAAE,IAAA,EAAM,OAAA,IAAU,EAAE;AAAA,QAC5C;AAAA,UACE,MAAA,EAAQ;AAAA,YACN,GAAA,EAAK,EAAE,QAAA,EAAU,WAAA,EAAa,QAAQ,SAAA,EAAU;AAAA,YAChD,KAAA,EAAO,EAAE,IAAA,EAAM,QAAA,EAAS;AAAA,YACxB,IAAA,EAAM,EAAE,SAAA,EAAW,MAAA,EAAO;AAAA,YAC1B,QAAA,EAAU,EAAE,IAAA,EAAM,aAAA,EAAc;AAAA,YAChC,MAAA,EAAQ,EAAE,MAAA,EAAQ,QAAA;AAAS;AAC7B,SACF;AAAA,QACA,EAAE,QAAA,EAAU,EAAE,UAAU,eAAA,EAAiB,MAAA,EAAQ,eAAe,KAAA,EAAO,CAAA,EAAG,IAAA,EAAM,EAAE,OAAO,OAAA,EAAQ,EAAG,UAAU,CAAA,EAAG,MAAA,EAAQ,GAAE,EAAE;AAAA,QAC7H,EAAE,KAAA,EAAO,EAAE,KAAA,EAAO,IAAG,EAAE;AAAA,QACvB,EAAE,QAAQ,EAAA;AAAG,OACd,EACA,OAAA,EAAQ;AAEX,MAAA,MAAM,OAAA,GAAU,WAAA,CAAY,GAAA,CAAI,CAAC,CAAA,KAAM;AACrC,QAAA,MAAM,GAAA,GAAM,MAAA,CAAO,GAAA,CAAI,CAAA,CAAE,IAAI,QAAQ,CAAA;AACrC,QAAA,OAAO;AAAA,UACL,QAAA,EAAU,EAAE,GAAA,CAAI,QAAA;AAAA,UAChB,MAAA,EAAQ,EAAE,GAAA,CAAI,MAAA;AAAA,UACd,eAAe,CAAA,CAAE,KAAA;AAAA,UACjB,UAAU,CAAA,CAAE,IAAA;AAAA,UACZ,UAAU,CAAA,CAAE,QAAA;AAAA,UACZ,UAAA,EAAY,EAAE,MAAA,CAAO,UAAA;AAAA,UACrB,SAAA,EAAW,EAAE,MAAA,CAAO,SAAA;AAAA,UACpB,kBAAA,EAAoB,EAAE,MAAA,CAAO,kBAAA;AAAA,UAC7B,KAAA,EAAO,KAAK,KAAA,IAAS,IAAA;AAAA,UACrB,OAAA,EAAS,CAAC,CAAC,GAAA,EAAK,OAAA;AAAA,UAChB,SAAA,EAAW,KAAK,MAAA,IAAU;AAAA,SAC5B;AAAA,MACF,CAAC,CAAA;AAED,MAAA,GAAA,CAAI,IAAA,CAAK;AAAA,QACP,OAAA;AAAA,QACA,OAAA;AAAA,QACA,aAAA,EAAe,OAAA,CAAQ,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA;AAAA,QAClC,aAAA,EAAe,MAAA,CAAO,MAAA,CAAO,KAAA,EAAO,aAAA,IAAiB;AAAA,OACtD,CAAA;AAAA,IACH,CAAC;AAAA,GACH;AAGA,EAAA,CAAA,CAAE,GAAA;AAAA,IACA,oBAAA;AAAA,IACA,YAAA,CAAa,OAAO,GAAA,EAAK,GAAA,KAAQ;AAC/B,MAAA,MAAM,EAAA,GAAK,MAAA,CAAO,GAAA,CAAI,MAAA,CAAO,MAAM,EAAE,CAAA;AACrC,MAAA,IAAI,CAAClB,oBAAAA,CAAI,IAAA,CAAK,EAAE,CAAA,EAAG;AACjB,QAAA,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,mBAAA,EAAqB,OAAA,EAAS,YAAA,EAAc,CAAA;AAAA,MACnF;AACA,MAAA,MAAM,IAAA,GAAQ,GAAA,CAAI,IAAA,IAAQ,EAAC;AAC3B,MAAA,IAAI,CAAC,IAAA,CAAK,KAAA,IAAS,OAAO,IAAA,CAAK,UAAU,QAAA,EAAU;AACjD,QAAA,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,mBAAA,EAAqB,OAAA,EAAS,mBAAA,EAAqB,CAAA;AAAA,MAC1F;AACA,MAAA,MAAM,QAAQ,IAAA,CAAK,KAAA,CAAM,MAAK,CAAE,KAAA,CAAM,GAAG,GAAG,CAAA;AAC5C,MAAA,IAAI,CAAC,KAAA,EAAO;AACV,QAAA,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,mBAAA,EAAqB,OAAA,EAAS,mBAAA,EAAqB,CAAA;AAAA,MAC1F;AACA,MAAA,MAAM,OAAA,GAAU,CAAC,CAAC,IAAA,CAAK,OAAA;AACvB,MAAA,MAAM,EAAE,eAAA,CAAgB,SAAA;AAAA,QACtB,EAAE,EAAA,EAAG;AAAA,QACL,EAAE,IAAA,EAAM,EAAE,EAAA,EAAI,OAAO,OAAA,EAAS,KAAA,EAAQ,GAAA,CAAY,KAAA,IAAS,SAAA,EAAW,KAAA,kBAAO,IAAI,IAAA,IAAO,EAAE;AAAA,QAC1F,EAAE,QAAQ,IAAA;AAAK,OACjB;AACA,MAAA,MAAM,OAAO,KAAA,CAAM;AAAA,QACjB,OAAQ,GAAA,CAAY,KAAA;AAAA,QACpB,MAAA,EAAQ,yBAAA;AAAA,QACR,QAAA,EAAU,EAAE,UAAA,EAAY,0BAAA,EAA4B,IAAI,EAAA,EAAG;AAAA,QAC3D,WAAA,EAAa,GAAG,EAAE,CAAA,SAAA,EAAO,KAAK,CAAA,CAAA,EAAI,OAAA,GAAU,eAAe,EAAE,CAAA;AAAA,OAC9D,CAAA;AACD,MAAA,GAAA,CAAI,IAAA,CAAK,EAAE,EAAA,EAAI,IAAA,EAAM,CAAA;AAAA,IACvB,CAAC;AAAA,GACH;AAEA,EAAA,CAAA,CAAE,MAAA;AAAA,IACA,oBAAA;AAAA,IACA,YAAA,CAAa,OAAO,GAAA,EAAK,GAAA,KAAQ;AAC/B,MAAA,MAAM,EAAA,GAAK,MAAA,CAAO,GAAA,CAAI,MAAA,CAAO,MAAM,EAAE,CAAA;AACrC,MAAA,IAAI,CAACA,oBAAAA,CAAI,IAAA,CAAK,EAAE,CAAA,EAAG;AACjB,QAAA,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,mBAAA,EAAqB,OAAA,EAAS,YAAA,EAAc,CAAA;AAAA,MACnF;AACA,MAAA,MAAM,SAAS,MAAM,CAAA,CAAE,gBAAgB,SAAA,CAAU,EAAE,IAAI,CAAA;AACvD,MAAA,MAAM,OAAO,KAAA,CAAM;AAAA,QACjB,OAAQ,GAAA,CAAY,KAAA;AAAA,QACpB,MAAA,EAAQ,yBAAA;AAAA,QACR,QAAA,EAAU,EAAE,UAAA,EAAY,0BAAA,EAA4B,IAAI,EAAA;AAAG,OAC5D,CAAA;AACD,MAAA,GAAA,CAAI,KAAK,EAAE,EAAA,EAAI,MAAM,OAAA,EAAS,MAAA,CAAO,cAAc,CAAA;AAAA,IACrD,CAAC;AAAA,GACH;AAGA,EAAA,CAAA,CAAE,GAAA;AAAA,IACA,OAAA;AAAA,IACA,YAAA,CAAa,OAAO,IAAA,EAAM,GAAA,KAAQ;AAChC,MAAA,MAAM,GAAA,GAAM,OAAO,MAAA,CAAO,IAAA;AAC1B,MAAA,MAAM,UAAA,GAAa,CAAC,CAAC,GAAA,EAAK,SAAA;AAC1B,MAAA,MAAM,MAAM,MAAM,CAAA,CAAE,cAAc,IAAA,CAAK,EAAE,CAAA,CAAE,IAAA,CAAK,EAAE,EAAA,EAAI,CAAA,EAAG,eAAe,EAAA,EAAI,EAAE,KAAA,CAAM,GAAI,EAAE,OAAA,EAAQ;AAClG,MAAA,MAAM,IAAA,uBAAW,GAAA,EAAwB;AACzC,MAAA,KAAA,MAAW,KAAK,GAAA,EAAK;AACnB,QAAA,MAAM,MAAM,IAAA,CAAK,GAAA,CAAI,CAAA,CAAE,EAAE,KAAK,EAAC;AAC/B,QAAA,IAAI,GAAA,CAAI,MAAA,GAAS,EAAA,EAAI,GAAA,CAAI,KAAK,CAAC,CAAA;AAC/B,QAAA,IAAA,CAAK,GAAA,CAAI,CAAA,CAAE,EAAA,EAAI,GAAG,CAAA;AAAA,MACpB;AACA,MAAA,MAAM,GAAA,GAAM,KAAA,CAAM,IAAA,CAAK,IAAA,CAAK,OAAA,EAAS,CAAA,CAAE,GAAA,CAAI,CAAC,CAAC,EAAA,EAAI,SAAS,CAAA,MAAO;AAAA,QAC/D,EAAA;AAAA,QACA,MAAA,EAAQ,SAAA,CAAU,CAAC,CAAA,IAAK,IAAA;AAAA,QACxB,OAAA,EAAS;AAAA,OACX,CAAE,CAAA;AACF,MAAA,GAAA,CAAI,IAAA,CAAK;AAAA,QACP,UAAA;AAAA,QACA,aAAA,EAAe,KAAK,aAAA,IAAiB,EAAA;AAAA,QACrC;AAAA,OACD,CAAA;AAAA,IACH,CAAC;AAAA,GACH;AAEA,EAAA,CAAA,CAAE,IAAA;AAAA,IACA,eAAA;AAAA,IACA,YAAA,CAAa,OAAO,GAAA,EAAK,GAAA,KAAQ;AAC/B,MAAA,MAAM,MAAA,GAAS,MAAM,WAAA,CAAY,MAAA,CAAO,kBAAiB,EAAG,EAAE,KAAA,EAAO,IAAA,EAAM,CAAA;AAC3E,MAAA,MAAM,OAAO,KAAA,CAAM;AAAA,QACjB,OAAQ,GAAA,CAAY,KAAA;AAAA,QACpB,MAAA,EAAQ,cAAA;AAAA,QACR,QAAA,EAAU,EAAE,UAAA,EAAY,uBAAA,EAAwB;AAAA,QAChD,WAAA,EAAa,MAAA,CAAO,GAAA,GAChB,CAAA,OAAA,EAAU,OAAO,UAAA,IAAc,CAAC,CAAA,YAAA,EAAe,MAAA,CAAO,aAAA,IAAiB,CAAC,CAAA,CAAA,GACxE,CAAA,SAAA,EAAY,OAAO,MAAM,CAAA;AAAA,OAC9B,CAAA;AACD,MAAA,GAAA,CAAI,KAAK,MAAM,CAAA;AAAA,IACjB,CAAC;AAAA,GACH;AAGA,EAAA,CAAA,CAAE,IAAA;AAAA,IACA,QAAA;AAAA,IACA,YAAA,CAAa,OAAO,GAAA,EAAK,GAAA,KAAQ;AAC/B,MAAA,MAAM,EAAE,IAAA,EAAM,IAAA,EAAM,WAAA,EAAa,OAAA,EAAS,MAAM,QAAA,EAAS,GAAI,GAAA,CAAI,IAAA,IAAQ,EAAC;AAC1E,MAAA,IAAI,CAAC,IAAA,IAAQ,CAAC,IAAA,IAAQ,CAAC,SAAS,SAAA,EAAW;AACzC,QAAA,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,mBAAA,EAAqB,OAAA,EAAS,4CAAA,EAA8C,CAAA;AAAA,MACnH;AACA,MAAA,MAAM,GAAA,uBAAU,IAAA,EAAK;AACrB,MAAA,MAAM,GAAA,GAAM;AAAA,QACV,IAAA;AAAA,QACA,IAAA;AAAA,QACA,aAAa,WAAA,IAAe,EAAA;AAAA,QAC5B,OAAA,EAAS,EAAE,IAAA,EAAM,OAAA,EAAkB,SAAA,EAAW,QAAQ,SAAA,EAAW,IAAA,EAAM,OAAA,CAAQ,IAAA,KAAS,KAAA,EAAM;AAAA,QAC9F,OAAA,EAAS,KAAA;AAAA,QACT,OAAO,EAAC;AAAA,QACR,OAAA,EAAS,CAAA;AAAA,QACT,KAAA,EAAO;AAAA,UACL,OAAO,EAAC;AAAA,UACR,KAAA,EAAO,eAAA;AAAA,UACP,cAAA,EAAiB,IAAY,KAAA,IAAS,SAAA;AAAA,UACtC,cAAA,EAAgB;AAAA,SAClB;AAAA,QACA,MAAM,IAAA,IAAQ,YAAA;AAAA,QACd,UAAU,QAAA,IAAY,EAAA;AAAA,QACtB,qBAAA,EAAuB,IAAA;AAAA,QACvB,KAAA,EAAO,EAAE,UAAA,EAAY,CAAA,EAAG,eAAe,CAAA,EAAG,UAAA,EAAY,CAAA,EAAG,cAAA,EAAgB,CAAA,EAAE;AAAA,QAC3E,iBAAA,EAAmB,IAAA;AAAA,QACnB,WAAA,EAAa,IAAA;AAAA,QACb,WAAA,EAAa,IAAA;AAAA,QACb,SAAA,EAAW,GAAA;AAAA,QACX,SAAA,EAAW;AAAA,OACb;AACA,MAAA,IAAI;AACF,QAAA,MAAM,CAAA,CAAE,KAAA,CAAM,SAAA,CAAU,GAAU,CAAA;AAAA,MACpC,SAAS,GAAA,EAAU;AACjB,QAAA,IAAI,GAAA,EAAK,IAAA,KAAS,IAAA,EAAO,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,YAAA,EAAc,CAAA;AAC5E,QAAA,MAAM,GAAA;AAAA,MACR;AACA,MAAA,MAAM,OAAO,KAAA,CAAM;AAAA,QACjB,OAAQ,GAAA,CAAY,KAAA;AAAA,QACpB,MAAA,EAAQ,aAAA;AAAA,QACR,QAAA,EAAU,EAAE,UAAA,EAAY,cAAA,EAAgB,IAAA;AAAK,OAC9C,CAAA;AACD,MAAA,OAAO,IAAI,IAAA,CAAK,EAAE,EAAA,EAAI,IAAA,EAAM,MAAM,CAAA;AAAA,IACpC,CAAC;AAAA,GACH;AAEA,EAAA,CAAA,CAAE,KAAA;AAAA,IACA,oBAAA;AAAA,IACA,YAAA,CAAa,OAAO,GAAA,EAAK,GAAA,KAAQ;AAC/B,MAAA,MAAM,IAAA,GAAO,MAAM,CAAA,CAAE,KAAA,CAAM,OAAA,CAAQ,EAAE,IAAA,EAAM,GAAA,CAAI,MAAA,CAAO,IAAA,EAAM,CAAA;AAC5D,MAAA,IAAI,CAAC,IAAA,EAAM,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,WAAA,EAAa,CAAA;AAC7D,MAAA,MAAM,EAAE,KAAA,EAAO,KAAA,EAAO,OAAA,EAAS,IAAA,EAAM,WAAA,EAAa,IAAA,EAAM,QAAA,EAAS,GAAI,GAAA,CAAI,IAAA,IAAQ,EAAC;AAElF,MAAA,MAAM,GAAA,GAA+B;AAAA,QACnC,wBAAyB,GAAA,CAAY,KAAA;AAAA,QACrC,sBAAA,sBAA4B,IAAA,EAAK;AAAA,QACjC,SAAA,sBAAe,IAAA;AAAK,OACtB;AACA,MAAA,IAAI,MAAM,OAAA,CAAQ,KAAK,CAAA,EAAG,GAAA,CAAI,aAAa,CAAA,GAAI,KAAA;AAC/C,MAAA,IAAI,OAAO,KAAA,KAAU,QAAA,EAAU,GAAA,CAAI,aAAa,CAAA,GAAI,KAAA;AACpD,MAAA,IAAI,OAAA,EAAS,SAAA,EAAW,GAAA,CAAI,OAAA,GAAU,EAAE,IAAA,EAAM,OAAA,EAAkB,SAAA,EAAW,OAAA,CAAQ,SAAA,EAAW,IAAA,EAAM,OAAA,CAAQ,SAAS,KAAA,EAAM;AAC3H,MAAA,IAAI,OAAO,IAAA,KAAS,QAAA,EAAU,GAAA,CAAI,IAAA,GAAO,IAAA;AACzC,MAAA,IAAI,OAAO,WAAA,KAAgB,QAAA,EAAU,GAAA,CAAI,WAAA,GAAc,WAAA;AACvD,MAAA,IAAI,OAAO,IAAA,KAAS,QAAA,EAAU,GAAA,CAAI,IAAA,GAAO,IAAA;AACzC,MAAA,IAAI,OAAO,QAAA,KAAa,QAAA,EAAU,GAAA,CAAI,QAAA,GAAW,QAAA;AAEjD,MAAA,MAAM,CAAA,CAAE,KAAA,CAAM,SAAA,CAAU,EAAE,GAAA,EAAK,IAAA,CAAK,GAAA,EAAI,EAAG,EAAE,IAAA,EAAM,GAAA,EAAK,CAAA;AACxD,MAAA,MAAM,OAAO,KAAA,CAAM;AAAA,QACjB,OAAQ,GAAA,CAAY,KAAA;AAAA,QACpB,MAAA,EAAQ,mBAAA;AAAA,QACR,QAAA,EAAU,EAAE,UAAA,EAAY,cAAA,EAAgB,IAAI,IAAA,CAAK,GAAA,EAAK,IAAA,EAAM,IAAA,CAAK,IAAA,EAAK;AAAA,QACtE,aAAa,CAAA,eAAA,EAAkB,KAAA,GAAQ,GAAG,KAAA,CAAM,MAAM,WAAW,eAAe,CAAA,CAAA;AAAA,OACjF,CAAA;AACD,MAAA,OAAO,GAAA,CAAI,IAAA,CAAK,EAAE,EAAA,EAAI,MAAM,CAAA;AAAA,IAC9B,CAAC;AAAA,GACH;AAEA,EAAA,CAAA,CAAE,IAAA;AAAA,IACA,sBAAA;AAAA,IACA,YAAA,CAAa,OAAO,GAAA,EAAK,GAAA,KAAQ;AAC/B,MAAA,MAAM,IAAA,GAAO,MAAM,CAAA,CAAE,KAAA,CAAM,OAAA,CAAQ,EAAE,IAAA,EAAM,GAAA,CAAI,MAAA,CAAO,IAAA,EAAM,CAAA;AAC5D,MAAA,IAAI,CAAC,IAAA,EAAM,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,WAAA,EAAa,CAAA;AAC7D,MAAA,MAAM,UAAA,GAAa,IAAA,CAAK,KAAA,EAAO,KAAA,IAAS,IAAA,CAAK,KAAA;AAC7C,MAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,UAAU,CAAA,IAAK,UAAA,CAAW,WAAW,CAAA,EAAG;AACzD,QAAA,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,YAAA,EAAc,OAAA,EAAS,8BAAA,EAAgC,CAAA;AAAA,MAC9F;AACA,MAAA,MAAM,WAAA,GAAA,CAAe,IAAA,CAAK,OAAA,IAAW,CAAA,IAAK,CAAA;AAC1C,MAAA,MAAM,GAAA,uBAAU,IAAA,EAAK;AACrB,MAAA,MAAM,CAAA,CAAE,aAAa,SAAA,CAAU;AAAA,QAC7B,QAAQ,IAAA,CAAK,GAAA;AAAA,QACb,OAAA,EAAS,WAAA;AAAA,QACT,KAAA,EAAO,UAAA;AAAA,QACP,SAAS,IAAA,CAAK,OAAA;AAAA,QACd,WAAA,EAAa,GAAA;AAAA,QACb,aAAc,GAAA,CAAY;AAAA,OAC3B,CAAA;AACD,MAAA,MAAM,EAAE,KAAA,CAAM,SAAA;AAAA,QACZ,EAAE,GAAA,EAAK,IAAA,CAAK,GAAA,EAAI;AAAA,QAChB;AAAA,UACE,IAAA,EAAM;AAAA,YACJ,KAAA,EAAO,UAAA;AAAA,YACP,OAAA,EAAS,WAAA;AAAA,YACT,OAAA,EAAS,IAAA;AAAA,YACT,KAAA,EAAO,IAAA;AAAA,YACP,WAAA,EAAa,GAAA;AAAA,YACb,aAAc,GAAA,CAAY,KAAA;AAAA,YAC1B,SAAA,EAAW;AAAA;AACb;AACF,OACF;AACA,MAAA,MAAM,OAAO,KAAA,CAAM;AAAA,QACjB,OAAQ,GAAA,CAAY,KAAA;AAAA,QACpB,MAAA,EAAQ,cAAA;AAAA,QACR,QAAA,EAAU,EAAE,UAAA,EAAY,cAAA,EAAgB,IAAI,IAAA,CAAK,GAAA,EAAK,IAAA,EAAM,IAAA,CAAK,IAAA,EAAK;AAAA,QACtE,WAAA,EAAa,cAAc,WAAW,CAAA;AAAA,OACvC,CAAA;AACD,MAAA,OAAO,IAAI,IAAA,CAAK,EAAE,IAAI,IAAA,EAAM,OAAA,EAAS,aAAa,CAAA;AAAA,IACpD,CAAC;AAAA,GACH;AAEA,EAAA,CAAA,CAAE,MAAA;AAAA,IACA,cAAA;AAAA,IACA,YAAA,CAAa,OAAO,GAAA,EAAK,GAAA,KAAQ;AAC/B,MAAA,MAAM,IAAA,GAAO,MAAM,CAAA,CAAE,KAAA,CAAM,OAAA,CAAQ,EAAE,IAAA,EAAM,GAAA,CAAI,MAAA,CAAO,IAAA,EAAM,CAAA;AAC5D,MAAA,IAAI,CAAC,IAAA,EAAM,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,WAAA,EAAa,CAAA;AAC7D,MAAA,MAAM,OAAA,GAAU,MAAM,CAAA,CAAE,QAAA,CAAS,cAAA,CAAe,EAAE,MAAA,EAAQ,IAAA,CAAK,GAAA,EAAI,EAAG,EAAE,KAAA,EAAO,GAAG,CAAA;AAClF,MAAA,IAAI,OAAA,GAAU,CAAA,EAAG,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,UAAA,EAAY,OAAA,EAAS,yCAAoC,CAAA;AAC/G,MAAA,MAAM,EAAE,KAAA,CAAM,SAAA,CAAU,EAAE,GAAA,EAAK,IAAA,CAAK,KAAK,CAAA;AACzC,MAAA,MAAM,OAAO,KAAA,CAAM;AAAA,QACjB,OAAQ,GAAA,CAAY,KAAA;AAAA,QACpB,MAAA,EAAQ,aAAA;AAAA,QACR,QAAA,EAAU,EAAE,UAAA,EAAY,cAAA,EAAgB,IAAI,IAAA,CAAK,GAAA,EAAK,IAAA,EAAM,IAAA,CAAK,IAAA;AAAK,OACvE,CAAA;AACD,MAAA,OAAO,GAAA,CAAI,IAAA,CAAK,EAAE,EAAA,EAAI,MAAM,CAAA;AAAA,IAC9B,CAAC;AAAA,GACH;AAGA,EAAA,CAAA,CAAE,IAAA;AAAA,IACA,YAAA;AAAA,IACA,YAAA,CAAa,OAAO,GAAA,EAAK,GAAA,KAAQ;AAC/B,MAAA,MAAM,EAAE,IAAA,EAAM,IAAA,EAAM,IAAA,EAAM,OAAA,EAAS,SAAA,EAAW,QAAA,EAAU,SAAA,EAAU,GAAI,GAAA,CAAI,IAAA,IAAQ,EAAC;AACnF,MAAA,IAAI,CAAC,IAAA,IAAQ,CAAC,IAAA,IAAQ,CAAC,IAAA,EAAM;AAC3B,QAAA,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,mBAAA,EAAqB,OAAA,EAAS,2BAAA,EAA6B,CAAA;AAAA,MAClG;AACA,MAAA,IAAI,IAAA,KAAS,WAAA,IAAe,IAAA,KAAS,eAAA,EAAiB;AACpD,QAAA,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,mBAAA,EAAqB,OAAA,EAAS,yCAAA,EAA2C,CAAA;AAAA,MAChH;AACA,MAAA,MAAM,iBAAA,GACJ,SAAA,KACC,IAAA,KAAS,eAAA,GAAkB,MAAA,CAAO,MAAA,CAAO,yBAAA,EAA2B,KAAA,GAAQ,MAAA,CAAA,IAC7E,MAAA,CAAO,MAAA,CAAO,YAAA,EAAc,KAAA,IAC5B,qBAAA;AACF,MAAA,MAAM,cAAc,oBAAA,CAAqB,iBAAA,EAAmB,IAAA,EAAM,MAAA,CAAO,OAAO,aAAa,CAAA;AAC7F,MAAA,IAAI,CAAC,YAAY,EAAA,EAAI;AACnB,QAAA,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK;AAAA,UAC1B,KAAA,EAAO,uBAAA;AAAA,UACP,MAAM,WAAA,CAAY,IAAA;AAAA,UAClB,SAAS,WAAA,CAAY;AAAA,SACtB,CAAA;AAAA,MACH;AACA,MAAA,MAAM,GAAA,uBAAU,IAAA,EAAK;AACrB,MAAA,IAAI;AACF,QAAA,MAAM,CAAA,CAAE,UAAU,SAAA,CAAU;AAAA,UAC1B,IAAA;AAAA,UACA,IAAA;AAAA,UACA,WAAA,EAAa,EAAA;AAAA,UACb,IAAA;AAAA,UACA,QAAA,EACE,QAAA,KACC,IAAA,KAAS,eAAA,GAAkB,MAAA,CAAO,MAAA,CAAO,yBAAA,EAA2B,IAAA,GAAO,KAAA,CAAA,CAAA,IAC5E,MAAA,CAAO,MAAA,CAAO,YAAA,EAAc,IAAA,IAC5B,SAAA;AAAA,UACF,SAAA,EAAW,iBAAA;AAAA,UACX,OAAA,EAAS,IAAA;AAAA,UACT,gBAAA,EAAkB,IAAA;AAAA,UAClB,OAAA,EAAS,OAAA,IAAW,CAAA,gBAAA,EAAc,IAAI,CAAA,CAAA;AAAA,UACtC,WAAW,SAAA,IAAa,EAAA;AAAA,UACxB,IAAA,EAAM,EAAE,IAAA,EAAM,EAAA,EAAI,UAAA,EAAY,IAAA,EAAM,IAAA,EAAM,EAAA,EAAI,SAAA,EAAW,EAAA,EAAI,UAAA,EAAY,IAAA,EAAK;AAAA,UAC9E,iBAAiB,EAAC;AAAA,UAClB,KAAA,EAAO;AAAA,YACL,OAAA,EAAS,OAAA,IAAW,CAAA,gBAAA,EAAc,IAAI,CAAA,CAAA;AAAA,YACtC,WAAW,SAAA,IAAa,EAAA;AAAA,YACxB,IAAA,EAAM,EAAA;AAAA,YACN,UAAA,EAAY,IAAA;AAAA,YACZ,KAAA,EAAO,eAAA;AAAA,YACP,gBAAiB,GAAA,CAAY,KAAA;AAAA,YAC7B,cAAA,EAAgB;AAAA,WAClB;AAAA,UACA,MAAM,EAAC;AAAA,UACP,UAAA,EAAY,WAAA;AAAA,UACZ,YAAY,IAAA,KAAS,WAAA;AAAA,UACrB,aAAa,IAAA,KAAS,WAAA;AAAA,UACtB,OAAO,EAAE,IAAA,EAAM,CAAA,EAAG,SAAA,EAAW,GAAG,MAAA,EAAQ,CAAA,EAAG,OAAA,EAAS,CAAA,EAAG,SAAS,CAAA,EAAG,UAAA,EAAY,GAAG,YAAA,EAAc,CAAA,EAAG,YAAY,IAAA,EAAK;AAAA,UACpH,WAAA,EAAa,IAAA;AAAA,UACb,WAAA,EAAa,IAAA;AAAA,UACb,SAAA,EAAW,GAAA;AAAA,UACX,SAAA,EAAW;AAAA,SACL,CAAA;AAAA,MACV,SAAS,GAAA,EAAU;AACjB,QAAA,IAAI,GAAA,EAAK,IAAA,KAAS,IAAA,EAAO,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,YAAA,EAAc,CAAA;AAC5E,QAAA,MAAM,GAAA;AAAA,MACR;AACA,MAAA,MAAM,OAAO,KAAA,CAAM;AAAA,QACjB,OAAQ,GAAA,CAAY,KAAA;AAAA,QACpB,MAAA,EAAQ,iBAAA;AAAA,QACR,QAAA,EAAU,EAAE,UAAA,EAAY,kBAAA,EAAoB,IAAA;AAAK,OAClD,CAAA;AACD,MAAA,OAAO,IAAI,IAAA,CAAK,EAAE,EAAA,EAAI,IAAA,EAAM,MAAM,CAAA;AAAA,IACpC,CAAC;AAAA,GACH;AAEA,EAAA,CAAA,CAAE,KAAA;AAAA,IACA,wBAAA;AAAA,IACA,YAAA,CAAa,OAAO,GAAA,EAAK,GAAA,KAAQ;AAC/B,MAAA,MAAM,GAAA,GAAM,MAAM,CAAA,CAAE,SAAA,CAAU,OAAA,CAAQ,EAAE,IAAA,EAAM,GAAA,CAAI,MAAA,CAAO,IAAA,EAAM,CAAA;AAC/D,MAAA,IAAI,CAAC,GAAA,EAAK,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,WAAA,EAAa,CAAA;AAE5D,MAAA,MAAM,EAAE,OAAA,EAAS,SAAA,EAAW,IAAA,EAAM,UAAA,EAAY,OAAO,IAAA,EAAM,QAAA,EAAU,SAAA,EAAW,OAAA,EAAS,MAAM,UAAA,EAAY,UAAA,EAAY,aAAY,GAAI,GAAA,CAAI,QAAQ,EAAC;AAEpJ,MAAA,MAAM,GAAA,GAA+B;AAAA,QACnC,wBAAyB,GAAA,CAAY,KAAA;AAAA,QACrC,sBAAA,sBAA4B,IAAA,EAAK;AAAA,QACjC,SAAA,sBAAe,IAAA;AAAK,OACtB;AACA,MAAA,IAAI,OAAO,OAAA,KAAY,QAAA,EAAU,GAAA,CAAI,eAAe,CAAA,GAAI,OAAA;AACxD,MAAA,IAAI,OAAO,SAAA,KAAc,QAAA,EAAU,GAAA,CAAI,iBAAiB,CAAA,GAAI,SAAA;AAC5D,MAAA,IAAI,OAAO,IAAA,KAAS,QAAA,EAAU,GAAA,CAAI,YAAY,CAAA,GAAI,IAAA;AAClD,MAAA,IAAI,UAAA,KAAe,MAAA,EAAW,GAAA,CAAI,kBAAkB,CAAA,GAAI,UAAA;AACxD,MAAA,IAAI,OAAO,KAAA,KAAU,QAAA,EAAU,GAAA,CAAI,aAAa,CAAA,GAAI,KAAA;AACpD,MAAA,IAAI,OAAO,IAAA,KAAS,QAAA,EAAU,GAAA,CAAI,IAAA,GAAO,IAAA;AACzC,MAAA,IAAI,OAAO,QAAA,KAAa,QAAA,EAAU,GAAA,CAAI,QAAA,GAAW,QAAA;AACjD,MAAA,IAAI,OAAO,SAAA,KAAc,QAAA,EAAU,GAAA,CAAI,SAAA,GAAY,SAAA;AACnD,MAAA,IAAI,OAAO,OAAA,KAAY,QAAA,IAAY,OAAA,KAAY,IAAA,MAAU,OAAA,GAAU,OAAA;AACnE,MAAA,IAAI,IAAA,KAAS,WAAA,IAAe,IAAA,KAAS,eAAA,MAAqB,IAAA,GAAO,IAAA;AAIjE,MAAA,IAAI,OAAO,SAAA,KAAc,QAAA,IAAY,IAAA,KAAS,WAAA,IAAe,SAAS,eAAA,EAAiB;AACrF,QAAA,MAAM,aAAA,GAAiB,GAAA,CAAI,IAAA,IAA4B,GAAA,CAAI,IAAA;AAC3D,QAAA,MAAM,kBAAA,GAAsB,GAAA,CAAI,SAAA,IAAwB,GAAA,CAAI,SAAA;AAC5D,QAAA,MAAM,cAAc,oBAAA,CAAqB,kBAAA,EAAoB,aAAA,EAAe,MAAA,CAAO,OAAO,aAAa,CAAA;AACvG,QAAA,IAAI,CAAC,YAAY,EAAA,EAAI;AACnB,UAAA,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK;AAAA,YAC1B,KAAA,EAAO,uBAAA;AAAA,YACP,MAAM,WAAA,CAAY,IAAA;AAAA,YAClB,SAAS,WAAA,CAAY;AAAA,WACtB,CAAA;AAAA,QACH;AAAA,MACF;AACA,MAAA,IAAI,qBAAA,CAAsB,QAAA,CAAS,UAAU,CAAA,MAAO,UAAA,GAAa,UAAA;AACjE,MAAA,IAAI,OAAO,UAAA,KAAe,SAAA,EAAW,GAAA,CAAI,UAAA,GAAa,UAAA;AACtD,MAAA,IAAI,OAAO,WAAA,KAAgB,SAAA,EAAW,GAAA,CAAI,WAAA,GAAc,WAAA;AAExD,MAAA,MAAM,CAAA,CAAE,SAAA,CAAU,SAAA,CAAU,EAAE,GAAA,EAAK,GAAA,CAAI,GAAA,EAAI,EAAG,EAAE,IAAA,EAAM,GAAA,EAAK,CAAA;AAC3D,MAAA,MAAM,OAAO,KAAA,CAAM;AAAA,QACjB,OAAQ,GAAA,CAAY,KAAA;AAAA,QACpB,MAAA,EAAQ,uBAAA;AAAA,QACR,QAAA,EAAU,EAAE,UAAA,EAAY,kBAAA,EAAoB,IAAI,GAAA,CAAI,GAAA,EAAK,IAAA,EAAM,GAAA,CAAI,IAAA;AAAK,OACzE,CAAA;AACD,MAAA,OAAO,GAAA,CAAI,IAAA,CAAK,EAAE,EAAA,EAAI,MAAM,CAAA;AAAA,IAC9B,CAAC;AAAA,GACH;AAGA,EAAA,CAAA,CAAE,GAAA;AAAA,IACA,8BAAA;AAAA,IACA,YAAA,CAAa,OAAO,GAAA,EAAK,GAAA,KAAQ;AAC/B,MAAA,MAAM,GAAA,GAAM,OAAO,MAAA,CAAO,UAAA;AAC1B,MAAA,MAAM,UAAA,GAAa,CAAC,CAAC,GAAA,EAAK,MAAA;AAC1B,MAAA,MAAM,GAAA,GAAM,MAAM,CAAA,CAAE,SAAA,CAAU,OAAA,CAAQ,EAAE,IAAA,EAAM,GAAA,CAAI,MAAA,CAAO,IAAA,EAAM,CAAA;AAC/D,MAAA,IAAI,CAAC,GAAA,EAAK,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,WAAA,EAAa,CAAA;AAO5D,MAAA,IAAI,QAAA,GAAW,EAAA;AACf,MAAA,IAAI,OAAA,GAAU,IAAI,OAAA,IAAW,EAAA;AAC7B,MAAA,IAAI,IAAI,KAAA,EAAO;AACb,QAAA,IAAI;AACF,UAAA,MAAM,WAAW,GAAA,CAAI,KAAA,CAAM,aACvB,MAAM,oBAAA,CAAqB,IAAI,KAAA,CAAM,UAAU,CAAA,GAC/C,GAAA,CAAI,MAAM,IAAA,GACV,MAAM,gBAAgB,GAAA,CAAI,KAAA,CAAM,IAAI,CAAA,GACpC,IAAA;AACJ,UAAA,IAAI,QAAA,EAAU;AACZ,YAAA,QAAA,GAAW,SAAA,CAAU,SAAS,IAAI,CAAA;AAClC,YAAA,OAAA,GAAU,GAAA,CAAI,MAAM,OAAA,IAAW,OAAA;AAAA,UACjC;AAAA,QACF,CAAA,CAAA,MAAQ;AAAA,QAER;AAAA,MACF;AACA,MAAA,IAAI,CAAC,QAAA,IAAY,GAAA,CAAI,IAAA,EAAM,IAAA,EAAM;AAC/B,QAAA,QAAA,GAAW,SAAA,CAAU,GAAA,CAAI,IAAA,CAAK,IAAI,CAAA;AAAA,MACpC;AACA,MAAA,MAAM,GAAA,GAAM,QAAA,GAAW,oBAAA,CAAqB,EAAE,QAAA,EAAU,SAAS,SAAA,EAAW,GAAA,CAAI,SAAA,EAAW,CAAA,GAAI,IAAA;AAC/F,MAAA,MAAM,MAAA,GAAS,MAAM,MAAM,eAAA,CAAgB,OAAO,gBAAA,EAAiB,EAAG,GAAG,CAAA,GAAI,IAAA;AAE7E,MAAA,GAAA,CAAI,IAAA,CAAK;AAAA,QACP,UAAA;AAAA,QACA,QAAA,EAAU,KAAK,QAAA,IAAY,CAAA;AAAA,QAC3B,YAAA,EAAc,CAAC,CAAC,GAAA,EAAK,YAAA;AAAA,QACrB,UAAA,EAAY,KAAK,UAAA,IAAc,EAAA;AAAA,QAC/B,KAAA,EAAO;AAAA,OACR,CAAA;AAAA,IACH,CAAC;AAAA,GACH;AAEA,EAAA,CAAA,CAAE,IAAA;AAAA,IACA,oCAAA;AAAA,IACA,YAAA,CAAa,OAAO,GAAA,EAAK,GAAA,KAAQ;AAC/B,MAAA,MAAM,SAAS,mBAAA,EAAoB;AACnC,MAAA,IAAI,CAAC,MAAA,EAAQ;AACX,QAAA,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK;AAAA,UAC1B,KAAA,EAAO,gBAAA;AAAA,UACP,OAAA,EAAS;AAAA,SACV,CAAA;AAAA,MACH;AAEA,MAAA,MAAM,GAAA,GAAM,MAAM,CAAA,CAAE,SAAA,CAAU,OAAA,CAAQ,EAAE,IAAA,EAAM,GAAA,CAAI,MAAA,CAAO,IAAA,EAAM,CAAA;AAC/D,MAAA,IAAI,CAAC,GAAA,EAAK,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,WAAA,EAAa,CAAA;AAC5D,MAAA,MAAM,QAAQ,GAAA,CAAI,KAAA;AAClB,MAAA,IAAI,CAAC,KAAA,EAAO,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,UAAA,EAAY,OAAA,EAAS,uDAAuD,CAAA;AAE7H,MAAA,IAAI,QAAA;AACJ,MAAA,IAAI;AACF,QAAA,IAAI,MAAM,UAAA,EAAY,QAAA,GAAW,MAAM,oBAAA,CAAqB,MAAM,UAAU,CAAA;AAAA,aAAA,IACnE,MAAM,IAAA,EAAM,QAAA,GAAW,MAAM,eAAA,CAAgB,MAAM,IAAI,CAAA;AAAA,aAC3D,OAAO,IAAI,MAAA,CAAO,GAAG,EAAE,IAAA,CAAK,EAAE,KAAA,EAAO,aAAA,EAAe,CAAA;AAAA,MAC3D,SAAS,GAAA,EAAU;AACjB,QAAA,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,KAAK,EAAE,KAAA,EAAO,gBAAA,EAAkB,OAAA,EAAS,MAAA,CAAO,GAAA,EAAK,OAAA,IAAW,GAAG,GAAG,CAAA;AAAA,MAC/F;AAEA,MAAA,MAAM,QAAA,GAAW,SAAA,CAAU,QAAA,CAAS,IAAI,CAAA;AACxC,MAAA,MAAM,UAAA,GAAa,oBAAA,CAAqB,EAAE,QAAA,EAAU,OAAA,EAAS,MAAM,OAAA,EAAS,SAAA,EAAW,GAAA,CAAI,SAAA,EAAW,CAAA;AACtG,MAAA,MAAM,GAAA,GAAM,OAAO,gBAAA,EAAiB;AAGpC,MAAA,MAAM,MAAA,GAAS,MAAM,eAAA,CAAgB,GAAA,EAAK,UAAU,CAAA;AACpD,MAAA,IAAI,MAAA,EAAQ;AACV,QAAA,OAAO,GAAA,CAAI,KAAK,EAAE,MAAA,EAAQ,MAAM,MAAA,EAAQ,OAAA,EAAS,KAAA,EAAO,MAAA,EAAQ,CAAA;AAAA,MAClE;AAKA,MAAA,MAAM,QAAA,GAAW,gBAAgB,MAAA,CAAO,SAAA,EAAW,IAAI,gBAAA,IAAoB,MAAA,CAAO,OAAO,eAAe,CAAA;AACxG,MAAA,IAAI,CAAC,QAAA,EAAU;AACb,QAAA,OAAO,GAAA,CAAI,OAAO,GAAG,CAAA,CAAE,KAAK,oBAAA,CAAqB,MAAA,EAAQ,GAAG,CAAC,CAAA;AAAA,MAC/D;AAGA,MAAA,MAAM,EAAE,OAAA,EAAS,YAAA,EAAa,GAAI,MAAM,OAAO,cAAA,EAAe;AAE9D,MAAA,IAAI;AACF,QAAA,MAAM,SAAS,IAAA,CAAK;AAAA,UAClB,EAAA,EAAI,YAAA;AAAA,UACJ,UAAU,GAAA,CAAI,QAAA;AAAA,UACd,WAAW,GAAA,CAAI,SAAA;AAAA,UACf,OAAA,EAAS,IAAI,OAAA,IAAW,KAAA,CAAA;AAAA,UACxB,SAAS,KAAA,CAAM,OAAA;AAAA;AAAA;AAAA,UAGf,GAAI,IAAI,UAAA,KAAe,WAAA,GAAc,EAAC,GAAI,EAAE,IAAA,EAAM,QAAA,CAAS,IAAA,EAAK;AAAA,UAChE,MAAM,QAAA,CAAS,SAAA;AAAA,UACf,SAAS,EAAC;AAAA,UACV,WAAA,EAAa,EAAE,iBAAA,EAAmB,OAAA;AAAQ,SAC3C,CAAA;AAAA,MACH,SAAS,GAAA,EAAU;AACjB,QAAA,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,KAAK,EAAE,KAAA,EAAO,aAAA,EAAe,OAAA,EAAS,MAAA,CAAO,GAAA,EAAK,OAAA,IAAW,GAAG,GAAG,CAAA;AAAA,MAC5F;AAEA,MAAA,MAAM,OAAO,KAAA,CAAM;AAAA,QACjB,OAAQ,GAAA,CAAY,KAAA;AAAA,QACpB,MAAA,EAAQ,yBAAA;AAAA,QACR,QAAA,EAAU,EAAE,UAAA,EAAY,2BAAA,EAA6B,IAAI,UAAA,EAAY,IAAA,EAAM,IAAI,IAAA,EAAK;AAAA,QACpF,WAAA,EAAa,CAAA,cAAA,EAAiB,YAAY,CAAA,uBAAA,EAA0B,OAAO,CAAA;AAAA,OAC5E,CAAA;AAED,MAAA,GAAA,CAAI,IAAA,CAAK;AAAA,QACP,MAAA,EAAQ,KAAA;AAAA,QACR,MAAA,EAAQ,SAAA;AAAA,QACR,OAAA;AAAA,QACA,UAAA;AAAA,QACA,OAAA,EAAS;AAAA,OACV,CAAA;AAAA,IACH,CAAC;AAAA,GACH;AAEA,EAAA,CAAA,CAAE,GAAA;AAAA,IACA,qCAAA;AAAA,IACA,YAAA,CAAa,OAAO,GAAA,EAAK,GAAA,KAAQ;AAC/B,MAAA,MAAM,SAAS,mBAAA,EAAoB;AACnC,MAAA,IAAI,CAAC,MAAA,EAAQ,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,gBAAA,EAAkB,CAAA;AAEpE,MAAA,MAAM,OAAA,GAAU,MAAA,CAAO,GAAA,CAAI,KAAA,CAAM,WAAW,EAAE,CAAA;AAC9C,MAAA,IAAI,CAAC,OAAA,EAAS,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,mBAAA,EAAqB,OAAA,EAAS,uBAAuB,CAAA;AAExG,MAAA,MAAM,GAAA,GAAM,MAAM,CAAA,CAAE,SAAA,CAAU,OAAA,CAAQ,EAAE,IAAA,EAAM,GAAA,CAAI,MAAA,CAAO,IAAA,EAAM,CAAA;AAC/D,MAAA,IAAI,CAAC,GAAA,EAAK,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,WAAA,EAAa,CAAA;AAC5D,MAAA,MAAM,QAAQ,GAAA,CAAI,KAAA;AAClB,MAAA,IAAI,CAAC,KAAA,EAAO,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,UAAA,EAAY,OAAA,EAAS,2BAA2B,CAAA;AAKjG,MAAA,IAAI,QAAA;AACJ,MAAA,IAAI;AACF,QAAA,IAAI,MAAM,UAAA,EAAY,QAAA,GAAW,MAAM,oBAAA,CAAqB,MAAM,UAAU,CAAA;AAAA,aAAA,IACnE,MAAM,IAAA,EAAM,QAAA,GAAW,MAAM,eAAA,CAAgB,MAAM,IAAI,CAAA;AAAA,aAC3D,OAAO,IAAI,MAAA,CAAO,GAAG,EAAE,IAAA,CAAK,EAAE,KAAA,EAAO,aAAA,EAAe,CAAA;AAAA,MAC3D,SAAS,GAAA,EAAU;AACjB,QAAA,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,KAAK,EAAE,KAAA,EAAO,gBAAA,EAAkB,OAAA,EAAS,MAAA,CAAO,GAAA,EAAK,OAAA,IAAW,GAAG,GAAG,CAAA;AAAA,MAC/F;AACA,MAAA,MAAM,aAAa,oBAAA,CAAqB;AAAA,QACtC,QAAA,EAAU,SAAA,CAAU,QAAA,CAAS,IAAI,CAAA;AAAA,QACjC,SAAS,KAAA,CAAM,OAAA;AAAA,QACf,WAAW,GAAA,CAAI;AAAA,OAChB,CAAA;AAED,MAAA,MAAM,MAAA,GAAS,MAAM,MAAA,CAAO,WAAA,CAAY,OAAO,CAAA;AAC/C,MAAA,IAAI,CAAC,OAAO,KAAA,EAAO;AACjB,QAAA,OAAO,IAAI,IAAA,CAAK,EAAE,QAAQ,SAAA,EAAW,KAAA,EAAO,MAAM,CAAA;AAAA,MACpD;AAEA,MAAA,MAAM,GAAA,GAAM,OAAO,gBAAA,EAAiB;AACpC,MAAA,MAAM,SAAA,GAAY,MAAM,YAAA,CAAa,GAAA,EAAK,EAAE,YAAA,EAAc,GAAA,CAAI,IAAA,EAAM,UAAA,EAAY,OAAA,EAAS,MAAA,EAAQ,CAAA;AACjG,MAAA,MAAM,OAAO,KAAA,CAAM;AAAA,QACjB,OAAQ,GAAA,CAAY,KAAA;AAAA,QACpB,MAAA,EAAQ,4BAAA;AAAA,QACR,QAAA,EAAU,EAAE,UAAA,EAAY,2BAAA,EAA6B,IAAI,UAAA,EAAY,IAAA,EAAM,IAAI,IAAA,EAAK;AAAA,QACpF,aAAa,CAAA,MAAA,EAAS,MAAA,CAAO,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAC,CAAA;AAAA,OAC9C,CAAA;AACD,MAAA,GAAA,CAAI,KAAK,EAAE,MAAA,EAAQ,OAAA,EAAS,KAAA,EAAO,WAAW,CAAA;AAAA,IAChD,CAAC;AAAA,GACH;AAEA,EAAA,CAAA,CAAE,IAAA;AAAA,IACA,uBAAA;AAAA,IACA,YAAA,CAAa,OAAO,GAAA,EAAK,GAAA,KAAQ;AAC/B,MAAA,MAAM,GAAA,GAAM,MAAM,CAAA,CAAE,SAAA,CAAU,OAAA,CAAQ,EAAE,IAAA,EAAM,GAAA,CAAI,MAAA,CAAO,IAAA,EAAM,CAAA;AAC/D,MAAA,IAAI,CAAC,GAAA,EAAK,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,WAAA,EAAa,CAAA;AAK5D,MAAA,MAAM,IAAA,GAAQ,GAAA,CAAI,IAAA,IAAQ,EAAC;AAS3B,MAAA,MAAM,UAAU,IAAA,CAAK,OAAA,IAAW,IAAI,KAAA,EAAO,OAAA,IAAW,IAAI,OAAA,IAAW,EAAA;AACrE,MAAA,MAAM,YAAY,IAAA,CAAK,SAAA,IAAa,IAAI,KAAA,EAAO,SAAA,IAAa,IAAI,SAAA,IAAa,EAAA;AAC7E,MAAA,MAAM,IAAA,GAAO,KAAK,IAAA,IAAQ,GAAA,CAAI,OAAO,IAAA,IAAQ,GAAA,CAAI,MAAM,IAAA,IAAQ,EAAA;AAC/D,MAAA,MAAM,UAAA,GAAa,IAAA,CAAK,UAAA,KAAe,MAAA,GAAY,IAAA,CAAK,UAAA,GAAc,GAAA,CAAI,KAAA,EAAO,UAAA,IAAc,GAAA,CAAI,IAAA,EAAM,UAAA,IAAc,IAAA;AACvH,MAAA,MAAM,SAAA,GAAY,IAAA,CAAK,SAAA,IAAa,GAAA,CAAI,SAAA;AAGxC,MAAA,MAAM,IAAA,GAAO,KAAK,IAAA,KAAS,WAAA,IAAe,KAAK,IAAA,KAAS,eAAA,GAAkB,IAAA,CAAK,IAAA,GAAO,GAAA,CAAI,IAAA;AAE1F,MAAA,IAAI,IAAA,GAAO,EAAA;AACX,MAAA,IAAI,SAAA,GAAY,EAAA;AAChB,MAAA,IAAI;AACF,QAAA,IAAI,UAAA,EAAY;AACd,UAAA,MAAM,QAAA,GAAW,MAAM,oBAAA,CAAqB,UAAU,CAAA;AACtD,UAAA,IAAA,GAAO,QAAA,CAAS,IAAA;AAChB,UAAA,SAAA,GAAY,QAAA,CAAS,SAAA;AAAA,QACvB,WAAW,IAAA,EAAM;AACf,UAAA,MAAM,QAAA,GAAW,MAAM,eAAA,CAAgB,IAAI,CAAA;AAC3C,UAAA,IAAA,GAAO,QAAA,CAAS,IAAA;AAChB,UAAA,SAAA,GAAY,QAAA,CAAS,SAAA;AAAA,QACvB;AAAA,MACF,SAAS,GAAA,EAAU;AACjB,QAAA,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK;AAAA,UAC1B,MAAA,EAAQ,CAAC,EAAE,IAAA,EAAM,kBAAkB,QAAA,EAAU,OAAA,EAAS,OAAA,EAAS,CAAA,eAAA,EAAkB,OAAO,GAAA,EAAK,OAAA,IAAW,GAAG,CAAC,IAAI,CAAA;AAAA,UAChH,UAAU,EAAC;AAAA,UACX,OAAO,EAAC;AAAA,UACR,aAAA,EAAe;AAAA,SAChB,CAAA;AAAA,MACH;AAMA,MAAA,IAAI,CAAC,QAAQ,OAAO,GAAA,CAAI,MAAM,IAAA,KAAS,QAAA,EAAU,IAAA,GAAO,GAAA,CAAI,IAAA,CAAK,IAAA;AACjE,MAAA,IAAI,CAAC,aAAa,OAAO,GAAA,CAAI,MAAM,SAAA,KAAc,QAAA,EAAU,SAAA,GAAY,GAAA,CAAI,IAAA,CAAK,SAAA;AAEhF,MAAA,MAAM,IAAA,GAAO,YAAA;AAAA,QACX,EAAE,SAAS,SAAA,EAAW,IAAA,EAAM,YAAY,IAAA,EAAM,SAAA,EAAW,MAAM,SAAA,EAAU;AAAA,QACzE,EAAE,aAAA,EAAe,MAAA,CAAO,MAAA,CAAO,aAAA,EAAe,gBAAgB,UAAA;AAAW,OAC3E;AACA,MAAA,GAAA,CAAI,KAAK,EAAE,GAAG,IAAA,EAAM,aAAA,EAAe,OAAO,CAAA;AAAA,IAC5C,CAAC;AAAA,GACH;AAEA,EAAA,CAAA,CAAE,IAAA;AAAA,IACA,0BAAA;AAAA,IACA,YAAA,CAAa,OAAO,GAAA,EAAK,GAAA,KAAQ;AAC/B,MAAA,MAAM,GAAA,GAAM,MAAM,CAAA,CAAE,SAAA,CAAU,OAAA,CAAQ,EAAE,IAAA,EAAM,GAAA,CAAI,MAAA,CAAO,IAAA,EAAM,CAAA;AAC/D,MAAA,IAAI,CAAC,GAAA,EAAK,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,WAAA,EAAa,CAAA;AAC5D,MAAA,MAAM,QAAQ,GAAA,CAAI,KAAA;AAClB,MAAA,IAAI,CAAC,KAAA,EAAO,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,UAAA,EAAY,CAAA;AAK7D,MAAA,MAAM,WAAA,GAAc,qBAAqB,GAAA,CAAI,SAAA,EAAW,IAAI,IAAA,EAAM,MAAA,CAAO,OAAO,aAAa,CAAA;AAC7F,MAAA,IAAI,CAAC,YAAY,EAAA,EAAI;AACnB,QAAA,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK;AAAA,UAC1B,KAAA,EAAO,uBAAA;AAAA,UACP,MAAM,WAAA,CAAY,IAAA;AAAA,UAClB,SAAS,WAAA,CAAY;AAAA,SACtB,CAAA;AAAA,MACH;AAEA,MAAA,IAAI,QAAA;AACJ,MAAA,IAAI;AACF,QAAA,IAAI,MAAM,UAAA,EAAY;AACpB,UAAA,QAAA,GAAW,MAAM,oBAAA,CAAqB,KAAA,CAAM,UAAU,CAAA;AAAA,QACxD,CAAA,MAAA,IAAW,MAAM,IAAA,EAAM;AACrB,UAAA,QAAA,GAAW,MAAM,eAAA,CAAgB,KAAA,CAAM,IAAI,CAAA;AAAA,QAC7C,CAAA,MAAO;AACL,UAAA,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,aAAA,EAAe,OAAA,EAAS,yCAAA,EAA2C,CAAA;AAAA,QAC1G;AAAA,MACF,SAAS,GAAA,EAAU;AAGjB,QAAA,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK;AAAA,UAC1B,KAAA,EAAO,gBAAA;AAAA,UACP,OAAA,EAAS,MAAA,CAAO,GAAA,EAAK,OAAA,IAAW,GAAG,CAAA;AAAA,UACnC,IAAA,EAAM;AAAA,YACJ,MAAA,EAAQ,CAAC,EAAE,IAAA,EAAM,kBAAkB,QAAA,EAAU,OAAA,EAAS,OAAA,EAAS,CAAA,eAAA,EAAkB,OAAO,GAAA,EAAK,OAAA,IAAW,GAAG,CAAC,IAAI,CAAA;AAAA,YAChH,UAAU,EAAC;AAAA,YACX,OAAO;AAAC;AACV,SACD,CAAA;AAAA,MACH;AAEA,MAAA,MAAM,IAAA,GAAO,YAAA;AAAA,QACX;AAAA,UACE,SAAS,KAAA,CAAM,OAAA;AAAA,UACf,WAAW,KAAA,CAAM,SAAA;AAAA,UACjB,IAAA,EAAM,MAAM,IAAA,IAAQ,EAAA;AAAA,UACpB,YAAY,KAAA,CAAM,UAAA;AAAA,UAClB,MAAM,QAAA,CAAS,IAAA;AAAA,UACf,WAAW,QAAA,CAAS,SAAA;AAAA,UACpB,MAAM,GAAA,CAAI,IAAA;AAAA,UACV,WAAW,GAAA,CAAI;AAAA,SACjB;AAAA,QACA,EAAE,aAAA,EAAe,MAAA,CAAO,MAAA,CAAO,aAAA,EAAe,gBAAgB,UAAA;AAAW,OAC3E;AAEA,MAAA,IAAI,IAAA,CAAK,MAAA,CAAO,MAAA,GAAS,CAAA,EAAG;AAC1B,QAAA,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK;AAAA,UAC1B,KAAA,EAAO,aAAA;AAAA,UACP,OAAA,EAAS,CAAA,4BAAA,EAA+B,IAAA,CAAK,MAAA,CAAO,MAAM,CAAA,kBAAA,CAAA;AAAA,UAC1D;AAAA,SACD,CAAA;AAAA,MACH;AAMA,MAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,GAAA,CAAI,IAAA,EAAM,gBAAgB,CAAA;AACjD,MAAA,IAAI,CAAC,MAAA,EAAQ;AACX,QAAA,MAAM,IAAA,GAAO,MAAM,sBAAA,CAAuB,MAAA,CAAO,kBAAiB,EAAG;AAAA,UACnE,QAAA,EAAU,SAAA,CAAU,QAAA,CAAS,IAAI,CAAA;AAAA,UACjC,SAAS,KAAA,CAAM,OAAA;AAAA,UACf,WAAW,GAAA,CAAI;AAAA,SAChB,CAAA;AACD,QAAA,IAAI,CAAC,KAAK,OAAA,EAAS;AACjB,UAAA,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK;AAAA,YAC1B,KAAA,EAAO,qBAAA;AAAA,YACP,MAAM,IAAA,CAAK,IAAA;AAAA,YACX,SAAS,IAAA,CAAK,MAAA;AAAA,YACd,OAAO,IAAA,CAAK,KAAA;AAAA,YACZ,IAAA,EACE,IAAA,CAAK,IAAA,KAAS,UAAA,GACV,mJAAA,GACA;AAAA,WACP,CAAA;AAAA,QACH;AAAA,MACF;AAEA,MAAA,MAAM,GAAA,uBAAU,IAAA,EAAK;AACrB,MAAA,MAAM,WAAA,GAAc,MAAM,CAAA,CAAE,gBAAA,CAAiB,cAAA,CAAe,EAAE,UAAA,EAAY,GAAA,CAAI,GAAA,EAAK,CAAA,GAAI,CAAA;AACvF,MAAA,MAAM,CAAA,CAAE,iBAAiB,SAAA,CAAU;AAAA,QACjC,YAAY,GAAA,CAAI,GAAA;AAAA,QAChB,OAAA,EAAS,WAAA;AAAA,QACT,MAAM,KAAA,CAAM,IAAA;AAAA,QACZ,MAAM,QAAA,CAAS,IAAA;AAAA,QACf,WAAW,QAAA,CAAS,SAAA;AAAA,QACpB,SAAS,KAAA,CAAM,OAAA;AAAA,QACf,WAAW,KAAA,CAAM,SAAA;AAAA,QACjB,WAAA,EAAa,GAAA;AAAA,QACb,aAAc,GAAA,CAAY;AAAA,OAC3B,CAAA;AAED,MAAA,MAAM,EAAE,SAAA,CAAU,SAAA;AAAA,QAChB,EAAE,GAAA,EAAK,GAAA,CAAI,GAAA,EAAI;AAAA,QACf;AAAA,UACE,IAAA,EAAM;AAAA,YACJ,SAAS,KAAA,CAAM,OAAA;AAAA,YACf,WAAW,KAAA,CAAM,SAAA;AAAA,YACjB,IAAA,EAAM;AAAA,cACJ,MAAM,KAAA,CAAM,IAAA;AAAA,cACZ,YAAY,KAAA,CAAM,UAAA;AAAA,cAClB,MAAM,QAAA,CAAS,IAAA;AAAA,cACf,WAAW,QAAA,CAAS,SAAA;AAAA,cACpB,UAAA,EAAY;AAAA,aACd;AAAA,YACA,KAAA,EAAO,IAAA;AAAA,YACP,WAAA,EAAa,GAAA;AAAA,YACb,aAAc,GAAA,CAAY,KAAA;AAAA,YAC1B,SAAA,EAAW;AAAA;AACb;AACF,OACF;AACA,MAAA,MAAM,OAAO,KAAA,CAAM;AAAA,QACjB,OAAQ,GAAA,CAAY,KAAA;AAAA,QACpB,MAAA,EAAQ,kBAAA;AAAA,QACR,QAAA,EAAU,EAAE,UAAA,EAAY,kBAAA,EAAoB,IAAI,GAAA,CAAI,GAAA,EAAK,IAAA,EAAM,GAAA,CAAI,IAAA,EAAK;AAAA,QACxE,WAAA,EAAa,cAAc,WAAW,CAAA;AAAA,OACvC,CAAA;AACD,MAAA,OAAO,IAAI,IAAA,CAAK;AAAA,QACd,EAAA,EAAI,IAAA;AAAA,QACJ,OAAA,EAAS,WAAA;AAAA,QACT,UAAU,QAAA,CAAS,MAAA;AAAA,QACnB;AAAA;AAAA,OACD,CAAA;AAAA,IACH,CAAC;AAAA,GACH;AAEA,EAAA,CAAA,CAAE,IAAA;AAAA,IACA,0BAAA;AAAA,IACA,YAAA,CAAa,OAAO,GAAA,EAAK,GAAA,KAAQ;AAC/B,MAAA,MAAM,GAAA,GAAM,MAAM,CAAA,CAAE,SAAA,CAAU,OAAA,CAAQ,EAAE,IAAA,EAAM,GAAA,CAAI,MAAA,CAAO,IAAA,EAAM,CAAA;AAC/D,MAAA,IAAI,CAAC,GAAA,EAAK,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,WAAA,EAAa,CAAA;AAE5D,MAAA,MAAM,QAAA,GAAW,GAAA,CAAI,IAAA,EAAM,QAAA,KAAa,KAAA;AACxC,MAAA,IAAI,IAAA,GAAO,EAAA;AACX,MAAA,IAAI,SAAA,GAAY,EAAA;AAChB,MAAA,IAAI,QAAA,IAAY,IAAI,KAAA,EAAO;AACzB,QAAA,MAAM,QAAA,GAAW,GAAA,CAAI,KAAA,CAAM,UAAA,GACvB,MAAM,oBAAA,CAAqB,GAAA,CAAI,KAAA,CAAM,UAAU,IAC/C,MAAM,eAAA,CAAgB,GAAA,CAAI,KAAA,CAAM,QAAQ,kCAAkC,CAAA;AAC9E,QAAA,IAAA,GAAO,QAAA,CAAS,IAAA;AAChB,QAAA,SAAA,GAAY,QAAA,CAAS,SAAA;AAAA,MACvB,CAAA,MAAO;AACL,QAAA,IAAI,CAAC,GAAA,CAAI,IAAA,EAAM,IAAA,EAAM;AACnB,UAAA,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,eAAA,EAAiB,OAAA,EAAS,sCAAA,EAAwC,CAAA;AAAA,QACzG;AACA,QAAA,IAAA,GAAO,IAAI,IAAA,CAAK,IAAA;AAChB,QAAA,SAAA,GAAY,IAAI,IAAA,CAAK,SAAA;AAAA,MACvB;AAKA,MAAA,IAAI,OAAA;AACJ,MAAA,MAAM,SAAA,GAAY,OAAO,GAAA,CAAI,IAAA,EAAM,cAAc,QAAA,GAAW,GAAA,CAAI,KAAK,SAAA,GAAY,IAAA;AACjF,MAAA,IAAI,SAAA,EAAW;AACb,QAAA,MAAM,KAAA,GAAQ,MAAM,MAAA,CAAO,OAAA,CAAQ,QAAQ,SAAS,CAAA;AACpD,QAAA,IAAI,CAAC,KAAA,EAAO,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,mBAAA,EAAqB,SAAA,EAAW,CAAA;AACjF,QAAA,OAAA,GAAU,KAAA;AAAA,MACZ,CAAA,MAAO;AACL,QAAA,OAAA,GAAU,GAAA,CAAI,MAAM,aAAA,IAAiB;AAAA,UACnC,UAAA,EAAY,iBAAA;AAAA,UACZ,KAAA,EAAO,qBAAA;AAAA,UACP,MAAM,EAAC;AAAA,UACP,MAAA,EAAQ,EAAE,SAAA,EAAW,MAAA;AAAO,SAC9B;AAAA,MACF;AAIA,MAAA,MAAM,eAAA,GACJ,GAAA,CAAI,IAAA,EAAM,eAAA,IAAmB,OAAO,GAAA,CAAI,IAAA,CAAK,eAAA,KAAoB,QAAA,GAC5D,GAAA,CAAI,IAAA,CAAK,eAAA,GACV,MAAA;AAEN,MAAA,IAAI,WAAoC,EAAC;AACzC,MAAA,IAAI;AACF,QAAA,QAAA,GAAW,MAAM,WAAA,CAAY,MAAA,CAAO,MAAA,CAAO,aAAa,OAAA,EAAS;AAAA,UAC/D,MAAA,EAAQ,SAAA;AAAA,UACR,cAAc,GAAA,CAAI,IAAA;AAAA,UAClB;AAAA,SACD,CAAA;AAAA,MACH,SAAS,GAAA,EAAU;AACjB,QAAA,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK;AAAA,UAC1B,KAAA,EAAO,qBAAA;AAAA,UACP,SAAS,CAAA,2BAAA,EAA8B,MAAA,CAAO,GAAA,EAAK,OAAA,IAAW,GAAG,CAAC,CAAA;AAAA,SACnE,CAAA;AAAA,MACH;AAEA,MAAA,MAAM,SAAA,GAAY;AAAA,QAChB,GAAG,QAAA;AAAA,QACH,OAAA;AAAA,QACA,IAAA,EAAM,GAAA,CAAI,IAAA,EAAM,IAAA,IAAQ,EAAC;AAAA,QACzB,KAAA,EAAO,mBAAmB,EAAC;AAAA,QAC3B,cAAA,EAAgB,CAAA,EAAG,MAAA,CAAO,MAAA,CAAO,SAAS,CAAA,gBAAA,CAAA;AAAA,QAC1C,aAAA,EAAe,OAAO,MAAA,CAAO;AAAA,OAC/B;AAEA,MAAA,MAAM,UAAA,GAAa,EAAE,GAAG,GAAA,EAAK,IAAA,EAAM,EAAE,GAAG,GAAA,CAAI,IAAA,EAAM,IAAA,EAAM,SAAA,EAAU,EAAE;AACpE,MAAA,MAAM,QAAA,GAAW,MAAM,cAAA,CAAe,UAAA,EAAmB,SAAA,EAAW,EAAE,OAAA,EAAS,MAAA,CAAO,MAAA,CAAO,iBAAA,EAAmB,CAAA;AAChH,MAAA,OAAO,IAAI,IAAA,CAAK;AAAA,QACd,SAAS,QAAA,CAAS,OAAA;AAAA,QAClB,WAAW,QAAA,CAAS,SAAA;AAAA,QACpB,MAAM,QAAA,CAAS,IAAA;AAAA,QACf,WAAW,QAAA,CAAS,SAAA;AAAA,QACpB,SAAS,EAAE,UAAA,EAAY,QAAQ,UAAA,EAAY,KAAA,EAAO,QAAQ,KAAA;AAAM,OACjE,CAAA;AAAA,IACH,CAAC;AAAA,GACH;AAEA,EAAA,CAAA,CAAE,IAAA;AAAA,IACA,4BAAA;AAAA,IACA,YAAA,CAAa,OAAO,GAAA,EAAK,GAAA,KAAQ;AAC/B,MAAA,MAAM,EAAE,IAAI,UAAA,EAAY,SAAA,EAAW,iBAAgB,GAAI,GAAA,CAAI,QAAQ,EAAC;AACpE,MAAA,IAAI,CAAC,EAAA,EAAI,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,aAAA,EAAe,CAAA;AAC7D,MAAA,MAAM,GAAA,GAAM,MAAM,CAAA,CAAE,SAAA,CAAU,OAAA,CAAQ,EAAE,IAAA,EAAM,GAAA,CAAI,MAAA,CAAO,IAAA,EAAM,CAAA;AAC/D,MAAA,IAAI,CAAC,GAAA,EAAK,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,WAAA,EAAa,CAAA;AAI5D,MAAA,IAAI,OAAA;AACJ,MAAA,IAAI,OAAO,SAAA,KAAc,QAAA,IAAY,SAAA,EAAW;AAC9C,QAAA,MAAM,KAAA,GAAQ,MAAM,MAAA,CAAO,OAAA,CAAQ,QAAQ,SAAS,CAAA;AACpD,QAAA,IAAI,CAAC,KAAA,EAAO,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,mBAAA,EAAqB,SAAA,EAAW,CAAA;AACjF,QAAA,OAAA,GAAU,EAAE,GAAG,KAAA,EAAO,KAAA,EAAO,EAAA,EAAG;AAAA,MAClC,CAAA,MAAO;AACL,QAAA,OAAA,GAAU,YAAY,OAAA,IAAW;AAAA,UAC/B,UAAA,EAAY,gBAAA;AAAA,UACZ,KAAA,EAAO,EAAA;AAAA,UACP,MAAM,EAAC;AAAA,UACP,MAAA,EAAQ,EAAE,SAAA,EAAW,MAAA;AAAO,SAC9B;AACA,QAAA,OAAA,CAAQ,KAAA,GAAQ,EAAA;AAAA,MAClB;AAEA,MAAA,MAAM,OAAA,GACJ,eAAA,IAAmB,OAAO,eAAA,KAAoB,WACzC,eAAA,GACD,MAAA;AAEN,MAAA,IAAI,WAAoC,EAAC;AACzC,MAAA,IAAI;AACF,QAAA,QAAA,GAAW,MAAM,WAAA,CAAY,MAAA,CAAO,MAAA,CAAO,aAAa,OAAA,EAAS;AAAA,UAC/D,MAAA,EAAQ,MAAA;AAAA,UACR,cAAc,GAAA,CAAI,IAAA;AAAA,UAClB,eAAA,EAAiB;AAAA,SAClB,CAAA;AAAA,MACH,SAAS,GAAA,EAAU;AACjB,QAAA,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK;AAAA,UAC1B,KAAA,EAAO,qBAAA;AAAA,UACP,SAAS,CAAA,2BAAA,EAA8B,MAAA,CAAO,GAAA,EAAK,OAAA,IAAW,GAAG,CAAC,CAAA;AAAA,SACnE,CAAA;AAAA,MACH;AAEA,MAAA,MAAM,SAAA,GAAY;AAAA,QAChB,GAAG,QAAA;AAAA,QACH,OAAA;AAAA,QACA,IAAA,EAAM,UAAA,EAAY,IAAA,IAAQ,EAAC;AAAA,QAC3B,KAAA,EAAO,WAAW,EAAC;AAAA,QACnB,cAAA,EAAgB,CAAA,EAAG,MAAA,CAAO,MAAA,CAAO,SAAS,CAAA,aAAA,CAAA;AAAA,QAC1C,aAAA,EAAe,OAAO,MAAA,CAAO;AAAA,OAC/B;AACA,MAAA,MAAM,QAAA,GAAW,MAAM,cAAA,CAAe,GAAA,EAAY,SAAA,EAAW,EAAE,OAAA,EAAS,MAAA,CAAO,MAAA,CAAO,iBAAA,EAAmB,CAAA;AACzG,MAAA,MAAM,QAAA,GAAW,aAAA,CAAc,QAAA,CAAS,IAAA,EAAM;AAAA,QAC5C,MAAA,EAAQ,CAAA,KAAA,EAAQ,IAAA,CAAK,GAAA,EAAK,CAAA,CAAA;AAAA,QAC1B,SAAA,EAAW,OAAO,MAAA,CAAO,SAAA;AAAA,QACzB,UAAA,EAAY,KAAA;AAAA,QACZ,WAAA,EAAa;AAAA,OACd,CAAA;AAED,MAAA,MAAM,QAAA,GAAW,gBAAgB,MAAA,CAAO,SAAA,EAAW,IAAI,gBAAA,IAAoB,MAAA,CAAO,OAAO,eAAe,CAAA;AACxG,MAAA,IAAI,CAAC,QAAA,EAAU;AACb,QAAA,OAAO,GAAA,CAAI,OAAO,GAAG,CAAA,CAAE,KAAK,oBAAA,CAAqB,MAAA,EAAQ,GAAG,CAAC,CAAA;AAAA,MAC/D;AACA,MAAA,MAAM,MAAA,GAAS,MAAM,QAAA,CAAS,IAAA,CAAK;AAAA,QACjC,EAAA;AAAA,QACA,UAAU,QAAA,CAAS,QAAA;AAAA,QACnB,WAAW,QAAA,CAAS,SAAA;AAAA,QACpB,OAAA,EAAS,CAAA,OAAA,EAAU,QAAA,CAAS,OAAO,CAAA,CAAA;AAAA;AAAA;AAAA,QAGnC,GAAI,IAAI,UAAA,KAAe,WAAA,GAAc,EAAC,GAAI,EAAE,IAAA,EAAM,QAAA,CAAS,IAAA,EAAK;AAAA,QAChE,MAAM,QAAA,CAAS;AAAA,OAChB,CAAA;AACD,MAAA,MAAM,OAAO,KAAA,CAAM;AAAA,QACjB,OAAQ,GAAA,CAAY,KAAA;AAAA,QACpB,MAAA,EAAQ,oBAAA;AAAA,QACR,UAAU,EAAE,UAAA,EAAY,kBAAA,EAAoB,IAAA,EAAM,IAAI,IAAA,EAAK;AAAA,QAC3D,WAAA,EAAa,MAAM,EAAE,CAAA;AAAA,OACtB,CAAA;AAGD,MAAA,OAAO,GAAA,CAAI,KAAK,EAAE,EAAA,EAAI,MAAM,UAAA,EAAY,MAAA,CAAO,YAAY,CAAA;AAAA,IAC7D,CAAC;AAAA,GACH;AAGA,EAAA,CAAA,CAAE,IAAA;AAAA,IACA,aAAA;AAAA,IACA,YAAA,CAAa,OAAO,GAAA,EAAK,GAAA,KAAQ;AAC/B,MAAA,MAAM,EAAE,MAAM,IAAA,EAAM,YAAA,EAAc,mBAAkB,GAAI,GAAA,CAAI,QAAQ,EAAC;AACrE,MAAA,IAAI,CAAC,IAAA,IAAQ,CAAC,IAAA,IAAQ,CAAC,YAAA,EAAc;AACnC,QAAA,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,mBAAA,EAAqB,OAAA,EAAS,mCAAA,EAAqC,CAAA;AAAA,MAC1G;AACA,MAAA,MAAM,GAAA,uBAAU,IAAA,EAAK;AACrB,MAAA,IAAI;AACF,QAAA,MAAM,CAAA,CAAE,WAAW,SAAA,CAAU;AAAA,UAC3B,IAAA;AAAA,UACA,IAAA;AAAA,UACA,YAAA;AAAA,UACA,iBAAA,EAAmB,iBAAA,IAAqB,EAAE,OAAA,EAAS,CAAC,EAAE,IAAA,EAAM,oBAAA,EAAsB,MAAA,EAAQ,YAAA,EAAc,CAAA,EAAE;AAAA,UAC1G,MAAA,EAAQ,OAAA;AAAA,UACR,WAAA,EAAa,IAAA;AAAA,UACb,SAAA,EAAW,IAAA;AAAA,UACX,WAAA,EAAa,IAAA;AAAA,UACb,oBAAA,EAAsB,IAAA;AAAA,UACtB,cAAA,EAAgB,IAAA;AAAA,UAChB,WAAA,EAAa,IAAA;AAAA,UACb,WAAA,EAAa,IAAA;AAAA,UACb,cAAA,EAAgB,IAAA;AAAA,UAChB,KAAA,EAAO,EAAE,IAAA,EAAM,CAAA,EAAG,WAAW,CAAA,EAAG,MAAA,EAAQ,CAAA,EAAG,OAAA,EAAS,GAAG,OAAA,EAAS,CAAA,EAAG,UAAA,EAAY,CAAA,EAAG,cAAc,CAAA,EAAE;AAAA,UAClG,SAAA,EAAW,GAAA;AAAA,UACX,WAAY,GAAA,CAAY,KAAA;AAAA,UACxB,SAAA,EAAW;AAAA,SACL,CAAA;AAAA,MACV,SAAS,GAAA,EAAU;AACjB,QAAA,IAAI,GAAA,EAAK,IAAA,KAAS,IAAA,EAAO,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,YAAA,EAAc,CAAA;AAC5E,QAAA,MAAM,GAAA;AAAA,MACR;AACA,MAAA,MAAM,OAAO,KAAA,CAAM;AAAA,QACjB,OAAQ,GAAA,CAAY,KAAA;AAAA,QACpB,MAAA,EAAQ,kBAAA;AAAA,QACR,QAAA,EAAU,EAAE,UAAA,EAAY,mBAAA,EAAqB,IAAA;AAAK,OACnD,CAAA;AACD,MAAA,OAAO,IAAI,IAAA,CAAK,EAAE,EAAA,EAAI,IAAA,EAAM,MAAM,CAAA;AAAA,IACpC,CAAC;AAAA,GACH;AAEA,EAAA,CAAA,CAAE,KAAA;AAAA,IACA,mBAAA;AAAA,IACA,YAAA,CAAa,OAAO,GAAA,EAAK,GAAA,KAAQ;AAC/B,MAAA,MAAM,CAAA,GAAI,MAAM,CAAA,CAAE,UAAA,CAAW,OAAA,CAAQ,EAAE,IAAA,EAAM,GAAA,CAAI,MAAA,CAAO,IAAA,EAAM,CAAA;AAC9D,MAAA,IAAI,CAAC,CAAA,EAAG,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,WAAA,EAAa,CAAA;AAC1D,MAAA,IAAI,CAAA,CAAE,MAAA,KAAW,OAAA,EAAS,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,WAAA,EAAa,CAAA;AAC5E,MAAA,MAAM,EAAE,IAAA,EAAM,YAAA,EAAc,mBAAkB,GAAI,GAAA,CAAI,QAAQ,EAAC;AAC/D,MAAA,MAAM,GAAA,GAA+B,EAAE,SAAA,kBAAW,IAAI,MAAK,EAAE;AAC7D,MAAA,IAAI,OAAO,IAAA,KAAS,QAAA,EAAU,GAAA,CAAI,IAAA,GAAO,IAAA;AACzC,MAAA,IAAI,OAAO,YAAA,KAAiB,QAAA,EAAU,GAAA,CAAI,YAAA,GAAe,YAAA;AACzD,MAAA,IAAI,iBAAA,MAAuB,iBAAA,GAAoB,iBAAA;AAC/C,MAAA,MAAM,CAAA,CAAE,UAAA,CAAW,SAAA,CAAU,EAAE,GAAA,EAAK,CAAA,CAAE,GAAA,EAAI,EAAG,EAAE,IAAA,EAAM,GAAA,EAAK,CAAA;AAC1D,MAAA,OAAO,GAAA,CAAI,IAAA,CAAK,EAAE,EAAA,EAAI,MAAM,CAAA;AAAA,IAC9B,CAAC;AAAA,GACH;AAEA,EAAA,CAAA,CAAE,IAAA;AAAA,IACA,iCAAA;AAAA,IACA,YAAA,CAAa,OAAO,GAAA,EAAK,GAAA,KAAQ;AAC/B,MAAA,MAAM,iBAAA,GAAoB,IAAI,IAAA,EAAM,iBAAA;AACpC,MAAA,IAAI,CAAC,iBAAA,EAAmB,OAAA,EAAS,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,kBAAA,EAAoB,CAAA;AAC1F,MAAA,MAAM,EAAA,GAAK,KAAK,GAAA,EAAI;AAQpB,MAAA,MAAM,aAAkB,EAAC;AACzB,MAAA,KAAA,MAAW,CAAA,IAAK,kBAAkB,OAAA,EAAS;AACzC,QAAA,IAAI,CAAA,CAAE,IAAA,KAAS,QAAA,EAAU,UAAA,CAAW,SAAS,CAAA,CAAE,GAAA;AAC/C,QAAA,IAAI,CAAA,CAAE,IAAA,KAAS,aAAA,EAAe,UAAA,CAAW,WAAA,GAAc,EAAE,KAAA,EAAO,CAAA,CAAE,KAAA,EAAO,KAAA,EAAO,CAAA,CAAE,KAAA,EAAM;AAAA,MAC1F;AACA,MAAA,MAAM,gBAAA,GAAmB,kBAAkB,OAAA,CAAQ,IAAA;AAAA,QAAK,CAAC,CAAA,KACvD,CAAC,oBAAA,EAAsB,cAAc,eAAA,EAAiB,WAAA,EAAa,QAAA,EAAU,WAAA,EAAa,iBAAA,EAAmB,kBAAkB,CAAA,CAAE,QAAA,CAAS,EAAE,IAAI;AAAA,OAClJ;AACA,MAAA,MAAM,UAAA,GAAa,MAAM,MAAA,CAAO,OAAA,CAAQ,MAAM,UAAU,CAAA;AACxD,MAAA,OAAO,IAAI,IAAA,CAAK;AAAA,QACd,UAAA;AAAA,QACA,WAAA,EAAa,gBAAA;AAAA,QACb,UAAA,EAAY,IAAA,CAAK,GAAA,EAAI,GAAI;AAAA,OAC1B,CAAA;AAAA,IACH,CAAC;AAAA,GACH;AAEA,EAAA,CAAA,CAAE,IAAA;AAAA,IACA,4BAAA;AAAA,IACA,YAAA,CAAa,OAAO,GAAA,EAAK,GAAA,KAAQ;AAC/B,MAAA,MAAM,CAAA,GAAI,MAAM,CAAA,CAAE,UAAA,CAAW,OAAA,CAAQ,EAAE,IAAA,EAAM,GAAA,CAAI,MAAA,CAAO,IAAA,EAAM,CAAA;AAC9D,MAAA,IAAI,CAAC,CAAA,EAAG,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,WAAA,EAAa,CAAA;AAC1D,MAAA,IAAI,CAAA,CAAE,MAAA,KAAW,OAAA,EAAS,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,WAAA,EAAa,CAAA;AAC5E,MAAA,MAAM,EAAE,WAAA,EAAa,cAAA,EAAgB,0BAAyB,GAAI,GAAA,CAAI,QAAQ,EAAC;AAC/E,MAAA,IAAI,CAAC,WAAA,EAAa,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,sBAAA,EAAwB,CAAA;AAC/E,MAAA,MAAM,SAAA,GAAY,IAAI,IAAA,CAAK,WAAW,CAAA;AACtC,MAAA,IAAI,MAAA,CAAO,KAAA,CAAM,SAAA,CAAU,OAAA,EAAS,CAAA,EAAG,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,mBAAmB,CAAA;AAE/F,MAAA,MAAM,SAAA,GAAY,OAAO,MAAA,CAAO,8BAAA;AAChC,MAAA,IAAI,OAAO,mBAAmB,QAAA,EAAU;AACtC,QAAA,OAAO,GAAA,CAAI,OAAO,GAAG,CAAA,CAAE,KAAK,EAAE,KAAA,EAAO,2BAA2B,CAAA;AAAA,MAClE;AAEA,MAAA,MAAM,GAAA,GAA+B;AAAA,QACnC,MAAA,EAAQ,WAAA;AAAA,QACR,WAAA,EAAa,SAAA;AAAA,QACb,cAAA;AAAA,QACA,WAAA,sBAAiB,IAAA,EAAK;AAAA,QACtB,aAAc,GAAA,CAAY,KAAA;AAAA,QAC1B,SAAA,sBAAe,IAAA;AAAK,OACtB;AACA,MAAA,IAAI,wBAAA,MAA8B,wBAAA,GAA2B,IAAA;AAE7D,MAAA,MAAM,CAAA,CAAE,UAAA,CAAW,SAAA,CAAU,EAAE,GAAA,EAAK,CAAA,CAAE,GAAA,EAAI,EAAG,EAAE,IAAA,EAAM,GAAA,EAAK,CAAA;AAC1D,MAAA,MAAM,OAAO,KAAA,CAAM;AAAA,QACjB,OAAQ,GAAA,CAAY,KAAA;AAAA,QACpB,MAAA,EAAQ,oBAAA;AAAA,QACR,QAAA,EAAU,EAAE,UAAA,EAAY,mBAAA,EAAqB,IAAI,CAAA,CAAE,GAAA,EAAK,IAAA,EAAM,CAAA,CAAE,IAAA,EAAK;AAAA,QACrE,WAAA,EAAa,gBAAgB,SAAA,CAAU,WAAA,EAAa,CAAA,qBAAA,EAAqB,cAAc,mBAAgB,SAAS,CAAA;AAAA,OACjH,CAAA;AACD,MAAA,OAAO,GAAA,CAAI,IAAA,CAAK,EAAE,EAAA,EAAI,MAAM,CAAA;AAAA,IAC9B,CAAC;AAAA,GACH;AAEA,EAAA,CAAA,CAAE,IAAA;AAAA,IACA,0BAAA;AAAA,IACA,YAAA,CAAa,OAAO,GAAA,EAAK,GAAA,KAAQ;AAC/B,MAAA,MAAM,CAAA,GAAI,MAAM,CAAA,CAAE,UAAA,CAAW,OAAA,CAAQ,EAAE,IAAA,EAAM,GAAA,CAAI,MAAA,CAAO,IAAA,EAAM,CAAA;AAC9D,MAAA,IAAI,CAAC,CAAA,EAAG,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,WAAA,EAAa,CAAA;AAC1D,MAAA,MAAM,EAAE,UAAA,CAAW,SAAA,CAAU,EAAE,GAAA,EAAK,CAAA,CAAE,KAAI,EAAG,EAAE,IAAA,EAAM,EAAE,QAAQ,WAAA,EAAa,SAAA,sBAAe,IAAA,EAAK,IAAK,CAAA;AACrG,MAAA,MAAM,OAAO,KAAA,CAAM;AAAA,QACjB,OAAQ,GAAA,CAAY,KAAA;AAAA,QACpB,MAAA,EAAQ,kBAAA;AAAA,QACR,QAAA,EAAU,EAAE,UAAA,EAAY,mBAAA,EAAqB,IAAI,CAAA,CAAE,GAAA,EAAK,IAAA,EAAM,CAAA,CAAE,IAAA;AAAK,OACtE,CAAA;AACD,MAAA,OAAO,GAAA,CAAI,IAAA,CAAK,EAAE,EAAA,EAAI,MAAM,CAAA;AAAA,IAC9B,CAAC;AAAA,GACH;AAGA,EAAA,CAAA,CAAE,GAAA,CAAI,CAAC,IAAA,EAAM,GAAA,KAAQ,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,WAAA,EAAa,CAAC,CAAA;AAEjE,EAAA,OAAO,CAAA;AACT;AAGA,SAAS,aAAa,EAAA,EAAkB;AACtC,EAAA,OAAO,CAAC,GAAA,EAAc,GAAA,EAAe,IAAA,KAAuB;AAC1D,IAAA,EAAA,CAAG,GAAA,EAAK,GAAA,EAAK,IAAI,CAAA,CAAE,MAAM,IAAI,CAAA;AAAA,EAC/B,CAAA;AACF;AAcA,SAAS,oBAAA,CACP,QACA,GAAA,EACqF;AACrF,EAAA,MAAM,QAAA,GAAW,IAAI,gBAAA,IAAoB,IAAA;AACzC,EAAA,MAAM,IAAA,GAAO,QAAA,IAAY,MAAA,CAAO,MAAA,CAAO,eAAA;AACvC,EAAA,MAAM,KAAA,GAAQ,uBAAA,CAAwB,MAAA,CAAO,SAAS,CAAA;AACtD,EAAA,MAAM,MAAA,GAAS,QAAA,GACX,CAAA,UAAA,EAAa,GAAA,CAAI,IAAA,IAAQ,GAAG,CAAA,6BAAA,EAAgC,IAAI,CAAA,CAAA,CAAA,GAChE,CAAA,mCAAA,EAAsC,IAAI,CAAA,CAAA,CAAA;AAC9C,EAAA,OAAO;AAAA,IACL,KAAA,EAAO,kBAAA;AAAA,IACP,OAAA,EACE,CAAA,EAAG,MAAM,CAAA,4DAAA,EACgB,KAAA,CAAM,SAAS,KAAA,CAAM,IAAA,CAAK,IAAI,CAAA,GAAI,QAAQ,CAAA,CAAA,CAAA;AAAA,IACrE,QAAA,EAAU,IAAA;AAAA,IACV,mBAAA,EAAqB;AAAA,GACvB;AACF;AAOA,eAAe,mBACb,MAAA,EAC8D;AAC9D,EAAA,MAAM,EAAA,GAAK,MAAA,CAAO,MAAA,CAAO,MAAA,CAAO,MAAM,CAAA;AAItC,EAAA,MAAM,GAAA,GAAM,OAAO,GAAA,KAAwE;AACzF,IAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,IAAA,IAAI,SAAA,GAAY,KAAA;AAChB,IAAA,KAAA,MAAW,KAAK,EAAA,EAAI;AAClB,MAAA,MAAM,EAAA,GAAK,EAAE,GAAG,CAAA;AAChB,MAAA,IAAI,CAAC,EAAA,EAAI;AACT,MAAA,IAAI;AACF,QAAA,MAAM,CAAA,GAAI,MAAM,EAAA,CAAG,IAAA,CAAK,CAAC,CAAA;AACzB,QAAA,IAAI,KAAK,IAAA,EAAM;AACf,QAAA,KAAA,IAAS,CAAA;AACT,QAAA,SAAA,GAAY,IAAA;AAAA,MACd,CAAA,CAAA,MAAQ;AAEN,QAAA,OAAO,IAAA;AAAA,MACT;AAAA,IACF;AACA,IAAA,OAAO,YAAY,KAAA,GAAQ,IAAA;AAAA,EAC7B,CAAA;AACA,EAAA,MAAM,CAAC,QAAA,EAAU,OAAO,CAAA,GAAI,MAAM,OAAA,CAAQ,GAAA,CAAI,CAAC,GAAA,CAAI,kBAAkB,CAAA,EAAG,GAAA,CAAI,iBAAiB,CAAC,CAAC,CAAA;AAC/F,EAAA,OAAO,EAAE,UAAU,OAAA,EAAQ;AAC7B;AAiBA,SAAS,cAAA,GAA4B;AACnC,EAAA,OAAO,EAAE,YAAY,CAAA,EAAG,aAAA,EAAe,GAAG,cAAA,EAAgB,CAAA,EAAG,YAAY,CAAA,EAAE;AAC7E;AAEA,eAAe,gBAAA,CAAiB,QAAgB,UAAA,EAAsD;AACpG,EAAA,MAAM,GAAA,uBAAU,GAAA,EAAuB;AACvC,EAAA,MAAM,QAAQ,UAAA,GAAa,EAAE,QAAA,EAAU,UAAA,KAAe,EAAC;AAEvD,EAAA,MAAM,OAAA,GAAU,MAAM,MAAA,CAAO,WAAA,CAAY,SACtC,SAAA,CAAwE;AAAA,IACvE,EAAE,QAAQ,KAAA,EAAM;AAAA,IAChB,EAAE,MAAA,EAAQ,EAAE,GAAA,EAAK,EAAE,QAAA,EAAU,WAAA,EAAa,MAAA,EAAQ,SAAA,IAAa,KAAA,EAAO,EAAE,IAAA,EAAM,CAAA,IAAI;AAAE,GACrF,EACA,OAAA,EAAQ;AACX,EAAA,KAAA,MAAW,OAAO,OAAA,EAAS;AACzB,IAAA,MAAM,IAAA,GAAO,IAAI,GAAA,CAAI,QAAA;AACrB,IAAA,IAAI,CAAC,IAAA,EAAM;AACX,IAAA,MAAM,GAAA,GAAM,GAAA,CAAI,GAAA,CAAI,IAAI,KAAK,cAAA,EAAe;AAC5C,IAAA,IAAI,IAAI,GAAA,CAAI,MAAA,KAAW,QAAA,EAAU,GAAA,CAAI,cAAc,GAAA,CAAI,KAAA;AAAA,SAAA,IAC9C,IAAI,GAAA,CAAI,MAAA,KAAW,WAAA,EAAa,GAAA,CAAI,iBAAiB,GAAA,CAAI,KAAA;AAClE,IAAA,GAAA,CAAI,GAAA,CAAI,MAAM,GAAG,CAAA;AAAA,EACnB;AAEA,EAAA,MAAM,YAAA,GAAe,IAAI,IAAA,CAAK,IAAA,CAAK,GAAA,KAAQ,CAAA,GAAI,EAAA,GAAK,EAAA,GAAK,EAAA,GAAK,GAAI,CAAA;AAClE,EAAA,MAAM,QAAA,GAAW,MAAM,MAAA,CAAO,WAAA,CAAY,MACvC,SAAA,CAAyD;AAAA,IACxD,EAAE,QAAQ,EAAE,SAAA,EAAW,EAAE,GAAA,EAAK,IAAA,IAAO,EAAE;AAAA,IACvC;AAAA,MACE,OAAA,EAAS;AAAA,QACP,IAAA,EAAM,MAAA,CAAO,WAAA,CAAY,QAAA,CAAS,cAAA;AAAA,QAClC,UAAA,EAAY,WAAA;AAAA,QACZ,YAAA,EAAc,KAAA;AAAA,QACd,EAAA,EAAI,KAAA;AAAA,QACJ,QAAA,EAAU,UAAA,GACN,CAAC,EAAE,MAAA,EAAQ,EAAE,QAAA,EAAU,UAAA,EAAW,EAAE,EAAG,EAAE,QAAA,EAAU,EAAE,QAAA,EAAU,CAAA,EAAE,EAAG,CAAA,GACpE,CAAC,EAAE,QAAA,EAAU,EAAE,QAAA,EAAU,CAAA,EAAE,EAAG;AAAA;AACpC,KACF;AAAA,IACA,EAAE,SAAS,MAAA,EAAO;AAAA,IAClB;AAAA,MACE,MAAA,EAAQ;AAAA,QACN,GAAA,EAAK,eAAA;AAAA,QACL,KAAA,EAAO,EAAE,IAAA,EAAM,CAAA,EAAE;AAAA,QACjB,OAAO,EAAE,IAAA,EAAM,EAAE,KAAA,EAAO,CAAC,EAAE,IAAA,EAAM,CAAC,WAAA,EAAa,YAAY,CAAA,EAAE,EAAG,CAAA,EAAG,CAAC,GAAE;AAAE;AAC1E;AACF,GACD,EACA,OAAA,EAAQ;AACX,EAAA,KAAA,MAAW,OAAO,QAAA,EAAU;AAC1B,IAAA,IAAI,CAAC,IAAI,GAAA,EAAK;AACd,IAAA,MAAM,MAAM,GAAA,CAAI,GAAA,CAAI,GAAA,CAAI,GAAG,KAAK,cAAA,EAAe;AAC/C,IAAA,GAAA,CAAI,aAAa,GAAA,CAAI,KAAA;AACrB,IAAA,GAAA,CAAI,iBAAiB,GAAA,CAAI,KAAA;AACzB,IAAA,GAAA,CAAI,GAAA,CAAI,GAAA,CAAI,GAAA,EAAK,GAAG,CAAA;AAAA,EACtB;AAEA,EAAA,OAAO,GAAA;AACT;AAUA,SAAS,kBAAA,GAAoC;AAC3C,EAAA,OAAO,EAAE,IAAA,EAAM,CAAA,EAAG,MAAA,EAAQ,CAAA,EAAG,OAAA,EAAS,CAAA,EAAG,OAAA,EAAS,CAAA,EAAG,aAAA,EAAe,CAAA,EAAG,UAAA,EAAY,IAAA,EAAK;AAC1F;AAEA,eAAe,oBAAA,CAAqB,QAAgB,UAAA,EAA0D;AAC5G,EAAA,MAAM,GAAA,uBAAU,GAAA,EAA2B;AAC3C,EAAA,MAAM,QAAiC,EAAC;AACxC,EAAA,IAAI,UAAA,QAAkB,YAAA,GAAe,UAAA;AACrC,EAAA,MAAM,YAAA,GAAe,IAAI,IAAA,CAAK,IAAA,CAAK,GAAA,KAAQ,CAAA,GAAI,EAAA,GAAK,EAAA,GAAK,EAAA,GAAK,GAAI,CAAA;AAElE,EAAA,MAAM,IAAA,GAAO,MAAM,MAAA,CAAO,WAAA,CAAY,MACnC,SAAA,CAQE;AAAA,IACD,EAAE,QAAQ,KAAA,EAAM;AAAA,IAChB;AAAA,MACE,MAAA,EAAQ;AAAA,QACN,GAAA,EAAK,eAAA;AAAA,QACL,IAAA,EAAM,EAAE,IAAA,EAAM,CAAA,EAAE;AAAA,QAChB,QAAQ,EAAE,IAAA,EAAM,EAAE,KAAA,EAAO,CAAC,EAAE,OAAA,EAAS,CAAC,WAAA,EAAa,KAAK,CAAA,EAAE,EAAG,CAAA,EAAG,CAAC,GAAE,EAAE;AAAA,QACrE,SAAS,EAAE,IAAA,EAAM,EAAE,KAAA,EAAO,CAAC,EAAE,OAAA,EAAS,CAAC,eAAA,EAAiB,KAAK,CAAA,EAAE,EAAG,CAAA,EAAG,CAAC,GAAE,EAAE;AAAA,QAC1E,SAAS,EAAE,IAAA,EAAM,EAAE,KAAA,EAAO,CAAC,EAAE,GAAA,EAAK,CAAC,SAAA,EAAW,SAAS,CAAA,EAAE,EAAG,CAAA,EAAG,CAAC,GAAE,EAAE;AAAA,QACpE,eAAe,EAAE,IAAA,EAAM,EAAE,KAAA,EAAO,CAAC,EAAE,IAAA,EAAM,CAAC,WAAA,EAAa,YAAY,CAAA,EAAE,EAAG,CAAA,EAAG,CAAC,GAAE,EAAE;AAAA,QAChF,UAAA,EAAY,EAAE,IAAA,EAAM,WAAA;AAAY;AAClC;AACF,GACD,EACA,OAAA,EAAQ;AACX,EAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,IAAA,IAAI,CAAC,IAAI,GAAA,EAAK;AACd,IAAA,GAAA,CAAI,GAAA,CAAI,IAAI,GAAA,EAAK;AAAA,MACf,MAAM,GAAA,CAAI,IAAA;AAAA,MACV,QAAQ,GAAA,CAAI,MAAA;AAAA,MACZ,SAAS,GAAA,CAAI,OAAA;AAAA,MACb,SAAS,GAAA,CAAI,OAAA;AAAA,MACb,eAAe,GAAA,CAAI,aAAA;AAAA,MACnB,UAAA,EAAY,IAAI,UAAA,IAAc;AAAA,KAC/B,CAAA;AAAA,EACH;AACA,EAAA,OAAO,GAAA;AACT;AAQA,SAAS,mBAAA,GAAsC;AAC7C,EAAA,OAAO,EAAE,WAAW,CAAA,EAAG,MAAA,EAAQ,GAAG,OAAA,EAAS,CAAA,EAAG,SAAS,CAAA,EAAE;AAC3D;AAEA,eAAe,qBAAA,CACb,QACA,QAAA,EACsC;AACtC,EAAA,MAAM,GAAA,uBAAU,GAAA,EAA4B;AAC5C,EAAA,MAAM,QAAiC,EAAE,WAAA,EAAa,EAAE,GAAA,EAAK,MAAK,EAAE;AACpE,EAAA,IAAI,QAAA,QAAgB,WAAA,GAAc,QAAA;AAElC,EAAA,MAAM,IAAA,GAAO,MAAM,MAAA,CAAO,WAAA,CAAY,MACnC,SAAA,CAME;AAAA,IACD,EAAE,QAAQ,KAAA,EAAM;AAAA,IAChB;AAAA,MACE,MAAA,EAAQ;AAAA,QACN,GAAA,EAAK,cAAA;AAAA,QACL,WAAW,EAAE,IAAA,EAAM,EAAE,KAAA,EAAO,CAAC,EAAE,GAAA,EAAK,CAAC,SAAA,EAAW,WAAW,CAAA,EAAE,EAAG,CAAA,EAAG,CAAC,GAAE,EAAE;AAAA,QACxE,QAAQ,EAAE,IAAA,EAAM,EAAE,KAAA,EAAO,CAAC,EAAE,OAAA,EAAS,CAAC,WAAA,EAAa,KAAK,CAAA,EAAE,EAAG,CAAA,EAAG,CAAC,GAAE,EAAE;AAAA,QACrE,SAAS,EAAE,IAAA,EAAM,EAAE,KAAA,EAAO,CAAC,EAAE,OAAA,EAAS,CAAC,eAAA,EAAiB,KAAK,CAAA,EAAE,EAAG,CAAA,EAAG,CAAC,GAAE,EAAE;AAAA,QAC1E,SAAS,EAAE,IAAA,EAAM,EAAE,KAAA,EAAO,CAAC,EAAE,GAAA,EAAK,CAAC,SAAA,EAAW,SAAS,CAAA,EAAE,EAAG,CAAA,EAAG,CAAC,GAAE;AAAE;AACtE;AACF,GACD,EACA,OAAA,EAAQ;AACX,EAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,IAAA,IAAI,CAAC,IAAI,GAAA,EAAK;AACd,IAAA,GAAA,CAAI,GAAA,CAAI,MAAA,CAAO,GAAA,CAAI,GAAG,CAAA,EAAG;AAAA,MACvB,WAAW,GAAA,CAAI,SAAA;AAAA,MACf,QAAQ,GAAA,CAAI,MAAA;AAAA,MACZ,SAAS,GAAA,CAAI,OAAA;AAAA,MACb,SAAS,GAAA,CAAI;AAAA,KACd,CAAA;AAAA,EACH;AACA,EAAA,OAAO,GAAA;AACT;;;AKxiEO,IAAM,kBAAA,GAAkC;AAAA,EAC7C,KAAA,CAAM,QAAQ,GAAA,EAAK;AACjB,IAAA,OAAA,CAAQ,KAAA,CAAM,GAAA,IAAO,yBAAA,EAA2B,MAAM,CAAA;AAAA,EACxD,CAAA;AAAA,EACA,IAAA,CAAK,QAAQ,GAAA,EAAK;AAChB,IAAA,OAAA,CAAQ,IAAA,CAAK,GAAA,IAAO,0BAAA,EAA4B,MAAM,CAAA;AAAA,EACxD,CAAA;AAAA,EACA,IAAA,CAAK,QAAQ,GAAA,EAAK;AAChB,IAAA,OAAA,CAAQ,IAAA,CAAK,GAAA,IAAO,kBAAA,EAAoB,MAAM,CAAA;AAAA,EAChD;AACF,CAAA;AAkBO,SAAS,IAAA,CAAK,QAAqB,OAAA,EAA4C;AACpF,EAAA,OAAO,OAAO,GAAA,EAAc,GAAA,EAAe,IAAA,KAAuB;AAChE,IAAA,IAAI;AACF,MAAA,MAAM,OAAA,CAAQ,GAAA,EAAK,GAAA,EAAK,IAAI,CAAA;AAAA,IAC9B,SAAS,GAAA,EAAK;AACZ,MAAA,MAAA,CAAO,QAAQ,EAAE,GAAA,EAAK,MAAM,GAAA,CAAI,WAAA,IAAe,yBAAyB,CAAA;AACxE,MAAA,IAAI,IAAI,WAAA,EAAa;AACrB,MAAA,GAAA,CAAI,OAAO,GAAG,CAAA,CAAE,KAAK,EAAE,KAAA,EAAO,kBAAkB,CAAA;AAAA,IAClD;AAAA,EACF,CAAA;AACF;;;AC0BA,IAAM,kBAAA,GAAqB,CAAC,MAAA,EAAQ,KAAA,EAAO,MAAM,CAAA;AAEjD,IAAM,YAAA,GAAe,gBAAA;AACrB,IAAM,sBAAA,GAAyB,KAAK,IAAA,GAAO,IAAA;AAC3C,IAAM,iBAAA,GAAoB,EAAA;AAMnB,SAAS,iBAAA,CACd,MAAA,EACA,MAAA,EACA,IAAA,EACA,MAAA,EACe;AACf,EAAA,MAAM,SAAS,IAAA,EAAM,MAAA;AACrB,EAAA,IAAI,CAAC,QAAQ,OAAO,MAAA,KAAW,YAAY,MAAA,CAAO,MAAA,KAAW,GAAG,OAAO,IAAA;AAEvE,EAAA,MAAM,SAAA,GAAY,KAAK,IAAA,IAAQ,YAAA;AAC/B,EAAA,MAAM,YAAA,GAAe,KAAK,YAAA,IAAgB,qBAAA;AAC1C,EAAA,MAAM,iBAAiB,gBAAA,CAAiB,IAAA,CAAK,cAAA,IAAkB,mBAAA,CAAoB,MAAM,CAAC,CAAA;AAE1F,EAAA,IAAI,cAAA,CAAe,SAAS,CAAA,EAAG;AAC7B,IAAA,MAAA,CAAO,IAAA;AAAA,MACL,EAAE,MAAM,SAAA,EAAU;AAAA,MAClB;AAAA,KACF;AAAA,EACF;AAEA,EAAA,MAAM,SAASoB,uBAAAA,CAAO;AAAA,IACpB,OAAA,EAASA,wBAAO,aAAA,EAAc;AAAA,IAC9B,MAAA,EAAQ;AAAA,MACN,QAAA,EAAU,KAAK,gBAAA,IAAoB,sBAAA;AAAA,MACnC,KAAA,EAAO,KAAK,QAAA,IAAY,iBAAA;AAAA;AAAA;AAAA,MAGxB,MAAA,EAAQ,EAAA;AAAA,MACR,WAAW,IAAA,GAAO;AAAA;AACpB,GACD,CAAA;AAKD,EAAA,MAAA,CAAO,IAAA;AAAA,IACL,SAAA;AAAA,IACA,IAAA,CAAK,MAAA,EAAQ,CAAC,GAAA,EAAc,KAAe,IAAA,KAAS;AAClD,MAAA,IAAI,CAAC,YAAA,CAAa,GAAA,EAAK,MAAM,CAAA,EAAG;AAC9B,QAAA,MAAA,CAAO,IAAA;AAAA,UACL,EAAE,IAAA,EAAM,SAAA,EAAW,EAAA,EAAI,IAAI,EAAA,EAAG;AAAA,UAC9B;AAAA,SACF;AAGA,QAAA,GAAA,CAAI,OAAO,GAAG,CAAA,CAAE,KAAK,EAAE,KAAA,EAAO,gBAAgB,CAAA;AAC9C,QAAA;AAAA,MACF;AACA,MAAA,IAAA,EAAK;AAAA,IACP,CAAC,CAAA;AAAA,IACD,CAAC,GAAA,EAAc,GAAA,EAAe,IAAA,KAAkC;AAC9D,MAAA,MAAA,CAAO,GAAA,EAAI,CAAE,GAAA,EAAK,GAAA,EAAK,CAAC,GAAA,KAAiB;AACvC,QAAA,IAAI,CAAC,GAAA,EAAK,OAAO,IAAA,EAAK;AACtB,QAAA,MAAM,OAAQ,GAAA,EAA2B,IAAA;AACzC,QAAA,MAAM,MAAA,GAAS,IAAA,KAAS,iBAAA,IAAqB,IAAA,KAAS,qBAAqB,GAAA,GAAM,GAAA;AACjF,QAAA,MAAA,CAAO,OAAO,EAAE,GAAA,EAAK,IAAA,EAAM,SAAA,IAAa,wCAAwC,CAAA;AAChF,QAAA,GAAA,CAAI,MAAA,CAAO,MAAM,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,iBAAA,EAAmB,OAAA,EAAS,MAAA,CAAO,IAAA,IAAQ,qBAAqB,CAAA,EAAG,CAAA;AAAA,MACtG,CAAC,CAAA;AAAA,IACH,CAAA;AAAA,IACA,IAAA,CAAK,MAAA,EAAQ,OAAO,GAAA,EAAc,GAAA,KAAkB;AAClD,MAAA,IAAI,WAAA;AACJ,MAAA,IAAI;AACF,QAAA,WAAA,GAAc,aAAa,GAAG,CAAA;AAAA,MAChC,SAAS,GAAA,EAAK;AACZ,QAAA,MAAA,CAAO,OAAO,EAAE,GAAA,EAAK,IAAA,EAAM,SAAA,IAAa,2CAA2C,CAAA;AACnF,QAAA,OAAO,GAAA,CAAI,OAAO,GAAG,CAAA,CAAE,KAAK,EAAE,KAAA,EAAO,eAAe,CAAA;AAAA,MACtD;AAEA,MAAA,MAAM,UAAA,GAAa,YAAY,MAAA,CAAO,CAAC,MAAM,mBAAA,CAAoB,CAAA,CAAE,QAAQ,CAAC,CAAA;AAC5E,MAAA,IAAI,UAAA,CAAW,WAAW,CAAA,EAAG;AAI3B,QAAA,MAAA,CAAO,IAAA;AAAA,UACL,EAAE,IAAA,EAAM,SAAA,EAAW,WAAA,EAAa,YAAY,MAAA,EAAO;AAAA,UACnD;AAAA,SACF;AACA,QAAA,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,EAAA,EAAI,IAAA,EAAM,QAAA,EAAU,CAAA,EAAG,OAAA,EAAS,WAAA,CAAY,QAAQ,CAAA;AAAA,MACpF;AAEA,MAAA,MAAM,GAAA,GAAM,OAAO,gBAAA,EAAiB;AACpC,MAAA,MAAM,WAAA,GACJ,cAAA,CAAe,IAAA,KAAS,CAAA,GAAI,KAAA,CAAA,GAAY,CAAC,CAAA,KAAc,cAAA,CAAe,GAAA,CAAI,CAAA,CAAE,WAAA,EAAa,CAAA;AAE3F,MAAA,MAAM,WAA4E,EAAC;AACnF,MAAA,MAAM,WAAyD,EAAC;AAEhE,MAAA,KAAA,MAAW,QAAQ,UAAA,EAAY;AAC7B,QAAA,IAAI;AACF,UAAA,MAAM,MAAA,GAAS,MAAM,qBAAA,CAAsB,GAAA,EAAK,IAAA,CAAK,QAAQ,IAAA,CAAK,QAAA,EAAU,EAAE,WAAA,EAAa,CAAA;AAC3F,UAAA,QAAA,CAAS,IAAA,CAAK,EAAE,QAAA,EAAU,MAAA,CAAO,QAAA,EAAU,MAAA,EAAQ,MAAA,CAAO,MAAA,EAAQ,SAAA,EAAW,MAAA,CAAO,SAAA,EAAW,CAAA;AAAA,QACjG,SAAS,GAAA,EAAc;AACrB,UAAA,MAAM,OAAA,GAAU,MAAA,CAAQ,GAAA,EAAe,OAAA,IAAW,GAAG,CAAA;AACrD,UAAA,QAAA,CAAS,KAAK,EAAE,QAAA,EAAU,IAAA,CAAK,QAAA,EAAU,SAAS,CAAA;AAClD,UAAA,MAAA,CAAO,IAAA;AAAA,YACL,EAAE,IAAA,EAAM,SAAA,EAAW,QAAA,EAAU,IAAA,CAAK,UAAU,GAAA,EAAI;AAAA,YAChD;AAAA,WACF;AAAA,QACF;AAAA,MACF;AAEA,MAAA,IAAI,QAAA,CAAS,WAAW,CAAA,EAAG;AAIzB,QAAA,OAAO,GAAA,CAAI,OAAO,GAAG,CAAA,CAAE,KAAK,EAAE,KAAA,EAAO,eAAA,EAAiB,QAAA,EAAU,CAAA;AAAA,MAClE;AACA,MAAA,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,EAAA,EAAI,IAAA,EAAM,QAAA,EAAU,QAAA,EAAU,CAAA;AAAA,IAC9D,CAAC;AAAA,GACH;AAEA,EAAA,OAAO,SAAA;AACT;AAaO,SAAS,YAAA,CAAa,KAAc,MAAA,EAAyB;AAClE,EAAA,MAAM,SAAA,GAAY,uBAAuB,GAAG,CAAA;AAC5C,EAAA,IAAI,SAAA,KAAc,MAAM,OAAO,KAAA;AAC/B,EAAA,OAAO,kBAAA,CAAmB,WAAW,MAAM,CAAA;AAC7C;AAEA,SAAS,uBAAuB,GAAA,EAA6B;AAC3D,EAAA,MAAM,MAAA,GAAS,IAAI,OAAA,CAAQ,aAAA;AAC3B,EAAA,IAAI,OAAO,MAAA,KAAW,QAAA,EAAU,OAAO,IAAA;AAEvC,EAAA,MAAM,CAAC,MAAA,EAAQ,GAAG,IAAI,CAAA,GAAI,MAAA,CAAO,MAAM,GAAG,CAAA;AAC1C,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,IAAA,CAAK,GAAG,EAAE,IAAA,EAAK;AAClC,EAAA,IAAI,CAAC,MAAA,IAAU,KAAA,KAAU,EAAA,EAAI,OAAO,IAAA;AAEpC,EAAA,QAAQ,MAAA,CAAO,aAAY;AAAG,IAC5B,KAAK,OAAA,EAAS;AACZ,MAAA,IAAI,OAAA;AACJ,MAAA,IAAI;AACF,QAAA,OAAA,GAAU,OAAO,IAAA,CAAK,KAAA,EAAO,QAAQ,CAAA,CAAE,SAAS,MAAM,CAAA;AAAA,MACxD,CAAA,CAAA,MAAQ;AACN,QAAA,OAAO,IAAA;AAAA,MACT;AACA,MAAA,MAAM,GAAA,GAAM,OAAA,CAAQ,OAAA,CAAQ,GAAG,CAAA;AAG/B,MAAA,OAAO,QAAQ,EAAA,GAAK,IAAA,GAAO,OAAA,CAAQ,KAAA,CAAM,MAAM,CAAC,CAAA;AAAA,IAClD;AAAA,IACA,KAAK,QAAA;AACH,MAAA,OAAO,KAAA;AAAA,IACT;AACE,MAAA,OAAO,IAAA;AAAA;AAEb;AAEA,SAAS,kBAAA,CAAmB,GAAW,CAAA,EAAoB;AAGzD,EAAA,MAAM,EAAA,GAAKC,mBAAW,QAAQ,CAAA,CAAE,OAAO,CAAA,EAAG,MAAM,EAAE,MAAA,EAAO;AACzD,EAAA,MAAM,EAAA,GAAKA,mBAAW,QAAQ,CAAA,CAAE,OAAO,CAAA,EAAG,MAAM,EAAE,MAAA,EAAO;AACzD,EAAA,OAAOC,uBAAA,CAAgB,IAAI,EAAE,CAAA;AAC/B;AAcO,IAAM,qBAAA,GAAuC,CAAC,GAAA,KAAQ;AAC3D,EAAA,MAAM,QAAS,GAAA,CAAuC,KAAA;AACtD,EAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,SAAU,EAAC;AACnC,EAAA,OAAO,KAAA,CACJ,MAAA,CAAO,CAAC,CAAA,KAAgC,OAAA,CAAQ,CAAC,CAAA,IAAK,MAAA,CAAO,QAAA,CAAU,CAAA,CAA0B,MAAM,CAAC,EACxG,GAAA,CAAI,CAAC,CAAA,MAAO,EAAE,QAAA,EAAU,YAAA,CAAa,CAAA,CAAE,YAAY,CAAA,EAAG,MAAA,EAAQ,CAAA,CAAE,MAAA,EAAO,CAAE,CAAA;AAC9E;AAOA,SAAS,aAAa,GAAA,EAAsB;AAC1C,EAAA,IAAI,OAAO,GAAA,KAAQ,QAAA,EAAU,OAAO,EAAA;AAEpC,EAAA,OAAO,GAAA,CAAI,OAAA,CAAQ,wBAAA,EAA0B,EAAE,CAAA,CAAE,OAAA,CAAQ,QAAA,EAAU,GAAG,CAAA,CAAE,KAAA,CAAM,CAAA,EAAG,GAAG,CAAA;AACtF;AAEA,SAAS,oBAAoB,QAAA,EAA2B;AACtD,EAAA,MAAM,KAAA,GAAQ,SAAS,WAAA,EAAY;AACnC,EAAA,OAAO,mBAAmB,IAAA,CAAK,CAAC,QAAQ,KAAA,CAAM,QAAA,CAAS,GAAG,CAAC,CAAA;AAC7D;AAMA,SAAS,iBAAiB,OAAA,EAAwC;AAChE,EAAA,MAAM,GAAA,uBAAU,GAAA,EAAY;AAC5B,EAAA,KAAA,MAAW,KAAK,OAAA,EAAS;AACvB,IAAA,IAAI,OAAO,MAAM,QAAA,EAAU;AAC3B,IAAA,MAAM,OAAA,GAAU,EAAE,IAAA,EAAK,CAAE,aAAY,CAAE,OAAA,CAAQ,QAAQ,EAAE,CAAA;AACzD,IAAA,IAAI,OAAA,EAAS,GAAA,CAAI,GAAA,CAAI,OAAO,CAAA;AAAA,EAC9B;AACA,EAAA,OAAO,GAAA;AACT;AASA,SAAS,oBAAoB,MAAA,EAA0B;AACrD,EAAA,MAAM,MAAgB,EAAC;AACvB,EAAA,MAAM,IAAA,GAAO,CAAC,MAAA,KAA+B;AAC3C,IAAA,IAAI,CAAC,MAAA,EAAQ;AACb,IAAA,GAAA,CAAI,KAAK,MAAM,CAAA;AAKf,IAAA,MAAM,MAAA,GAAS,MAAA,CAAO,KAAA,CAAM,GAAG,CAAA;AAC/B,IAAA,IAAI,MAAA,CAAO,MAAA,GAAS,CAAA,EAAG,GAAA,CAAI,IAAA,CAAK,MAAA,CAAO,KAAA,CAAM,EAAE,CAAA,CAAE,IAAA,CAAK,GAAG,CAAC,CAAA;AAAA,EAC5D,CAAA;AAEA,EAAA,KAAA,MAAW,MAAA,IAAU,MAAA,CAAO,IAAA,CAAK,MAAA,CAAO,MAAA,CAAO,aAAA,IAAiB,EAAE,CAAA,EAAG,IAAA,CAAK,MAAA,CAAO,WAAA,EAAa,CAAA;AAC9F,EAAA,IAAA,CAAK,WAAA,CAAY,MAAA,CAAO,MAAA,CAAO,YAAA,EAAc,KAAK,CAAC,CAAA;AACnD,EAAA,IAAA,CAAK,WAAA,CAAY,MAAA,CAAO,MAAA,CAAO,yBAAA,EAA2B,KAAK,CAAC,CAAA;AAChE,EAAA,IAAA,CAAK,WAAA,CAAY,MAAA,CAAO,MAAA,CAAO,aAAa,CAAC,CAAA;AAC7C,EAAA,OAAO,GAAA;AACT;AAEA,SAAS,YAAY,KAAA,EAA+C;AAClE,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,EAAU,OAAO,MAAA;AACtC,EAAA,MAAM,EAAA,GAAK,KAAA,CAAM,WAAA,CAAY,GAAG,CAAA;AAChC,EAAA,IAAI,EAAA,KAAO,IAAI,OAAO,MAAA;AACtB,EAAA,MAAM,MAAA,GAAS,MAAM,KAAA,CAAM,EAAA,GAAK,CAAC,CAAA,CAAE,IAAA,GAAO,WAAA,EAAY;AACtD,EAAA,OAAO,MAAA,IAAU,MAAA;AACnB;;;AClTA,IAAM,QAAQ,MAAA,CAAO,IAAA;AAAA,EACnB,8FAAA;AAAA,EACA;AACF,CAAA;AAEO,SAAS,kBAAA,CAAmB,MAAA,EAAgB,IAAA,GAA4B,EAAC,EAAW;AACzF,EAAA,MAAM,SAASN,cAAAA,EAAO;AACtB,EAAA,MAAM,MAAA,GAAS,KAAK,MAAA,IAAU,kBAAA;AAI9B,EAAA,MAAM,iBAAA,GAAoB,IAAA,CAAK,iBAAA,IAAqB,MAAA,CAAO,OAAO,iBAAA,IAAqB,IAAA;AACvF,EAAA,IAAI,IAAA,CAAK,iBAAA,IAAqB,CAAC,MAAA,CAAO,OAAO,iBAAA,EAAmB;AAC9D,IAAA,MAAA,CAAO,IAAA;AAAA,MACL,EAAE,IAAA,EAAM,IAAA,CAAK,iBAAA,EAAkB;AAAA,MAC/B;AAAA,KACF;AAAA,EACF;AACA,EAAA,IAAI,CAAC,iBAAA,EAAmB;AACtB,IAAA,MAAA,CAAO,IAAA;AAAA,MACL,EAAC;AAAA,MACD;AAAA,KACF;AAAA,EACF;AAMA,EAAA,MAAM,mBAAmB,iBAAA,CAAkB,MAAA,EAAQ,MAAA,EAAQ,IAAA,CAAK,cAAc,MAAM,CAAA;AACpF,EAAA,IAAI,gBAAA,EAAkB;AACpB,IAAA,MAAA,CAAO,IAAA;AAAA,MACL,EAAE,MAAM,gBAAA,EAAiB;AAAA,MACzB;AAAA,KACF;AAAA,EACF;AAGA,EAAA,MAAA,CAAO,GAAA;AAAA,IACL,WAAA;AAAA,IACAC,yBAAQ,IAAA,CAAK;AAAA,MACX,KAAA,EAAO,KAAA;AAAA,MACP,MAAA,EAAQ,CAAC,GAAA,EAAU,IAAA,EAAM,GAAA,KAAQ;AAC/B,QAAA,GAAA,CAAI,OAAA,GAAU,GAAA;AAAA,MAChB;AAAA,KACD;AAAA,GACH;AAIA,EAAA,MAAA,CAAO,GAAA,CAAI,UAAUA,wBAAAA,CAAQ,UAAA,CAAW,EAAE,QAAA,EAAU,KAAA,EAAO,CAAC,CAAA;AAK5D,EAAA,MAAA,CAAO,IAAI,mBAAA,EAAqB,IAAA,CAAK,MAAA,EAAQ,OAAO,KAAc,GAAA,KAAkB;AAKlF,IAAA,GAAA,CAAI,SAAA,CAAU,gBAAgB,WAAW,CAAA;AACzC,IAAA,GAAA,CAAI,SAAA,CAAU,gBAAA,EAAkB,MAAA,CAAO,KAAA,CAAM,MAAM,CAAC,CAAA;AACpD,IAAA,GAAA,CAAI,SAAA,CAAU,iBAAiB,gDAAgD,CAAA;AAC/E,IAAA,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,GAAA,CAAI,KAAK,CAAA;AAGzB,IAAA,MAAM,MAAA,GAAS,cAAA,CAAgB,GAAA,CAAI,MAAA,CAAe,MAAgB,CAAA;AAClE,IAAA,IAAI,CAAC,MAAA,EAAQ;AACb,IAAA,MAAM,EAAE,EAAA,EAAI,GAAA,EAAI,GAAI,MAAA;AACpB,IAAA,IAAI,CAAC9B,gBAAAA,CAAS,OAAA,CAAQ,EAAE,CAAA,EAAG;AAC3B,IAAA,MAAM,MAAA,GAAS,IAAIA,gBAAAA,CAAS,EAAE,CAAA;AAE9B,IAAA,MAAM,UAAU,sBAAA,CAAuB;AAAA,MACrC,KAAA,EAAO,MAAA;AAAA,MACP,MAAA,EAAQ,EAAE,MAAA,EAAQ,EAAA,EAAG;AAAA,MACrB,GAAA;AAAA,MACA,MAAA,EAAQ,OAAO,MAAA,CAAO,iBAAA;AAAA,MACtB,aAAA,EAAe,OAAO,MAAA,CAAO,yBAAA;AAAA,MAC7B,MAAA;AAAA,MACA,MAAA,EAAQ,EAAE,MAAA,EAAQ,EAAA;AAAG,KACtB,CAAA;AACD,IAAA,IAAI,YAAY,UAAA,EAAY;AAE5B,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,GAAO,MAAM,MAAA,CAAO,WAAA,CAAY,KAAA,CAAM,OAAA;AAAA,QAC1C,EAAE,KAAK,MAAA,EAAO;AAAA,QACd,EAAE,UAAA,EAAY,EAAE,UAAU,CAAA,EAAG,QAAA,EAAU,GAAE;AAAE,OAC7C;AACA,MAAA,IAAI,CAAC,IAAA,EAAM;AACX,MAAA,IAAI,iBAAA,CAAkB,IAAA,EAAM,MAAA,CAAO,MAAA,CAAO,uBAAuB,CAAA,EAAG;AAClE,QAAA,MAAA,CAAO,IAAA,GAAO,EAAE,MAAA,EAAQ,EAAA,IAAM,wEAAmE,CAAA;AACjG,QAAA;AAAA,MACF;AACA,MAAA,MAAM,GAAA,uBAAU,IAAA,EAAK;AACrB,MAAA,MAAM,MAAA,CAAO,YAAY,KAAA,CAAM,SAAA;AAAA,QAC7B,EAAE,KAAK,MAAA,EAAO;AAAA,QACd;AAAA,UACE,IAAA,EAAM;AAAA,YACJ,QAAA,EAAU,KAAK,QAAA,IAAY,GAAA;AAAA,YAC3B,MAAA,EAAQ;AAAA,WACV;AAAA,UACA,IAAA,EAAM,EAAE,SAAA,EAAW,CAAA,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA,UAKrB,KAAA,EAAO;AAAA,YACL,KAAA,EAAO;AAAA,cACL,KAAA,EAAO,CAAC,EAAE,QAAA,EAAU,KAAK,SAAA,EAAW,gBAAA,CAAiB,GAAG,CAAA,EAAG,CAAA;AAAA,cAC3D,QAAQ,CAAC;AAAA;AACX;AACF;AACF,OACF;AAAA,IACF,SAAS,GAAA,EAAK;AACZ,MAAA,MAAA,CAAO,QAAQ,EAAE,GAAA,EAAK,MAAA,EAAQ,EAAA,IAAM,mCAAmC,CAAA;AAAA,IACzE;AAAA,EACF,CAAC,CAAC,CAAA;AAKF,EAAA,MAAA,CAAO,IAAI,+BAAA,EAAiC,IAAA,CAAK,MAAA,EAAQ,OAAO,KAAc,GAAA,KAAkB;AAC9F,IAAA,MAAM,EAAE,MAAA,EAAQ,SAAA,EAAW,MAAA,EAAQ,GAAA,KAAQ,GAAA,CAAI,MAAA;AAK/C,IAAA,IAAI,CAACA,gBAAAA,CAAS,OAAA,CAAQ,SAAS,CAAA,SAAU,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,GAAA,EAAI;AAC7D,IAAA,MAAM,MAAA,GAAS,IAAIA,gBAAAA,CAAS,SAAS,CAAA;AAIrC,IAAA,MAAM,UAAU,sBAAA,CAAuB;AAAA,MACrC,KAAA,EAAO,OAAA;AAAA,MACP,MAAA,EAAQ,EAAE,MAAA,EAAQ,SAAA,EAAW,MAAA,EAAO;AAAA,MACpC,GAAA;AAAA,MACA,MAAA,EAAQ,OAAO,MAAA,CAAO,iBAAA;AAAA,MACtB,aAAA,EAAe,OAAO,MAAA,CAAO,yBAAA;AAAA,MAC7B,MAAA;AAAA,MACA,MAAA,EAAQ,EAAE,MAAA,EAAQ,SAAA,EAAW,MAAA;AAAO,KACrC,CAAA;AACD,IAAA,IAAI,YAAY,UAAA,EAAY,OAAO,IAAI,MAAA,CAAO,GAAG,EAAE,GAAA,EAAI;AAEvD,IAAA,MAAM,IAAA,GAAO,MAAM,MAAA,CAAO,WAAA,CAAY,KAAA,CAAM,OAAA;AAAA,MAC1C,EAAE,KAAK,MAAA,EAAO;AAAA,MACd,EAAE,YAAY,EAAE,KAAA,EAAO,GAAG,YAAA,EAAc,CAAA,EAAG,QAAA,EAAU,CAAA,EAAE;AAAE,KAC3D;AACA,IAAA,IAAI,CAAC,IAAA,EAAM,OAAO,IAAI,MAAA,CAAO,GAAG,EAAE,GAAA,EAAI;AAEtC,IAAA,IAAI,iBAAA,CAAkB,IAAA,EAAM,MAAA,CAAO,MAAA,CAAO,uBAAuB,CAAA,EAAG;AAClE,MAAA,MAAA,CAAO,IAAA;AAAA,QACL,EAAE,MAAA,EAAQ,SAAA,EAAW,MAAA,EAAO;AAAA,QAC5B;AAAA,OACF;AACA,MAAA,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,GAAA,EAAI;AAAA,IAC7B;AAEA,IAAA,MAAM,IAAA,GAAA,CAAQ,IAAA,CAAK,KAAA,IAAS,EAAC,EAAG,KAAK,CAAC,CAAA,KAAM,CAAA,CAAE,MAAA,KAAW,MAAM,CAAA;AAC/D,IAAA,IAAI,CAAC,IAAA,EAAM,OAAO,IAAI,MAAA,CAAO,GAAG,EAAE,GAAA,EAAI;AAKtC,IAAA,IAAI,CAAC,oBAAA,CAAqB,IAAA,CAAK,GAAG,CAAA,EAAG;AACnC,MAAA,MAAA,CAAO,IAAA;AAAA,QACL,EAAE,MAAA,EAAQ,SAAA,EAAW,MAAA,EAAQ,GAAA,EAAK,KAAK,GAAA,EAAI;AAAA,QAC3C;AAAA,OACF;AACA,MAAA,OAAO,GAAA,CACJ,OAAO,GAAG,CAAA,CACV,KAAK,MAAM,CAAA,CACX,KAAK,6EAA6E,CAAA;AAAA,IACvF;AAEA,IAAA,GAAA,CAAI,QAAA,CAAS,GAAA,EAAK,IAAA,CAAK,GAAG,CAAA;AAE1B,IAAA,IAAI;AACF,MAAA,MAAM,MAAA,CAAO,YAAY,KAAA,CAAM,SAAA;AAAA,QAC7B,EAAE,KAAK,MAAA,EAAO;AAAA,QACd;AAAA,UACE,MAAM,EAAE,YAAA,EAAc,KAAK,YAAA,oBAAgB,IAAI,MAAK,EAAE;AAAA,UACtD,IAAA,EAAM,EAAE,UAAA,EAAY,CAAA,EAAE;AAAA,UACtB,KAAA,EAAO;AAAA,YACL,YAAA,EAAc;AAAA,cACZ,KAAK,IAAA,CAAK,GAAA;AAAA,cACV,MAAA;AAAA,cACA,SAAA,sBAAe,IAAA,EAAK;AAAA;AAAA;AAAA,cAGpB,SAAA,EAAW,iBAAiB,GAAG;AAAA;AACjC;AACF;AACF,OACF;AAAA,IACF,SAAS,GAAA,EAAK;AACZ,MAAA,MAAA,CAAO,QAAQ,EAAE,GAAA,EAAK,QAAQ,SAAA,EAAW,MAAA,IAAU,iCAAiC,CAAA;AAAA,IACtF;AAAA,EACF,CAAC,CAAC,CAAA;AAKF,EAAA,MAAA,CAAO,IAAI,eAAA,EAAiB,IAAA,CAAK,MAAA,EAAQ,CAAC,KAAc,GAAA,KAAkB;AACxE,IAAA,MAAM,UAAU,sBAAA,CAAwB,GAAA,CAAI,OAAe,KAAA,EAAO,MAAA,CAAO,OAAO,iBAAiB,CAAA;AACjG,IAAA,IAAI,CAAC,OAAA,EAAS,OAAO,cAAA,CAAe,KAAK,0BAA0B,CAAA;AAEnE,IAAA,GAAA,CAAI,OAAO,GAAG,CAAA,CAAE,IAAA,CAAK,MAAM,EAAE,IAAA,CAAK,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mDAAA,EAOe,UAAA,CAAW,QAAQ,KAAK,CAAC,YAAY,OAAA,CAAQ,KAAA,KAAU,KAAA,GAAQ,kBAAA,GAAqB,wBAAwB,CAAA;AAAA,8BAAA,EACjI,UAAA,CAAW,GAAA,CAAI,WAAW,CAAC,CAAA;AAAA;AAAA;AAAA,cAAA,CAG5C,CAAA;AAAA,EACb,CAAC,CAAC,CAAA;AAwBF,EAAA,MAAA,CAAO,KAAK,eAAA,EAAiB,IAAA,CAAK,MAAA,EAAQ,OAAO,KAAc,GAAA,KAAkB;AAC/E,IAAA,MAAM,UAAU,sBAAA,CAAwB,GAAA,CAAI,OAAe,KAAA,EAAO,MAAA,CAAO,OAAO,iBAAiB,CAAA;AACjG,IAAA,IAAI,CAAC,OAAA,EAAS;AACZ,MAAA,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,GAAA,EAAI;AACpB,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,WAAA,CAAY,OAAA,CAAQ,KAAA,EAAO;AAAA,MAC9C,OAAO,OAAA,CAAQ,KAAA;AAAA,MACf,MAAA,EAAQ,cAAA;AAAA,MACR,MAAA,EAAQ;AAAA,KACT,CAAA;AAED,IAAA,IAAI,OAAA,GAAmB,IAAA;AACvB,IAAA,IAAI;AACF,MAAA,MAAM,WAAA,CAAY,KAAA,EAAO,MAAA,CAAO,MAAA,CAAO,yBAAyB,CAAA;AAAA,IAClE,SAAS,GAAA,EAAK;AACZ,MAAA,OAAA,GAAU,GAAA,IAAO,IAAI,KAAA,CAAM,0BAA0B,CAAA;AAIrD,MAAA,KAAK,KAAA,CAAM,MAAM,MAAM;AAAA,MAAC,CAAC,CAAA;AAAA,IAC3B;AAEA,IAAA,IAAI,OAAA,EAAS;AACX,MAAA,IAAI,CAAC,iBAAA,EAAmB;AACtB,QAAA,MAAA,CAAO,KAAA;AAAA,UACL,EAAE,KAAK,OAAA,EAAQ;AAAA,UACf;AAAA,SACF;AACA,QAAA,OAAO,qBAAqB,GAAG,CAAA;AAAA,MACjC;AACA,MAAA,IAAI;AACF,QAAA,kBAAA,CAAmB,iBAAA,EAAmB;AAAA,UACpC,OAAO,OAAA,CAAQ,KAAA;AAAA,UACf,OAAO,OAAA,CAAQ,KAAA;AAAA,UACf,EAAA,EAAI,KAAK,GAAA;AAAI,SACd,CAAA;AACD,QAAA,MAAA,CAAO,IAAA;AAAA,UACL,EAAE,GAAA,EAAK,OAAA,EAAS,IAAA,EAAM,iBAAA,EAAkB;AAAA,UACxC;AAAA,SACF;AAAA,MACF,SAAS,OAAA,EAAS;AAChB,QAAA,MAAA,CAAO,KAAA;AAAA,UACL,EAAE,GAAA,EAAK,OAAA,EAAS,OAAA,EAAS,MAAM,iBAAA,EAAkB;AAAA,UACjD;AAAA,SACF;AACA,QAAA,OAAO,qBAAqB,GAAG,CAAA;AAAA,MACjC;AAAA,IACF;AAEA,IAAA,GAAA,CAAI,OAAO,GAAG,CAAA,CAAE,KAAK,MAAM,CAAA,CAAE,KAAK,uEAAuE,CAAA;AAAA,EAC3G,CAAC,CAAC,CAAA;AAKF,EAAA,MAAA,CAAO,IAAI,qBAAA,EAAuB,IAAA,CAAK,MAAA,EAAQ,OAAO,KAAc,GAAA,KAAkB;AACpF,IAAA,MAAM,KAAA,GAAS,IAAI,MAAA,CAAe,KAAA;AAClC,IAAA,MAAM,OAAA,GAAU,cAAA,CAAe,KAAA,EAAO,MAAA,CAAO,OAAO,iBAAiB,CAAA;AACrE,IAAA,IAAI,CAAC,OAAA,EAAS;AACZ,MAAA,OAAO,GAAA,CAAI,OAAO,GAAG,CAAA,CAAE,KAAK,MAAM,CAAA,CAAE,KAAK,0FAA0F,CAAA;AAAA,IACrI;AACA,IAAA,MAAM,GAAA,uBAAU,IAAA,EAAK;AACrB,IAAA,MAAM,MAAA,GAAS,MAAM,MAAA,CAAO,WAAA,CAAY,aAAA,CAAc,SAAA;AAAA,MACpD,EAAE,UAAA,EAAY,OAAA,CAAQ,UAAA,EAAY,QAAQ,aAAA,EAAc;AAAA,MACxD;AAAA,QACE,IAAA,EAAM;AAAA,UACJ,MAAA,EAAQ,YAAA;AAAA,UACR,YAAA,EAAc,GAAA;AAAA,UACd,cAAA,EAAgB,GAAA;AAAA,UAChB,KAAA,EAAO,IAAI,EAAA,IAAM,IAAA;AAAA,UACjB,YAAA,EAAe,GAAA,CAAI,OAAA,CAAQ,YAAY,CAAA,IAA4B,IAAA;AAAA,UACnE,SAAA,EAAW;AAAA;AACb;AACF,KACF;AACA,IAAA,IAAI,MAAA,CAAO,iBAAiB,CAAA,EAAG;AAC7B,MAAA,OAAO,GAAA,CAAI,OAAO,GAAG,CAAA,CAAE,KAAK,MAAM,CAAA,CAAE,KAAK,4EAA4E,CAAA;AAAA,IACvH;AACA,IAAA,IAAI;AACF,MAAA,MAAM,MAAA,CAAO,IAAA,CAAK,wBAAA,EAA0B,OAAA,CAAQ,UAAA,EAAY,EAAC,EAAG,CAAA,cAAA,EAAiB,OAAA,CAAQ,UAAU,CAAA,CAAE,CAAA;AAAA,IAC3G,CAAA,CAAA,MAAQ;AAAA,IAER;AACA,IAAA,OAAO,GAAA,CAAI,OAAO,GAAG,CAAA,CAAE,KAAK,MAAM,CAAA,CAAE,KAAK,kFAA8E,CAAA;AAAA,EACzH,CAAC,CAAC,CAAA;AAKF,EAAA,MAAA,CAAO,KAAK,qBAAA,EAAuB,IAAA,CAAK,MAAA,EAAQ,OAAO,KAAc,GAAA,KAAkB;AACrF,IAAA,MAAM,YAAA,GAAgB,IAAI,MAAA,CAAe,QAAA;AACzC,IAAA,MAAM,QAAA,GAAW,eAAA,CAAgB,MAAA,CAAO,SAAA,EAAW,YAAY,CAAA;AAC/D,IAAA,IAAI,CAAC,QAAA,EAAU,OAAO,IAAI,MAAA,CAAO,GAAG,EAAE,GAAA,EAAI;AAE1C,IAAA,MAAM,UAAW,GAAA,CAAY,OAAA;AAC7B,IAAA,IAAI,CAAC,OAAA,EAAS,OAAO,IAAI,MAAA,CAAO,GAAG,EAAE,GAAA,EAAI;AAEzC,IAAA,MAAM,OAAA,GAAU,gBAAA,CAAiB,GAAA,CAAI,OAAO,CAAA;AAC5C,IAAA,MAAM,KAAA,GAAQ,MAAM,QAAA,CAAS,aAAA,CAAc,SAAS,OAAO,CAAA;AAC3D,IAAA,IAAI,CAAC,KAAA,EAAO,OAAO,IAAI,MAAA,CAAO,GAAG,EAAE,GAAA,EAAI;AAEvC,IAAA,MAAM,MAAA,GAAS,QAAA,CAAS,kBAAA,CAAmB,GAAA,CAAI,MAAM,OAAO,CAAA;AAG5D,IAAA,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,GAAA,EAAI;AAKpB,IAAA,MAAM,aAAa,GAAA,CAAI,IAAA;AACvB,IAAA,KAAA,MAAW,OAAO,MAAA,EAAQ;AACxB,MAAA,IAAI;AACF,QAAA,MAAM,MAAA,CAAO,YAAY,aAAA,CAAc,SAAA;AAAA,UACrC,EAAE,QAAA,EAAU,YAAA,EAAc,eAAA,EAAiB,IAAI,eAAA,EAAgB;AAAA,UAC/D;AAAA,YACE,YAAA,EAAc;AAAA,cACZ,QAAA,EAAU,YAAA;AAAA,cACV,iBAAiB,GAAA,CAAI,eAAA;AAAA,cACrB,WAAW,GAAA,CAAI,IAAA;AAAA,cACf,gBAAgB,GAAA,CAAI,IAAA;AAAA,cACpB,mBAAmB,GAAA,CAAI,iBAAA;AAAA,cACvB,OAAO,GAAA,CAAI,KAAA;AAAA,cACX,YAAY,GAAA,CAAI,UAAA;AAAA,cAChB,UAAA,sBAAgB,IAAA,EAAK;AAAA,cACrB,SAAA,EAAW,KAAA;AAAA,cACX,GAAA,EAAK,EAAE,UAAA,EAAY,GAAA,EAAK,cAAc,UAAA;AAAW;AACnD,WACF;AAAA,UACA,EAAE,QAAQ,IAAA;AAAK,SACjB;AAAA,MACF,SAAS,GAAA,EAAK;AACZ,QAAA,MAAA,CAAO,KAAA;AAAA,UACL,EAAE,GAAA,EAAK,QAAA,EAAU,YAAA,EAAc,eAAA,EAAiB,IAAI,eAAA,EAAgB;AAAA,UACpE;AAAA,SACF;AAAA,MACF;AAAA,IACF;AAEA,IAAA,IAAI,MAAA,CAAO,SAAS,CAAA,EAAG;AACrB,MAAA,IAAI;AACF,QAAA,MAAM,MAAA,CAAO,OAAO,OAAA,CAAQ,GAAA,CAAI,WAAW,EAAE,QAAA,EAAU,cAAc,CAAA;AAAA,MACvE,CAAA,CAAA,MAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF,CAAC,CAAC,CAAA;AAEF,EAAA,OAAO,MAAA;AACT;AAOA,IAAM,iBAAA,GAAoB,EAAA;AAG1B,IAAM,aAAA,GAAgB,GAAA;AAEtB,SAAS,iBAAiB,GAAA,EAA6B;AACrD,EAAA,MAAM,EAAA,GAAK,GAAA,CAAI,OAAA,CAAQ,YAAY,CAAA;AACnC,EAAA,IAAI,OAAO,EAAA,KAAO,QAAA,IAAY,GAAG,IAAA,EAAK,KAAM,IAAI,OAAO,IAAA;AACvD,EAAA,OAAO,EAAA,CAAG,KAAA,CAAM,CAAA,EAAG,aAAa,CAAA;AAClC;AAUA,SAAS,eAAe,GAAA,EAAmD;AACzE,EAAA,IAAI,OAAO,GAAA,KAAQ,QAAA,EAAU,OAAO,IAAA;AACpC,EAAA,MAAM,KAAA,GAAQ,GAAA,CAAI,KAAA,CAAM,GAAG,CAAA;AAC3B,EAAA,IAAI,KAAA,CAAM,WAAW,CAAA,EAAG,OAAO,EAAE,EAAA,EAAI,KAAA,CAAM,CAAC,CAAA,EAAG;AAC/C,EAAA,IAAI,KAAA,CAAM,MAAA,KAAW,CAAA,EAAG,OAAO,EAAE,EAAA,EAAI,KAAA,CAAM,CAAC,CAAA,EAAI,GAAA,EAAK,KAAA,CAAM,CAAC,CAAA,EAAG;AAC/D,EAAA,OAAO,IAAA;AACT;AAuBA,SAAS,uBAAuB,IAAA,EAQZ;AAClB,EAAA,MAAM,EAAE,GAAA,EAAK,MAAA,EAAQ,MAAA,EAAQ,OAAM,GAAI,IAAA;AAEvC,EAAA,IAAI,GAAA,KAAQ,MAAA,IAAa,GAAA,KAAQ,EAAA,EAAI;AACnC,IAAA,IAAI,KAAK,aAAA,EAAe;AACtB,MAAA,MAAA,CAAO,IAAA;AAAA,QACL,EAAE,GAAG,MAAA,EAAQ,KAAA,EAAM;AAAA,QACnB;AAAA,OACF;AACA,MAAA,OAAO,UAAA;AAAA,IACT;AAKA,IAAA,MAAA,CAAO,IAAA;AAAA,MACL,EAAE,GAAG,MAAA,EAAQ,KAAA,EAAM;AAAA,MACnB;AAAA,KACF;AACA,IAAA,OAAO,QAAA;AAAA,EACT;AAEA,EAAA,IAAI,CAAC,oBAAoB,GAAA,EAAK,KAAA,EAAO,KAAK,MAAA,EAAQ,IAAA,CAAK,MAAM,CAAA,EAAG;AAC9D,IAAA,MAAA,CAAO,OAAO,EAAE,GAAG,MAAA,EAAQ,KAAA,IAAS,yCAAyC,CAAA;AAC7E,IAAA,OAAO,UAAA;AAAA,EACT;AACA,EAAA,OAAO,QAAA;AACT;AAWA,SAAS,kBAAkB,IAAA,EAAiC,YAAA,EAAsB,GAAA,mBAAY,IAAI,MAAK,EAAY;AACjH,EAAA,IAAI,CAAC,YAAA,IAAgB,YAAA,IAAgB,CAAA,EAAG,OAAO,KAAA;AAC/C,EAAA,MAAM,WAAW,IAAA,CAAK,QAAA;AACtB,EAAA,IAAI,EAAE,oBAAoB,IAAA,CAAA,IAAS,MAAA,CAAO,MAAM,QAAA,CAAS,OAAA,EAAS,CAAA,EAAG,OAAO,KAAA;AAC5E,EAAA,OAAO,GAAA,CAAI,SAAQ,GAAI,QAAA,CAAS,SAAQ,GAAI,YAAA,GAAe,EAAA,GAAK,EAAA,GAAK,EAAA,GAAK,GAAA;AAC5E;AAEA,SAAS,cAAA,CAAe,KAAe,GAAA,EAAuB;AAC5D,EAAA,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,MAAM,CAAA,CAAE,IAAA,CAAK,CAAA,8BAAA,EAAiC,UAAA,CAAW,GAAG,CAAC,CAAA,kBAAA,CAAoB,CAAA;AAC/G;AAOA,SAAS,qBAAqB,GAAA,EAAyB;AACrD,EAAA,OAAO,GAAA,CACJ,MAAA,CAAO,GAAG,CAAA,CACV,GAAA,CAAI,eAAe,IAAI,CAAA,CACvB,IAAA,CAAK,MAAM,CAAA,CACX,IAAA;AAAA,IACC;AAAA,GAEF;AACJ;AAUA,SAAS,WAAA,CAAe,GAAe,EAAA,EAAwB;AAC7D,EAAA,IAAI,CAAC,MAAA,CAAO,QAAA,CAAS,EAAE,CAAA,IAAK,EAAA,IAAM,GAAG,OAAO,CAAA;AAC5C,EAAA,OAAO,IAAI,OAAA,CAAW,CAAC,OAAA,EAAS,MAAA,KAAW;AACzC,IAAA,MAAM,KAAA,GAAQ,WAAW,MAAM;AAC7B,MAAA,MAAA,CAAO,IAAI,KAAA,CAAM,CAAA,gBAAA,EAAmB,EAAE,IAAI,CAAC,CAAA;AAAA,IAC7C,GAAG,EAAE,CAAA;AACL,IAAA,IAAI,OAAO,KAAA,CAAM,KAAA,KAAU,UAAA,QAAkB,KAAA,EAAM;AACnD,IAAA,CAAA,CAAE,IAAA;AAAA,MACA,CAAC,CAAA,KAAM;AACL,QAAA,YAAA,CAAa,KAAK,CAAA;AAClB,QAAA,OAAA,CAAQ,CAAC,CAAA;AAAA,MACX,CAAA;AAAA,MACA,CAAC,GAAA,KAAQ;AACP,QAAA,YAAA,CAAa,KAAK,CAAA;AAClB,QAAA,MAAA,CAAO,GAAG,CAAA;AAAA,MACZ;AAAA,KACF;AAAA,EACF,CAAC,CAAA;AACH;AAEA,SAAS,WAAW,CAAA,EAAmB;AACrC,EAAA,OAAO,EACJ,OAAA,CAAQ,IAAA,EAAM,OAAO,CAAA,CACrB,OAAA,CAAQ,MAAM,MAAM,CAAA,CACpB,QAAQ,IAAA,EAAM,MAAM,EACpB,OAAA,CAAQ,IAAA,EAAM,QAAQ,CAAA,CACtB,OAAA,CAAQ,MAAM,OAAO,CAAA;AAC1B;AAGA,IAAM,6CAA6B,IAAI,GAAA,CAAI,CAAC,OAAA,EAAS,QAAQ,CAAC,CAAA;AAiB9D,SAAS,qBAAqB,GAAA,EAA6B;AACzD,EAAA,IAAI,OAAO,GAAA,KAAQ,QAAA,EAAU,OAAO,KAAA;AACpC,EAAA,MAAM,OAAA,GAAU,IAAI,IAAA,EAAK;AACzB,EAAA,IAAI,OAAA,KAAY,IAAI,OAAO,KAAA;AAC3B,EAAA,IAAI,MAAA;AACJ,EAAA,IAAI;AACF,IAAA,MAAA,GAAS,IAAI,IAAI,OAAO,CAAA;AAAA,EAC1B,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,KAAA;AAAA,EACT;AACA,EAAA,OAAO,0BAAA,CAA2B,GAAA,CAAI,MAAA,CAAO,QAAQ,CAAA;AACvD;AAEA,SAAS,iBAAiB,CAAA,EAAgC;AACxD,EAAA,MAAM,MAA8B,EAAC;AACrC,EAAA,KAAA,MAAW,CAAA,IAAK,MAAA,CAAO,IAAA,CAAK,CAAC,CAAA,EAAG;AAC9B,IAAA,MAAM,CAAA,GAAI,EAAE,CAAC,CAAA;AACb,IAAA,GAAA,CAAI,CAAA,CAAE,WAAA,EAAa,CAAA,GAAI,MAAM,OAAA,CAAQ,CAAC,CAAA,GAAI,CAAA,CAAE,IAAA,CAAK,GAAG,CAAA,GAAI,MAAA,CAAO,KAAK,EAAE,CAAA;AAAA,EACxE;AACA,EAAA,OAAO,GAAA;AACT;;;ACloBO,IAAM,eAAA,GAAiD;AAAA,EAC5D,EAAE,KAAA,EAAO,MAAA,EAAc,KAAA,EAAO,MAAA,EAAc,MAAM,OAAA,EAAY,SAAA,EAAW,MAAA,EAAa,WAAA,EAAa,iDAAA,EAAkD;AAAA,EACrJ,EAAE,KAAA,EAAO,WAAA,EAAc,KAAA,EAAO,WAAA,EAAc,MAAM,QAAA,EAAY,SAAA,EAAW,WAAA,EAAa,WAAA,EAAa,8CAAA,EAA+C;AAAA,EAClJ,EAAE,KAAA,EAAO,QAAA,EAAc,KAAA,EAAO,QAAA,EAAc,MAAM,QAAA,EAAY,SAAA,EAAW,WAAA,EAAa,WAAA,EAAa,0DAAA,EAA2D;AAAA,EAC9J,EAAE,KAAA,EAAO,MAAA,EAAc,KAAA,EAAO,MAAA,EAAc,MAAM,MAAA,EAAY,SAAA,EAAW,MAAA,EAAa,WAAA,EAAa,iCAAA,EAAkC;AAAA,EACrI,EAAE,KAAA,EAAO,KAAA,EAAc,KAAA,EAAO,KAAA,EAAc,MAAM,KAAA,EAAY,SAAA,EAAW,KAAA,EAAa,WAAA,EAAa,oCAAA,EAAqC;AAAA,EACxI,EAAE,KAAA,EAAO,YAAA,EAAc,KAAA,EAAO,YAAA,EAAc,MAAM,UAAA,EAAY,SAAA,EAAW,MAAA,EAAa,WAAA,EAAa,gDAAA,EAAiD;AAAA,EACpJ,EAAE,KAAA,EAAO,SAAA,EAAc,KAAA,EAAO,SAAA,EAAc,MAAM,SAAA,EAAY,SAAA,EAAW,KAAA,EAAa,WAAA,EAAa,0BAAA,EAA2B;AAAA,EAC9H,EAAE,KAAA,EAAO,MAAA,EAAc,KAAA,EAAO,MAAA,EAAc,MAAM,MAAA,EAAY,SAAA,EAAW,MAAA,EAAa,WAAA,EAAa,sCAAA;AACrG;AAEO,SAAS,gBAAgB,IAAA,EAAkC;AAChE,EAAA,QAAQ,IAAA;AAAM,IACZ,KAAK,MAAA;AAAc,MAAA,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,KAAA,EAAO,CAAA,EAAG,MAAM,MAAA,EAAO;AAAA,IACjE,KAAK,WAAA;AAAc,MAAA,OAAO,EAAE,MAAM,WAAA,EAAa,IAAA,EAAM,EAAE,MAAA,EAAQ,SAAA,EAAU,EAAG,OAAA,EAAS,MAAA,EAAO;AAAA,IAC5F,KAAK,QAAA;AAAc,MAAA,OAAO,EAAE,IAAA,EAAM,QAAA,EAAU,IAAA,EAAM,EAAE,MAAA,EAAQ,KAAA,EAAM,EAAG,WAAA,EAAa,EAAC,EAAG,YAAA,EAAc,EAAC,EAAE;AAAA,IACvG,KAAK,MAAA;AAAc,MAAA,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,YAAA,EAAc,EAAA,EAAG;AAAA,IAC3D,KAAK,KAAA;AAAc,MAAA,OAAO,EAAE,MAAM,KAAA,EAAO,OAAA,EAAS,EAAC,EAAG,UAAA,EAAY,EAAC,EAAE;AAAA,IACrE,KAAK,YAAA;AAAc,MAAA,OAAO,EAAE,IAAA,EAAM,YAAA,EAAc,SAAA,EAAW,EAAA,EAAG;AAAA,IAC9D,KAAK,SAAA;AAAc,MAAA,OAAO,EAAE,IAAA,EAAM,SAAA,EAAW,GAAA,EAAK,EAAA,EAAI,QAAQ,MAAA,EAAO;AAAA,IACrE,KAAK,MAAA;AAAc,MAAA,OAAO,EAAE,MAAM,MAAA,EAAO;AAAA;AAE7C;AA8BO,IAAM,eAAA,GAAkD;AAAA,EAC7D,EAAE,KAAA,EAAO,QAAA,EAAU,KAAA,EAAO,SAAA,EAAU;AAAA,EACpC,EAAE,KAAA,EAAO,WAAA,EAAa,KAAA,EAAO,mBAAA,EAAoB;AAAA,EACjD,EAAE,KAAA,EAAO,aAAA,EAAe,KAAA,EAAO,cAAA,EAAe;AAAA,EAC9C,EAAE,KAAA,EAAO,aAAA,EAAe,KAAA,EAAO,cAAA,EAAe;AAAA,EAC9C,EAAE,KAAA,EAAO,uBAAA,EAAyB,KAAA,EAAO,yBAAA,EAA0B;AAAA,EACnE,EAAE,KAAA,EAAO,uBAAA,EAAyB,KAAA,EAAO,yBAAA,EAA0B;AAAA,EACnE,EAAE,KAAA,EAAO,eAAA,EAAiB,KAAA,EAAO,aAAA,EAAc;AAAA,EAC/C,EAAE,KAAA,EAAO,kBAAA,EAAoB,KAAA,EAAO,qBAAA,EAAsB;AAAA,EAC1D,EAAE,KAAA,EAAO,oBAAA,EAAsB,KAAA,EAAO,qBAAA,EAAsB;AAAA,EAC5D,EAAE,KAAA,EAAO,WAAA,EAAa,KAAA,EAAO,QAAA,EAAU,OAAO,IAAA,EAAK;AAAA,EACnD,EAAE,KAAA,EAAO,YAAA,EAAc,KAAA,EAAO,SAAA,EAAW,OAAO,IAAA,EAAK;AAAA,EACrD,EAAE,KAAA,EAAO,wBAAA,EAA0B,KAAA,EAAO,qBAAA,EAAsB;AAAA,EAChE,EAAE,KAAA,EAAO,yBAAA,EAA2B,KAAA,EAAO,sBAAA,EAAuB;AAAA,EAClE,EAAE,KAAA,EAAO,gBAAA,EAAkB,KAAA,EAAO,mBAAA,EAAoB;AAAA,EACtD,EAAE,KAAA,EAAO,iBAAA,EAAmB,KAAA,EAAO,oBAAA;AACrC;AAGO,SAAS,cAAc,CAAA,EAAuD;AACnF,EAAA,IAAI,CAAC,GAAG,OAAO,IAAA;AACf,EAAA,KAAA,MAAW,KAAK,eAAA,EAAiB;AAC/B,IAAA,IAAI,CAAA,CAAE,KAAA,IAAU,CAAA,EAAc,OAAO,CAAA,CAAE,KAAA;AAAA,EACzC;AACA,EAAA,OAAO,IAAA;AACT;AAEO,SAAS,iBAAiB,IAAA,EAAgC;AAC/D,EAAA,QAAQ,IAAA;AAAM,IACZ,KAAK,QAAA;AAAU,MAAA,OAAO,EAAE,QAAQ,SAAA,EAAU;AAAA,IAC1C,KAAK,WAAA;AAAa,MAAA,OAAO,EAAE,WAAW,MAAA,EAAO;AAAA,IAC7C,KAAK,aAAA;AAAe,MAAA,OAAO,EAAE,WAAA,EAAa,EAAE,OAAO,MAAA,EAAQ,KAAA,EAAO,OAAM,EAAE;AAAA,IAC1E,KAAK,aAAA;AAAe,MAAA,OAAO,EAAE,aAAa,MAAA,EAAO;AAAA,IACjD,KAAK,uBAAA;AAAyB,MAAA,OAAO,EAAE,qBAAA,EAAuB,EAAE,KAAK,MAAA,EAAQ,KAAA,EAAO,OAAM,EAAE;AAAA,IAC5F,KAAK,uBAAA;AAAyB,MAAA,OAAO,EAAE,uBAAuB,aAAA,EAAc;AAAA,IAC5E,KAAK,eAAA;AAAiB,MAAA,OAAO,EAAE,eAAe,eAAA,EAAgB;AAAA,IAC9D,KAAK,kBAAA;AAAoB,MAAA,OAAO,EAAE,kBAAkB,WAAA,EAAY;AAAA,IAChE,KAAK,oBAAA;AAAsB,MAAA,OAAO,EAAE,oBAAoB,YAAA,EAAa;AAAA,IACrE,KAAK,WAAA;AAAa,MAAA,OAAO,EAAE,SAAA,EAAW,EAAE,cAAA,EAAgB,MAAK,EAAE;AAAA,IAC/D,KAAK,YAAA;AAAc,MAAA,OAAO,EAAE,UAAA,EAAY,EAAE,cAAA,EAAgB,MAAK,EAAE;AAAA,IACjE,KAAK,wBAAA;AAA0B,MAAA,OAAO,EAAE,sBAAA,EAAwB,EAAE,cAAA,EAAgB,MAAK,EAAE;AAAA,IACzF,KAAK,yBAAA;AAA2B,MAAA,OAAO,EAAE,uBAAA,EAAyB,EAAE,cAAA,EAAgB,MAAK,EAAE;AAAA,IAC3F,KAAK,gBAAA;AAAkB,MAAA,OAAO,EAAE,cAAA,EAAgB,EAAE,OAAO,CAAA,EAAG,UAAA,EAAY,GAAE,EAAE;AAAA,IAC5E,KAAK,iBAAA;AAAmB,MAAA,OAAO,EAAE,eAAA,EAAiB,EAAE,OAAO,CAAA,EAAG,UAAA,EAAY,GAAE,EAAE;AAAA;AAElF;AAeO,IAAM,oBAAA,GAA2D;AAAA,EACtE,EAAE,KAAA,EAAO,oBAAA,EAAsB,KAAA,EAAO,qBAAA,EAAuB,MAAM,QAAA,EAAS;AAAA,EAC5E,EAAE,KAAA,EAAO,QAAA,EAAU,KAAA,EAAO,SAAA,EAAW,MAAM,MAAA,EAAO;AAAA,EAClD,EAAE,KAAA,EAAO,WAAA,EAAa,KAAA,EAAO,mBAAA,EAAqB,MAAM,MAAA,EAAO;AAAA,EAC/D,EAAE,KAAA,EAAO,aAAA,EAAe,KAAA,EAAO,cAAA,EAAgB,MAAM,MAAA,EAAO;AAAA,EAC5D,EAAE,KAAA,EAAO,SAAA,EAAW,KAAA,EAAO,eAAA,EAAiB,MAAM,MAAA,EAAO;AAAA,EACzD,EAAE,KAAA,EAAO,aAAA,EAAe,KAAA,EAAO,cAAA,EAAgB,MAAM,MAAA,EAAO;AAAA,EAC5D,EAAE,KAAA,EAAO,YAAA,EAAc,KAAA,EAAO,aAAA,EAAe,MAAM,QAAA,EAAS;AAAA,EAC5D,EAAE,KAAA,EAAO,eAAA,EAAiB,KAAA,EAAO,qBAAA,EAAuB,MAAM,QAAA,EAAS;AAAA,EACvE,EAAE,KAAA,EAAO,iBAAA,EAAmB,KAAA,EAAO,kBAAA,EAAoB,MAAM,QAAA,EAAS;AAAA,EACtE,EAAE,KAAA,EAAO,kBAAA,EAAoB,KAAA,EAAO,mBAAA,EAAqB,MAAM,QAAA,EAAS;AAAA,EACxE,EAAE,KAAA,EAAO,QAAA,EAAU,KAAA,EAAO,QAAA,EAAU,MAAM,QAAA,EAAS;AAAA,EACnD,EAAE,KAAA,EAAO,WAAA,EAAa,KAAA,EAAO,cAAA,EAAgB,MAAM,QAAA,EAAS;AAAA,EAC5D,EAAE,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,aAAA,EAAe,MAAM,WAAA,EAAY;AAAA,EACxD,EAAE,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,MAAM,WAAA;AACtC;AAEO,SAAS,qBAAqB,IAAA,EAAwC;AAC3E,EAAA,QAAQ,IAAA;AAAM,IACZ,KAAK,oBAAA;AAAsB,MAAA,OAAO,EAAE,IAAA,EAAM,oBAAA,EAAsB,MAAA,EAAQ,YAAA,EAAa;AAAA,IACrF,KAAK,QAAA;AAAU,MAAA,OAAO,EAAE,IAAA,EAAM,QAAA,EAAU,GAAA,EAAK,EAAA,EAAG;AAAA,IAChD,KAAK,WAAA;AAAa,MAAA,OAAO,EAAE,IAAA,EAAM,WAAA,EAAa,GAAA,EAAK,EAAA,EAAG;AAAA,IACtD,KAAK,aAAA;AAAe,MAAA,OAAO,EAAE,IAAA,EAAM,aAAA,EAAe,KAAA,EAAO,EAAA,EAAI,OAAO,EAAA,EAAG;AAAA,IACvE,KAAK,SAAA;AAAW,MAAA,OAAO,EAAE,IAAA,EAAM,SAAA,EAAW,OAAO,EAAA,EAAI,MAAA,EAAQ,EAAC,EAAE;AAAA,IAChE,KAAK,aAAA;AAAe,MAAA,OAAO,EAAE,IAAA,EAAM,aAAA,EAAe,KAAA,EAAO,EAAA,EAAG;AAAA,IAC5D,KAAK,YAAA;AAAc,MAAA,OAAO,EAAE,IAAA,EAAM,YAAA,EAAc,SAAA,EAAW,EAAA,EAAI,YAAY,EAAA,EAAG;AAAA,IAC9E,KAAK,eAAA;AAAiB,MAAA,OAAO,EAAE,IAAA,EAAM,eAAA,EAAiB,SAAA,EAAW,EAAA,EAAI,YAAY,EAAA,EAAG;AAAA,IACpF,KAAK,iBAAA;AAAmB,MAAA,OAAO,EAAE,IAAA,EAAM,iBAAA,EAAmB,IAAA,EAAM,IAAI,IAAA,CAAK,IAAA,CAAK,GAAA,EAAI,GAAI,EAAA,GAAK,KAAU,CAAA,EAAE;AAAA,IACvG,KAAK,kBAAA;AAAoB,MAAA,OAAO,EAAE,IAAA,EAAM,kBAAA,EAAoB,IAAA,kBAAM,IAAI,MAAK,EAAE;AAAA,IAC7E,KAAK,QAAA;AAAU,MAAA,OAAO,EAAE,IAAA,EAAM,QAAA,EAAU,UAAA,EAAY,EAAA,EAAG;AAAA,IACvD,KAAK,WAAA;AAAa,MAAA,OAAO,EAAE,IAAA,EAAM,WAAA,EAAa,UAAA,EAAY,EAAA,EAAG;AAAA,IAC7D,KAAK,KAAA;AAAO,MAAA,OAAO,EAAE,IAAA,EAAM,KAAA,EAAO,OAAA,EAAS,EAAC,EAAE;AAAA,IAC9C,KAAK,KAAA;AAAO,MAAA,OAAO,EAAE,MAAM,KAAA,EAAO,MAAA,EAAQ,EAAE,IAAA,EAAM,QAAA,EAAU,GAAA,EAAK,EAAA,EAAG,EAAE;AAAA;AAE1E;AAaO,IAAM,eAAA,GAAiD;AAAA,EAC5D;AAAA,IACE,KAAA,EAAO,kBAAA;AAAA,IACP,KAAA,EAAO,kBAAA;AAAA,IACP,WAAA,EAAa,wCAAA;AAAA,IACb,eAAA,EAAiB;AAAA,GACnB;AAAA,EACA;AAAA,IACE,KAAA,EAAO,cAAA;AAAA,IACP,KAAA,EAAO,cAAA;AAAA,IACP,WAAA,EAAa,qCAAA;AAAA,IACb,eAAA,EAAiB;AAAA,GACnB;AAAA,EACA;AAAA,IACE,KAAA,EAAO,YAAA;AAAA,IACP,KAAA,EAAO,YAAA;AAAA,IACP,WAAA,EAAa,yCAAA;AAAA,IACb,eAAA,EAAiB;AAAA;AAErB;;;AXjMO,IAAM,OAAA,GAAgD,QAAA","file":"index.cjs","sourcesContent":["/**\n * VarsAdapter — host-provided template variables, resolved at render time.\n *\n * The host declares a zod schema (the contract templates can rely on) plus a\n * `resolve` function that loads those values from the host's own database for\n * a given contact. Resolved keys are merged into the render context root, so\n * a schema key `user` is referenced in templates as `{{user.name}}`.\n *\n * The schema does double duty: it is exposed to the admin SPA as JSON Schema\n * (GET /vars-schema) to drive editor autocomplete, and the content linter\n * uses it to flag `{{paths}}` that don't exist.\n */\n\nimport { z } from 'zod'\n\nimport type { Contact } from '../../shared/types.js'\n\nexport interface VarsResolveInfo {\n /** Why the vars are being resolved. Previews and tests should be side-effect free. */\n reason: 'send' | 'preview' | 'test'\n /** Slug of the template being rendered, when known. */\n templateSlug?: string\n /** Slug of the flow the send belongs to, when the render is part of a flow run. */\n flowSlug?: string\n /** Name of the event that triggered the flow run, when applicable. */\n eventName?: string\n /**\n * Properties of the triggering event (`mailer.fire(name, id, properties)`).\n * This is how a resolver scopes lookups for account/topic flows:\n * `info.eventProperties?.accountId` tells it WHICH account the run is about.\n * Also available raw in templates as `{{event.*}}`.\n */\n eventProperties?: Record<string, unknown>\n}\n\nexport interface VarsAdapter<S extends z.ZodType = z.ZodType> {\n /** Contract for what `resolve` returns. Root keys become root template variables. */\n schema: S\n /** Load the variables for one contact from the host's data. */\n resolve(contact: Contact, info: VarsResolveInfo): Promise<z.infer<S>> | z.infer<S>\n}\n\n/**\n * Identity helper that pins `resolve`'s return type to `z.infer<schema>` —\n * without it, TypeScript widens the schema generic and the return type is\n * unchecked.\n *\n * const varsAdapter = defineVars({\n * schema: z.object({ user: z.object({ name: z.string() }) }),\n * async resolve(contact) {\n * return { user: { name: await lookupName(contact.externalId) } }\n * },\n * })\n */\nexport function defineVars<S extends z.ZodType>(adapter: VarsAdapter<S>): VarsAdapter<S> {\n return adapter\n}\n\n/**\n * Render-context keys mailery owns. Resolved vars never override these — a\n * schema that declares one is rejected at Mailer.init.\n */\nexport const RESERVED_VAR_KEYS = [\n 'contact',\n 'vars',\n 'event',\n 'unsubscribeUrl',\n 'viewInBrowserUrl',\n 'preferenceCenterUrl',\n 'senderAddress',\n] as const\n\n/**\n * Throw if the schema's root keys collide with reserved render-context keys.\n * Called once at Mailer.init — fail fast, not per send.\n */\nexport function assertNoReservedVarKeys(adapter: VarsAdapter): void {\n const json = varsJsonSchema(adapter)\n const props = json && typeof json === 'object' ? (json as any).properties : undefined\n if (!props) return\n const clashes = RESERVED_VAR_KEYS.filter((k) => k in props)\n if (clashes.length > 0) {\n throw new Error(\n `varsAdapter schema declares reserved key(s): ${clashes.join(', ')}. ` +\n `These names are provided by mailery itself — rename them in your schema.`,\n )\n }\n}\n\n/** JSON Schema for the adapter's zod schema (wire format for the admin SPA + linter). */\nexport function varsJsonSchema(adapter: VarsAdapter): Record<string, unknown> {\n return z.toJSONSchema(adapter.schema, { io: 'output' }) as Record<string, unknown>\n}\n\n/**\n * Resolve vars for a contact, or `{}` when no adapter is configured.\n * Errors propagate to the caller — send paths let the queue retry, preview\n * paths surface the message to the operator.\n */\nexport async function resolveVars(\n adapter: VarsAdapter | undefined,\n contact: Contact,\n info: VarsResolveInfo,\n): Promise<Record<string, unknown>> {\n if (!adapter) return {}\n const resolved = await adapter.resolve(contact, info)\n if (!resolved || typeof resolved !== 'object') return {}\n // Belt-and-braces: drop reserved keys even if the init-time assert was\n // bypassed (e.g. a hand-built adapter object with a lying schema).\n const out: Record<string, unknown> = { ...(resolved as Record<string, unknown>) }\n for (const k of RESERVED_VAR_KEYS) delete out[k]\n return out\n}\n","/**\n * MongoContactAdapter — reads contacts directly from the host's `users`\n * collection (read-mostly; optional narrow tag writes). Mailer never\n * duplicates identity data — the host is the source of truth.\n */\n\nimport type { Collection, Db, Filter } from 'mongodb'\nimport { ObjectId } from 'mongodb'\n\nimport type {\n AdapterFilter,\n Contact,\n ContactAdapter,\n} from '../../shared/types.js'\n\nexport interface MongoContactAdapterOptions {\n db: Db\n collection: string\n emailField?: string\n idField?: string\n /** Path to the tags array on the user document. */\n tagsField?: string\n /** When true, mailer writes tags via `$addToSet` / `$pull` on the user doc. */\n tagsWritable?: boolean\n /** 'strings' = ['vip','beta'], 'objects' = [{ name: 'vip' }]. */\n tagsArrayShape?: 'strings' | 'objects'\n /** Customize the projection mailer sees. Defaults pick up email + tags + a few common fields. */\n toContact?: (userDoc: any) => Contact\n /** Customize how AdapterFilter becomes a Mongo query. */\n translateFilter?: (filter: AdapterFilter) => Filter<any>\n /** Per-call default for query() limit. */\n batchSize?: number\n}\n\nexport class MongoContactAdapter implements ContactAdapter {\n private readonly col: Collection<any>\n private readonly emailField: string\n private readonly idField: string\n private readonly tagsField: string | null\n private readonly tagsWritable: boolean\n private readonly tagsArrayShape: 'strings' | 'objects'\n private readonly toContactFn: (doc: any) => Contact\n private readonly translateFilterFn: (filter: AdapterFilter) => Filter<any>\n private readonly batchSize: number\n\n constructor(opts: MongoContactAdapterOptions) {\n this.col = opts.db.collection(opts.collection)\n this.emailField = opts.emailField ?? 'email'\n this.idField = opts.idField ?? '_id'\n this.tagsField = opts.tagsField ?? null\n this.tagsWritable = !!opts.tagsWritable\n this.tagsArrayShape = opts.tagsArrayShape ?? 'strings'\n this.toContactFn = opts.toContact ?? this.defaultToContact.bind(this)\n this.translateFilterFn = opts.translateFilter ?? this.defaultTranslateFilter.bind(this)\n this.batchSize = opts.batchSize ?? 500\n\n // Only expose tag write methods if the host opted in.\n if (this.tagsWritable && this.tagsField) {\n this.addTags = this.addTagsImpl.bind(this)\n this.removeTags = this.removeTagsImpl.bind(this)\n }\n }\n\n async getById(externalId: string): Promise<Contact | null> {\n const filter = this.idFilter(externalId)\n const doc = await this.col.findOne(filter)\n return doc ? this.toContactFn(doc) : null\n }\n\n async getByEmail(email: string): Promise<Contact | null> {\n const doc = await this.col.findOne({ [this.emailField]: email.toLowerCase() })\n return doc ? this.toContactFn(doc) : null\n }\n\n async getBatch(externalIds: string[]): Promise<Map<string, Contact>> {\n if (externalIds.length === 0) return new Map()\n const tryObjectId = externalIds.every(canBeObjectId)\n const ids: any[] = tryObjectId ? externalIds.map((s) => new ObjectId(s)) : externalIds\n const docs = await this.col.find({ [this.idField]: { $in: ids } }).toArray()\n const out = new Map<string, Contact>()\n for (const doc of docs) {\n const c = this.toContactFn(doc)\n out.set(c.externalId, c)\n }\n return out\n }\n\n async query(\n filter: AdapterFilter,\n opts: { limit: number; cursor?: string },\n ): Promise<{ contacts: Contact[]; nextCursor?: string }> {\n const query = this.translateFilterFn(filter)\n const limit = Math.min(opts.limit, this.batchSize)\n\n // Cursor is an ObjectId-or-externalId encoded as a string; we use it as a >\n // bound on the idField for stable pagination ordered by id.\n if (opts.cursor) {\n const cursorVal = canBeObjectId(opts.cursor) ? new ObjectId(opts.cursor) : opts.cursor\n ;(query as any)[this.idField] = { ...((query as any)[this.idField] ?? {}), $gt: cursorVal }\n }\n\n const docs = await this.col\n .find(query)\n .sort({ [this.idField]: 1 })\n .limit(limit + 1)\n .toArray()\n\n const hasMore = docs.length > limit\n const slice = hasMore ? docs.slice(0, limit) : docs\n const contacts = slice.map((d) => this.toContactFn(d))\n const last = slice[slice.length - 1]\n const nextCursor = hasMore && last ? String((last as any)[this.idField]) : undefined\n return { contacts, nextCursor }\n }\n\n async count(filter: AdapterFilter): Promise<number> {\n const query = this.translateFilterFn(filter)\n return await this.col.countDocuments(query)\n }\n\n addTags?: (externalId: string, tags: string[]) => Promise<void>\n removeTags?: (externalId: string, tags: string[]) => Promise<void>\n\n // -------------------------------------------------------------------------\n // Private helpers\n // -------------------------------------------------------------------------\n\n private idFilter(externalId: string): Filter<any> {\n if (this.idField === '_id' && canBeObjectId(externalId)) {\n return { _id: new ObjectId(externalId) } as Filter<any>\n }\n return { [this.idField]: externalId }\n }\n\n private defaultToContact(doc: any): Contact {\n const tagsRaw = this.tagsField ? doc[this.tagsField] ?? [] : []\n const tags: string[] =\n this.tagsArrayShape === 'objects'\n ? (Array.isArray(tagsRaw) ? tagsRaw : []).map((t: any) => String(t.name ?? t))\n : (Array.isArray(tagsRaw) ? tagsRaw : []).map((t: any) => String(t))\n\n const externalId = String(doc[this.idField] ?? '')\n const email = String(doc[this.emailField] ?? '').toLowerCase()\n\n // Default projection: everything that's not _id / email / tags becomes a field.\n const fields: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(doc)) {\n if (k === this.idField || k === this.emailField || k === this.tagsField) continue\n fields[k] = v\n }\n\n return {\n externalId,\n email,\n tags,\n fields,\n timezone: typeof doc.timezone === 'string' ? doc.timezone : undefined,\n locale: typeof doc.locale === 'string' ? doc.locale : undefined,\n }\n }\n\n private defaultTranslateFilter(filter: AdapterFilter): Filter<any> {\n const q: Record<string, unknown> = {}\n\n if (filter.emailIn && filter.emailIn.length > 0) {\n q[this.emailField] = { $in: filter.emailIn.map((e) => e.toLowerCase()) }\n }\n if (filter.externalIdIn && filter.externalIdIn.length > 0) {\n const tryObjectId = filter.externalIdIn.every(canBeObjectId)\n q[this.idField] = {\n $in: tryObjectId ? filter.externalIdIn.map((s) => new ObjectId(s)) : filter.externalIdIn,\n }\n }\n if (filter.fieldEquals) {\n q[filter.fieldEquals.field] = filter.fieldEquals.value\n }\n if (filter.fieldIn) {\n q[filter.fieldIn.field] = { $in: filter.fieldIn.values }\n }\n if (filter.fieldExists) {\n q[filter.fieldExists] = { $exists: true }\n }\n if (filter.createdAfter || filter.createdBefore) {\n const r: any = {}\n if (filter.createdAfter) r.$gte = filter.createdAfter\n if (filter.createdBefore) r.$lte = filter.createdBefore\n q.createdAt = r\n }\n if (this.tagsField) {\n if (filter.hasTag) {\n q[this.tagsField] = filter.hasTag\n }\n if (filter.hasTagIn && filter.hasTagIn.length > 0) {\n q[this.tagsField] = { $in: filter.hasTagIn }\n }\n }\n return q\n }\n\n private async addTagsImpl(externalId: string, tags: string[]): Promise<void> {\n if (!this.tagsField || tags.length === 0) return\n const value =\n this.tagsArrayShape === 'objects'\n ? tags.map((name) => ({ name }))\n : tags\n await this.col.updateOne(this.idFilter(externalId), {\n $addToSet: { [this.tagsField]: { $each: value } } as any,\n })\n }\n\n private async removeTagsImpl(externalId: string, tags: string[]): Promise<void> {\n if (!this.tagsField || tags.length === 0) return\n const value =\n this.tagsArrayShape === 'objects'\n ? { $in: tags.map((name) => ({ name })) }\n : { $in: tags }\n await this.col.updateOne(this.idFilter(externalId), {\n $pull: { [this.tagsField]: value } as any,\n })\n }\n}\n\nfunction canBeObjectId(s: string): boolean {\n return typeof s === 'string' && /^[a-f0-9]{24}$/i.test(s)\n}\n","/**\n * Replay-window helpers shared by provider webhook verification.\n *\n * A signature proves a payload came from the provider. It does not prove the\n * payload is *current* — a captured request replays forever unless the signed\n * timestamp is also checked for recency. Every provider that signs\n * `timestamp + body` (SendGrid today; Postmark/SES/Mailgun when they land)\n * needs the same window logic, so it lives here rather than in one adapter.\n *\n * Policy, per the maintainer's direction: on by default, overridable per\n * provider, explicitly disable-able for hosts whose proxy delays delivery.\n */\n\n/**\n * Default replay window, in seconds, applied when a provider is constructed\n * without an explicit tolerance.\n *\n * 300s (5 minutes) is the conventional value — it's what Stripe's SDKs use as\n * their default tolerance, and it is comfortably wider than any plausible\n * NTP-synced clock drift or provider retry jitter while still shrinking a\n * \"replayable forever\" window down to a five-minute one.\n */\nexport const DEFAULT_WEBHOOK_TOLERANCE_SECONDS = 300\n\n/**\n * Per-provider tolerance option: seconds, or `0` / `false` to disable the\n * freshness check entirely.\n */\nexport type WebhookToleranceOption = number | false\n\n/**\n * Normalize the constructor option into a number of seconds, where `0` means\n * \"disabled\".\n *\n * Anything nonsensical (negative, NaN, Infinity) falls back to the default\n * rather than being read as \"disabled\" — a typo in config should not silently\n * turn the replay window off.\n */\nexport function resolveWebhookToleranceSeconds(\n option?: WebhookToleranceOption,\n): number {\n if (option === false || option === 0) return 0\n if (option === undefined || option === null) return DEFAULT_WEBHOOK_TOLERANCE_SECONDS\n if (typeof option !== 'number' || !Number.isFinite(option) || option < 0) {\n return DEFAULT_WEBHOOK_TOLERANCE_SECONDS\n }\n return option\n}\n\n/**\n * Is a provider-supplied unix-seconds timestamp inside the replay window?\n *\n * Rejects in both directions: too old (the replay case) and too far in the\n * future (a forged or badly-skewed clock). Clock skew cuts both ways, so the\n * window is symmetric.\n *\n * Fails closed — a missing, empty, or non-integer timestamp is not fresh.\n * Returns a plain boolean so callers can fold it into an existing\n * \"valid / not valid\" decision without leaking *why* through an error.\n */\nexport function isWebhookTimestampFresh(\n rawTimestamp: string | undefined,\n toleranceSeconds: number,\n now: Date = new Date(),\n): boolean {\n // Disabled: the caller opted out of the window. The signature still had to\n // cover this timestamp to get here, so nothing else is weakened.\n if (toleranceSeconds === 0) return true\n if (!rawTimestamp) return false\n\n // Strict digits-only parse. `Number()`/`parseInt` would happily accept\n // ' 12 ', '1e12', '0x10', or '12abc' — none of which a provider sends, and\n // each of which widens what an attacker can put in the signed prefix.\n if (!/^\\d{1,15}$/.test(rawTimestamp)) return false\n\n const timestampMs = Number(rawTimestamp) * 1000\n if (!Number.isFinite(timestampMs)) return false\n\n const deltaMs = Math.abs(now.getTime() - timestampMs)\n return deltaMs <= toleranceSeconds * 1000\n}\n","/**\n * SendGridProvider — sends mail through @sendgrid/mail, verifies the Event\n * Webhook signature with the ECDSA public key configured in SendGrid, and\n * normalizes inbound event payloads into our shared shape.\n *\n * Setup steps required on the SendGrid side (one-time):\n * 1. Authenticate sender domain (SPF, DKIM, DMARC).\n * 2. Configure event webhook → POST to https://your.host/m/webhooks/sendgrid\n * 3. Enable: delivered, open, click, bounce, dropped, spamreport, unsubscribe\n * 4. Generate Signed Event Webhook key → store as webhookVerificationKey\n */\n\nimport crypto from 'node:crypto'\nimport sgMail from '@sendgrid/mail'\n\nimport type {\n MailProvider,\n NormalizedEvent,\n SendArgs,\n SendResult,\n} from '../../shared/types.js'\nimport {\n isWebhookTimestampFresh,\n resolveWebhookToleranceSeconds,\n type WebhookToleranceOption,\n} from './webhook-tolerance.js'\n\nexport interface SendGridProviderOptions {\n apiKey: string\n /** ECDSA public key (PEM) from SendGrid → Settings → Mail Settings → Signed Event Webhook. */\n webhookVerificationKey?: string\n /**\n * Replay window for the signed webhook timestamp, in seconds.\n * Defaults to 300 (5 minutes). A signed payload older — or more than this\n * far in the future — than the window is rejected, so a captured request\n * can't be replayed indefinitely.\n *\n * Set `0` or `false` to disable the check, for hosts whose proxy or queue\n * legitimately delays webhook delivery past the window.\n */\n webhookToleranceSeconds?: WebhookToleranceOption\n /** Send-rate cap per second (BullMQ group limiter consults this). */\n sendRatePerSecond?: number\n /** Sandbox mode bypasses actual delivery — useful in dev/test. */\n sandbox?: boolean\n}\n\nconst SG_SIG_HEADER = 'x-twilio-email-event-webhook-signature'\nconst SG_TS_HEADER = 'x-twilio-email-event-webhook-timestamp'\n\nexport class SendGridProvider implements MailProvider {\n readonly name = 'sendgrid'\n readonly sendRatePerSecond: number\n /** Resolved replay window in seconds; `0` means the check is disabled. */\n readonly webhookToleranceSeconds: number\n\n constructor(private readonly opts: SendGridProviderOptions) {\n sgMail.setApiKey(opts.apiKey)\n this.sendRatePerSecond = opts.sendRatePerSecond ?? 10\n this.webhookToleranceSeconds = resolveWebhookToleranceSeconds(opts.webhookToleranceSeconds)\n }\n\n async send(args: SendArgs): Promise<SendResult> {\n const msg: sgMail.MailDataRequired = {\n to: args.to,\n from: { name: args.fromName, email: args.fromEmail },\n replyTo: args.replyTo,\n subject: args.subject,\n text: args.text,\n // Omit the key entirely rather than sending `html: undefined` — a\n // text_only template must produce a single-part text/plain message, and\n // an explicit undefined can still serialize into an empty HTML part.\n ...(args.html ? { html: args.html } : {}),\n headers: args.headers,\n customArgs: args.messageMeta,\n trackingSettings: {\n // We do our own click/open tracking — let provider stay out of it.\n clickTracking: { enable: false, enableText: false },\n openTracking: { enable: false },\n },\n mailSettings: {\n sandboxMode: { enable: this.opts.sandbox ?? false },\n },\n }\n\n const [response] = await sgMail.send(msg)\n const providerId =\n (response.headers['x-message-id'] as string | undefined) ?? `sg-${Date.now()}`\n return {\n providerId,\n status: response.statusCode < 300 ? 'accepted' : 'rejected',\n raw: response,\n }\n }\n\n async verifyWebhook(rawBody: Buffer, headers: Record<string, string>): Promise<boolean> {\n if (!this.opts.webhookVerificationKey) return false\n const sig = headers[SG_SIG_HEADER]\n const ts = headers[SG_TS_HEADER]\n if (!sig || !ts) return false\n\n const payload = Buffer.concat([Buffer.from(ts, 'utf8'), rawBody])\n try {\n const verifier = crypto.createVerify('sha256')\n verifier.update(payload)\n if (!verifier.verify(this.opts.webhookVerificationKey, sig, 'base64')) return false\n } catch {\n return false\n }\n\n // Signature checks out, so the timestamp is authentic — but authentic is\n // not the same as current. Reject outside the replay window (both stale\n // and implausibly future) so a captured request has a five-minute life,\n // not an unbounded one. Signature first, freshness second, mirroring the\n // verify-then-expiry order in ../tokens.ts.\n return isWebhookTimestampFresh(ts, this.webhookToleranceSeconds)\n }\n\n parseWebhookEvents(payload: unknown): NormalizedEvent[] {\n if (!Array.isArray(payload)) return []\n return payload\n .map((raw) => normalizeSendGridEvent(raw))\n .filter((e): e is NormalizedEvent => e !== null)\n }\n}\n\nfunction normalizeSendGridEvent(e: any): NormalizedEvent | null {\n const type = mapEventType(e.event)\n if (!type) return null\n return {\n type,\n providerEventId: String(e.sg_event_id ?? e['smtp-id'] ?? `${e.event}-${e.timestamp}-${e.email}`),\n providerMessageId: String(e.sg_message_id ?? e['smtp-id'] ?? ''),\n email: String(e.email ?? '').toLowerCase(),\n occurredAt: new Date(Number(e.timestamp) * 1000),\n details: {\n bounceType:\n e.event === 'bounce' ? (e.type === 'bounce' ? 'hard' : 'soft') : undefined,\n bounceReason: e.reason,\n clickedUrl: e.url,\n userAgent: e.useragent,\n ipAddress: e.ip,\n },\n }\n}\n\nfunction mapEventType(sgEvent: string): NormalizedEvent['type'] | null {\n switch (sgEvent) {\n case 'delivered':\n return 'delivered'\n case 'open':\n return 'open'\n case 'click':\n return 'click'\n case 'bounce':\n case 'dropped':\n return 'bounce'\n case 'spamreport':\n return 'spam_report'\n case 'unsubscribe':\n case 'group_unsubscribe':\n return 'unsubscribe'\n default:\n return null\n }\n}\n","/**\n * Zod schemas for runtime validation at write boundaries — public API entry\n * points (fire, upsertSubscription, suppress, sendOneOff, scheduleBroadcast)\n * and REST handler bodies.\n *\n * Domain TypeScript types live in `./types.ts`; these schemas overlap with\n * those types deliberately so we get both compile-time and runtime checking\n * at the surfaces that need it.\n */\n\nimport { z } from 'zod'\n\n// ---------------------------------------------------------------------------\n// Primitive helpers\n// ---------------------------------------------------------------------------\n\nexport const externalIdSchema = z.string().min(1).max(256)\nexport const emailSchema = z.string().email().toLowerCase().trim()\nexport const slugSchema = z\n .string()\n .min(1)\n .max(128)\n .regex(/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/, 'must be kebab-case slug')\n\n// ---------------------------------------------------------------------------\n// Public API inputs\n// ---------------------------------------------------------------------------\n\nexport const fireInputSchema = z.object({\n eventName: z.string().min(1).max(128),\n externalId: externalIdSchema,\n properties: z.record(z.string(), z.unknown()).optional(),\n dedupeKey: z.string().min(1).max(512).optional(),\n})\nexport type FireInput = z.infer<typeof fireInputSchema>\n\nexport const registerEventSchema = z.object({\n name: z.string().min(1).max(128),\n dedupePolicy: z.enum(['once-per-contact', 'once-per-day', 'every-time']),\n})\nexport type RegisterEventInput = z.infer<typeof registerEventSchema>\n\nexport const upsertSubscriptionSchema = z.object({\n externalId: externalIdSchema,\n source: z.string().min(1).max(256),\n consentTimestamp: z.date().optional(),\n consentIp: z.string().optional(),\n consentUserAgent: z.string().optional(),\n})\nexport type UpsertSubscriptionInput = z.infer<typeof upsertSubscriptionSchema>\n\nexport const unsubscribeScopeSchema = z.enum(['all', 'marketing', 'transactional'])\nexport const unsubscribeReasonSchema = z.enum([\n 'user_request',\n 'hard_bounce',\n 'complaint',\n 'manual',\n 'gdpr_forget',\n 'list_cleaning',\n])\n\nexport const unsubscribeInputSchema = z.object({\n email: emailSchema,\n scope: unsubscribeScopeSchema,\n reason: unsubscribeReasonSchema.default('user_request'),\n source: z.string().max(256).default('manual'),\n notes: z.string().max(1024).optional(),\n})\nexport type UnsubscribeInput = z.infer<typeof unsubscribeInputSchema>\n\nexport const suppressInputSchema = z.object({\n email: emailSchema,\n scope: unsubscribeScopeSchema,\n reason: z.enum(['unsubscribed', 'hard_bounce', 'complaint', 'manual', 'list_cleaning', 'gdpr_forget']),\n source: z.string().max(256).default('manual'),\n notes: z.string().max(1024).optional(),\n expiresAt: z.date().optional(),\n})\nexport type SuppressInput = z.infer<typeof suppressInputSchema>\n\nexport const tagInputSchema = z.object({\n externalId: externalIdSchema,\n tag: z.string().min(1).max(128),\n})\nexport type TagInput = z.infer<typeof tagInputSchema>\n\nexport const abortFlowInputSchema = z.object({\n flowSlug: slugSchema,\n externalId: externalIdSchema,\n reason: z.string().min(1).max(200).optional(),\n /**\n * Restrict the abort to runs whose trigger event carried these properties —\n * e.g. `{ accountId }` to cancel one account's series while the same\n * contact's other accounts keep running. Omit to abort every active run for\n * the contact on this flow.\n *\n * Keys and values are both constrained because these go straight into a\n * Mongo query. Values are primitives only: an object value like\n * `{ $ne: null }` would reach the query as an OPERATOR and match every\n * scoped run, turning a one-account abort into abort-everything. Hosts\n * typically pass an id from a request body, so treat it as untrusted. The\n * key regex likewise blocks `$`-prefixed keys and dots (a dot would silently\n * extend the path and change match semantics).\n */\n matchTriggerProperties: z\n .record(\n z.string().regex(/^[A-Za-z0-9_]+$/),\n z.union([z.string(), z.number(), z.boolean(), z.null()]),\n )\n .optional(),\n})\nexport type AbortFlowInput = z.infer<typeof abortFlowInputSchema>\n\nexport const abortAllFlowsInputSchema = abortFlowInputSchema.omit({ flowSlug: true })\nexport type AbortAllFlowsInput = z.infer<typeof abortAllFlowsInputSchema>\n\nexport const sendOneOffInputSchema = z.object({\n templateSlug: slugSchema,\n externalId: externalIdSchema,\n vars: z.record(z.string(), z.unknown()).optional(),\n providerOverride: z.string().optional(),\n dedupeKey: z.string().min(1).max(512),\n})\nexport type SendOneOffInput = z.infer<typeof sendOneOffInputSchema>\n\n// ---------------------------------------------------------------------------\n// Flow step + predicate schemas (mirror types.ts)\n// ---------------------------------------------------------------------------\n\nexport const flowStepSchema: z.ZodType<unknown> = z.lazy(() =>\n z.discriminatedUnion('type', [\n z.object({\n type: z.literal('wait'),\n value: z.number().int().positive(),\n unit: z.enum(['minutes', 'hours', 'days', 'weeks']),\n }),\n z.object({\n type: z.literal('condition'),\n test: predicateSchema,\n ifFalse: z.enum(['continue', 'exit']),\n }),\n z.object({\n type: z.literal('branch'),\n test: predicateSchema,\n ifTrueSteps: z.array(flowStepSchema),\n ifFalseSteps: z.array(flowStepSchema),\n }),\n z.object({\n type: z.literal('send'),\n templateSlug: slugSchema,\n providerOverride: z.string().optional(),\n vars: z.record(z.string(), z.unknown()).optional(),\n delivery: z\n .object({\n weekdaysOnly: z.boolean().optional(),\n timeOfDay: z.string().regex(/^([01]\\d|2[0-3]):[0-5]\\d$/, 'expected HH:mm').optional(),\n useContactTimezone: z.boolean().optional(),\n timezone: z.string().optional(),\n })\n .optional(),\n }),\n z.object({\n type: z.literal('tag'),\n addTags: z.array(z.string()).optional(),\n removeTags: z.array(z.string()).optional(),\n }),\n z.object({\n type: z.literal('fire_event'),\n eventName: z.string().min(1).max(128),\n properties: z.record(z.string(), z.unknown()).optional(),\n }),\n z.object({\n type: z.literal('webhook'),\n // `url` is validated for shape only and is deliberately never templated —\n // see the comment on handleWebhookStep in src/server/runner/step.ts, and\n // INVARIANT 16. Rendering contact/event data into this field would turn an\n // admin-authored flow into a server-side request forgery primitive.\n url: z.string().url(),\n method: z.enum(['POST', 'PUT']).optional(),\n payload: z.record(z.string(), z.unknown()).optional(),\n failureMode: z.enum(['soft', 'fail_run']).optional(),\n }),\n z.object({\n type: z.literal('exit'),\n reason: z.string().optional(),\n }),\n ]),\n)\n\nexport const predicateSchema: z.ZodType<unknown> = z.lazy(() =>\n z.union([\n z.object({ hasTag: z.string() }),\n z.object({ notHasTag: z.string() }),\n z.object({ fieldEquals: z.object({ field: z.string(), value: z.unknown() }) }),\n z.object({ fieldExists: z.string() }),\n z.object({\n triggerPropertyEquals: z.object({\n key: z.string().min(1),\n value: z.union([z.string(), z.number(), z.boolean(), z.null()]),\n }),\n }),\n z.object({ triggerPropertyTruthy: z.string().min(1) }),\n z.object({\n hasFiredEvent: z.string(),\n sinceFlowStart: z.boolean().optional(),\n withinDays: z.number().int().positive().optional(),\n }),\n z.object({\n notHasFiredEvent: z.string(),\n withinDays: z.number().int().positive().optional(),\n }),\n z.object({\n subscriptionStatus: z.enum(['subscribed', 'unsubscribed', 'pending_doi', 'bounced', 'complained']),\n }),\n z.object({\n hasOpened: z.object({\n templateSlug: slugSchema.optional(),\n sinceFlowStart: z.boolean().optional(),\n withinDays: z.number().int().positive().optional(),\n }),\n }),\n z.object({\n hasClicked: z.object({\n templateSlug: slugSchema.optional(),\n sinceFlowStart: z.boolean().optional(),\n withinDays: z.number().int().positive().optional(),\n }),\n }),\n z.object({\n hasOpenedExcludingBots: z.object({\n templateSlug: slugSchema.optional(),\n sinceFlowStart: z.boolean().optional(),\n withinDays: z.number().int().positive().optional(),\n }),\n }),\n z.object({\n hasClickedExcludingBots: z.object({\n templateSlug: slugSchema.optional(),\n sinceFlowStart: z.boolean().optional(),\n withinDays: z.number().int().positive().optional(),\n }),\n }),\n z.object({\n openedAtLeastN: z.object({ count: z.number().int().positive(), withinDays: z.number().int().positive() }),\n }),\n z.object({\n clickedAtLeastN: z.object({ count: z.number().int().positive(), withinDays: z.number().int().positive() }),\n }),\n z.object({ all: z.array(predicateSchema) }),\n z.object({ any: z.array(predicateSchema) }),\n z.object({ not: predicateSchema }),\n ]),\n)\n","/**\n * Mailer configuration shape. Required + optional surfaces with sane defaults.\n */\n\nimport type { Db } from 'mongodb'\nimport type Handlebars from 'handlebars'\nimport type {\n ContactAdapter,\n MailProvider,\n} from '../shared/types.js'\nimport type { QueueDriverConfig } from './queues/types.js'\nimport type { SenderDomainRegistry } from './templates/sender-domain.js'\nimport type { VarsAdapter } from './adapters/vars.js'\n\nexport type { SenderDomainConfig, SenderDomainRegistry } from './templates/sender-domain.js'\n\nexport interface RedisOptions {\n host?: string\n port?: number\n password?: string\n url?: string\n db?: number\n username?: string\n tls?: boolean\n}\n\nexport interface DnsblListSpec {\n /** DNS suffix to query, e.g. `'dbl.spamhaus.org'`. */\n host: string\n /** Display label for the UI, e.g. `'Spamhaus DBL'`. */\n label: string\n}\n\nexport interface DnsblConfig {\n /** Domain block lists (DBLs) — queried as `<domain>.<host>`. */\n domainLists?: DnsblListSpec[]\n /** IP block lists — queried as `<reversed-octets>.<host>`. */\n ipLists?: DnsblListSpec[]\n /** Dedicated sending IPs to check. Most operators on shared ESPs leave empty. */\n dedicatedIps?: string[]\n /** Hours between automatic runs. Default 24. Set to 0 to disable scheduled runs. */\n intervalHours?: number\n}\n\nexport const DEFAULT_DOMAIN_DNSBL_LISTS: DnsblListSpec[] = [\n { host: 'dbl.spamhaus.org', label: 'Spamhaus DBL' },\n { host: 'multi.surbl.org', label: 'SURBL' },\n { host: 'multi.uribl.com', label: 'URIBL' },\n]\n\nexport const DEFAULT_IP_DNSBL_LISTS: DnsblListSpec[] = [\n { host: 'zen.spamhaus.org', label: 'Spamhaus ZEN' },\n { host: 'b.barracudacentral.org', label: 'Barracuda' },\n { host: 'dnsbl.sorbs.net', label: 'SORBS' },\n { host: 'bl.spamcop.net', label: 'SpamCop' },\n]\n\nexport interface MailTesterConfig {\n /** API key from your Mail-Tester paid plan. */\n apiKey: string\n /** Minimum score (0-10) below which publish is blocked. Default 8.0. */\n minScore?: number\n /**\n * When true, publishing content that has no cached score is blocked too —\n * the operator must run a deliverability check for that exact content first.\n * Default false, which only blocks content already known to score below\n * `minScore`; in that mode any edit (even whitespace) changes the content\n * key, misses the cache, and publishes freely.\n */\n requireScore?: boolean\n /**\n * How long a successful score remains cached for the same content. Default 24.\n * Re-publishing the same body within the window does not burn a credit.\n */\n cacheHours?: number\n /** API base URL. Defaults to `https://mail-tester.com/api`. Override for staging or alternate provider. */\n baseUrl?: string\n}\n\nexport interface DmarcSourceTag {\n /** Source IP, e.g. `'149.72.45.10'`. */\n ip: string\n /** Operator-provided label, e.g. `'SendGrid (transactional)'` or `'Hubspot'`. */\n label: string\n /** When true, ignore failures from this source in the alignment-trend headline. */\n ignored?: boolean\n}\n\nexport interface DmarcConfig {\n /**\n * Operator-tagged sources. After RUA reports start arriving, the operator\n * marks each source IP as known/legit (with a label) or rogue. Tagged\n * sources are excluded from the headline failure count, surfacing only\n * unknown senders.\n */\n knownSources?: DmarcSourceTag[]\n /**\n * How many days of failure rows to retain. Default 90. Older rows are\n * trimmed by the daily tick to keep the collection bounded.\n */\n retentionDays?: number\n}\n\nexport interface SndsConfig {\n /**\n * SNDS automated-access key. Obtained per-account from the SNDS portal at\n * https://sendersupport.olc.protection.outlook.com/snds/ once each\n * sending IP has been added and verified.\n */\n accessKey: string\n /**\n * Optional IP filter — when set, only rows for these IPs are persisted.\n * Useful when an SNDS account covers a wider IP pool than this mailery\n * deployment uses. Defaults to keeping all rows the API returns.\n */\n ips?: string[]\n /** Hours between automatic pulls. Default 24. Set to 0 to disable scheduled pulls. */\n intervalHours?: number\n}\n\nexport interface PostmasterConfig {\n /** OAuth client ID from a Google Cloud project with Postmaster Tools API enabled. */\n clientId: string\n clientSecret: string\n /**\n * A refresh token obtained via the OAuth consent flow with scope\n * `https://www.googleapis.com/auth/postmaster.readonly` for the user that\n * verified the domain(s) in Postmaster Tools. See\n * docs/guide/deliverability.md → \"Google Postmaster Tools\" for the\n * one-time setup procedure.\n */\n refreshToken: string\n /**\n * Domains to pull data for. When omitted, mailery uses every domain from the\n * senderDomains registry plus the From defaults. Each must be verified in\n * Postmaster Tools under the same Google account.\n */\n domains?: string[]\n /** Hours between automatic pulls. Default 24. Set to 0 to disable scheduled pulls. */\n intervalHours?: number\n}\n\nexport interface CircuitBreakerThresholds {\n /** Trip when last-hour hard-bounce rate >= this percent (e.g. 2 = 2%). */\n hardBounceRatePctTrip: number\n complaintRatePctTrip: number\n combinedBounceRatePctTrip: number\n failedToSendRatePctDegrade: number\n windowMinutes: number\n minSendsBeforeEval: number\n}\n\nexport interface BotFilterConfig {\n /**\n * User agents matching this pattern are treated as automated. Applied to\n * recorded open and click user agents alike.\n *\n * Default: `/Mimecast|SafeLinks|proofpoint|HeadlessChrome|Googlebot|bingbot/i`\n * (`DEFAULT_BOT_UA_RE`). Replace it to cover your own corporate scanners;\n * extend rather than replace if you want to keep the built-ins.\n */\n userAgentPattern?: RegExp\n /**\n * Opens recorded within this many milliseconds of the send being queued are\n * treated as automated regardless of user agent — corporate scanners and\n * gateway prefetchers fetch the pixel within seconds of delivery, and a\n * human cannot.\n *\n * Default `0` — disabled. It is off by default because it is a heuristic\n * with a real false-positive tail (a recipient already reading their inbox\n * when the mail lands) and because enabling it silently changes the counts\n * every existing flow branches on. `10000` (10s) is the value worth trying\n * first if your open counts look implausible.\n */\n minOpenDelayMs?: number\n}\n\nexport interface MailerConfig {\n // ---- Storage --------------------------------------------------------------\n db: Db\n collectionPrefix?: string\n adapter: ContactAdapter\n /**\n * Optional host-provided template variables. `resolve(contact)` runs at\n * send/preview/test render time; its result is merged into the template\n * context root (schema key `user` → `{{user.name}}`). The zod schema\n * drives admin-editor autocomplete and the `unknown_variable` lint rule.\n * Build one with `defineVars({ schema, resolve })`.\n */\n varsAdapter?: VarsAdapter<any>\n\n // ---- Queue ----------------------------------------------------------------\n /**\n * Queue driver selection. One of:\n * - `{ driver: 'bull', redis: ... }` — BullMQ (default for prod; requires Redis)\n * - `{ driver: 'agenda' }` — @hokify/agenda using this Mongo (no Redis required, single-process)\n * - `{ driver: 'noop' }` — no background workers (tests, synchronous-only hosts)\n */\n queue: QueueDriverConfig\n\n // ---- Providers ------------------------------------------------------------\n providers: Record<string, MailProvider>\n defaultProvider: string\n defaultTransactionalProvider?: string\n\n // ---- Identity / URLs ------------------------------------------------------\n publicUrl: string\n unsubscribeSecret: string\n senderAddress?: string\n fromDefaults?: { name: string; email: string }\n transactionalFromDefaults?: { name: string; email: string }\n /**\n * Optional registry of sender domains by kind. When set, mailery enforces at\n * template publish time that a template's `fromEmail` domain is declared and\n * matches the template's `kind`. Used to keep marketing reputation isolated\n * from transactional reputation by sending from separate verified domains.\n *\n * Domains are case-insensitive. If unset, no enforcement happens.\n */\n senderDomains?: SenderDomainRegistry\n\n // ---- Compliance -----------------------------------------------------------\n requireDoubleOptIn?: boolean\n unsubscribeTokenLifetimeDays?: number\n transactionalRespectUnsubscribe?: boolean\n /**\n * Absolute path to the pending-unsubscribe journal (INVARIANT 8).\n *\n * When `POST /m/unsub/:token` cannot reach Mongo, the opt-out is appended\n * here as JSONL and replayed by the tick drain\n * (`drainPendingUnsubscribes`). The file is created 0600 inside a 0700\n * directory and opened `O_NOFOLLOW`.\n *\n * **There is no default, and that is deliberate.** The journal holds\n * recipient email addresses in plaintext outside the database, and a library\n * mounted into an unknown host cannot pick a directory that is at once\n * writable, durable and private — which is how the previous default ended up\n * being `/tmp` (world-writable, wiped on reboot, and never read back).\n *\n * With this unset the endpoint answers **503** when Mongo is unreachable,\n * rather than promising an unsubscribe it has nowhere to record. Set it to a\n * durable, private, node-local path to get the journal instead — e.g.\n * `/var/lib/mailery/pending-unsubs.jsonl` (systemd: `StateDirectory=mailery`).\n *\n * Must not be on a shared network filesystem: claiming a batch relies on\n * `rename` being atomic within the directory.\n */\n pendingUnsubsPath?: string\n /**\n * How long `POST /m/unsub/:token` waits for the Mongo write before falling\n * back to the journal. Default 5000ms.\n *\n * The tension is INVARIANT 8's own: the response must be fast (clients are\n * impatient, providers retry) *and* must not claim an unsubscribe that was\n * never recorded. A healthy write is sub-millisecond, so this budget is only\n * ever spent during an outage, and spending it is what makes the difference\n * between a truthful 200 and a lie.\n */\n unsubscribeWriteTimeoutMs?: number\n /** Slug of the transactional template sent for DOI confirmation. Defaults to 'doi-confirmation'. */\n doiTemplateSlug?: string\n /** How long the DOI token stays valid. Default 7 days. */\n doiTokenLifetimeDays?: number\n\n // ---- Circuit breaker ------------------------------------------------------\n circuitBreaker?: Partial<CircuitBreakerThresholds>\n\n // ---- DNSBL monitoring -----------------------------------------------------\n /**\n * Daily DNS-based block-list checks on sender domains and (optionally) any\n * dedicated sending IPs. Results surface in setup-status and on the Health\n * screen. No external API needed — plain DNS lookups.\n */\n dnsbl?: DnsblConfig\n\n // ---- Google Postmaster Tools ---------------------------------------------\n /**\n * Pulls daily reputation tiers + spam ratio + auth pass rates from Google\n * Postmaster Tools. Trips the (domain × marketing) circuit breaker when a\n * domain falls to reputation `BAD`. Only meaningful at >100/day to Gmail.\n */\n postmaster?: PostmasterConfig\n\n // ---- Microsoft SNDS ------------------------------------------------------\n /**\n * Pulls daily Outlook/Hotmail/Live IP reputation from Microsoft's Smart\n * Network Data Services. IP-level rather than domain-level — only useful\n * if you send from a dedicated IP. Visibility-only: RED filter results\n * surface as a setup-status error, no auto-trip.\n */\n snds?: SndsConfig\n\n // ---- Mail-Tester deliverability check ------------------------------------\n /**\n * Optional Mail-Tester integration. When set, the template editor exposes\n * a \"Run deliverability check\" button that sends a copy of the rendered\n * draft to a Mail-Tester address and polls for a score (0-10) covering\n * SpamAssassin verdict, auth alignment, content red flags, and link\n * reputation. Score < minScore blocks publish until re-run or overridden.\n */\n mailTester?: MailTesterConfig\n\n // ---- DMARC aggregate report ingestion ------------------------------------\n /**\n * DMARC RUA aggregate reports tell you who is sending mail that claims to\n * be from your domain — both legitimate sources and spoofers. Mailery\n * decompresses, parses, and surfaces alignment failures + unknown senders.\n *\n * Two ways in:\n * - the operator uploads attachments in the admin UI\n * (`POST /admin/mailer/api/dmarc/upload`, behind your admin guard)\n * - the inbound webhook, for SendGrid Inbound Parse and friends:\n * `createPublicRouter(mailer, { dmarcInbound: { secret } })`. Off unless\n * that secret is set. Do **not** point Inbound Parse at the admin\n * upload route — it sits behind the host's `requireAdmin` guard, which\n * Inbound Parse cannot satisfy. (Versions before 0.15 recommended\n * exactly that, and it never worked.)\n */\n dmarc?: DmarcConfig\n\n // ---- Broadcast safety + throughput ---------------------------------------\n broadcastConfirmationThreshold?: number\n broadcastEnqueueBatchSize?: number\n broadcastEnqueueMaxWaiting?: number\n\n // ---- Worker behavior ------------------------------------------------------\n workerless?: boolean\n tickIntervalSeconds?: number\n sendConcurrency?: number\n sendRatePerSecond?: number\n softBouncePromotionThreshold?: number\n softBouncePromotionWindowDays?: number\n webhookRetryAttempts?: number\n sendRetryAttempts?: number\n\n // ---- Tracking -------------------------------------------------------------\n trackOpens?: boolean\n trackClicks?: boolean\n storeTrackingIp?: boolean\n storeRenderedBody?: boolean\n /**\n * Reject `/m/open` and `/m/click` hits that carry no signature.\n *\n * Default `false` — grace mode. Newly rendered mail is always signed; this\n * flag only decides what happens to the *unsigned* URLs sitting in mail that\n * was already delivered. In grace mode they are still counted and each one is\n * logged (`mailery: unsigned tracking URL accepted`) so the operator can watch\n * the legacy rate fall to zero and then flip this to `true`.\n *\n * A signature that is *present but wrong* is always rejected, in both modes.\n */\n requireSignedTrackingUrls?: boolean\n /**\n * How long a tracking URL stays valid, in days, measured from the send's\n * `queuedAt`. Default `0` — never expires.\n *\n * Never-expire is the right default: an email sits in an inbox for years and\n * a legitimate open six months later is real data, not an attack. The\n * signature already proves the caller was handed the URL. Operators with a\n * data-retention policy can set a window; because the deadline is derived\n * from the send row rather than baked into the token, changing this value\n * takes effect immediately for already-delivered mail and costs no URL bytes.\n */\n trackingUrlLifetimeDays?: number\n /**\n * Tuning for `hasOpenedExcludingBots` / `hasClickedExcludingBots` /\n * `openedAtLeastN` / `clickedAtLeastN`. See `BotFilterConfig`.\n */\n botFilter?: BotFilterConfig\n\n // ---- Hooks ----------------------------------------------------------------\n getAdminActor?: (req: any) => string\n onCircuitBreakerTrip?: (info: { reason: string; rates: Record<string, number> }) => Promise<void> | void\n onSendFailure?: (info: { send: any; error: Error }) => Promise<void> | void\n handlebarsHelpers?: Record<string, Handlebars.HelperDelegate>\n}\n\nexport type ResolvedConfig = Required<\n Pick<\n MailerConfig,\n | 'collectionPrefix'\n | 'requireDoubleOptIn'\n | 'unsubscribeTokenLifetimeDays'\n | 'transactionalRespectUnsubscribe'\n | 'unsubscribeWriteTimeoutMs'\n | 'doiTemplateSlug'\n | 'doiTokenLifetimeDays'\n | 'broadcastConfirmationThreshold'\n | 'broadcastEnqueueBatchSize'\n | 'broadcastEnqueueMaxWaiting'\n | 'workerless'\n | 'tickIntervalSeconds'\n | 'sendConcurrency'\n | 'sendRatePerSecond'\n | 'softBouncePromotionThreshold'\n | 'softBouncePromotionWindowDays'\n | 'webhookRetryAttempts'\n | 'sendRetryAttempts'\n | 'trackOpens'\n | 'trackClicks'\n | 'storeTrackingIp'\n | 'storeRenderedBody'\n | 'requireSignedTrackingUrls'\n | 'trackingUrlLifetimeDays'\n >\n> & {\n circuitBreaker: CircuitBreakerThresholds\n} & MailerConfig\n\nexport const DEFAULTS = {\n collectionPrefix: 'mailer_',\n requireDoubleOptIn: false,\n unsubscribeTokenLifetimeDays: 90,\n transactionalRespectUnsubscribe: false,\n unsubscribeWriteTimeoutMs: 5000,\n doiTemplateSlug: 'doi-confirmation',\n doiTokenLifetimeDays: 7,\n broadcastConfirmationThreshold: 1000,\n broadcastEnqueueBatchSize: 1000,\n broadcastEnqueueMaxWaiting: 5000,\n workerless: false,\n tickIntervalSeconds: 60,\n sendConcurrency: 5,\n sendRatePerSecond: 10,\n softBouncePromotionThreshold: 3,\n softBouncePromotionWindowDays: 30,\n webhookRetryAttempts: 3,\n sendRetryAttempts: 4,\n trackOpens: true,\n trackClicks: true,\n storeTrackingIp: false,\n storeRenderedBody: false,\n requireSignedTrackingUrls: false,\n trackingUrlLifetimeDays: 0,\n} as const\n\nexport const CIRCUIT_BREAKER_DEFAULTS: CircuitBreakerThresholds = {\n hardBounceRatePctTrip: 2,\n complaintRatePctTrip: 0.3,\n combinedBounceRatePctTrip: 5,\n failedToSendRatePctDegrade: 10,\n windowMinutes: 60,\n minSendsBeforeEval: 100,\n}\n\nexport function resolveConfig(c: MailerConfig): ResolvedConfig {\n return {\n ...c,\n collectionPrefix: c.collectionPrefix ?? DEFAULTS.collectionPrefix,\n requireDoubleOptIn: c.requireDoubleOptIn ?? DEFAULTS.requireDoubleOptIn,\n unsubscribeTokenLifetimeDays: c.unsubscribeTokenLifetimeDays ?? DEFAULTS.unsubscribeTokenLifetimeDays,\n transactionalRespectUnsubscribe: c.transactionalRespectUnsubscribe ?? DEFAULTS.transactionalRespectUnsubscribe,\n unsubscribeWriteTimeoutMs: c.unsubscribeWriteTimeoutMs ?? DEFAULTS.unsubscribeWriteTimeoutMs,\n doiTemplateSlug: c.doiTemplateSlug ?? DEFAULTS.doiTemplateSlug,\n doiTokenLifetimeDays: c.doiTokenLifetimeDays ?? DEFAULTS.doiTokenLifetimeDays,\n broadcastConfirmationThreshold: c.broadcastConfirmationThreshold ?? DEFAULTS.broadcastConfirmationThreshold,\n broadcastEnqueueBatchSize: c.broadcastEnqueueBatchSize ?? DEFAULTS.broadcastEnqueueBatchSize,\n broadcastEnqueueMaxWaiting: c.broadcastEnqueueMaxWaiting ?? DEFAULTS.broadcastEnqueueMaxWaiting,\n workerless: c.workerless ?? DEFAULTS.workerless,\n tickIntervalSeconds: c.tickIntervalSeconds ?? DEFAULTS.tickIntervalSeconds,\n sendConcurrency: c.sendConcurrency ?? DEFAULTS.sendConcurrency,\n sendRatePerSecond: c.sendRatePerSecond ?? DEFAULTS.sendRatePerSecond,\n softBouncePromotionThreshold: c.softBouncePromotionThreshold ?? DEFAULTS.softBouncePromotionThreshold,\n softBouncePromotionWindowDays: c.softBouncePromotionWindowDays ?? DEFAULTS.softBouncePromotionWindowDays,\n webhookRetryAttempts: c.webhookRetryAttempts ?? DEFAULTS.webhookRetryAttempts,\n sendRetryAttempts: c.sendRetryAttempts ?? DEFAULTS.sendRetryAttempts,\n trackOpens: c.trackOpens ?? DEFAULTS.trackOpens,\n trackClicks: c.trackClicks ?? DEFAULTS.trackClicks,\n storeTrackingIp: c.storeTrackingIp ?? DEFAULTS.storeTrackingIp,\n storeRenderedBody: c.storeRenderedBody ?? DEFAULTS.storeRenderedBody,\n requireSignedTrackingUrls: c.requireSignedTrackingUrls ?? DEFAULTS.requireSignedTrackingUrls,\n trackingUrlLifetimeDays: c.trackingUrlLifetimeDays ?? DEFAULTS.trackingUrlLifetimeDays,\n circuitBreaker: { ...CIRCUIT_BREAKER_DEFAULTS, ...(c.circuitBreaker ?? {}) },\n }\n}\n","/**\n * Mongo collection helpers + indexes for every mailer-owned collection.\n *\n * The single source of truth for `mailer_*` schemas lives in\n * `plans/02-data-model.md`. The TS interfaces here track that doc.\n *\n * const collections = getCollections(db)\n * await ensureIndexes(db)\n * await collections.events.insertOne({ ... })\n */\n\nimport type { Db, Collection, ObjectId } from 'mongodb'\n\nimport type {\n SubscriptionStatus,\n SendStatus,\n TemplateKind,\n TemplateBodyFormat,\n SuppressionScope,\n SuppressionReason,\n FlowRunStatus,\n BroadcastStatus,\n HealthStatus,\n FlowGoal,\n} from '../../shared/enums.js'\nimport type { FlowStep, SegmentDefinition } from '../../shared/types.js'\n\n// ---------------------------------------------------------------------------\n// Document interfaces (per collection)\n// ---------------------------------------------------------------------------\n\nexport interface SubscriptionDoc {\n _id?: ObjectId\n externalId: string\n status: SubscriptionStatus\n subscribedAt: Date | null\n unsubscribedAt: Date | null\n unsubscribeReason: string | null\n doiTokenHash: string | null\n doiRequestedAt: Date | null\n doiConfirmedAt: Date | null\n doiIp: string | null\n doiUserAgent: string | null\n source: string\n emailAtSubscribe: string\n createdAt: Date\n updatedAt: Date\n}\n\nexport interface LeadDoc {\n _id?: ObjectId\n email: string\n source: string\n capturedFields: Record<string, unknown>\n status: 'lead' | 'promoted' | 'rejected'\n promotedToExternalId: string | null\n promotedAt: Date | null\n consentedAt: Date | null\n consentIp: string | null\n unsubscribedAt: Date | null\n createdAt: Date\n updatedAt: Date\n}\n\nexport interface EventDoc {\n _id?: ObjectId\n externalId: string\n name: string\n properties: Record<string, unknown>\n dedupeKey: string\n occurredAt: Date\n createdAt: Date\n}\n\nexport interface FlowTrigger {\n type: 'event' | 'segment_enter' | 'cron'\n eventName?: string\n segmentDefinition?: SegmentDefinition\n cronExpression?: string\n once: boolean\n}\n\nexport interface FlowDraft {\n steps: FlowStep[]\n notes: string\n lastModifiedBy: string\n lastModifiedAt: Date\n}\n\nexport interface FlowDoc {\n _id?: ObjectId\n slug: string\n name: string\n description: string\n trigger: FlowTrigger\n enabled: boolean\n steps: FlowStep[]\n version: number\n draft: FlowDraft | null\n goal: FlowGoal\n audience: string\n expectedVolumePerWeek: number | null\n stats: {\n activeRuns: number\n completedRuns: number\n sendsTotal: number\n sendsLast7Days: number\n }\n lastTriggerScanAt: Date | null\n publishedAt: Date | null\n publishedBy: string | null\n createdAt: Date\n updatedAt: Date\n}\n\nexport interface FlowVersionDoc {\n _id?: ObjectId\n flowId: ObjectId\n version: number\n steps: FlowStep[]\n trigger: FlowTrigger\n publishedAt: Date\n publishedBy: string\n}\n\nexport interface FlowRunHistoryEntry {\n stepIndex: number\n action:\n | 'entered'\n | 'wait_started'\n | 'wait_completed'\n | 'condition_evaluated'\n | 'branch_taken'\n | 'sent'\n | 'send_skipped'\n | 'send_deferred'\n | 'tagged'\n | 'event_fired'\n | 'webhook_called'\n | 'exited'\n | 'failed'\n at: Date\n details?: Record<string, unknown>\n}\n\nexport interface FlowRunDoc {\n _id?: ObjectId\n externalId: string\n flowId: ObjectId\n flowSlug: string\n flowVersion: number\n emailAtEntry: string\n /**\n * Snapshot of the event that triggered this run. Properties surface in\n * templates as `{{event.*}}` and in `varsAdapter.resolve` via\n * `info.eventProperties` — this is how account/topic-scoped flows know\n * which account or topic the run is about. Null for non-event entries.\n */\n triggerEvent?: { name: string; properties: Record<string, unknown>; occurredAt: Date } | null\n /**\n * Dedupe key of the triggering event. Unique per flow (partial index) so the\n * trigger scan's overlap window can re-read an event without creating a\n * second run. Null for non-event entries (manual/API).\n */\n triggerDedupeKey?: string | null\n enteredAt: Date\n status: FlowRunStatus\n currentStepIndex: number\n currentBranchPath: Array<number | 'true' | 'false'>\n nextActionAt: Date\n attemptsForCurrentStep: number\n history: FlowRunHistoryEntry[]\n exitedAt: Date | null\n exitReason: string | null\n createdAt: Date\n updatedAt: Date\n}\n\nexport interface TemplateDraft {\n subject: string\n preheader: string\n /** MJML source (when template is authored as MJML). Empty string if Maily-authored. */\n mjml: string\n /** Maily editor JSON (when template is authored via the WYSIWYG editor). null otherwise. */\n editorJson: Record<string, unknown> | null\n notes: string\n lastModifiedBy: string\n lastModifiedAt: Date\n}\n\nexport interface TemplateDoc {\n _id?: ObjectId\n slug: string\n name: string\n description: string\n kind: TemplateKind\n fromName: string\n fromEmail: string\n replyTo: string | null\n providerOverride: string | null\n subject: string\n preheader: string\n body: {\n /** MJML source (set when published from MJML). */\n mjml: string\n /** Maily editor JSON (set when published from the WYSIWYG editor). null otherwise. */\n editorJson: Record<string, unknown> | null\n html: string\n plainText: string\n compiledAt: Date | null\n }\n variablesSchema: Record<\n string,\n {\n type: 'string' | 'number' | 'boolean' | 'date' | 'url'\n required: boolean\n description?: string\n defaultValue?: unknown\n }\n >\n draft: TemplateDraft | null\n tags: string[]\n /** Wire format for the body. Absent on documents written before 0.11. */\n bodyFormat?: TemplateBodyFormat\n trackOpens: boolean\n trackClicks: boolean\n stats: {\n sent: number\n delivered: number\n opened: number\n clicked: number\n bounced: number\n complained: number\n unsubscribed: number\n lastSentAt: Date | null\n }\n publishedAt: Date | null\n publishedBy: string | null\n createdAt: Date\n updatedAt: Date\n}\n\nexport interface TemplateVersionDoc {\n _id?: ObjectId\n templateId: ObjectId\n version: number\n mjml: string\n html: string\n plainText: string\n subject: string\n preheader: string\n publishedAt: Date\n publishedBy: string\n}\n\nexport interface SendDoc {\n _id?: ObjectId\n dedupeKey: string\n externalId: string\n emailAtSend: string\n templateId: ObjectId\n templateSlug: string\n flowRunId: ObjectId | null\n broadcastId: ObjectId | null\n manualSendBy: string | null\n kind: TemplateKind\n provider: string\n providerMessageId: string | null\n fromName: string\n fromEmail: string\n subject: string\n bodyHash: string\n status: SendStatus\n errorMessage: string | null\n bounceType: 'hard' | 'soft' | null\n bounceReason: string | null\n /** Pre-send map: every rewritten link's linkId → original URL. Lookup target on click. */\n links: Array<{ linkId: string; url: string }>\n /** Render-time vars from the flow step or one-off send. Re-applied at dispatch. */\n vars: Record<string, unknown>\n openedAt: Date | null\n openCount: number\n /**\n * Per-open history, capped at the most recent `MAX_TRACKED_OPENS`. Exists so\n * the bot filter (`hasOpenedExcludingBots`) has something to filter on —\n * `openCount` alone cannot distinguish a scanner from a reader.\n *\n * `userAgent` is null when the requesting client sent no `User-Agent`, which\n * is common for image fetches; see `predicate.ts` for how unknown is scored.\n * Absent entirely on sends recorded before the field existed.\n */\n opens?: Array<{ openedAt: Date; userAgent: string | null }>\n firstClickAt: Date | null\n clickCount: number\n /** History of actual clicks (a linkId may appear multiple times). */\n clickedLinks: Array<{ url: string; linkId: string; clickedAt: Date; userAgent?: string | null }>\n unsubscribedAt: Date | null\n complainedAt: Date | null\n queuedAt: Date\n /** Last time the row was mutated; used by the stranded-send sweep. */\n updatedAt: Date\n sentAt: Date | null\n deliveredAt: Date | null\n}\n\nexport interface SuppressionDoc {\n _id?: ObjectId\n email: string | null\n emailHash: string\n scope: SuppressionScope\n reason: SuppressionReason\n source: string\n notes: string | null\n addedAt: Date\n expiresAt: Date | null\n}\n\nexport interface BroadcastDoc {\n _id?: ObjectId\n slug: string\n name: string\n templateSlug: string\n segmentDefinition: SegmentDefinition\n status: BroadcastStatus\n scheduledAt: Date | null\n startedAt: Date | null\n completedAt: Date | null\n confirmationRequired: boolean\n confirmedCount: number | null\n confirmedAt: Date | null\n confirmedBy: string | null\n recipientCount: number | null\n /** When true, dispatch fires each recipient at their local-timezone equivalent of `scheduledAt`. */\n respectRecipientTimezone?: boolean\n stats: {\n sent: number\n delivered: number\n opened: number\n clicked: number\n bounced: number\n complained: number\n unsubscribed: number\n }\n createdAt: Date\n createdBy: string\n updatedAt: Date\n}\n\nexport interface OutboxDoc {\n _id?: ObjectId\n payload: {\n type: 'event' | 'upsert_subscription' | 'unsubscribe'\n data: Record<string, unknown>\n dedupeKey: string\n }\n status: 'pending' | 'processed' | 'failed' | 'duplicate'\n attempts: number\n lastAttemptAt: Date | null\n lastError: string | null\n enqueuedAt: Date\n processedAt: Date | null\n}\n\nexport interface AuditLogDoc {\n _id?: ObjectId\n actor: string\n action: string\n resource: { collection: string; id?: ObjectId | string; slug?: string }\n before: Record<string, unknown> | null\n after: Record<string, unknown> | null\n diffSummary: string | null\n ip: string | null\n userAgent: string | null\n requestId: string | null\n occurredAt: Date\n}\n\nexport interface WebhookEventDoc {\n _id?: ObjectId\n provider: string\n providerEventId: string\n eventType: string\n normalizedType: 'delivered' | 'open' | 'click' | 'bounce' | 'complaint' | 'unsubscribe' | 'spam_report'\n providerMessageId: string\n email: string\n occurredAt: Date\n receivedAt: Date\n processed: boolean\n raw: unknown\n}\n\n/**\n * Health bucket. One doc per (senderDomain, kind) pair plus a single aggregate\n * doc with _id='agg' that rolls up everything.\n *\n * _id: 'agg' // cross-domain, cross-kind roll-up\n * _id: 'd:<senderDomain>|k:<kind>' // per-bucket\n *\n * The aggregate is informational only — it never trips. Trips live on\n * buckets so one subdomain tanking doesn't hold mail for the others.\n */\nexport interface HealthDoc {\n _id: string\n /** null on the aggregate doc, set on bucket docs. */\n senderDomain: string | null\n /** null on the aggregate doc, set on bucket docs. */\n kind: TemplateKind | null\n windowStartedAt: Date\n windowDurationMs: number\n counters: {\n sent: number\n delivered: number\n bounced: number\n hardBounced: number\n softBounced: number\n complained: number\n failedToSend: number\n }\n rates: {\n bounceRate: number\n hardBounceRate: number\n complaintRate: number\n failureRate: number\n }\n status: HealthStatus\n trippedAt: Date | null\n trippedReason: string | null\n manuallyResumedAt: Date | null\n updatedAt: Date\n}\n\nexport const HEALTH_AGG_ID = 'agg'\n\nexport function healthBucketId(senderDomain: string | null, kind: TemplateKind): string {\n return `d:${senderDomain ?? '_unknown'}|k:${kind}`\n}\n\nexport type PostmasterReputation = 'HIGH' | 'MEDIUM' | 'LOW' | 'BAD' | 'REPUTATION_CATEGORY_UNSPECIFIED'\n\n/**\n * One day's traffic stats for a domain from Google Postmaster Tools.\n * Stored per (domain, date) so we can chart trends.\n */\nexport interface PostmasterSnapshotDoc {\n _id?: ObjectId\n domain: string\n /** Reporting date in YYYY-MM-DD per Postmaster's stat day. */\n date: string\n domainReputation: PostmasterReputation | null\n ipReputations: Array<{ reputation: PostmasterReputation; ipCount: number }> | null\n userReportedSpamRatio: number | null\n spfSuccessRatio: number | null\n dkimSuccessRatio: number | null\n dmarcSuccessRatio: number | null\n outboundEncryptionRatio: number | null\n inboundEncryptionRatio: number | null\n deliveryErrors: Array<{ errorType: string; errorClass: string; errorRatio: number }> | null\n spammyFeedbackLoops: Array<{ id: string; spamRatio: number }> | null\n fetchedAt: Date\n}\n\nexport interface MailTesterFeedback {\n category: string\n severity: 'info' | 'warning' | 'error'\n message: string\n}\n\n/**\n * Cached Mail-Tester deliverability score for a given (template content)\n * fingerprint. Operators don't burn a credit re-running on identical\n * content within cacheHours.\n */\nexport interface MailTesterScoreDoc {\n _id?: ObjectId\n templateSlug: string\n /** Hash of bodyHash + subject + fromEmail — the cache key. */\n contentKey: string\n checkId: string\n score: number\n feedback: MailTesterFeedback[]\n rawSummary: string | null\n fetchedAt: Date\n expiresAt: Date\n}\n\nexport type DmarcPolicy = 'none' | 'quarantine' | 'reject'\nexport type DmarcAuthResult = 'pass' | 'fail' | 'softfail' | 'neutral' | 'temperror' | 'permerror' | 'none' | 'unknown'\n\n/**\n * One DMARC RUA aggregate report. Receivers (Google, Yahoo, Microsoft, etc.)\n * email one per day per sending domain. We store one DmarcReportDoc per\n * incoming report, plus one DmarcFailureDoc per non-aligned record row.\n */\nexport interface DmarcReportDoc {\n _id?: ObjectId\n reportId: string\n /** Reporting org, e.g. 'google.com', 'enterprise.protection.outlook.com'. */\n orgName: string\n /** Reporter contact email from <report_metadata>. */\n email: string\n /** The domain we publish DMARC for, from <policy_published><domain>. */\n domain: string\n policyP: DmarcPolicy\n /** % of mail subject to the policy (1-100). */\n policyPct: number\n /** Activity window the report covers. */\n rangeStart: Date\n rangeEnd: Date\n /** Sum of <count> across all records. */\n totalMessages: number\n /** Messages that passed DMARC (DKIM aligned OR SPF aligned). */\n passCount: number\n failCount: number\n receivedAt: Date\n}\n\n/**\n * One alignment-failing source × day. Composite key `(sourceIp, domain, day)`\n * lets us roll up \"this IP sent N misaligned messages over the past week.\"\n * Failures from multiple reports for the same key get counted once per\n * report (we de-dupe on reportId × sourceIp).\n */\nexport interface DmarcFailureDoc {\n _id?: ObjectId\n reportId: string\n domain: string\n sourceIp: string\n count: number\n headerFrom: string\n dkimResult: DmarcAuthResult\n spfResult: DmarcAuthResult\n dispositionApplied: 'none' | 'quarantine' | 'reject' | string\n /** YYYY-MM-DD bucket derived from the reporting window's mid-point. */\n day: string\n receivedAt: Date\n}\n\n/**\n * Operator-set DMARC source tag. Created/updated/deleted from the admin UI\n * so operators can mark \"this IP is our SendGrid\", \"this is Hubspot\", etc.\n * Merged with `MailerConfig.dmarc.knownSources` at read time — the config\n * version is read-only baseline, the collection is mutable runtime state.\n */\nexport interface DmarcSourceTagDoc {\n _id?: ObjectId\n ip: string\n label: string\n ignored: boolean\n setBy: string\n setAt: Date\n}\n\nexport type SndsFilterResult = 'GREEN' | 'YELLOW' | 'RED' | 'UNKNOWN'\n\n/**\n * One row from a Microsoft SNDS data export covering a single activity\n * window for one sending IP. Stored unique per (ip, activityStart) so\n * historical windows accumulate without re-writing.\n */\nexport interface SndsSnapshotDoc {\n _id?: ObjectId\n ip: string\n activityStart: Date\n activityEnd: Date\n rcptCommands: number\n dataCommands: number\n messageRecipients: number\n filterResult: SndsFilterResult\n /** 0-1 fraction. SNDS reports as \"<0.1%\", \"0.1-0.3%\", etc; we store the upper bound. null when unknown. */\n complaintRate: number | null\n trapMessageCount: number\n sampleHelo: string | null\n sampleMailFrom: string | null\n fetchedAt: Date\n}\n\nexport type DnsblResult = 'clean' | 'listed' | 'error'\nexport type DnsblTargetKind = 'domain' | 'ip'\n\n/**\n * Latest DNSBL check result per (target, list). Replaced in-place on each run\n * so the collection stays small. History (if needed later) lives in audit_log.\n */\nexport interface DnsblCheckDoc {\n _id?: ObjectId\n /** Domain (e.g. `mkt.example.com`) or dotted-quad IP (e.g. `203.0.113.5`). */\n target: string\n targetKind: DnsblTargetKind\n /** DNS suffix queried (e.g. `dbl.spamhaus.org`). */\n list: string\n /** Display label for the UI (e.g. `Spamhaus DBL`). */\n listLabel: string\n result: DnsblResult\n /** A records returned by the lookup, when listed. */\n returnCodes: string[]\n /** When result is 'error', the message; otherwise null. */\n errorMessage: string | null\n runAt: Date\n}\n\nexport interface ContactTagDoc {\n _id?: ObjectId\n externalId: string\n tag: string\n appliedBy: 'flow' | 'admin' | 'script' | 'import'\n appliedAt: Date\n}\n\n// ---------------------------------------------------------------------------\n// Collection factory\n// ---------------------------------------------------------------------------\n\nexport interface Collections {\n subscriptions: Collection<SubscriptionDoc>\n leads: Collection<LeadDoc>\n events: Collection<EventDoc>\n flows: Collection<FlowDoc>\n flowVersions: Collection<FlowVersionDoc>\n flowRuns: Collection<FlowRunDoc>\n templates: Collection<TemplateDoc>\n templateVersions: Collection<TemplateVersionDoc>\n sends: Collection<SendDoc>\n suppressions: Collection<SuppressionDoc>\n broadcasts: Collection<BroadcastDoc>\n outbox: Collection<OutboxDoc>\n auditLog: Collection<AuditLogDoc>\n webhookEvents: Collection<WebhookEventDoc>\n health: Collection<HealthDoc>\n contactTags: Collection<ContactTagDoc>\n dnsblChecks: Collection<DnsblCheckDoc>\n postmasterSnapshots: Collection<PostmasterSnapshotDoc>\n sndsSnapshots: Collection<SndsSnapshotDoc>\n dmarcReports: Collection<DmarcReportDoc>\n dmarcFailures: Collection<DmarcFailureDoc>\n dmarcSourceTags: Collection<DmarcSourceTagDoc>\n mailTesterScores: Collection<MailTesterScoreDoc>\n}\n\nexport function getCollections(db: Db, prefix = 'mailer_'): Collections {\n return {\n subscriptions: db.collection<SubscriptionDoc>(`${prefix}subscriptions`),\n leads: db.collection<LeadDoc>(`${prefix}leads`),\n events: db.collection<EventDoc>(`${prefix}events`),\n flows: db.collection<FlowDoc>(`${prefix}flows`),\n flowVersions: db.collection<FlowVersionDoc>(`${prefix}flow_versions`),\n flowRuns: db.collection<FlowRunDoc>(`${prefix}flow_runs`),\n templates: db.collection<TemplateDoc>(`${prefix}templates`),\n templateVersions: db.collection<TemplateVersionDoc>(`${prefix}template_versions`),\n sends: db.collection<SendDoc>(`${prefix}sends`),\n suppressions: db.collection<SuppressionDoc>(`${prefix}suppressions`),\n broadcasts: db.collection<BroadcastDoc>(`${prefix}broadcasts`),\n outbox: db.collection<OutboxDoc>(`${prefix}outbox`),\n auditLog: db.collection<AuditLogDoc>(`${prefix}audit_log`),\n webhookEvents: db.collection<WebhookEventDoc>(`${prefix}webhook_events`),\n health: db.collection<HealthDoc>(`${prefix}health`),\n contactTags: db.collection<ContactTagDoc>(`${prefix}contact_tags`),\n dnsblChecks: db.collection<DnsblCheckDoc>(`${prefix}dnsbl_checks`),\n postmasterSnapshots: db.collection<PostmasterSnapshotDoc>(`${prefix}postmaster_snapshots`),\n sndsSnapshots: db.collection<SndsSnapshotDoc>(`${prefix}snds_snapshots`),\n dmarcReports: db.collection<DmarcReportDoc>(`${prefix}dmarc_reports`),\n dmarcFailures: db.collection<DmarcFailureDoc>(`${prefix}dmarc_failures`),\n dmarcSourceTags: db.collection<DmarcSourceTagDoc>(`${prefix}dmarc_source_tags`),\n mailTesterScores: db.collection<MailTesterScoreDoc>(`${prefix}mail_tester_scores`),\n }\n}\n\n// ---------------------------------------------------------------------------\n// Index ensurer\n// ---------------------------------------------------------------------------\n\nexport async function ensureIndexes(db: Db, prefix = 'mailer_'): Promise<void> {\n const c = getCollections(db, prefix)\n\n await Promise.all([\n c.subscriptions.createIndexes([\n { key: { externalId: 1 }, unique: true },\n { key: { status: 1, unsubscribedAt: -1 } },\n ]),\n c.leads.createIndexes([\n { key: { email: 1 }, unique: true },\n { key: { status: 1, createdAt: -1 } },\n ]),\n c.events.createIndexes([\n { key: { dedupeKey: 1 }, unique: true },\n { key: { externalId: 1, occurredAt: -1 } },\n { key: { name: 1, occurredAt: -1 } },\n { key: { name: 1, createdAt: 1 } },\n { key: { externalId: 1, name: 1 } },\n ]),\n c.flows.createIndexes([\n { key: { slug: 1 }, unique: true },\n { key: { enabled: 1, 'trigger.type': 1, 'trigger.eventName': 1 } },\n ]),\n c.flowVersions.createIndexes([{ key: { flowId: 1, version: 1 }, unique: true }]),\n c.flowRuns.createIndexes([\n { key: { status: 1, nextActionAt: 1 } },\n { key: { externalId: 1, flowId: 1 } },\n { key: { flowId: 1, status: 1 } },\n {\n key: { flowId: 1, triggerDedupeKey: 1 },\n unique: true,\n partialFilterExpression: { triggerDedupeKey: { $type: 'string' } },\n },\n ]),\n c.templates.createIndexes([\n { key: { slug: 1 }, unique: true },\n { key: { tags: 1 } },\n { key: { kind: 1 } },\n ]),\n c.templateVersions.createIndexes([{ key: { templateId: 1, version: 1 }, unique: true }]),\n c.sends.createIndexes([\n { key: { dedupeKey: 1 }, unique: true },\n { key: { externalId: 1, sentAt: -1 } },\n { key: { templateId: 1, sentAt: -1 } },\n { key: { flowRunId: 1 }, sparse: true },\n { key: { broadcastId: 1 }, sparse: true },\n { key: { providerMessageId: 1 }, sparse: true },\n { key: { status: 1, queuedAt: 1 } },\n { key: { status: 1, updatedAt: 1 } },\n ]),\n c.suppressions.createIndexes([\n { key: { email: 1, scope: 1 }, unique: true, partialFilterExpression: { email: { $type: 'string' } } },\n { key: { emailHash: 1 } },\n { key: { addedAt: -1 } },\n ]),\n c.broadcasts.createIndexes([\n { key: { slug: 1 }, unique: true },\n { key: { status: 1, scheduledAt: 1 } },\n ]),\n c.outbox.createIndexes([\n { key: { status: 1, enqueuedAt: 1 } },\n { key: { 'payload.dedupeKey': 1 }, unique: true },\n ]),\n c.auditLog.createIndexes([\n { key: { occurredAt: -1 } },\n { key: { 'resource.collection': 1, 'resource.id': 1, occurredAt: -1 } },\n { key: { actor: 1, occurredAt: -1 } },\n ]),\n c.webhookEvents.createIndexes([\n { key: { provider: 1, providerEventId: 1 }, unique: true },\n { key: { providerMessageId: 1 } },\n { key: { processed: 1, receivedAt: 1 } },\n ]),\n c.contactTags.createIndexes([\n { key: { externalId: 1, tag: 1 }, unique: true },\n { key: { tag: 1 } },\n ]),\n c.health.createIndexes([\n { key: { senderDomain: 1, kind: 1 } },\n { key: { status: 1 } },\n // setup-status reads the most-recently-touched health doc as a heartbeat.\n { key: { updatedAt: -1 } },\n ]),\n c.dnsblChecks.createIndexes([\n { key: { target: 1, list: 1 }, unique: true },\n // Supports the admin /dnsbl GET sort: result asc, then target asc, list asc.\n { key: { result: 1, target: 1, list: 1 } },\n // TTL — stale rows for targets the operator removed disappear after\n // 60 days without manual cleanup. The puller refreshes runAt on\n // every active target so existing targets stay indefinitely.\n { key: { runAt: 1 }, expireAfterSeconds: 60 * 24 * 60 * 60 },\n ]),\n c.postmasterSnapshots.createIndexes([\n { key: { domain: 1, date: 1 }, unique: true },\n { key: { domain: 1, fetchedAt: -1 } },\n { key: { domainReputation: 1 } },\n ]),\n c.sndsSnapshots.createIndexes([\n { key: { ip: 1, activityStart: 1 }, unique: true },\n { key: { ip: 1, fetchedAt: -1 } },\n { key: { filterResult: 1 } },\n ]),\n c.dmarcReports.createIndexes([\n { key: { reportId: 1, orgName: 1 }, unique: true },\n { key: { domain: 1, rangeEnd: -1 } },\n // Cross-domain \"most recent reports\" queries scan a lot without this.\n { key: { rangeEnd: -1 } },\n { key: { receivedAt: -1 } },\n ]),\n c.dmarcFailures.createIndexes([\n { key: { reportId: 1, sourceIp: 1 }, unique: true },\n { key: { domain: 1, day: -1 } },\n { key: { sourceIp: 1, day: -1 } },\n { key: { receivedAt: 1 } }, // for retention pruning\n ]),\n c.dmarcSourceTags.createIndexes([\n { key: { ip: 1 }, unique: true },\n ]),\n c.mailTesterScores.createIndexes([\n { key: { contentKey: 1 }, unique: true },\n { key: { templateSlug: 1, fetchedAt: -1 } },\n // TTL — Mongo auto-deletes expired scores so we never serve stale data.\n { key: { expiresAt: 1 }, expireAfterSeconds: 0 },\n ]),\n ])\n\n // One-shot migrations — run after indexes are in place so any DELETE\n // plan can use them. Idempotent at MongoDB level (returns 0 when\n // nothing is there).\n await c.health.deleteOne({ _id: 'singleton' as any }).catch(() => {})\n}\n","/**\n * Event registry + dedupe-key policy. INVARIANT 1: every `mailer_events` row\n * has a unique dedupeKey. Callers either pass one or `mailer.registerEvent`\n * declares a policy and we derive it.\n */\n\nimport crypto from 'node:crypto'\n\nexport type DedupePolicy = 'once-per-contact' | 'once-per-day' | 'every-time'\n\nexport interface EventRegistration {\n name: string\n dedupePolicy: DedupePolicy\n}\n\nexport class EventRegistry {\n private readonly policies = new Map<string, DedupePolicy>()\n\n register(reg: EventRegistration): void {\n this.policies.set(reg.name, reg.dedupePolicy)\n }\n\n has(name: string): boolean {\n return this.policies.has(name)\n }\n\n policy(name: string): DedupePolicy | undefined {\n return this.policies.get(name)\n }\n\n list(): EventRegistration[] {\n return Array.from(this.policies, ([name, dedupePolicy]) => ({ name, dedupePolicy }))\n }\n\n /**\n * Derive a dedupeKey for an event call. Returns null when no policy is\n * registered AND no key was passed — caller should throw.\n */\n deriveKey(\n name: string,\n externalId: string,\n passedKey: string | undefined,\n now: Date,\n ): string | null {\n if (passedKey) return passedKey\n const policy = this.policies.get(name)\n if (!policy) return null\n\n switch (policy) {\n case 'once-per-contact':\n return `${externalId}:${name}`\n case 'once-per-day':\n return `${externalId}:${name}:${isoDay(now)}`\n case 'every-time':\n return `${externalId}:${name}:${randomId()}`\n }\n }\n}\n\nfunction isoDay(d: Date): string {\n return d.toISOString().slice(0, 10)\n}\n\nfunction randomId(): string {\n return crypto.randomBytes(8).toString('hex')\n}\n","/**\n * Guarded lookup into the provider map.\n *\n * `Mailer.providers` is a plain object literal (`Record<string, MailProvider>`),\n * so a bare `providers[name]` also resolves inherited `Object.prototype`\n * members: `constructor`, `toString`, `valueOf` and friends all return\n * something truthy, sail past an `if (!provider)` guard, and reach\n * `provider.send(...)` / `provider.verifyWebhook(...)` as a non-provider.\n * `__proto__` resolves to the prototype object itself.\n *\n * Two gates, because either alone is incomplete: `Object.hasOwn` rejects\n * inherited keys, and the shape check rejects an own key whose value was never\n * a provider (a host building the map from untyped JSON, say).\n *\n * The shape check requires the *whole* `MailProvider` method surface rather\n * than just the methods a given call site is about to use. The map is typed\n * `Record<string, MailProvider>`; a value missing any of them was never a\n * provider, and having one lookup answer the same way everywhere is worth more\n * than letting a half-built object through on the routes that happen not to\n * touch its missing half.\n *\n * Lives here — a leaf module next to `mailer.ts`, importing nothing but a type\n * — so the public router, the admin router and the send runner can all share\n * it without any of them importing each other and without a cycle through\n * `mailer.ts` (which imports the runner).\n */\n\nimport type { MailProvider } from '../shared/types.js'\n\n/** Methods that make a value a `MailProvider` rather than an arbitrary object. */\nconst PROVIDER_METHODS = ['send', 'verifyWebhook', 'parseWebhookEvents'] as const\n\nfunction isMailProvider(candidate: unknown): candidate is MailProvider {\n if (!candidate || typeof candidate !== 'object') return false\n const p = candidate as Partial<Record<(typeof PROVIDER_METHODS)[number], unknown>>\n return PROVIDER_METHODS.every((m) => typeof p[m] === 'function')\n}\n\n/**\n * Resolve `name` against `providers`, or `null` when it does not name a\n * registered provider. Never throws, and never returns something that isn't a\n * provider — callers can go straight to a method call on a non-null result.\n */\nexport function resolveProvider(\n providers: Record<string, MailProvider>,\n name: unknown,\n): MailProvider | null {\n if (typeof name !== 'string' || !Object.hasOwn(providers, name)) return null\n const candidate: unknown = providers[name]\n return isMailProvider(candidate) ? candidate : null\n}\n\n/**\n * Names that `resolveProvider` would actually resolve, sorted. For error\n * messages on admin-gated routes, where telling the operator what *is*\n * registered is the difference between a fixable report and a dead end.\n */\nexport function registeredProviderNames(providers: Record<string, MailProvider>): string[] {\n return Object.keys(providers)\n .filter((name) => resolveProvider(providers, name) !== null)\n .sort()\n}\n","/**\n * HMAC-signed tokens for unsubscribe + preference-center URLs.\n *\n * Format: base64url(payload) '.' base64url(hmac)\n * payload = JSON.stringify({ e: email, s: scope, x: expiresAtMs })\n * hmac = HMAC-SHA256(secret, payload)\n *\n * Tokens expire because long-lived signed URLs are a liability.\n */\n\nimport crypto from 'node:crypto'\nimport type { SuppressionScope } from '../shared/enums.js'\n\nexport interface UnsubscribeTokenPayload {\n email: string\n scope: SuppressionScope\n expiresAt: Date\n}\n\nexport function signUnsubscribeToken(\n payload: UnsubscribeTokenPayload,\n secret: string,\n): string {\n const body = JSON.stringify({\n e: payload.email.toLowerCase(),\n s: payload.scope,\n x: payload.expiresAt.getTime(),\n })\n const bodyB64 = b64url(Buffer.from(body, 'utf8'))\n const hmac = crypto.createHmac('sha256', secret).update(bodyB64).digest()\n return `${bodyB64}.${b64url(hmac)}`\n}\n\nexport function verifyUnsubscribeToken(\n token: string,\n secret: string,\n now: Date = new Date(),\n): UnsubscribeTokenPayload | null {\n const parts = token.split('.')\n if (parts.length !== 2) return null\n const [bodyB64, sigB64] = parts as [string, string]\n\n const expected = crypto.createHmac('sha256', secret).update(bodyB64).digest()\n let actual: Buffer\n try {\n actual = b64urlDecode(sigB64)\n } catch {\n return null\n }\n if (expected.length !== actual.length) return null\n if (!crypto.timingSafeEqual(expected, actual)) return null\n\n let body: { e?: string; s?: string; x?: number }\n try {\n body = JSON.parse(b64urlDecode(bodyB64).toString('utf8'))\n } catch {\n return null\n }\n if (!body.e || !body.s || typeof body.x !== 'number') return null\n if (body.x < now.getTime()) return null\n if (body.s !== 'all' && body.s !== 'marketing' && body.s !== 'transactional') return null\n\n return {\n email: body.e,\n scope: body.s,\n expiresAt: new Date(body.x),\n }\n}\n\n// ---------------------------------------------------------------------------\n// Tracking-URL signatures\n// ---------------------------------------------------------------------------\n\n/**\n * Scopes a tracking signature can be issued for. An allowlist, mirroring the\n * `k: 'doi'` discriminator on the DOI token: the scope is part of the signed\n * message, so an `/m/open` signature cannot be replayed as an `/m/click` one\n * even for the same send.\n */\nexport type TrackingScope = 'open' | 'click'\n\nconst TRACKING_SCOPES: readonly string[] = ['open', 'click']\n\n/**\n * Signature length in base64url characters. 12 chars = 72 bits of the\n * HMAC-SHA256 digest.\n *\n * Truncation is deliberate. These signatures are embedded in every link of\n * every email, and the pixel URL in particular is parsed by mail clients with\n * their own length quirks, so bytes are not free. 72 bits is far beyond what an\n * online forgery attack can reach: an attacker gets no oracle beyond \"the open\n * was counted\", each guess is a live HTTP request, and there is no offline\n * verification step. Nothing here is a bearer credential for anything except\n * \"this recipient was sent this mail\".\n */\nexport const TRACKING_SIG_LENGTH = 12\n\nexport interface TrackingTokenParams {\n sendId: string\n /** Present for `click` scope, absent for `open`. */\n linkId?: string\n}\n\n/**\n * The signed message. Versioned so a future format change (longer signature,\n * different digest) can be distinguished rather than silently mis-verified.\n * Components are joined with `:`, a character that appears in neither an\n * ObjectId hex string nor a `shortHash` linkId, so the encoding is unambiguous.\n */\nfunction trackingMessage(scope: TrackingScope, params: TrackingTokenParams): string {\n const tail = params.linkId === undefined ? '' : `:${params.linkId}`\n return `mailery.track.v1:${scope}:${params.sendId}${tail}`\n}\n\n/**\n * Sign a tracking URL. Returns `TRACKING_SIG_LENGTH` base64url characters.\n *\n * Keyed with `unsubscribeSecret` — the same secret the unsubscribe and DOI\n * tokens use, so there is exactly one secret to provision\n * (`MAILER_UNSUBSCRIBE_SECRET`) and one to rotate. The scope prefix keeps the\n * key domains separate.\n */\nexport function signTrackingToken(\n scope: TrackingScope,\n params: TrackingTokenParams,\n secret: string,\n): string {\n if (!TRACKING_SCOPES.includes(scope)) {\n throw new Error(`signTrackingToken: unknown scope ${String(scope)}`)\n }\n const mac = crypto.createHmac('sha256', secret).update(trackingMessage(scope, params)).digest()\n return b64url(mac).slice(0, TRACKING_SIG_LENGTH)\n}\n\n/**\n * Verify a tracking-URL signature in constant time.\n *\n * The length pre-check before `timingSafeEqual` is required, not defensive:\n * `crypto.timingSafeEqual` throws on mismatched lengths, and a thrown\n * verification is a rejection that leaks length through a different channel.\n * Same shape as `verifyUnsubscribeToken`.\n */\nexport function verifyTrackingToken(\n token: unknown,\n scope: TrackingScope,\n params: TrackingTokenParams,\n secret: string,\n): boolean {\n if (typeof token !== 'string') return false\n if (!TRACKING_SCOPES.includes(scope)) return false\n if (token.length !== TRACKING_SIG_LENGTH) return false\n const expected = Buffer.from(signTrackingToken(scope, params, secret), 'utf8')\n const actual = Buffer.from(token, 'utf8')\n if (expected.length !== actual.length) return false\n return crypto.timingSafeEqual(expected, actual)\n}\n\nfunction b64url(buf: Buffer): string {\n return buf.toString('base64').replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '')\n}\n\nfunction b64urlDecode(s: string): Buffer {\n const padded = s.replace(/-/g, '+').replace(/_/g, '/') + '==='.slice((s.length + 3) % 4)\n return Buffer.from(padded, 'base64')\n}\n\n/**\n * sha256 hex digest, used for storing email hashes (GDPR forget) and dedup helpers.\n */\nexport function sha256Hex(input: string): string {\n return crypto.createHash('sha256').update(input).digest('hex')\n}\n\n// ---------------------------------------------------------------------------\n// Double opt-in tokens\n// ---------------------------------------------------------------------------\n\nexport interface DoiTokenPayload {\n externalId: string\n expiresAt: Date\n}\n\n/**\n * Sign a DOI confirmation token. Same shape as the unsubscribe token, but\n * scoped to \"this externalId confirmed their subscription.\"\n */\nexport function signDoiToken(payload: DoiTokenPayload, secret: string): string {\n const body = JSON.stringify({\n i: payload.externalId,\n x: payload.expiresAt.getTime(),\n k: 'doi',\n })\n const bodyB64 = b64url(Buffer.from(body, 'utf8'))\n const hmac = crypto.createHmac('sha256', secret).update(bodyB64).digest()\n return `${bodyB64}.${b64url(hmac)}`\n}\n\nexport function verifyDoiToken(token: string, secret: string, now: Date = new Date()): DoiTokenPayload | null {\n const parts = token.split('.')\n if (parts.length !== 2) return null\n const [bodyB64, sigB64] = parts as [string, string]\n\n const expected = crypto.createHmac('sha256', secret).update(bodyB64).digest()\n let actual: Buffer\n try {\n actual = b64urlDecode(sigB64)\n } catch {\n return null\n }\n if (expected.length !== actual.length) return null\n if (!crypto.timingSafeEqual(expected, actual)) return null\n\n let body: { i?: string; x?: number; k?: string }\n try {\n body = JSON.parse(b64urlDecode(bodyB64).toString('utf8'))\n } catch {\n return null\n }\n if (!body.i || typeof body.x !== 'number' || body.k !== 'doi') return null\n if (body.x < now.getTime()) return null\n\n return { externalId: body.i, expiresAt: new Date(body.x) }\n}\n","/**\n * The one place an unsubscribe is written.\n *\n * Extracted from `Mailer.unsubscribe` so the tick drain\n * (`runner/pending-unsubs.ts`) can replay a journaled opt-out through exactly\n * the same two writes. A second copy of this logic is how a replayed\n * unsubscribe quietly stops matching the real one.\n *\n * Both writes are idempotent, which is what makes the drain safe to re-run:\n * - the suppression is a `$setOnInsert` upsert keyed on (email, scope), so\n * re-applying never rewrites `addedAt`/`source` of the original opt-out\n * - the subscription update is a `$set` to a terminal state\n */\n\nimport type { Collections } from './models/index.js'\nimport type { UnsubscribeInput } from '../shared/schemas.js'\nimport { sha256Hex } from './tokens.js'\n\n/**\n * Apply an unsubscribe: suppression row + subscription status.\n *\n * `input` must already be parsed by `unsubscribeInputSchema` — the caller owns\n * validation so this stays a pure write.\n */\nexport async function applyUnsubscribe(\n collections: Collections,\n input: UnsubscribeInput,\n now: Date = new Date(),\n): Promise<void> {\n const normalized = input.email\n\n await collections.suppressions.updateOne(\n { email: normalized, scope: input.scope },\n {\n $setOnInsert: {\n email: normalized,\n emailHash: sha256Hex(normalized),\n scope: input.scope,\n // mailer_suppressions canonical reason — see plans/02-data-model.md.\n reason: 'unsubscribed' as const,\n source: input.source,\n notes: input.notes ?? null,\n addedAt: now,\n expiresAt: null,\n },\n },\n { upsert: true },\n )\n\n await collections.subscriptions.updateOne(\n { emailAtSubscribe: normalized },\n {\n $set: {\n status: 'unsubscribed' as const,\n unsubscribedAt: now,\n unsubscribeReason: input.reason,\n updatedAt: now,\n },\n },\n )\n}\n","/**\n * BullMQ driver. Four named queues backed by Redis. Job-level `attempts`,\n * `backoff`, `delay`, and `jobId` pass through to BullMQ's native semantics.\n * Send rate limit is enforced via BullMQ's `limiter` option (Redis Lua script).\n */\n\nimport type { Queue, Worker } from 'bullmq'\nimport IORedis, { type RedisOptions as IORedisOptions } from 'ioredis'\n\nimport type { RedisOptions } from '../config.js'\nimport type {\n AddOptions,\n QueueAPI,\n QueueDriver,\n Queues,\n WorkerStartOptions,\n} from './types.js'\n\ninterface BullQueues {\n tick: Queue\n advance: Queue\n send: Queue\n webhook: Queue\n}\n\ninterface BullModule {\n Queue: typeof Queue\n Worker: typeof Worker\n}\n\nconst QUEUE_NAMES = {\n tick: 'mailer-tick',\n advance: 'mailer-advance',\n send: 'mailer-send',\n webhook: 'mailer-webhook',\n} as const\n\nexport class BullDriver implements QueueDriver {\n readonly queues: Queues\n private redis: IORedis\n private bullQueues: BullQueues\n private workers: { tick: Worker; advance: Worker; send: Worker; webhook: Worker } | null = null\n private bull: BullModule\n\n static async create(redisConfig: RedisOptions | IORedis, prefix?: string): Promise<BullDriver> {\n let bull: BullModule\n try {\n bull = (await import('bullmq')) as unknown as BullModule\n } catch {\n throw new Error(\n \"mailery: queue driver 'bull' requires the 'bullmq' peer dependency. Run `npm install bullmq ioredis`.\",\n )\n }\n if (prefix?.includes(':')) {\n throw new Error(\n `mailery: queue prefix \"${prefix}\" must not contain ':' — BullMQ uses it as the Redis key separator.`,\n )\n }\n const redis = isRedisLike(redisConfig) ? (redisConfig as IORedis) : connect(redisConfig as RedisOptions)\n return new BullDriver(bull, redis, prefix)\n }\n\n private prefix?: string\n\n private constructor(bull: BullModule, redis: IORedis, prefix?: string) {\n this.bull = bull\n this.redis = redis\n this.prefix = prefix\n // Bounded retention: completed/failed jobs must not accumulate in Redis\n // forever. Completed jobs also need to leave promptly so jobId-based\n // idempotent re-adds aren't dropped against a stale completed job.\n const opts = {\n connection: redis,\n prefix,\n defaultJobOptions: {\n removeOnComplete: { age: 24 * 3600, count: 1000 },\n removeOnFail: { age: 7 * 24 * 3600 },\n },\n }\n this.bullQueues = {\n tick: new bull.Queue(QUEUE_NAMES.tick, opts),\n advance: new bull.Queue(QUEUE_NAMES.advance, opts),\n send: new bull.Queue(QUEUE_NAMES.send, opts),\n webhook: new bull.Queue(QUEUE_NAMES.webhook, opts),\n }\n this.queues = {\n tick: adaptBullQueue(this.bullQueues.tick),\n advance: adaptBullQueue(this.bullQueues.advance),\n send: adaptBullQueue(this.bullQueues.send),\n webhook: adaptBullQueue(this.bullQueues.webhook),\n }\n }\n\n async scheduleRepeatingTick(intervalSeconds: number): Promise<void> {\n await (this.bullQueues.tick as any).upsertJobScheduler(\n 'mailer-tick-repeat',\n { every: intervalSeconds * 1000 },\n {\n name: 'tick',\n data: {},\n opts: { removeOnComplete: { count: 20 }, removeOnFail: { count: 50 } },\n },\n )\n }\n\n async startWorkers(opts: WorkerStartOptions): Promise<void> {\n if (this.workers) return\n // Workers must share the queues' prefix or they'd poll different keys.\n const base = { connection: this.redis, prefix: this.prefix }\n const { Worker } = this.bull\n\n const tick = new Worker(\n QUEUE_NAMES.tick,\n async (job: any) => opts.handlers.tick(job.data),\n { ...base, concurrency: 1 },\n )\n const advance = new Worker(\n QUEUE_NAMES.advance,\n async (job: any) => opts.handlers.advance(job.data),\n { ...base, concurrency: 10 },\n )\n const send = new Worker(\n QUEUE_NAMES.send,\n async (job: any) => opts.handlers.send(job.data),\n {\n ...base,\n concurrency: opts.concurrency.send,\n limiter: opts.sendRateLimit\n ? { max: opts.sendRateLimit.max, duration: opts.sendRateLimit.durationMs }\n : undefined,\n },\n )\n const webhook = new Worker(\n QUEUE_NAMES.webhook,\n async (job: any) => opts.handlers.webhook(job.data),\n { ...base, concurrency: 4 },\n )\n\n this.workers = { tick, advance, send, webhook }\n }\n\n async stopWorkers(): Promise<void> {\n if (!this.workers) return\n await Promise.all([\n this.workers.tick.close(),\n this.workers.advance.close(),\n this.workers.send.close(),\n this.workers.webhook.close(),\n ])\n this.workers = null\n }\n\n async close(): Promise<void> {\n await this.stopWorkers()\n await Promise.all([\n this.bullQueues.tick.close(),\n this.bullQueues.advance.close(),\n this.bullQueues.send.close(),\n this.bullQueues.webhook.close(),\n ])\n }\n}\n\nfunction adaptBullQueue(q: Queue): QueueAPI {\n return {\n add: (name, data, opts) => q.add(name, data as any, opts as any),\n getWaitingCount: () => q.getWaitingCount(),\n getInFlightCount: async () => {\n const [active, waiting] = await Promise.all([q.getActiveCount(), q.getWaitingCount()])\n return active + waiting\n },\n getDelayedCount: () => q.getDelayedCount(),\n close: () => q.close(),\n }\n}\n\nfunction isRedisLike(x: unknown): boolean {\n return !!x && typeof x === 'object' && typeof (x as any).get === 'function' && typeof (x as any).set === 'function'\n}\n\nfunction connect(opts: RedisOptions): IORedis {\n const config: IORedisOptions = {\n maxRetriesPerRequest: null, // BullMQ requirement\n enableReadyCheck: false,\n }\n if (opts.url) return new IORedis(opts.url, config)\n return new IORedis({\n ...config,\n host: opts.host ?? '127.0.0.1',\n port: opts.port ?? 6379,\n password: opts.password,\n db: opts.db,\n username: opts.username,\n tls: opts.tls ? {} : undefined,\n })\n}\n\n// Re-exports needed by the broader queue surface\nexport type { AddOptions }\n","/**\n * Agenda driver. Backed by the same MongoDB instance the rest of mailery uses,\n * so no Redis is required. Uses `agenda` + `@agendajs/mongo-backend`.\n *\n * Single-process only: send rate limit is enforced via an in-memory Bottleneck\n * wrapped around the send handler. Multi-process Agenda deployments would\n * fan-out beyond the rate cap — out of scope.\n *\n * Retry/backoff: applied per-definition via Agenda's built-in\n * `backoffStrategies.exponential`. Per-call `attempts` from add() is ignored;\n * the driver uses the shared config-level `sendRetryAttempts`.\n *\n * Idempotency: per-call `jobId` is stored as `data.__jobId`. Before scheduling\n * we look for a pending (not-yet-run, not-finished) job with the same key.\n *\n * Retention: Agenda keeps every job document forever by default, which for a\n * mailer means one doc per send/advance/webhook accumulating in Mongo without\n * bound. Succeeded one-shot jobs are removed on completion (`removeOnComplete`);\n * failed ones are swept on an interval, since Agenda's auto-remove only fires\n * on success. The repeating tick is a single document whose `nextRunAt` is\n * recomputed in place, so it is never a source of growth — and the sweep\n * explicitly skips repeating jobs so it can't delete it.\n */\n\nimport type { Db } from 'mongodb'\nimport type { Agenda, Job } from 'agenda'\nimport type Bottleneck from 'bottleneck'\n\nimport type {\n AddOptions,\n QueueAPI,\n QueueDriver,\n Queues,\n WorkerStartOptions,\n} from './types.js'\n\ninterface AgendaModule {\n Agenda: typeof Agenda\n backoffStrategies: { exponential: (opts: { delay: number; maxRetries: number; factor?: number }) => any }\n}\n\ninterface MongoBackendModule {\n MongoBackend: new (cfg: { mongo: Db; collection?: string; ensureIndex?: boolean }) => any\n}\n\ninterface BottleneckCtor {\n new (opts: { minTime?: number; maxConcurrent?: number }): Bottleneck\n}\n\nconst QUEUE_NAMES = {\n tick: 'mailer-tick',\n advance: 'mailer-advance',\n send: 'mailer-send',\n webhook: 'mailer-webhook',\n} as const\n\n/** Default jobs collection. Kept as-is when no prefix is configured. */\nconst DEFAULT_COLLECTION = '_mailerJobs'\n\n/** How long a failed job document is kept before the sweep deletes it. */\nconst DEFAULT_FAILED_RETENTION_DAYS = 7\n\n/** How often the failed-job sweep runs. */\nconst FAILED_SWEEP_INTERVAL_MS = 60 * 60 * 1000\n\nexport interface AgendaDriverOptions {\n db: Db\n processEverySeconds?: number\n lockLifetimeSeconds?: number\n collectionName?: string\n /**\n * Namespaces the jobs collection so multiple mailery instances can share one\n * Mongo database — the Agenda counterpart to the Bull driver's Redis key\n * prefix. Ignored when `collectionName` is given explicitly.\n */\n prefix?: string\n /** Days to keep failed job documents. 0 disables the sweep. */\n failedJobRetentionDays?: number\n}\n\nexport class AgendaDriver implements QueueDriver {\n readonly queues: Queues\n private agenda: Agenda\n private agendaMod: AgendaModule\n private sendLimiter: Bottleneck | null = null\n private started = false\n\n static async create(opts: AgendaDriverOptions): Promise<AgendaDriver> {\n let agendaMod: AgendaModule\n let backendMod: MongoBackendModule\n try {\n agendaMod = (await import('agenda')) as unknown as AgendaModule\n backendMod = (await import('@agendajs/mongo-backend')) as unknown as MongoBackendModule\n } catch {\n throw new Error(\n \"mailery: queue driver 'agenda' requires the 'agenda' and '@agendajs/mongo-backend' peer dependencies. Run `npm install agenda @agendajs/mongo-backend bottleneck`.\",\n )\n }\n\n const collectionName = opts.collectionName ?? collectionFor(opts.prefix)\n const backend = new backendMod.MongoBackend({\n mongo: opts.db,\n collection: collectionName,\n })\n\n const agenda = new agendaMod.Agenda({\n backend,\n processEvery: `${opts.processEverySeconds ?? 5} seconds`,\n defaultLockLifetime: (opts.lockLifetimeSeconds ?? 10 * 60) * 1000,\n maxConcurrency: 50,\n defaultConcurrency: 5,\n // Drop succeeded one-shot jobs instead of retaining them forever.\n // Agenda guards this on `!nextRunAt`, so repeating jobs survive.\n removeOnComplete: true,\n } as any)\n\n const retentionDays = opts.failedJobRetentionDays ?? DEFAULT_FAILED_RETENTION_DAYS\n\n // The sweep filters on failedAt; without an index it's a collection scan\n // every hour. Non-fatal — a driver that can't index still works.\n try {\n await opts.db.collection(collectionName).createIndex({ failedAt: 1 }, { sparse: true })\n } catch (err) {\n console.error('mailery: could not index the Agenda jobs collection on failedAt', err)\n }\n\n return new AgendaDriver(agenda, agendaMod, opts.db, collectionName, retentionDays)\n }\n\n private db: Db\n private collName: string\n private failedRetentionDays: number\n private sweepTimer: ReturnType<typeof setInterval> | null = null\n\n private constructor(\n agenda: Agenda,\n agendaMod: AgendaModule,\n db: Db,\n collectionName: string,\n failedRetentionDays: number,\n ) {\n this.agenda = agenda\n this.agendaMod = agendaMod\n this.db = db\n this.collName = collectionName\n this.failedRetentionDays = failedRetentionDays\n this.queues = {\n tick: this.makeQueueAPI(QUEUE_NAMES.tick),\n advance: this.makeQueueAPI(QUEUE_NAMES.advance),\n send: this.makeQueueAPI(QUEUE_NAMES.send),\n webhook: this.makeQueueAPI(QUEUE_NAMES.webhook),\n }\n }\n\n private makeQueueAPI(name: string): QueueAPI {\n return {\n add: async (_jobName: string, data: unknown, opts?: AddOptions) => {\n const payload: Record<string, unknown> = { ...(data as object) }\n if (opts?.jobId) {\n payload.__jobId = opts.jobId\n if (await this.findPending(name, opts.jobId)) return\n }\n const job = this.agenda.create(name, payload as any)\n if (opts?.delay) job.schedule(new Date(Date.now() + opts.delay))\n await job.save()\n },\n getWaitingCount: async () => {\n return this.jobsCollection().countDocuments({\n name,\n $or: [{ lockedAt: null }, { lockedAt: { $exists: false } }],\n nextRunAt: { $lte: new Date() },\n })\n },\n close: async () => {},\n }\n }\n\n /** Direct access to the Mongo collection Agenda persists jobs into. */\n private jobsCollection() {\n return this.db.collection(this.collName)\n }\n\n private async findPending(name: string, jobId: string): Promise<unknown> {\n return this.jobsCollection().findOne({\n name,\n 'data.__jobId': jobId,\n $or: [{ lastFinishedAt: null }, { lastFinishedAt: { $exists: false } }],\n })\n }\n\n async scheduleRepeatingTick(intervalSeconds: number): Promise<void> {\n // Persist the repeating job only — do NOT start Agenda here. Starting with\n // a placeholder tick handler would let a process that never calls\n // startWorkers (API-only process in a web/worker split) lock and complete\n // tick jobs as no-ops, silently swallowing real ticks. Agenda starts in\n // startWorkers, after the real handlers are defined.\n await this.agenda.every(`${intervalSeconds} seconds`, QUEUE_NAMES.tick)\n }\n\n async startWorkers(opts: WorkerStartOptions): Promise<void> {\n const exp = this.agendaMod.backoffStrategies.exponential\n\n if (opts.sendRateLimit) {\n try {\n const Bottleneck = (await import('bottleneck')).default as unknown as BottleneckCtor\n this.sendLimiter = new Bottleneck({\n minTime: Math.ceil(opts.sendRateLimit.durationMs / opts.sendRateLimit.max),\n maxConcurrent: opts.concurrency.send,\n })\n } catch {\n throw new Error(\n \"mailery: queue driver 'agenda' with sendRateLimit requires the 'bottleneck' peer dependency. Run `npm install bottleneck`.\",\n )\n }\n }\n\n const retryBackoff = exp({ delay: 60_000, maxRetries: Math.max(0, opts.retryAttempts - 1), factor: 2 })\n\n this.agenda.define(QUEUE_NAMES.tick, async (job: Job) => {\n await opts.handlers.tick(job.attrs.data)\n }, { concurrency: 1 })\n\n this.agenda.define(QUEUE_NAMES.advance, async (job: Job) => {\n await opts.handlers.advance(job.attrs.data as any)\n }, { concurrency: 10, backoff: retryBackoff })\n\n this.agenda.define(QUEUE_NAMES.send, async (job: Job) => {\n const data = job.attrs.data as any\n if (this.sendLimiter) {\n await this.sendLimiter.schedule(() => opts.handlers.send(data))\n } else {\n await opts.handlers.send(data)\n }\n }, { concurrency: opts.concurrency.send, backoff: retryBackoff })\n\n this.agenda.define(QUEUE_NAMES.webhook, async (job: Job) => {\n await opts.handlers.webhook(job.attrs.data as any)\n }, { concurrency: 4, backoff: retryBackoff })\n\n if (!this.started) {\n await this.agenda.start()\n this.started = true\n this.startFailedJobSweep()\n }\n }\n\n /**\n * Agenda's auto-remove only fires on success, so failed documents would\n * otherwise be retained forever. Runs once on worker start, then hourly.\n */\n private startFailedJobSweep(): void {\n if (this.failedRetentionDays <= 0 || this.sweepTimer) return\n void this.sweepFailedJobs()\n this.sweepTimer = setInterval(() => void this.sweepFailedJobs(), FAILED_SWEEP_INTERVAL_MS)\n // Don't hold the event loop open on an otherwise-idle process.\n this.sweepTimer.unref?.()\n }\n\n /** Delete failed, fully-retired job documents older than the retention window. */\n async sweepFailedJobs(): Promise<number> {\n const cutoff = new Date(Date.now() - this.failedRetentionDays * 24 * 3600 * 1000)\n try {\n const res = await this.jobsCollection().deleteMany({\n failedAt: { $lt: cutoff },\n // Never touch the repeating tick.\n repeatInterval: { $in: [null, undefined] },\n // Leave anything still scheduled for a retry, and anything a worker\n // currently holds a lock on.\n $and: [\n { $or: [{ nextRunAt: null }, { nextRunAt: { $exists: false } }, { nextRunAt: { $lt: cutoff } }] },\n { $or: [{ lockedAt: null }, { lockedAt: { $exists: false } }, { lockedAt: { $lt: cutoff } }] },\n ],\n })\n return res.deletedCount ?? 0\n } catch (err) {\n console.error('mailery: failed-job sweep failed', err)\n return 0\n }\n }\n\n async stopWorkers(): Promise<void> {\n if (this.sweepTimer) {\n clearInterval(this.sweepTimer)\n this.sweepTimer = null\n }\n if (!this.started) return\n await this.agenda.stop()\n this.started = false\n if (this.sendLimiter) {\n await this.sendLimiter.stop({ dropWaitingJobs: true }).catch(() => {})\n this.sendLimiter = null\n }\n }\n\n async close(): Promise<void> {\n await this.stopWorkers()\n }\n}\n\n/**\n * Resolve the jobs collection from an optional prefix. No prefix keeps the\n * historical `_mailerJobs` name — changing that default would strand queued\n * jobs in the old collection on upgrade.\n */\nexport function collectionFor(prefix?: string): string {\n if (!prefix) return DEFAULT_COLLECTION\n if (!/^[A-Za-z0-9_-]+$/.test(prefix)) {\n throw new Error(\n `mailery: queue prefix \"${prefix}\" must contain only letters, digits, '_' or '-' — it becomes part of a MongoDB collection name.`,\n )\n }\n return `${DEFAULT_COLLECTION}_${prefix}`\n}\n","/**\n * No-op queue driver. Used by tests and by hosts that drive the runner\n * synchronously (no background workers, no Redis, no Agenda). `add()` is a\n * no-op; the caller is expected to invoke runner functions directly.\n */\n\nimport type {\n QueueAPI,\n QueueDriver,\n Queues,\n WorkerStartOptions,\n} from './types.js'\n\nfunction noopQueueAPI(): QueueAPI {\n return {\n add: async () => undefined,\n getWaitingCount: async () => 0,\n close: async () => undefined,\n }\n}\n\nexport class NoopDriver implements QueueDriver {\n readonly queues: Queues = {\n tick: noopQueueAPI(),\n advance: noopQueueAPI(),\n send: noopQueueAPI(),\n webhook: noopQueueAPI(),\n }\n\n async scheduleRepeatingTick(_intervalSeconds: number): Promise<void> {\n /* noop */\n }\n\n async startWorkers(_opts: WorkerStartOptions): Promise<void> {\n /* noop */\n }\n\n async stopWorkers(): Promise<void> {\n /* noop */\n }\n\n async close(): Promise<void> {\n /* noop */\n }\n}\n","/**\n * Queue subsystem entry point. Exports the driver interface, the three\n * built-in drivers (Bull, Agenda, Noop), and a factory that resolves a\n * `QueueDriverConfig` to a concrete driver.\n */\n\nimport type { Db } from 'mongodb'\n\nimport { BullDriver } from './bull.js'\nimport { AgendaDriver } from './agenda.js'\nimport { NoopDriver } from './noop.js'\nimport type { QueueDriver, QueueDriverConfig } from './types.js'\n\nexport { BullDriver } from './bull.js'\nexport { AgendaDriver } from './agenda.js'\nexport { NoopDriver } from './noop.js'\nexport type {\n AddOptions,\n QueueAPI,\n QueueDriver,\n QueueDriverConfig,\n QueueHandlers,\n Queues,\n WorkerStartOptions,\n} from './types.js'\n\nexport async function createQueueDriver(\n config: QueueDriverConfig,\n fallbackDb: Db,\n): Promise<QueueDriver> {\n switch (config.driver) {\n case 'bull':\n return BullDriver.create(config.redis, config.prefix)\n case 'agenda':\n return AgendaDriver.create({\n db: config.db ?? fallbackDb,\n processEverySeconds: config.processEverySeconds,\n lockLifetimeSeconds: config.lockLifetimeSeconds,\n collectionName: config.collectionName,\n prefix: config.prefix,\n failedJobRetentionDays: config.failedJobRetentionDays,\n })\n case 'noop':\n return new NoopDriver()\n default: {\n const _exhaustive: never = config\n void _exhaustive\n throw new Error(`mailery: unknown queue driver`)\n }\n }\n}\n","/**\n * Event-trigger scan. Finds new event firings since each flow's\n * lastTriggerScanAt watermark, creates flow_runs for matching contacts,\n * enqueues immediate-advance jobs.\n */\n\nimport type { RunnerContext } from './index.js'\nimport type { FlowDoc, EventDoc } from '../models/index.js'\n\nconst BATCH_SIZE = 1000\n\n/**\n * Re-scan window. The watermark advances on `createdAt` (insert time), but a\n * concurrent `fire()` can commit a row with a createdAt slightly before the\n * scan's read. Re-reading this much history every pass closes that race; the\n * unique (flowId, triggerDedupeKey) index makes re-reads harmless.\n */\nconst SCAN_OVERLAP_MS = 30_000\n\nexport async function processNewlyFiredEventTriggers(ctx: RunnerContext): Promise<void> {\n const flows = await ctx.collections.flows.find({ enabled: true, 'trigger.type': 'event' }).toArray()\n for (const flow of flows) {\n await processFlowTriggers(flow, ctx)\n }\n}\n\nasync function processFlowTriggers(flow: FlowDoc, ctx: RunnerContext): Promise<void> {\n const eventName = flow.trigger.eventName\n if (!eventName) return\n // Watermark on createdAt, not occurredAt: occurredAt can lag insert time\n // (outbox-drained events carry the host-transaction timestamp), so an\n // occurredAt watermark permanently skips any event that lands \"in the past.\"\n // createdAt only ever moves forward with inserts.\n const since = flow.lastTriggerScanAt ?? flow.createdAt\n const scanFrom = new Date(since.getTime() - SCAN_OVERLAP_MS)\n\n const events = await ctx.collections.events\n .find({ name: eventName, createdAt: { $gt: scanFrom } })\n .sort({ createdAt: 1 })\n .limit(BATCH_SIZE)\n .toArray()\n\n if (events.length === 0) return\n\n for (const event of events) {\n await tryEnterFlow(flow, event, ctx)\n }\n\n const newestCreatedAt = events[events.length - 1]!.createdAt\n if (newestCreatedAt.getTime() > since.getTime()) {\n await ctx.collections.flows.updateOne(\n { _id: flow._id },\n { $set: { lastTriggerScanAt: newestCreatedAt, updatedAt: new Date() } },\n )\n }\n}\n\nasync function tryEnterFlow(flow: FlowDoc, event: EventDoc, ctx: RunnerContext): Promise<void> {\n if (flow.trigger.once) {\n const existing = await ctx.collections.flowRuns.findOne(\n { externalId: event.externalId, flowId: flow._id },\n { projection: { _id: 1 } },\n )\n if (existing) return\n }\n\n // Flow entry requires an active subscription — flows are marketing-scope.\n // Transactional mail for not-subscribed contacts goes through sendOneOff.\n const sub = await ctx.collections.subscriptions.findOne({ externalId: event.externalId })\n if (!sub || sub.status !== 'subscribed') return\n\n let result\n try {\n result = await ctx.collections.flowRuns.insertOne({\n externalId: event.externalId,\n flowId: flow._id!,\n flowSlug: flow.slug,\n flowVersion: flow.version,\n emailAtEntry: sub.emailAtSubscribe,\n triggerEvent: { name: event.name, properties: event.properties ?? {}, occurredAt: event.occurredAt },\n triggerDedupeKey: event.dedupeKey,\n enteredAt: new Date(),\n status: 'active',\n currentStepIndex: 0,\n currentBranchPath: [],\n nextActionAt: new Date(),\n attemptsForCurrentStep: 0,\n history: [{ stepIndex: -1, action: 'entered', at: new Date(), details: { eventDedupeKey: event.dedupeKey } }],\n exitedAt: null,\n exitReason: null,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n } catch (err: any) {\n // Event already entered this flow (overlap-window re-read) — no-op.\n if (err?.code !== 11000) throw err\n return\n }\n\n await ctx.queues.advance.add('advance', { flowRunId: String(result.insertedId) })\n}\n","/**\n * Sender-domain validator.\n *\n * Hosts may declare a `senderDomains` registry mapping a domain to which kind\n * of email is allowed to send from it. Used to isolate marketing reputation\n * from transactional reputation:\n *\n * senderDomains: {\n * 'news.example.com': { kind: 'marketing' },\n * 'mail.example.com': { kind: 'transactional' },\n * 'tools.example.com': { kind: 'both' }, // OK for either kind\n * }\n *\n * The check runs at template publish time. If a template's `fromEmail` domain\n * isn't declared, or is declared for the wrong kind, publish fails with a\n * descriptive 400. Hosts who don't set `senderDomains` get no enforcement —\n * back-compat default.\n */\n\nimport type { TemplateKind } from '../../shared/enums.js'\n\nexport interface SenderDomainConfig {\n /** Which template `kind` may use this domain as a From address. */\n kind: 'marketing' | 'transactional' | 'both'\n}\n\nexport type SenderDomainRegistry = Record<string, SenderDomainConfig>\n\nexport type SenderDomainValidation =\n | { ok: true }\n | { ok: false; code: 'invalid_email' | 'unregistered_domain' | 'wrong_kind'; reason: string }\n\nexport function validateSenderDomain(\n fromEmail: string,\n templateKind: TemplateKind,\n registry: SenderDomainRegistry | undefined,\n): SenderDomainValidation {\n if (!registry || Object.keys(registry).length === 0) return { ok: true }\n\n const domain = extractDomain(fromEmail)\n if (!domain) {\n return {\n ok: false,\n code: 'invalid_email',\n reason: `invalid fromEmail \"${fromEmail}\" — expected \"name@domain\"`,\n }\n }\n\n const entry = registry[domain]\n if (!entry) {\n const known = Object.keys(registry).join(', ')\n return {\n ok: false,\n code: 'unregistered_domain',\n reason: `sender domain \"${domain}\" is not declared in senderDomains (allowed: ${known})`,\n }\n }\n\n if (entry.kind === 'both') return { ok: true }\n if (entry.kind !== templateKind) {\n return {\n ok: false,\n code: 'wrong_kind',\n reason: `sender domain \"${domain}\" is configured for ${entry.kind} email, but this template's kind is ${templateKind}`,\n }\n }\n\n return { ok: true }\n}\n\nexport function extractDomain(email: string): string | null {\n if (typeof email !== 'string') return null\n const at = email.lastIndexOf('@')\n if (at <= 0 || at === email.length - 1) return null\n return email.slice(at + 1).toLowerCase().trim()\n}\n","/**\n * Circuit breaker. Tracks rolling counters in mailer_health per\n * (senderDomain, kind) bucket plus a single aggregate roll-up. Computes rates\n * on each tick and trips individual buckets when thresholds are exceeded.\n *\n * status: 'healthy' — normal\n * 'degraded' — non-blocking warnings (e.g. high failed-to-send rate)\n * 'tripped' — marketing sends held; transactional bypasses (INVARIANT 6)\n *\n * The aggregate doc is informational only — it never trips. Trips live on\n * buckets so one subdomain tanking doesn't hold mail for the others.\n *\n * Recovery is manual (admin UI: POST /api/health/resume[?domain&kind]).\n */\n\nimport type { TemplateKind } from '../../shared/enums.js'\nimport type { HealthDoc } from '../models/index.js'\nimport { HEALTH_AGG_ID, healthBucketId } from '../models/index.js'\nimport { extractDomain } from '../templates/sender-domain.js'\nimport type { RunnerContext } from './index.js'\n\ntype CounterKey =\n | 'sent'\n | 'delivered'\n | 'bounced'\n | 'hardBounced'\n | 'softBounced'\n | 'complained'\n | 'failedToSend'\n\nexport interface HealthDims {\n /** Caller passes the raw `fromEmail`; we extract the domain here. */\n fromEmail: string | null\n kind: TemplateKind\n}\n\nconst ZERO_COUNTERS = {\n sent: 0,\n delivered: 0,\n bounced: 0,\n hardBounced: 0,\n softBounced: 0,\n complained: 0,\n failedToSend: 0,\n}\n\nconst ZERO_RATES = {\n bounceRate: 0,\n hardBounceRate: 0,\n complaintRate: 0,\n failureRate: 0,\n}\n\n/**\n * Bump a counter on the relevant bucket doc plus the aggregate doc. Called\n * from the send / webhook paths. Idempotent at the document level (upsert).\n *\n * `dims` is null when we can't attribute the event (e.g. webhook event with\n * no matching send) — in that case only the aggregate is updated.\n */\nexport async function recordHealthCounter(\n ctx: RunnerContext,\n counter: CounterKey,\n dims: HealthDims | null,\n by = 1,\n): Promise<void> {\n const windowMs = ctx.config.circuitBreaker.windowMinutes * 60 * 1000\n const writes: Array<Promise<unknown>> = []\n\n writes.push(upsertCounter(ctx, HEALTH_AGG_ID, null, null, counter, by, windowMs))\n\n if (dims) {\n // Skip the bucket write when we can't extract a real domain from\n // fromEmail rather than funneling unrelated invalid-sender sends into a\n // shared `_unknown` bucket — that bucket can collect bounces from many\n // unrelated sources and falsely trip them all at once.\n const domain = dims.fromEmail ? extractDomain(dims.fromEmail) : null\n if (domain) {\n const id = healthBucketId(domain, dims.kind)\n writes.push(upsertCounter(ctx, id, domain, dims.kind, counter, by, windowMs))\n }\n }\n\n await Promise.all(writes)\n}\n\nasync function upsertCounter(\n ctx: RunnerContext,\n _id: string,\n senderDomain: string | null,\n kind: TemplateKind | null,\n counter: CounterKey,\n by: number,\n windowMs: number,\n): Promise<void> {\n await ctx.collections.health.updateOne(\n { _id },\n {\n $inc: { [`counters.${counter}`]: by },\n $setOnInsert: {\n _id,\n senderDomain,\n kind,\n windowStartedAt: new Date(),\n windowDurationMs: windowMs,\n status: 'healthy',\n trippedAt: null,\n trippedReason: null,\n manuallyResumedAt: null,\n rates: { ...ZERO_RATES },\n } as Partial<HealthDoc>,\n $set: { updatedAt: new Date() },\n },\n { upsert: true },\n )\n}\n\n/**\n * Recompute rates from the rolling window for every bucket and trip individual\n * buckets when thresholds are exceeded. The aggregate doc is updated but never\n * tripped. Called from the tick.\n */\nexport async function evaluateHealth(ctx: RunnerContext): Promise<void> {\n const cb = ctx.config.circuitBreaker\n const windowMs = cb.windowMinutes * 60 * 1000\n\n const docs = await ctx.collections.health.find({}).toArray()\n if (docs.length === 0) return\n\n // Ensure the aggregate doc exists so the worker-heartbeat check has\n // something to look at as soon as any bucket exists.\n const hasAgg = docs.some((d) => d._id === HEALTH_AGG_ID)\n if (!hasAgg) {\n await upsertCounter(ctx, HEALTH_AGG_ID, null, null, 'sent', 0, windowMs)\n }\n\n for (const doc of docs) {\n const isAgg = doc._id === HEALTH_AGG_ID\n const windowAge = Date.now() - new Date(doc.windowStartedAt).getTime()\n\n if (windowAge > windowMs && doc.status !== 'tripped') {\n // Window roll: zero out counters AND reset status to healthy. A bucket\n // that was 'degraded' on the prior window but receives no samples in\n // the new window should not stay degraded — degraded is a function of\n // the current window's failureRate, not a sticky state.\n await ctx.collections.health.updateOne(\n { _id: doc._id },\n {\n $set: {\n windowStartedAt: new Date(),\n windowDurationMs: windowMs,\n counters: { ...ZERO_COUNTERS },\n rates: { ...ZERO_RATES },\n status: 'healthy',\n updatedAt: new Date(),\n },\n },\n )\n continue\n }\n\n const c = doc.counters\n const total = c.sent || 1\n const rates = {\n bounceRate: c.bounced / total,\n hardBounceRate: c.hardBounced / total,\n complaintRate: c.complained / total,\n failureRate: c.failedToSend / total,\n }\n\n await ctx.collections.health.updateOne(\n { _id: doc._id },\n { $set: { rates, updatedAt: new Date() } },\n )\n\n // Aggregate never trips, only reports.\n if (isAgg) continue\n\n if (c.sent < cb.minSendsBeforeEval) continue\n if (doc.status === 'tripped') continue\n\n let trippedReason: string | null = null\n if (rates.hardBounceRate * 100 >= cb.hardBounceRatePctTrip) {\n trippedReason = `hard bounce rate ${(rates.hardBounceRate * 100).toFixed(2)}% >= ${cb.hardBounceRatePctTrip}%`\n } else if (rates.complaintRate * 100 >= cb.complaintRatePctTrip) {\n trippedReason = `complaint rate ${(rates.complaintRate * 100).toFixed(2)}% >= ${cb.complaintRatePctTrip}%`\n } else if (rates.bounceRate * 100 >= cb.combinedBounceRatePctTrip) {\n trippedReason = `combined bounce rate ${(rates.bounceRate * 100).toFixed(2)}% >= ${cb.combinedBounceRatePctTrip}%`\n }\n\n if (trippedReason) {\n // Gate the trip write on the current non-tripped status so two\n // concurrent ticks can't both transition the same bucket. The\n // matchedCount check below tells us whether *this* tick was the one\n // that flipped it — only then do we fire the alert + audit log.\n const result = await ctx.collections.health.updateOne(\n { _id: doc._id, status: { $in: ['healthy', 'degraded'] } },\n { $set: { status: 'tripped', trippedAt: new Date(), trippedReason, updatedAt: new Date() } },\n )\n if (result.modifiedCount > 0) {\n // Audit log so the admin UI's \"Recent trips\" panel has rows to render.\n if (ctx.audit) {\n try {\n await ctx.audit({\n actor: 'system:circuit-breaker',\n action: 'health.trip',\n resource: {\n collection: 'mailer_health',\n id: String(doc._id),\n slug: `${doc.senderDomain ?? '_unknown'}|${doc.kind}`,\n },\n diffSummary: trippedReason,\n })\n } catch {\n /* swallow — audit failure must not block runner */\n }\n }\n if (ctx.config.onCircuitBreakerTrip) {\n try {\n await ctx.config.onCircuitBreakerTrip({\n reason: `[${doc.senderDomain ?? '_unknown'} / ${doc.kind}] ${trippedReason}`,\n rates,\n })\n } catch {\n /* swallow — alert hook failures don't propagate */\n }\n }\n }\n continue\n }\n\n if (rates.failureRate * 100 >= cb.failedToSendRatePctDegrade) {\n if (doc.status !== 'degraded') {\n await ctx.collections.health.updateOne(\n { _id: doc._id },\n { $set: { status: 'degraded', updatedAt: new Date() } },\n )\n }\n } else if (doc.status === 'degraded') {\n await ctx.collections.health.updateOne(\n { _id: doc._id },\n { $set: { status: 'healthy', updatedAt: new Date() } },\n )\n }\n }\n}\n\n/**\n * Look up the bucket status that gates a marketing send. Returns the\n * bucket doc when found, otherwise null (which the caller treats as healthy\n * — sends from a never-seen-before bucket flow through).\n */\nexport async function getBucketStatus(\n ctx: RunnerContext,\n fromEmail: string | null,\n kind: TemplateKind,\n): Promise<HealthDoc | null> {\n const domain = fromEmail ? extractDomain(fromEmail) : null\n const id = healthBucketId(domain, kind)\n return ctx.collections.health.findOne({ _id: id })\n}\n\n/**\n * Derive an effective overall status across all buckets. The aggregate doc\n * itself never trips, so callers that want a single \"is anything wrong\"\n * answer use this. Returns null when no buckets exist yet (no tick has run).\n */\nexport function effectiveOverallStatus(docs: HealthDoc[]): HealthDoc['status'] | null {\n // Only canonical bucket docs (id prefix 'd:') participate. The aggregate\n // never trips and a legacy 'singleton' doc, if it survives the migration,\n // is ignored.\n const buckets = docs.filter((d) => typeof d._id === 'string' && d._id.startsWith('d:'))\n if (buckets.length === 0) {\n return docs.length === 0 ? null : 'healthy'\n }\n if (buckets.some((d) => d.status === 'tripped')) return 'tripped'\n if (buckets.some((d) => d.status === 'degraded')) return 'degraded'\n return 'healthy'\n}\n","/**\n * Apply a normalized provider event to the corresponding Send + cascading\n * suppression / subscription updates. Called from the webhook worker.\n */\n\nimport type { NormalizedEvent } from '../../shared/types.js'\nimport type { SendDoc } from '../models/index.js'\nimport type { RunnerContext } from './index.js'\nimport { sha256Hex } from '../tokens.js'\nimport { recordHealthCounter, type HealthDims } from './health.js'\n\nfunction dimsFromSend(send: SendDoc | null | undefined): HealthDims | null {\n if (!send) return null\n return { fromEmail: send.fromEmail, kind: send.kind }\n}\n\n/**\n * Apply unprocessed rows from mailer_webhook_events. Called by the webhook\n * worker (no age filter) and by the tick as a fallback (`olderThanMs` set) for\n * events whose enqueue failed at ingest — those would otherwise sit unprocessed\n * until the next webhook happened to arrive. The tick's age filter keeps it out\n * of the webhook worker's way in the normal path.\n */\nexport async function processWebhookBacklog(\n ctx: RunnerContext,\n opts: { olderThanMs?: number } = {},\n): Promise<void> {\n const filter: Record<string, unknown> = { processed: false }\n if (opts.olderThanMs) {\n filter.receivedAt = { $lt: new Date(Date.now() - opts.olderThanMs) }\n }\n const batch = await ctx.collections.webhookEvents.find(filter).limit(500).toArray()\n\n for (const evt of batch) {\n // At-most-once: claim the event BEFORE applying. Concurrent workers scan\n // the same unprocessed batch; without the claim each would apply the same\n // event, double-counting bounces/complaints into the circuit-breaker\n // health counters. Losing an event to a crash mid-apply is the cheaper\n // failure mode.\n const claimed = await ctx.collections.webhookEvents.findOneAndUpdate(\n { _id: evt._id, processed: false },\n { $set: { processed: true } },\n )\n if (!claimed) continue\n\n try {\n // The stored `raw` wraps the normalized event we captured at ingest;\n // pull details back out so applyWebhookEvent has the bounce reason etc.\n const normalized = (evt.raw as any)?.normalized\n const details = normalized?.details ?? {}\n await applyWebhookEvent(\n {\n type: evt.normalizedType,\n providerEventId: evt.providerEventId,\n providerMessageId: evt.providerMessageId,\n email: evt.email,\n occurredAt: evt.occurredAt,\n details,\n },\n ctx,\n )\n } catch (err) {\n console.error('mailery: webhook apply failed', { id: String(evt._id), err })\n }\n }\n}\n\nexport async function applyWebhookEvent(event: NormalizedEvent, ctx: RunnerContext): Promise<void> {\n const send = await ctx.collections.sends.findOne(\n event.providerMessageId\n ? { $or: [{ providerMessageId: event.providerMessageId }, { emailAtSend: event.email }] }\n : { emailAtSend: event.email },\n { sort: { queuedAt: -1 } },\n )\n\n switch (event.type) {\n case 'delivered':\n if (send) {\n await ctx.collections.sends.updateOne(\n { _id: send._id },\n { $set: { status: 'delivered', deliveredAt: event.occurredAt } },\n )\n }\n await recordHealthCounter(ctx, 'delivered', dimsFromSend(send))\n break\n\n case 'open':\n if (send) {\n await ctx.collections.sends.updateOne(\n { _id: send._id },\n {\n $set: {\n openedAt: send.openedAt ?? event.occurredAt,\n status: send.status === 'sent' ? 'delivered' : send.status,\n },\n $inc: { openCount: 1 },\n },\n )\n }\n break\n\n case 'click':\n if (send) {\n await ctx.collections.sends.updateOne(\n { _id: send._id },\n {\n $set: { firstClickAt: send.firstClickAt ?? event.occurredAt },\n $inc: { clickCount: 1 },\n $push: {\n clickedLinks: {\n url: event.details.clickedUrl ?? '',\n linkId: '',\n clickedAt: event.occurredAt,\n },\n },\n },\n )\n }\n break\n\n case 'bounce': {\n const bounceType = event.details.bounceType ?? 'hard'\n if (send) {\n await ctx.collections.sends.updateOne(\n { _id: send._id },\n {\n $set: {\n status: 'bounced',\n bounceType,\n bounceReason: event.details.bounceReason ?? null,\n },\n },\n )\n }\n if (bounceType === 'hard') {\n await suppressOnce(ctx, event.email, 'hard_bounce', 'all')\n await ctx.collections.subscriptions.updateOne(\n { emailAtSubscribe: event.email },\n { $set: { status: 'bounced', updatedAt: new Date() } },\n )\n }\n {\n const dims = dimsFromSend(send)\n await recordHealthCounter(ctx, 'bounced', dims)\n await recordHealthCounter(ctx, bounceType === 'hard' ? 'hardBounced' : 'softBounced', dims)\n }\n break\n }\n\n case 'complaint':\n case 'spam_report':\n if (send) {\n await ctx.collections.sends.updateOne(\n { _id: send._id },\n { $set: { complainedAt: event.occurredAt, status: 'complained' } },\n )\n }\n await suppressOnce(ctx, event.email, 'complaint', 'all')\n await ctx.collections.subscriptions.updateOne(\n { emailAtSubscribe: event.email },\n { $set: { status: 'complained', updatedAt: new Date() } },\n )\n await recordHealthCounter(ctx, 'complained', dimsFromSend(send))\n break\n\n case 'unsubscribe':\n if (send) {\n await ctx.collections.sends.updateOne({ _id: send._id }, { $set: { unsubscribedAt: event.occurredAt } })\n }\n await suppressOnce(ctx, event.email, 'unsubscribed', 'marketing')\n await ctx.collections.subscriptions.updateOne(\n { emailAtSubscribe: event.email },\n {\n $set: {\n status: 'unsubscribed',\n unsubscribedAt: event.occurredAt,\n unsubscribeReason: 'user_request',\n updatedAt: new Date(),\n },\n },\n )\n break\n }\n}\n\nasync function suppressOnce(\n ctx: RunnerContext,\n email: string,\n reason: 'hard_bounce' | 'complaint' | 'unsubscribed',\n scope: 'all' | 'marketing' | 'transactional',\n): Promise<void> {\n const normalized = email.toLowerCase()\n await ctx.collections.suppressions.updateOne(\n { email: normalized, scope },\n {\n $setOnInsert: {\n email: normalized,\n emailHash: sha256Hex(normalized),\n scope,\n reason,\n source: 'provider_webhook',\n notes: null,\n addedAt: new Date(),\n expiresAt: null,\n },\n },\n { upsert: true },\n )\n}\n","/**\n * Predicate evaluator. Resolves all Predicate variants from `shared/types.ts`\n * against a Contact (host-side fields/tags) + mailer state (events, sends,\n * subscription).\n *\n * Network calls hit Mongo. Cache the Contact at the call site if you evaluate\n * many predicates in a row.\n */\n\nimport type { Contact, Predicate } from '../../shared/types.js'\nimport type { BotFilterConfig } from '../config.js'\nimport type { Collections, FlowRunDoc, SendDoc } from '../models/index.js'\n\nexport interface PredicateContext {\n contact: Contact\n run: FlowRunDoc\n collections: Collections\n now?: Date\n /**\n * Tuning for the `…ExcludingBots` / `…AtLeastN` predicates. Omit for the\n * defaults (`DEFAULT_BOT_UA_RE`, no timing filter).\n */\n botFilter?: BotFilterConfig\n}\n\n/**\n * User agents treated as automated unless the host overrides\n * `botFilter.userAgentPattern`. Deliberately short: these are the scanners that\n * announce themselves. Anything that impersonates a browser is not catchable\n * from the UA string and is out of scope here — see INVARIANT 7.\n */\nexport const DEFAULT_BOT_UA_RE = /Mimecast|SafeLinks|proofpoint|HeadlessChrome|Googlebot|bingbot/i\n\nexport async function evaluatePredicate(\n predicate: Predicate,\n ctx: PredicateContext,\n): Promise<boolean> {\n const p = predicate as any\n\n if ('hasTag' in p) return ctx.contact.tags.includes(p.hasTag)\n if ('notHasTag' in p) return !ctx.contact.tags.includes(p.notHasTag)\n\n if ('fieldEquals' in p) {\n return ctx.contact.fields[p.fieldEquals.field] === p.fieldEquals.value\n }\n if ('fieldExists' in p) {\n return ctx.contact.fields[p.fieldExists] !== undefined\n }\n\n // Read from the run's own trigger event, NOT the contact — two concurrent\n // runs for the same person can legitimately disagree here.\n if ('triggerPropertyEquals' in p) {\n return (\n (ctx.run.triggerEvent?.properties ?? {})[p.triggerPropertyEquals.key] ===\n p.triggerPropertyEquals.value\n )\n }\n if ('triggerPropertyTruthy' in p) {\n return Boolean((ctx.run.triggerEvent?.properties ?? {})[p.triggerPropertyTruthy])\n }\n\n if ('subscriptionStatus' in p) {\n const sub = await ctx.collections.subscriptions.findOne({ externalId: ctx.contact.externalId })\n return sub?.status === p.subscriptionStatus\n }\n\n if ('hasFiredEvent' in p) {\n return hasEvent(ctx, p.hasFiredEvent, { sinceFlowStart: p.sinceFlowStart, withinDays: p.withinDays })\n }\n if ('notHasFiredEvent' in p) {\n return !(await hasEvent(ctx, p.notHasFiredEvent, { withinDays: p.withinDays }))\n }\n\n if ('hasOpened' in p) return await openOrClickCount(ctx, 'opened', p.hasOpened, false) > 0\n if ('hasClicked' in p) return await openOrClickCount(ctx, 'clicked', p.hasClicked, false) > 0\n if ('hasOpenedExcludingBots' in p) return await openOrClickCount(ctx, 'opened', p.hasOpenedExcludingBots, true) > 0\n if ('hasClickedExcludingBots' in p) return await openOrClickCount(ctx, 'clicked', p.hasClickedExcludingBots, true) > 0\n if ('openedAtLeastN' in p) return await openOrClickCount(ctx, 'opened', p.openedAtLeastN, true) >= p.openedAtLeastN.count\n if ('clickedAtLeastN' in p) return await openOrClickCount(ctx, 'clicked', p.clickedAtLeastN, true) >= p.clickedAtLeastN.count\n\n if ('all' in p) {\n for (const sub of p.all) {\n if (!(await evaluatePredicate(sub, ctx))) return false\n }\n return true\n }\n if ('any' in p) {\n for (const sub of p.any) {\n if (await evaluatePredicate(sub, ctx)) return true\n }\n return false\n }\n if ('not' in p) {\n return !(await evaluatePredicate(p.not, ctx))\n }\n\n return false\n}\n\nasync function hasEvent(\n ctx: PredicateContext,\n name: string,\n opts: { sinceFlowStart?: boolean; withinDays?: number },\n): Promise<boolean> {\n const filter: any = { externalId: ctx.contact.externalId, name }\n const lower = effectiveLowerBound(ctx, opts)\n if (lower) filter.occurredAt = { $gt: lower }\n const found = await ctx.collections.events.findOne(filter, { projection: { _id: 1 } })\n return !!found\n}\n\nasync function openOrClickCount(\n ctx: PredicateContext,\n kind: 'opened' | 'clicked',\n opts: { templateSlug?: string; sinceFlowStart?: boolean; withinDays?: number },\n excludeBots: boolean,\n): Promise<number> {\n const filter: any = { externalId: ctx.contact.externalId }\n if (opts.templateSlug) filter.templateSlug = opts.templateSlug\n if (kind === 'opened') filter.openedAt = { $ne: null }\n if (kind === 'clicked') filter.firstClickAt = { $ne: null }\n const lower = effectiveLowerBound(ctx, opts)\n if (lower) filter[kind === 'opened' ? 'openedAt' : 'firstClickAt'] = { $gt: lower }\n\n if (!excludeBots) {\n return await ctx.collections.sends.countDocuments(filter)\n }\n\n // Bot filtering is best-effort by construction — see INVARIANT 7. A send\n // counts when at least one of its recorded opens (or clicks) looks human;\n // one scanner hit does not disqualify a send the recipient also read.\n const docs = await ctx.collections.sends.find(filter).limit(1000).toArray()\n const botRe = ctx.botFilter?.userAgentPattern ?? DEFAULT_BOT_UA_RE\n const minOpenDelayMs = ctx.botFilter?.minOpenDelayMs ?? 0\n let n = 0\n for (const s of docs) {\n const doc = s as SendDoc\n const human =\n kind === 'opened'\n ? hasHumanOpen(doc, botRe, minOpenDelayMs)\n : (doc.clickedLinks ?? []).some((c) => !isBotUserAgent(c.userAgent, botRe))\n if (human) n++\n }\n return n\n}\n\n/**\n * A user agent is \"bot\" only when it is present *and* matches the pattern.\n *\n * Unknown counts as human. That is the deliberate choice, and it is the same\n * one the click path has always made:\n *\n * - Image fetches frequently carry no `User-Agent` at all, and Apple Mail\n * Privacy Protection proxies strip identifying headers. Scoring unknown as\n * bot would drop a large share of genuine opens on the floor, silently.\n * - It preserves today's counts for sends recorded before user agents were\n * stored, so enabling this fix cannot retroactively empty a running flow.\n *\n * The cost is that a scanner which sends no UA still counts. Treating unknown\n * as bot would be the safer posture against forgery, but forgery is what the\n * URL signature is for; this filter's job is only to be honest about scanners\n * that identify themselves.\n */\nfunction isBotUserAgent(ua: string | null | undefined, botRe: RegExp): boolean {\n if (typeof ua !== 'string' || ua.trim() === '') return false\n return botRe.test(ua)\n}\n\n/**\n * Does this send have at least one open that looks like a person?\n *\n * Sends recorded before `opens[]` existed fall back to the single `openedAt`\n * timestamp with an unknown user agent — which, per the rule above, counts as\n * human. Legacy data therefore behaves exactly as it does today.\n */\nfunction hasHumanOpen(send: SendDoc, botRe: RegExp, minOpenDelayMs: number): boolean {\n const opens =\n send.opens && send.opens.length > 0\n ? send.opens\n : send.openedAt\n ? [{ openedAt: send.openedAt, userAgent: null }]\n : []\n return opens.some((o) => {\n if (isBotUserAgent(o.userAgent, botRe)) return false\n if (isPrefetchOpen(o.openedAt, send.queuedAt, minOpenDelayMs)) return false\n return true\n })\n}\n\n/**\n * Optional second signal (`botFilter.minOpenDelayMs`, default 0 = off): an open\n * that lands within a few seconds of the send being queued is a gateway\n * prefetch or a security scanner, not a reader.\n *\n * Off by default — a recipient who happens to be looking at their inbox when\n * the mail arrives is a real false positive, and turning it on silently changes\n * the numbers every existing flow branches on.\n */\nfunction isPrefetchOpen(openedAt: unknown, queuedAt: unknown, minOpenDelayMs: number): boolean {\n if (!minOpenDelayMs || minOpenDelayMs <= 0) return false\n if (!(openedAt instanceof Date) || !(queuedAt instanceof Date)) return false\n const delta = openedAt.getTime() - queuedAt.getTime()\n if (!Number.isFinite(delta) || delta < 0) return false\n return delta < minOpenDelayMs\n}\n\nfunction effectiveLowerBound(ctx: PredicateContext, opts: { sinceFlowStart?: boolean; withinDays?: number }): Date | null {\n const now = ctx.now ?? new Date()\n if (opts.sinceFlowStart) return ctx.run.enteredAt\n if (opts.withinDays && opts.withinDays > 0) {\n return new Date(now.getTime() - opts.withinDays * 24 * 60 * 60 * 1000)\n }\n return null\n}\n","/**\n * Delivery-window math. Pure — no I/O, no Date.now(); callers pass `now`.\n *\n * Given the moment a send step becomes runnable, `computeDeliveryTime`\n * returns the earliest instant the email is allowed to go out. It only ever\n * moves forward: a send already inside its window returns `now` unchanged.\n *\n * Timezone handling uses the Intl API (no dependency). DST transitions are\n * resolved with a two-pass offset fix; the worst case during a transition is\n * being off by the shifted hour, which is fine for email delivery.\n */\n\nimport type { DeliveryWindow } from '../../shared/types.js'\n\n/**\n * Ticks fire with jitter, so a send arriving shortly AFTER its timeOfDay slot\n * still goes out rather than waiting a full day.\n */\nconst TIME_OF_DAY_GRACE_MS = 60 * 60_000\n\nexport function computeDeliveryTime(\n now: Date,\n window: DeliveryWindow,\n contactTimezone?: string,\n): Date {\n const tz = pickTimezone(window, contactTimezone)\n let candidate = now\n\n if (window.timeOfDay) {\n const [hh, mm] = window.timeOfDay.split(':').map(Number) as [number, number]\n const local = localParts(candidate, tz)\n const todaySlot = utcFromLocal(local.y, local.mo, local.d, hh, mm, tz)\n if (candidate.getTime() < todaySlot.getTime()) {\n candidate = todaySlot\n } else if (candidate.getTime() - todaySlot.getTime() > TIME_OF_DAY_GRACE_MS) {\n const next = addLocalDays(local, 1)\n candidate = utcFromLocal(next.y, next.mo, next.d, hh, mm, tz)\n }\n // else: within grace of today's slot — send now.\n }\n\n if (window.weekdaysOnly) {\n for (let guard = 0; guard < 3; guard++) {\n const local = localParts(candidate, tz)\n if (local.weekday !== 'Sat' && local.weekday !== 'Sun') break\n const shift = local.weekday === 'Sat' ? 2 : 1\n const moved = addLocalDays(local, shift)\n // Preserve the local clock time (timeOfDay slot, or the wall-clock\n // moment the step became runnable).\n candidate = utcFromLocal(moved.y, moved.mo, moved.d, local.hh, local.mi, tz)\n }\n }\n\n return candidate\n}\n\nfunction pickTimezone(window: DeliveryWindow, contactTimezone?: string): string {\n const candidates = [\n window.useContactTimezone ? contactTimezone : undefined,\n window.timezone,\n 'UTC',\n ]\n for (const tz of candidates) {\n if (tz && isValidTimezone(tz)) return tz\n }\n return 'UTC'\n}\n\nconst validatedZones = new Map<string, boolean>()\n\nfunction isValidTimezone(tz: string): boolean {\n const cached = validatedZones.get(tz)\n if (cached !== undefined) return cached\n let ok = true\n try {\n new Intl.DateTimeFormat('en-US', { timeZone: tz })\n } catch {\n ok = false\n }\n validatedZones.set(tz, ok)\n return ok\n}\n\ninterface LocalParts {\n y: number\n mo: number\n d: number\n hh: number\n mi: number\n ss: number\n weekday: string // 'Mon'…'Sun'\n}\n\nconst partFormatters = new Map<string, Intl.DateTimeFormat>()\n\nfunction formatterFor(tz: string): Intl.DateTimeFormat {\n let f = partFormatters.get(tz)\n if (!f) {\n f = new Intl.DateTimeFormat('en-US', {\n timeZone: tz,\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n weekday: 'short',\n hour12: false,\n })\n partFormatters.set(tz, f)\n }\n return f\n}\n\nfunction localParts(date: Date, tz: string): LocalParts {\n const parts: Record<string, string> = {}\n for (const p of formatterFor(tz).formatToParts(date)) parts[p.type] = p.value\n return {\n y: Number(parts.year),\n mo: Number(parts.month),\n d: Number(parts.day),\n hh: Number(parts.hour) % 24, // Intl emits '24' for midnight in some locales\n mi: Number(parts.minute),\n ss: Number(parts.second),\n weekday: parts.weekday!,\n }\n}\n\n/** UTC instant for a wall-clock time in `tz`. Two passes to converge across DST. */\nfunction utcFromLocal(y: number, mo: number, d: number, hh: number, mi: number, tz: string): Date {\n let ts = Date.UTC(y, mo - 1, d, hh, mi, 0)\n for (let i = 0; i < 2; i++) {\n const p = localParts(new Date(ts), tz)\n const asUtc = Date.UTC(p.y, p.mo - 1, p.d, p.hh, p.mi, p.ss)\n const offset = asUtc - ts\n ts = Date.UTC(y, mo - 1, d, hh, mi, 0) - offset\n }\n return new Date(ts)\n}\n\n/** Add days to a local calendar date (normalizes month/year rollover). */\nfunction addLocalDays(p: LocalParts, days: number): { y: number; mo: number; d: number } {\n const dt = new Date(Date.UTC(p.y, p.mo - 1, p.d + days))\n return { y: dt.getUTCFullYear(), mo: dt.getUTCMonth() + 1, d: dt.getUTCDate() }\n}\n","/**\n * Template render pipeline.\n *\n * authorMjml + handlebarsContext\n * ↓ Handlebars render → MJML with substituted vars\n * ↓ mjml-core compile → HTML\n * ↓ html-to-text derive → plain text alternative\n * ↓ applyTracking(sendId) → tracked HTML with rewritten links + open pixel\n *\n * Subject and preheader run through Handlebars too. Plain text is auto-derived\n * unless the template explicitly overrides it.\n */\n\nimport crypto from 'node:crypto'\nimport Handlebars from 'handlebars'\nimport { convert as htmlToText } from 'html-to-text'\nimport mjml2html from 'mjml'\n\nimport type { Contact } from '../../shared/types.js'\nimport type { TemplateDoc } from '../models/index.js'\nimport { signTrackingToken } from '../tokens.js'\n\n// ---------------------------------------------------------------------------\n// Compile (publish-time)\n// ---------------------------------------------------------------------------\n\nexport interface CompileResult {\n html: string\n plainText: string\n errors: Array<{ line?: number; message: string; tagName?: string; formattedMessage?: string }>\n}\n\n/** Compile MJML → HTML, then derive plain text. Called at template publish time. */\nexport async function compileTemplate(mjml: string): Promise<CompileResult> {\n const out = await mjml2html(mjml, { validationLevel: 'soft', minify: false })\n const plainText = derivePlaintext(out.html)\n return { html: out.html, plainText, errors: out.errors ?? [] }\n}\n\n/**\n * Compile Maily editor JSON (Tiptap-shape) → HTML via `@maily-to/render`, then\n * derive plain text. Called at template publish time when the template was\n * authored via the WYSIWYG editor.\n */\nexport async function compileMailyTemplate(content: unknown): Promise<CompileResult> {\n const { render } = await import('@maily-to/render')\n const html = await render(content as any)\n const plainText = derivePlaintext(html)\n return { html, plainText, errors: [] }\n}\n\n/** Auto-derive plain text from compiled HTML. */\nexport function derivePlaintext(html: string): string {\n return htmlToText(html, {\n wordwrap: 80,\n selectors: [\n { selector: 'img', format: 'skip' },\n { selector: 'a', options: { hideLinkHrefIfSameAsText: true } },\n ],\n }).trim()\n}\n\n// ---------------------------------------------------------------------------\n// Render (send-time)\n// ---------------------------------------------------------------------------\n\nexport interface RenderContext {\n /**\n * Host-resolved variables (varsAdapter) live at the context root, so a\n * schema key `user` renders as `{{user.name}}`. Reserved keys below always\n * win over resolved keys.\n */\n [resolvedVar: string]: unknown\n contact: Contact\n vars: Record<string, unknown>\n /** Properties of the event that triggered the flow run ({{event.*}}). Empty outside flow sends. */\n event?: Record<string, unknown>\n /** URL the recipient hits to one-click unsubscribe. */\n unsubscribeUrl: string\n /** URL to view this email in a browser (when implemented). */\n viewInBrowserUrl?: string\n /** URL for the preference center (when implemented). */\n preferenceCenterUrl?: string\n /** Configured sender postal address (CAN-SPAM). */\n senderAddress?: string\n}\n\nexport interface RenderedTemplate {\n subject: string\n preheader: string\n html: string\n plainText: string\n fromName: string\n fromEmail: string\n replyTo: string | null\n}\n\nexport interface RenderOptions {\n /** Extra Handlebars helpers contributed by the host. */\n helpers?: Record<string, Handlebars.HelperDelegate>\n}\n\n/**\n * Compile options for the text/plain alternative, which is not HTML and has\n * nothing downstream to decode entities. Handlebars' default escaping is\n * corruption there rather than safety: a substituted URL ships as\n * `https://host/p?u&#x3D;123&amp;token&#x3D;abc`, which mail clients render\n * literally, so the recipient follows a link whose query string has fallen\n * apart — every param after the first silently lost. `{{ }}` still\n * interpolates; it just stops escaping what it substitutes.\n */\nconst PLAIN_TEXT: CompileOptions = { noEscape: true }\n\n/**\n * Render a published template against a contact + vars context. Returns the\n * substituted subject/preheader/html/plainText. Tracking is NOT applied here —\n * that step needs the send id and runs separately via `applyTracking`.\n */\nexport async function renderTemplate(\n template: TemplateDoc,\n ctx: RenderContext,\n opts: RenderOptions = {},\n): Promise<RenderedTemplate> {\n const hb = makeHandlebars(opts.helpers)\n\n // Both stay escaped: the preheader is injected into the HTML body, and the\n // subject reaches HTML surfaces (admin lists, previews) that render it.\n const subject = hb.compile(template.subject)(ctx)\n const preheader = hb.compile(template.preheader)(ctx)\n\n // Prefer the compiled HTML if present; fall back to compiling MJML on the fly.\n let html: string\n if (template.body.html) {\n html = hb.compile(template.body.html)(ctx)\n } else {\n const compiled = await compileTemplate(template.body.mjml)\n html = hb.compile(compiled.html)(ctx)\n }\n\n const plainText = template.body.plainText\n ? hb.compile(template.body.plainText, PLAIN_TEXT)(ctx)\n : derivePlaintext(html)\n\n return {\n subject,\n preheader,\n html,\n plainText,\n fromName: template.fromName,\n fromEmail: template.fromEmail,\n replyTo: template.replyTo,\n }\n}\n\n// ---------------------------------------------------------------------------\n// Tracking application\n// ---------------------------------------------------------------------------\n\nexport interface TrackingOptions {\n sendId: string\n publicUrl: string\n trackOpens: boolean\n trackClicks: boolean\n /** URL that must NOT be rewritten (e.g. the resolved unsubscribe URL). */\n preserveUrls?: string[]\n /**\n * HMAC key for tracking-URL signatures — pass `config.unsubscribeSecret`.\n *\n * When set, every generated `/m/open` and `/m/click` URL carries a truncated\n * HMAC so it cannot be forged or enumerated from a neighbouring ObjectId.\n * When omitted the legacy unsigned shape is emitted; that path exists for\n * preview/test renders that never reach the tracking endpoints, not as a\n * supported production mode.\n */\n signingSecret?: string\n}\n\nexport interface TrackingResult {\n html: string\n /** linkId → original URL map; persist on `mailer_sends.links` for click resolution. */\n links: Array<{ linkId: string; url: string }>\n}\n\n/**\n * Rewrite `<a href>` in `html` to /m/click/<sendId>/<linkId>/<sig> and append\n * an open pixel at /m/open/<sendId>.<sig>.png. Returns the modified HTML plus\n * the link map to persist on the send document.\n *\n * The `<sig>` components are 12-character truncated HMACs (see\n * `signTrackingToken`) and are present whenever `opts.signingSecret` is set.\n * Without them a Mongo ObjectId is the only thing standing between an attacker\n * and a forged open — and ObjectIds are a timestamp plus a per-process counter,\n * so one received email hands out its neighbours.\n */\nexport function applyTracking(html: string, opts: TrackingOptions): TrackingResult {\n const preserve = new Set((opts.preserveUrls ?? []).map((u) => u.trim()))\n const links: Array<{ linkId: string; url: string }> = []\n const seen = new Map<string, string>() // url → linkId\n\n let out = html\n\n if (opts.trackClicks) {\n out = out.replace(/<a\\b([^>]*?)\\bhref=([\"'])([^\"']+)\\2([^>]*)>/gi, (full, pre, _q, rawUrl, post) => {\n // Handlebars `{{ }}` escapes substituted URLs (& → &amp;, = → &#x3D;). That is\n // correct in HTML source, but the stored/redirect URL must be the decoded one.\n const url = decodeHtmlEntities(rawUrl)\n if (shouldSkipClickRewrite(url, preserve, full)) return full\n let linkId = seen.get(url)\n if (!linkId) {\n linkId = shortHash(`${opts.sendId}:${url}:${links.length}`)\n seen.set(url, linkId)\n links.push({ linkId, url })\n }\n const sig = opts.signingSecret\n ? `/${signTrackingToken('click', { sendId: opts.sendId, linkId }, opts.signingSecret)}`\n : ''\n const newHref = `${opts.publicUrl}/m/click/${opts.sendId}/${linkId}${sig}`\n return `<a${pre}href=\"${newHref}\"${post}>`\n })\n }\n\n if (opts.trackOpens) {\n const sig = opts.signingSecret\n ? `.${signTrackingToken('open', { sendId: opts.sendId }, opts.signingSecret)}`\n : ''\n const pixel = `<img src=\"${opts.publicUrl}/m/open/${opts.sendId}${sig}.png\" width=\"1\" height=\"1\" alt=\"\" style=\"display:block;border:0\" />`\n if (/<\\/body>/i.test(out)) {\n out = out.replace(/<\\/body>/i, `${pixel}</body>`)\n } else {\n out = out + pixel\n }\n }\n\n return { html: out, links }\n}\n\nfunction shouldSkipClickRewrite(url: string, preserve: Set<string>, fullTag: string): boolean {\n if (!url) return true\n if (url.startsWith('#')) return true\n if (url.startsWith('{{') || url.startsWith('{')) return true // unrendered handlebars\n if (preserve.has(url.trim())) return true\n if (/data-mailer-notrack=[\"']true[\"']/.test(fullTag)) return true\n // Defence in depth for the click redirect (which validates the scheme again\n // at redirect time): an href whose scheme isn't http(s) is left exactly as\n // authored, gets no linkId, and is therefore never stored on the send and\n // never becomes a `/m/click/…` URL. Covers `mailto:` and `tel:` — which were\n // already skipped by name — and everything else, including a `javascript:`\n // that arrived via a substituted Handlebars variable.\n //\n // A malformed href is skipped, never thrown on: one bad variable in one link\n // must not fail the render and block the whole send.\n if (!isHttpUrl(url)) return true\n return false\n}\n\n/** True only for an absolute `http:`/`https:` URL. Anything unparseable is false. */\nfunction isHttpUrl(url: string): boolean {\n let parsed: URL\n try {\n parsed = new URL(url.trim())\n } catch {\n return false\n }\n return parsed.protocol === 'http:' || parsed.protocol === 'https:'\n}\n\nconst NAMED_ENTITIES: Record<string, string> = {\n amp: '&',\n lt: '<',\n gt: '>',\n quot: '\"',\n apos: \"'\",\n nbsp: ' ',\n}\n\n/**\n * Decode the HTML entities Handlebars' escapeExpression emits (plus numeric\n * forms), so a captured href round-trips to the URL the browser would request.\n * `&amp;` is decoded last-wins via a single pass so `&amp;lt;` stays `&lt;`.\n */\nfunction decodeHtmlEntities(input: string): string {\n return input.replace(/&(#x[0-9a-f]+|#\\d+|[a-z][a-z0-9]*);/gi, (match, body: string) => {\n if (body[0] === '#') {\n const code =\n body[1] === 'x' || body[1] === 'X'\n ? parseInt(body.slice(2), 16)\n : parseInt(body.slice(1), 10)\n if (!Number.isFinite(code) || code < 0 || code > 0x10ffff) return match\n try {\n return String.fromCodePoint(code)\n } catch {\n return match\n }\n }\n const named = NAMED_ENTITIES[body.toLowerCase()]\n return named ?? match\n })\n}\n\nfunction shortHash(input: string): string {\n return crypto.createHash('sha256').update(input).digest('hex').slice(0, 12)\n}\n\n// ---------------------------------------------------------------------------\n// Handlebars instance + helpers\n// ---------------------------------------------------------------------------\n\nfunction makeHandlebars(extra?: Record<string, Handlebars.HelperDelegate>): typeof Handlebars {\n const hb = Handlebars.create()\n\n hb.registerHelper('eq', (a: unknown, b: unknown) => a === b)\n hb.registerHelper('ne', (a: unknown, b: unknown) => a !== b)\n hb.registerHelper('gt', (a: any, b: any) => a > b)\n hb.registerHelper('lt', (a: any, b: any) => a < b)\n hb.registerHelper('gte', (a: any, b: any) => a >= b)\n hb.registerHelper('lte', (a: any, b: any) => a <= b)\n hb.registerHelper('and', (...args: any[]) => args.slice(0, -1).every(Boolean))\n hb.registerHelper('or', (...args: any[]) => args.slice(0, -1).some(Boolean))\n hb.registerHelper('not', (a: unknown) => !a)\n\n hb.registerHelper('formatDate', (value: unknown, fmt?: string) => {\n if (!value) return ''\n const d = value instanceof Date ? value : new Date(String(value))\n if (Number.isNaN(d.getTime())) return ''\n if (fmt === 'long') return d.toLocaleDateString('en-US', { dateStyle: 'long' })\n if (fmt === 'short') return d.toLocaleDateString('en-US', { dateStyle: 'short' })\n return d.toISOString().slice(0, 10)\n })\n\n hb.registerHelper('formatNumber', (n: unknown) => {\n const v = Number(n)\n return Number.isFinite(v) ? v.toLocaleString('en-US') : ''\n })\n\n hb.registerHelper('formatCurrency', (cents: unknown, currency: string = 'usd') => {\n const v = Number(cents)\n if (!Number.isFinite(v)) return ''\n return new Intl.NumberFormat('en-US', { style: 'currency', currency }).format(v / 100)\n })\n\n hb.registerHelper('pluralize', (n: unknown, one: string, many: string) =>\n Number(n) === 1 ? one : many,\n )\n\n if (extra) {\n for (const [name, fn] of Object.entries(extra)) {\n hb.registerHelper(name, fn)\n }\n }\n\n return hb\n}\n\nexport { makeHandlebars }\n","/**\n * Send pipeline. `handleSend` is called by the runner state machine; it creates\n * the Send document and enqueues a mailer:send job. `dispatchSend` is the\n * worker — re-checks suppression + circuit breaker, applies tracking, calls\n * the provider, updates the Send row.\n */\n\nimport crypto from 'node:crypto'\nimport { ObjectId } from 'mongodb'\n\nimport type { Contact, FlowStep } from '../../shared/types.js'\nimport type { FlowRunDoc, FlowDoc, SendDoc, TemplateDoc } from '../models/index.js'\nimport {\n applyTracking,\n renderTemplate,\n type RenderContext,\n} from '../templates/render.js'\nimport { signUnsubscribeToken } from '../tokens.js'\nimport { registeredProviderNames, resolveProvider } from '../provider-lookup.js'\nimport { resolveVars } from '../adapters/vars.js'\nimport { isSuppressed } from './suppression.js'\nimport { advanceStep, failFlowRun } from './step.js'\nimport { getBucketStatus, recordHealthCounter } from './health.js'\nimport type { RunnerContext } from './index.js'\n\nexport async function handleSend(\n run: FlowRunDoc,\n step: Extract<FlowStep, { type: 'send' }>,\n contact: Contact,\n flow: FlowDoc,\n ctx: RunnerContext,\n): Promise<void> {\n const template = await ctx.collections.templates.findOne({ slug: step.templateSlug })\n if (!template) {\n await failFlowRun(run, `template not found: ${step.templateSlug}`, ctx)\n return\n }\n\n const dedupeKey = `flowrun:${run._id}:step${run.currentStepIndex}`\n\n // Idempotency: has this exact step already produced a send?\n const existing = await ctx.collections.sends.findOne({ dedupeKey })\n if (existing) {\n await advanceStep(run, ctx, {\n action: 'sent',\n details: { dedupeKey, alreadySent: true, sendId: String(existing._id) },\n })\n return\n }\n\n const providerName = pickProviderName(step.providerOverride, template, ctx)\n\n // Render now (with fresh contact + vars). Tracking application happens in\n // dispatchSend once we have the persisted sendId.\n const renderCtx = buildRenderContext(contact, run, step.vars ?? {}, ctx)\n let rendered\n try {\n rendered = await renderTemplate(template, renderCtx, { helpers: ctx.handlebarsHelpers })\n } catch (err: any) {\n await ctx.collections.sends.insertOne(\n newSendDoc({\n dedupeKey,\n run,\n contact,\n template,\n flow,\n providerName,\n renderedSubject: template.subject,\n bodyHash: '',\n status: 'failed',\n errorMessage: `render error: ${err?.message ?? err}`,\n }),\n )\n await advanceStep(run, ctx, {\n action: 'send_skipped',\n details: { reason: 'render_error', message: String(err?.message ?? err) },\n })\n return\n }\n\n const sendId = new ObjectId()\n await ctx.collections.sends.insertOne(\n newSendDoc({\n _id: sendId,\n dedupeKey,\n run,\n contact,\n template,\n flow,\n providerName,\n renderedSubject: rendered.subject,\n bodyHash: sha256(rendered.html),\n status: 'queued',\n renderedFrom: rendered.fromName ? { name: rendered.fromName, email: rendered.fromEmail } : undefined,\n vars: step.vars ?? {},\n }),\n )\n\n await ctx.queues.send.add(\n 'send',\n { sendId: String(sendId) },\n { attempts: ctx.config.sendRetryAttempts, backoff: { type: 'exponential', delay: 60_000 } },\n )\n\n await advanceStep(run, ctx, { action: 'sent', details: { dedupeKey, sendId: String(sendId) } })\n}\n\n// ---------------------------------------------------------------------------\n// Send worker entry point\n// ---------------------------------------------------------------------------\n\nexport async function dispatchSend(sendId: ObjectId, ctx: RunnerContext): Promise<void> {\n // Atomic claim: flip queued/failed → sending so exactly one worker proceeds.\n // The stranded-send sweep and the queue's stalled-job retry can both fire a\n // job for the same send; a read-then-act status check lets both through and\n // the recipient gets the email twice. Every downstream path writes a\n // terminal status (or resets to 'queued' for the breaker retry); a crash\n // leaves 'sending', which the stranded-send sweep resets after 5 minutes.\n const send = await ctx.collections.sends.findOneAndUpdate(\n { _id: sendId, status: { $in: ['queued', 'failed'] } },\n { $set: { status: 'sending', updatedAt: new Date() } },\n )\n if (!send) return // already claimed / dispatched / cancelled\n\n const template = await ctx.collections.templates.findOne({ _id: send.templateId })\n if (!template) {\n await markFailed(send._id!, 'template_missing', ctx)\n return\n }\n\n // 1. Suppression check (INVARIANT 3: always re-checked at send time).\n const supp = await isSuppressed(ctx.collections, send.emailAtSend, send.kind)\n if (supp.suppressed) {\n await ctx.collections.sends.updateOne(\n { _id: send._id },\n { $set: { status: 'suppressed', errorMessage: `suppressed: ${supp.reason}` } },\n )\n return\n }\n\n // 2. Circuit-breaker check (only blocks marketing). The breaker is scoped\n // per (senderDomain, kind) bucket — one bad subdomain doesn't hold mail for\n // the others.\n if (send.kind === 'marketing') {\n const bucket = await getBucketStatus(ctx, send.fromEmail, send.kind)\n if (bucket?.status === 'tripped') {\n // Release the claim so the delayed retry can re-claim it.\n await ctx.collections.sends.updateOne(\n { _id: send._id },\n { $set: { status: 'queued', updatedAt: new Date() } },\n )\n await ctx.queues.send.add('send', { sendId: String(send._id) }, { delay: 60_000 })\n return\n }\n }\n\n // 3. Pull the contact + re-render (use the contact that exists now, not at flow entry).\n const contact = await ctx.adapter.getById(send.externalId)\n if (!contact) {\n await markFailed(send._id!, 'contact_missing', ctx)\n return\n }\n\n const run = send.flowRunId ? await ctx.collections.flowRuns.findOne({ _id: send.flowRunId }) : null\n\n // Aborted-run guard: closes the race where a send is enqueued between the\n // abort's send-cancellation sweep and dispatch. Only host aborts block here —\n // completed/naturally-exited runs may still have legitimately queued mail.\n if (run && run.status === 'exited' && run.exitReason?.startsWith('aborted_by_host')) {\n await ctx.collections.sends.updateOne(\n { _id: send._id },\n { $set: { status: 'cancelled', errorMessage: `cancelled: ${run.exitReason}`, updatedAt: new Date() } },\n )\n return\n }\n\n // Resolve host vars + render. A throw here (host DB hiccup, bad template)\n // marks the send failed and rethrows so the queue retries with backoff —\n // never dispatch a half-rendered email.\n let renderCtx: RenderContext\n let rendered: Awaited<ReturnType<typeof renderTemplate>>\n try {\n const resolved = await resolveVars(ctx.varsAdapter, contact, {\n reason: 'send',\n templateSlug: template.slug,\n flowSlug: run?.flowSlug,\n eventName: run?.triggerEvent?.name,\n eventProperties: run?.triggerEvent?.properties,\n })\n renderCtx = buildRenderContext(contact, run, send.vars ?? {}, ctx, resolved)\n rendered = await renderTemplate(template, renderCtx, { helpers: ctx.handlebarsHelpers })\n } catch (err: any) {\n await markFailed(send._id!, `render error: ${String(err?.message ?? err)}`, ctx)\n throw err // let the queue retry per the attempts policy\n }\n\n // 4. Apply tracking using the now-known send id.\n //\n // text_only skips this entirely: the open pixel needs an HTML part to live\n // in, and click rewriting would replace readable URLs with opaque redirects\n // in text a recipient reads literally — the opposite of what the format is\n // for. Such a send reports no opens and no clicks by design.\n const textOnly = template.bodyFormat === 'text_only'\n const tracking = textOnly\n ? { html: '', links: [] as Array<{ linkId: string; url: string }> }\n : applyTracking(rendered.html, {\n sendId: String(send._id),\n publicUrl: ctx.config.publicUrl,\n trackOpens: template.trackOpens ?? ctx.config.trackOpens,\n trackClicks: template.trackClicks ?? ctx.config.trackClicks,\n preserveUrls: [renderCtx.unsubscribeUrl],\n signingSecret: ctx.config.unsubscribeSecret,\n })\n\n await ctx.collections.sends.updateOne(\n { _id: send._id },\n {\n $set: {\n links: tracking.links,\n // Hash what actually goes out, so a text_only send's fingerprint\n // tracks the text body rather than an HTML part it never had.\n bodyHash: sha256(textOnly ? rendered.plainText : tracking.html),\n status: 'sending',\n fromName: rendered.fromName,\n fromEmail: rendered.fromEmail,\n subject: rendered.subject,\n updatedAt: new Date(),\n },\n },\n )\n\n // 5. Provider dispatch.\n //\n // Guarded lookup (see provider-lookup.ts): a bare `ctx.providers[name]` also\n // resolves inherited Object.prototype keys, so a send row whose `provider` is\n // `constructor` or `toString` used to yield a truthy non-provider that blew up\n // on `.send(...)` further down — inside the try/catch below, so it surfaced as\n // a failed send reading \"provider.send is not a function\" and then burned the\n // full retry budget on a config error no retry can fix.\n //\n // No fallback to the default provider. `send.provider` is written by\n // pickProviderName, which has *already* applied the default; if the name on\n // the row still doesn't resolve it is stale, renamed or mistyped, and quietly\n // routing the mail through a different provider than the row records would\n // send it from the wrong reputation and hide the misconfiguration. Fail this\n // one send with a reason an operator can act on, exactly like the\n // template_missing / contact_missing paths above: no throw, so the send's\n // queue job settles instead of retrying, and nothing else in flight is\n // affected.\n const provider = resolveProvider(ctx.providers, send.provider)\n if (!provider) {\n const known = registeredProviderNames(ctx.providers)\n await markFailed(\n send._id!,\n `provider_unknown: no provider is registered as \"${send.provider}\". ` +\n `Registered providers: ${known.length ? known.join(', ') : '(none)'}.`,\n ctx,\n )\n return\n }\n\n // List-Unsubscribe belongs on bulk mail only. The unsubscribe token is\n // scoped 'marketing', so advertising one-click unsub on a password reset\n // both misrepresents the header and offers an opt-out that wouldn't stop\n // the transactional mail the recipient is looking at.\n const headers: Record<string, string> =\n send.kind === 'marketing'\n ? {\n 'List-Unsubscribe': `<${renderCtx.unsubscribeUrl}>`,\n 'List-Unsubscribe-Post': 'List-Unsubscribe=One-Click',\n }\n : {}\n\n try {\n const result = await provider.send({\n to: send.emailAtSend,\n fromName: rendered.fromName,\n fromEmail: rendered.fromEmail,\n replyTo: rendered.replyTo ?? undefined,\n subject: rendered.subject,\n ...(textOnly ? {} : { html: tracking.html }),\n text: rendered.plainText,\n headers,\n messageMeta: { sendId: String(send._id) },\n })\n\n await ctx.collections.sends.updateOne(\n { _id: send._id },\n {\n $set: {\n status: 'sent',\n sentAt: new Date(),\n providerMessageId: result.providerId,\n },\n },\n )\n // Use send.fromEmail (same field getBucketStatus reads) so the breaker\n // gate and the counter record into the same bucket even if a\n // hypothetical render-time fromDefaults swap ever lands.\n await recordHealthCounter(ctx, 'sent', { fromEmail: send.fromEmail, kind: send.kind })\n } catch (err: any) {\n await ctx.collections.sends.updateOne(\n { _id: send._id },\n { $set: { status: 'failed', errorMessage: String(err?.message ?? err) } },\n )\n await recordHealthCounter(ctx, 'failedToSend', { fromEmail: send.fromEmail, kind: send.kind })\n if (ctx.config.onSendFailure) {\n try {\n await ctx.config.onSendFailure({ send, error: err })\n } catch {\n /* swallow */\n }\n }\n throw err // let BullMQ retry per the attempts policy\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction pickProviderName(stepOverride: string | undefined, tpl: TemplateDoc, ctx: RunnerContext): string {\n if (stepOverride) return stepOverride\n if (tpl.providerOverride) return tpl.providerOverride\n if (tpl.kind === 'transactional' && ctx.config.defaultTransactionalProvider) {\n return ctx.config.defaultTransactionalProvider\n }\n return ctx.config.defaultProvider\n}\n\nfunction buildRenderContext(\n contact: Contact,\n run: FlowRunDoc | null,\n vars: Record<string, unknown>,\n ctx: RunnerContext,\n resolved: Record<string, unknown> = {},\n): RenderContext {\n const scope = 'marketing'\n const expiresAt = new Date(Date.now() + ctx.config.unsubscribeTokenLifetimeDays * 24 * 60 * 60 * 1000)\n const token = signUnsubscribeToken(\n { email: contact.email, scope, expiresAt },\n ctx.config.unsubscribeSecret,\n )\n const unsubscribeUrl = `${ctx.config.publicUrl}/m/unsub/${token}`\n\n return {\n ...resolved,\n contact,\n vars,\n event: run?.triggerEvent?.properties ?? {},\n unsubscribeUrl,\n senderAddress: ctx.config.senderAddress,\n }\n}\n\ninterface NewSendInput {\n _id?: ObjectId\n dedupeKey: string\n run: FlowRunDoc\n contact: Contact\n template: TemplateDoc\n flow: FlowDoc\n providerName: string\n renderedSubject: string\n bodyHash: string\n status: SendDoc['status']\n errorMessage?: string\n renderedFrom?: { name: string; email: string }\n vars?: Record<string, unknown>\n}\n\nfunction newSendDoc(input: NewSendInput): SendDoc {\n const now = new Date()\n return {\n _id: input._id,\n dedupeKey: input.dedupeKey,\n externalId: input.run.externalId,\n emailAtSend: input.contact.email,\n templateId: input.template._id!,\n templateSlug: input.template.slug,\n flowRunId: input.run._id!,\n broadcastId: null,\n manualSendBy: null,\n kind: input.template.kind,\n provider: input.providerName,\n providerMessageId: null,\n fromName: input.renderedFrom?.name ?? input.template.fromName,\n fromEmail: input.renderedFrom?.email ?? input.template.fromEmail,\n subject: input.renderedSubject,\n bodyHash: input.bodyHash,\n status: input.status,\n errorMessage: input.errorMessage ?? null,\n bounceType: null,\n bounceReason: null,\n links: [],\n vars: input.vars ?? {},\n openedAt: null,\n openCount: 0,\n firstClickAt: null,\n clickCount: 0,\n clickedLinks: [],\n unsubscribedAt: null,\n complainedAt: null,\n queuedAt: now,\n updatedAt: now,\n sentAt: null,\n deliveredAt: null,\n }\n}\n\nasync function markFailed(sendId: ObjectId, reason: string, ctx: RunnerContext): Promise<void> {\n await ctx.collections.sends.updateOne(\n { _id: sendId },\n { $set: { status: 'failed', errorMessage: reason } },\n )\n}\n\nfunction sha256(s: string): string {\n return crypto.createHash('sha256').update(s).digest('hex')\n}\n","/**\n * Suppression checks. INVARIANT 3: re-checked at send time, never trusted\n * from enqueue time. INVARIANT 9: hashed-suppression records (GDPR forget)\n * block sends without retaining the plaintext email.\n */\n\nimport type { Collections } from '../models/index.js'\nimport type { SuppressionScope, TemplateKind } from '../../shared/enums.js'\nimport { sha256Hex } from '../tokens.js'\n\nexport interface SuppressionResult {\n suppressed: boolean\n scope?: string\n reason?: string\n}\n\nconst SCOPES_BY_KIND: Record<TemplateKind, SuppressionScope[]> = {\n marketing: ['all', 'marketing'],\n transactional: ['all', 'transactional'],\n}\n\nexport async function isSuppressed(\n collections: Collections,\n email: string,\n kind: TemplateKind,\n): Promise<SuppressionResult> {\n const normalized = email.toLowerCase()\n const allowed = SCOPES_BY_KIND[kind]\n\n const byEmail = await collections.suppressions.findOne({\n email: normalized,\n scope: { $in: allowed },\n $or: [{ expiresAt: null }, { expiresAt: { $gt: new Date() } }],\n })\n if (byEmail) return { suppressed: true, scope: byEmail.scope, reason: byEmail.reason }\n\n const hashed = await collections.suppressions.findOne({\n emailHash: sha256Hex(normalized),\n scope: { $in: allowed },\n })\n if (hashed) return { suppressed: true, scope: hashed.scope, reason: hashed.reason }\n\n return { suppressed: false }\n}\n","/**\n * Flow_run state machine. One step transition per `processOneRunStep` call.\n * Idempotent — optimistic concurrency on `currentStepIndex` means two workers\n * racing on the same run advance exactly once.\n */\n\nimport type { ObjectId } from 'mongodb'\n\nimport type { FlowStep } from '../../shared/types.js'\nimport type { FlowRunDoc, FlowDoc } from '../models/index.js'\nimport { evaluatePredicate } from './predicate.js'\nimport type { RunnerContext } from './index.js'\nimport { computeDeliveryTime } from './delivery-window.js'\nimport { handleSend } from './send.js'\n\n/**\n * Tolerance on the not-yet-due check below. A delayed job may fire a few\n * milliseconds early, and clocks between app servers drift; without slack\n * those runs would bounce to the sweep and stall for a whole tick.\n */\nconst DUE_SKEW_MS = 1_000\n\nexport async function processOneRunStep(runId: ObjectId, ctx: RunnerContext): Promise<void> {\n const run = await ctx.collections.flowRuns.findOne({ _id: runId })\n if (!run || run.status !== 'active') return\n\n // Don't touch a run that is parked in the future. The schedule used to be\n // enforced only by the callers — the sweep's `nextActionAt <= now` filter and\n // the advance job's delay — which is a time-of-check/time-of-use race: the\n // sweep selects a run that is due, the run's own advance job parks it on a\n // wait in the meantime, and the sweep then processes the step AFTER the wait,\n // skipping it entirely. That is reachable on every tick, because a freshly\n // triggered run is inserted with `nextActionAt = now` and `runTick` runs the\n // trigger scan and the sweep back to back — so a flow whose first step is a\n // wait could lose it. The invariant belongs with the state, not the caller.\n if (run.nextActionAt && run.nextActionAt.getTime() > Date.now() + DUE_SKEW_MS) return\n\n const flow = await ctx.collections.flows.findOne({ _id: run.flowId })\n if (!flow) {\n await failFlowRun(run, 'flow_missing', ctx)\n return\n }\n\n const steps = await loadStepsForRun(run, flow, ctx)\n const step = locateStep(steps, run.currentStepIndex, run.currentBranchPath)\n if (!step) {\n await completeFlowRun(run, 'completed', ctx)\n return\n }\n\n const contact = await ctx.adapter.getById(run.externalId)\n if (!contact) {\n await exitFlowRun(run, 'contact_missing', ctx)\n return\n }\n\n // Subscription gate: flows are marketing-scope. Any non-subscribed status\n // exits the run before the next step, regardless of template kind — there is\n // deliberately no transactional bypass here. Transactional mail that must\n // reach not-subscribed contacts (receipts, password resets) goes through\n // sendOneOff, not a flow. Entry is gated the same way in triggers.ts.\n const sub = await ctx.collections.subscriptions.findOne({ externalId: run.externalId })\n if (sub && sub.status !== 'subscribed') {\n await exitFlowRun(run, sub.status, ctx)\n return\n }\n\n switch (step.type) {\n case 'wait':\n return handleWait(run, step, ctx)\n case 'condition':\n return handleCondition(run, step, contact, ctx)\n case 'branch':\n return handleBranch(run, step, contact, ctx)\n case 'send': {\n // Delivery window: push the send to the next allowed slot (weekday /\n // time-of-day, optionally in the contact's timezone) before rendering.\n if (step.delivery) {\n const deliverAt = computeDeliveryTime(new Date(), step.delivery, contact.timezone)\n if (deliverAt.getTime() > Date.now() + 30_000) {\n return deferSendForWindow(run, deliverAt, ctx)\n }\n }\n return handleSend(run, step, contact, flow, ctx)\n }\n case 'tag':\n return handleTag(run, step, ctx)\n case 'fire_event':\n return handleFireEvent(run, step, ctx)\n case 'webhook':\n return handleWebhookStep(run, step, ctx)\n case 'exit':\n return exitFlowRun(run, step.reason ?? 'exit_step', ctx)\n }\n}\n\n// ---------------------------------------------------------------------------\n// Step handlers\n// ---------------------------------------------------------------------------\n\nasync function handleWait(\n run: FlowRunDoc,\n step: Extract<FlowStep, { type: 'wait' }>,\n ctx: RunnerContext,\n): Promise<void> {\n const ms = unitToMs(step.value, step.unit)\n const nextAt = new Date(Date.now() + ms)\n\n const updated = await ctx.collections.flowRuns.findOneAndUpdate(\n { _id: run._id, currentStepIndex: run.currentStepIndex },\n {\n $set: { nextActionAt: nextAt, attemptsForCurrentStep: 0, updatedAt: new Date() },\n $inc: { currentStepIndex: 1 },\n $push: {\n history: {\n stepIndex: run.currentStepIndex,\n action: 'wait_started',\n at: new Date(),\n details: { until: nextAt },\n },\n },\n },\n { returnDocument: 'after' },\n )\n\n if (!updated) return // another worker advanced; their job will fire.\n\n await ctx.queues.advance.add(\n 'advance',\n { flowRunId: String(run._id) },\n { delay: ms, jobId: `advance:${run._id}:${branchKey(run)}:${run.currentStepIndex + 1}` },\n )\n}\n\nasync function handleCondition(\n run: FlowRunDoc,\n step: Extract<FlowStep, { type: 'condition' }>,\n contact: Awaited<ReturnType<typeof ctx.adapter.getById>>,\n ctx: RunnerContext,\n): Promise<void> {\n if (!contact) return\n const result = await evaluatePredicate(step.test, { contact, run, collections: ctx.collections, botFilter: ctx.config.botFilter })\n\n if (result) {\n await advanceStep(run, ctx, { action: 'condition_evaluated', details: { result: true } })\n return\n }\n if (step.ifFalse === 'continue') {\n await advanceStep(run, ctx, { action: 'condition_evaluated', details: { result: false, skipped: 1 } }, { stepInc: 2 })\n return\n }\n await exitFlowRun(run, 'condition_false', ctx)\n}\n\nasync function handleBranch(\n run: FlowRunDoc,\n step: Extract<FlowStep, { type: 'branch' }>,\n contact: Awaited<ReturnType<typeof ctx.adapter.getById>>,\n ctx: RunnerContext,\n): Promise<void> {\n if (!contact) return\n const result = await evaluatePredicate(step.test, { contact, run, collections: ctx.collections, botFilter: ctx.config.botFilter })\n const newPath = [...run.currentBranchPath, run.currentStepIndex, result ? 'true' : 'false', 0] as Array<number | 'true' | 'false'>\n\n const updated = await ctx.collections.flowRuns.findOneAndUpdate(\n { _id: run._id, currentStepIndex: run.currentStepIndex },\n {\n $set: {\n currentBranchPath: newPath,\n currentStepIndex: 0,\n nextActionAt: new Date(),\n attemptsForCurrentStep: 0,\n updatedAt: new Date(),\n },\n $push: {\n history: {\n stepIndex: run.currentStepIndex,\n action: 'branch_taken',\n at: new Date(),\n details: { result },\n },\n },\n },\n { returnDocument: 'after' },\n )\n\n if (!updated) return\n await ctx.queues.advance.add('advance', { flowRunId: String(run._id) })\n}\n\nasync function handleTag(\n run: FlowRunDoc,\n step: Extract<FlowStep, { type: 'tag' }>,\n ctx: RunnerContext,\n): Promise<void> {\n const adds = step.addTags ?? []\n const removes = step.removeTags ?? []\n\n if (ctx.adapter.addTags && adds.length > 0) {\n await ctx.adapter.addTags(run.externalId, adds)\n } else if (adds.length > 0) {\n await ctx.collections.contactTags.bulkWrite(\n adds.map((tag) => ({\n updateOne: {\n filter: { externalId: run.externalId, tag },\n update: { $setOnInsert: { externalId: run.externalId, tag, appliedBy: 'flow', appliedAt: new Date() } },\n upsert: true,\n },\n })),\n )\n }\n\n if (ctx.adapter.removeTags && removes.length > 0) {\n await ctx.adapter.removeTags(run.externalId, removes)\n } else if (removes.length > 0) {\n await ctx.collections.contactTags.deleteMany({ externalId: run.externalId, tag: { $in: removes } })\n }\n\n await advanceStep(run, ctx, { action: 'tagged', details: { addTags: adds, removeTags: removes } })\n}\n\nasync function handleFireEvent(\n run: FlowRunDoc,\n step: Extract<FlowStep, { type: 'fire_event' }>,\n ctx: RunnerContext,\n): Promise<void> {\n const dedupeKey = `flowrun:${run._id}:step${run.currentStepIndex}:${step.eventName}`\n try {\n await ctx.collections.events.insertOne({\n externalId: run.externalId,\n name: step.eventName,\n // Inherit the triggering event's properties so a handoff carries the\n // context that identifies what the run is ABOUT (which account, order,\n // subscription, ...). A step's `properties` are static — authored once in\n // the flow definition — so without this a fired event can only ever say\n // \"this contact\", losing the scope the originating event supplied, and\n // the receiving flow has nothing to resolve variables against. Explicit\n // step.properties win on conflict.\n properties: { ...(run.triggerEvent?.properties ?? {}), ...(step.properties ?? {}) },\n dedupeKey,\n occurredAt: new Date(),\n createdAt: new Date(),\n })\n } catch (err: any) {\n if (err?.code !== 11000) throw err\n }\n await advanceStep(run, ctx, { action: 'event_fired', details: { name: step.eventName } })\n}\n\nasync function handleWebhookStep(\n run: FlowRunDoc,\n step: Extract<FlowStep, { type: 'webhook' }>,\n ctx: RunnerContext,\n): Promise<void> {\n try {\n // `step.url` is passed to fetch VERBATIM — deliberately NOT rendered through\n // Handlebars, and it must stay that way.\n //\n // The URL comes only from a flow definition authored through the admin routes,\n // so the set of reachable destinations is fixed by a privileged system admin.\n // Under that constraint, \"this server can POST to an arbitrary URL\" is an\n // intended admin capability, not a vulnerability.\n //\n // Templating it would invert that. A URL like `{{contact.callbackUrl}}` is a\n // natural-sounding request, but it hands the destination of a server-side\n // fetch — one that originates INSIDE the deployment's network, past any\n // perimeter — to whoever controls the template data: contact fields, event\n // properties, adapter vars. That is a textbook SSRF vector (cloud metadata\n // endpoints, internal admin services, localhost) reachable by an unprivileged\n // party. If templated webhook URLs are ever genuinely needed, they require a\n // destination allowlist plus DNS/redirect-aware egress filtering, not a\n // render call added here.\n //\n // Note the zod schema (`url: z.string().url()` in src/shared/schemas.ts)\n // validates SHAPE only — it accepts http://169.254.169.254/ quite happily and\n // provides no protection whatsoever on this point.\n //\n // The `advanceStep` audit entry below records the resolved URL and response\n // status (and the error on the failure path), so every outbound call a flow\n // makes is attributable after the fact.\n const res = await fetch(step.url, {\n method: step.method ?? 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(step.payload ?? { externalId: run.externalId, flowRunId: String(run._id) }),\n signal: AbortSignal.timeout(10_000),\n })\n if (!res.ok) throw new Error(`webhook step returned ${res.status}`)\n await advanceStep(run, ctx, { action: 'webhook_called', details: { url: step.url, status: res.status } })\n } catch (err: any) {\n const attempts = (run.attemptsForCurrentStep ?? 0) + 1\n if (attempts >= ctx.config.webhookRetryAttempts) {\n if (step.failureMode === 'fail_run') {\n await failFlowRun(run, `webhook failed: ${err?.message}`, ctx)\n } else {\n // Soft fail — log and advance.\n await advanceStep(run, ctx, {\n action: 'webhook_called',\n details: { url: step.url, error: err?.message, exhausted: true },\n })\n }\n } else {\n await ctx.collections.flowRuns.updateOne(\n { _id: run._id, currentStepIndex: run.currentStepIndex },\n { $inc: { attemptsForCurrentStep: 1 }, $set: { nextActionAt: new Date(Date.now() + 60_000) } },\n )\n await ctx.queues.advance.add(\n 'advance',\n { flowRunId: String(run._id) },\n { delay: 60_000, jobId: `advance:${run._id}:${branchKey(run)}:${run.currentStepIndex}:retry-${attempts}` },\n )\n }\n }\n}\n\n/**\n * Park the run on the SAME step until the delivery window opens, then let the\n * normal advance job re-enter processOneRunStep — at which point the window\n * check passes and handleSend runs. Idempotent via the jobId (one defer job\n * per step per slot) and the nextActionAt guard.\n */\nasync function deferSendForWindow(run: FlowRunDoc, deliverAt: Date, ctx: RunnerContext): Promise<void> {\n const updated = await ctx.collections.flowRuns.findOneAndUpdate(\n // Only write once per deferral — if nextActionAt already points at (or\n // past) the slot, another worker/tick got here first.\n { _id: run._id, currentStepIndex: run.currentStepIndex, nextActionAt: { $lt: deliverAt } },\n {\n $set: { nextActionAt: deliverAt, updatedAt: new Date() },\n $push: {\n history: {\n stepIndex: run.currentStepIndex,\n action: 'send_deferred' as const,\n at: new Date(),\n details: { until: deliverAt },\n },\n },\n },\n { returnDocument: 'after' },\n )\n if (!updated) return\n\n await ctx.queues.advance.add(\n 'advance',\n { flowRunId: String(run._id) },\n {\n delay: Math.max(0, deliverAt.getTime() - Date.now()),\n jobId: `advance:${run._id}:${branchKey(run)}:${run.currentStepIndex}:window:${deliverAt.getTime()}`,\n },\n )\n}\n\n// ---------------------------------------------------------------------------\n// Common helpers\n// ---------------------------------------------------------------------------\n\nexport interface AdvanceOptions {\n stepInc?: number\n}\n\nexport interface AdvanceLog {\n action: FlowRunDoc['history'][number]['action']\n details?: Record<string, unknown>\n}\n\nexport async function advanceStep(\n run: FlowRunDoc,\n ctx: RunnerContext,\n log: AdvanceLog,\n opts: AdvanceOptions = {},\n): Promise<void> {\n const stepInc = opts.stepInc ?? 1\n const updated = await ctx.collections.flowRuns.findOneAndUpdate(\n { _id: run._id, currentStepIndex: run.currentStepIndex },\n {\n $set: { nextActionAt: new Date(), attemptsForCurrentStep: 0, updatedAt: new Date() },\n $inc: { currentStepIndex: stepInc },\n $push: {\n history: { stepIndex: run.currentStepIndex, action: log.action, at: new Date(), details: log.details },\n },\n },\n { returnDocument: 'after' },\n )\n if (!updated) return\n await ctx.queues.advance.add('advance', { flowRunId: String(run._id) })\n}\n\nexport async function exitFlowRun(run: FlowRunDoc, reason: string, ctx: RunnerContext): Promise<void> {\n await ctx.collections.flowRuns.updateOne(\n { _id: run._id, status: 'active' },\n {\n $set: { status: 'exited', exitedAt: new Date(), exitReason: reason, updatedAt: new Date() },\n $push: { history: { stepIndex: run.currentStepIndex, action: 'exited', at: new Date(), details: { reason } } },\n },\n )\n}\n\nexport async function completeFlowRun(run: FlowRunDoc, reason: string, ctx: RunnerContext): Promise<void> {\n await ctx.collections.flowRuns.updateOne(\n { _id: run._id, status: 'active' },\n {\n $set: { status: 'completed', exitedAt: new Date(), exitReason: reason, updatedAt: new Date() },\n },\n )\n}\n\nexport async function failFlowRun(run: FlowRunDoc, reason: string, ctx: RunnerContext): Promise<void> {\n await ctx.collections.flowRuns.updateOne(\n { _id: run._id, status: 'active' },\n {\n $set: { status: 'failed', exitedAt: new Date(), exitReason: reason, updatedAt: new Date() },\n $push: { history: { stepIndex: run.currentStepIndex, action: 'failed', at: new Date(), details: { reason } } },\n },\n )\n}\n\nexport async function loadStepsForRun(\n run: FlowRunDoc,\n flow: FlowDoc,\n ctx: RunnerContext,\n): Promise<FlowStep[]> {\n if (run.flowVersion === flow.version) return flow.steps\n const snapshot = await ctx.collections.flowVersions.findOne({ flowId: run.flowId, version: run.flowVersion })\n return snapshot?.steps ?? flow.steps\n}\n\n/**\n * Walk a branch path through nested branch steps to find the active step.\n * Branch path layout: [parentStepIndex, 'true'|'false', childStepIndex, ...repeat]\n */\nexport function locateStep(\n steps: FlowStep[],\n currentStepIndex: number,\n branchPath: ReadonlyArray<number | 'true' | 'false'>,\n): FlowStep | null {\n let arr: FlowStep[] = steps\n\n for (let i = 0; i < branchPath.length; i += 3) {\n const parentIndex = branchPath[i] as number\n const branchKey = branchPath[i + 1] as 'true' | 'false'\n const parent = arr[parentIndex]\n if (!parent || parent.type !== 'branch') return null\n arr = branchKey === 'true' ? parent.ifTrueSteps : parent.ifFalseSteps\n }\n\n return arr[currentStepIndex] ?? null\n}\n\n/**\n * Branch-path discriminator for advance jobIds. `currentStepIndex` resets to 0\n * on branch entry, so (runId, stepIndex) alone is not unique across a run's\n * lifetime — the same numeric index recurs inside each branch arm.\n */\nfunction branchKey(run: FlowRunDoc): string {\n return run.currentBranchPath.join('_')\n}\n\nfunction unitToMs(value: number, unit: 'minutes' | 'hours' | 'days' | 'weeks'): number {\n const m = 60_000\n switch (unit) {\n case 'minutes':\n return value * m\n case 'hours':\n return value * 60 * m\n case 'days':\n return value * 24 * 60 * m\n case 'weeks':\n return value * 7 * 24 * 60 * m\n }\n}\n","/**\n * Recovery sweep: finds active flow_runs whose `nextActionAt` has passed but\n * weren't woken by their delayed `mailer:advance` job (worker restart, BullMQ\n * data loss). Processes each one inline.\n */\n\nimport { processOneRunStep } from './step.js'\nimport type { RunnerContext } from './index.js'\n\nconst SWEEP_LIMIT = 500\n\nexport async function sweepStrandedFlowRuns(ctx: RunnerContext): Promise<void> {\n const runs = await ctx.collections.flowRuns\n .find({ status: 'active', nextActionAt: { $lte: new Date() } })\n .sort({ nextActionAt: 1 })\n .limit(SWEEP_LIMIT)\n .toArray()\n\n for (const run of runs) {\n try {\n await processOneRunStep(run._id!, ctx)\n } catch (err) {\n console.error('mailery: sweep advance failed', { runId: String(run._id), err })\n }\n }\n}\n","/**\n * Broadcast dispatch. Picks up scheduled broadcasts whose `scheduledAt` has\n * passed, streams the segment via the adapter cursor + mailer-side post-filter,\n * and bulk-enqueues Send docs + jobs. Per-provider rate limiting + bounded\n * enqueue (pause when waitingCount > broadcastEnqueueMaxWaiting).\n */\n\nimport { ObjectId } from 'mongodb'\n\nimport type { Contact, SegmentDefinition, SegmentFilter, AdapterFilter } from '../../shared/types.js'\nimport type { BroadcastDoc, SendDoc, TemplateDoc } from '../models/index.js'\nimport { isSuppressed } from './suppression.js'\nimport { sha256Hex } from '../tokens.js'\nimport type { RunnerContext } from './index.js'\n\n/**\n * Broadcasts stuck in 'sending' with updatedAt older than this are assumed\n * dead (worker crashed mid-dispatch). dispatchBroadcast heartbeats updatedAt\n * on every page, so a stale timestamp means no live dispatcher.\n */\nconst STALLED_BROADCAST_THRESHOLD_MS = 10 * 60 * 1000\n\n/**\n * Process scheduled broadcasts whose `scheduledAt` has passed. Called from the\n * tick. Marks each broadcast `sending` before dispatch so concurrent ticks\n * don't double-dispatch.\n */\nexport async function processScheduledBroadcasts(ctx: RunnerContext): Promise<void> {\n const now = new Date()\n const due = await ctx.collections.broadcasts\n .find({ status: 'scheduled', scheduledAt: { $lte: now } })\n .toArray()\n\n for (const b of due) {\n // Optimistic claim — only one worker takes this broadcast.\n const claimed = await ctx.collections.broadcasts.findOneAndUpdate(\n { _id: b._id, status: 'scheduled' },\n { $set: { status: 'sending', startedAt: now, updatedAt: now } },\n { returnDocument: 'after' },\n )\n if (!claimed) continue\n await startBroadcastDispatch(claimed, ctx)\n }\n}\n\n/**\n * Hand the (potentially hours-long) recipient enqueue off the tick. With a\n * real queue driver, dispatch runs as an advance job so a large broadcast\n * can't starve trigger scans and sweeps — the tick worker has concurrency 1.\n * The noop driver has no workers (hosts drive the runner synchronously), so\n * dispatch stays inline there.\n */\nasync function startBroadcastDispatch(broadcast: BroadcastDoc, ctx: RunnerContext): Promise<void> {\n if (ctx.config.queue.driver === 'noop') {\n await runBroadcastDispatch(broadcast, ctx)\n return\n }\n await ctx.queues.advance.add(\n 'advance',\n { broadcastId: String(broadcast._id) },\n {\n attempts: 3,\n backoff: { type: 'exponential', delay: 60_000 },\n jobId: `broadcast-dispatch:${broadcast._id}`,\n },\n )\n}\n\n/** Advance-worker entry point for `{ broadcastId }` jobs. */\nexport async function dispatchBroadcastById(broadcastId: ObjectId, ctx: RunnerContext): Promise<void> {\n const broadcast = await ctx.collections.broadcasts.findOne({ _id: broadcastId, status: 'sending' })\n if (!broadcast) return\n await runBroadcastDispatch(broadcast, ctx)\n}\n\n/**\n * Rescue broadcasts whose dispatcher died. Re-dispatch is idempotent: the\n * per-recipient dedupeKey unique index skips send rows already inserted, so\n * a resumed broadcast picks up where the dead worker left off.\n */\nexport async function resumeStalledBroadcasts(ctx: RunnerContext): Promise<void> {\n const cutoff = new Date(Date.now() - STALLED_BROADCAST_THRESHOLD_MS)\n const stalled = await ctx.collections.broadcasts\n .find({ status: 'sending', updatedAt: { $lt: cutoff } })\n .toArray()\n\n for (const b of stalled) {\n // Touch before re-dispatch so subsequent ticks don't stack rescues.\n await ctx.collections.broadcasts.updateOne(\n { _id: b._id },\n { $set: { updatedAt: new Date() } },\n )\n await startBroadcastDispatch(b, ctx)\n }\n}\n\nasync function runBroadcastDispatch(broadcast: BroadcastDoc, ctx: RunnerContext): Promise<void> {\n try {\n await dispatchBroadcast(broadcast, ctx)\n } catch (err) {\n console.error('mailery: broadcast dispatch failed', { id: String(broadcast._id), err })\n await ctx.collections.broadcasts.updateOne(\n { _id: broadcast._id },\n { $set: { status: 'failed', updatedAt: new Date() } },\n )\n }\n}\n\nasync function dispatchBroadcast(broadcast: BroadcastDoc, ctx: RunnerContext): Promise<void> {\n const template = await ctx.collections.templates.findOne({ slug: broadcast.templateSlug })\n if (!template) {\n await ctx.collections.broadcasts.updateOne(\n { _id: broadcast._id },\n { $set: { status: 'failed', updatedAt: new Date() } },\n )\n return\n }\n\n const hostFilter = toAdapterFilter(broadcast.segmentDefinition)\n const postFilters = broadcast.segmentDefinition.filters.filter((f) => isMailerSide(f))\n\n let cursor: string | undefined = undefined\n let total = 0\n const batchSize = ctx.config.broadcastEnqueueBatchSize\n const maxWaiting = ctx.config.broadcastEnqueueMaxWaiting\n const respectTimezone = broadcast.respectRecipientTimezone === true\n const scheduledMs = broadcast.scheduledAt?.getTime() ?? Date.now()\n\n for (;;) {\n // Progress heartbeat — resumeStalledBroadcasts treats a stale updatedAt\n // as a dead dispatcher, so touch it every page (and during backpressure).\n await ctx.collections.broadcasts.updateOne(\n { _id: broadcast._id },\n { $set: { updatedAt: new Date() } },\n )\n\n const page = await ctx.adapter.query(hostFilter, { limit: batchSize, cursor })\n if (page.contacts.length === 0) break\n\n // Stage B: mailer-side post-filter.\n const eligible = await applyPostFilters(page.contacts, postFilters, ctx)\n\n if (eligible.length > 0) {\n // Backpressure: wait until the send queue's waiting set drains below cap.\n while ((await ctx.queues.send.getWaitingCount()) > maxWaiting) {\n await ctx.collections.broadcasts.updateOne(\n { _id: broadcast._id },\n { $set: { updatedAt: new Date() } },\n )\n await sleep(2000)\n }\n\n const sendDocs = await Promise.all(\n eligible.map(async (contact) => buildSendDoc(broadcast, template, contact, ctx, scheduledMs, respectTimezone)),\n )\n\n // Filter out suppressed (mailer-side suppression check is the same one\n // dispatchSend would do; we short-circuit here to avoid enqueuing).\n const inserted: Array<{ sendId: ObjectId; delayMs: number }> = []\n for (const { doc, delayMs } of sendDocs) {\n if (!doc) continue\n try {\n await ctx.collections.sends.insertOne(doc)\n inserted.push({ sendId: doc._id!, delayMs })\n } catch (err: any) {\n if (err?.code !== 11000) throw err\n // dup dedupeKey — already dispatched somewhere\n }\n }\n\n // Bulk enqueue.\n if (inserted.length > 0) {\n await Promise.all(\n inserted.map(({ sendId, delayMs }) =>\n ctx.queues.send.add(\n 'send',\n { sendId: String(sendId) },\n {\n attempts: ctx.config.sendRetryAttempts,\n backoff: { type: 'exponential', delay: 60_000 },\n ...(delayMs > 0 ? { delay: delayMs } : {}),\n },\n ),\n ),\n )\n }\n\n total += inserted.length\n }\n\n if (!page.nextCursor) break\n cursor = page.nextCursor\n }\n\n await ctx.collections.broadcasts.updateOne(\n { _id: broadcast._id },\n {\n $set: {\n status: 'sent',\n completedAt: new Date(),\n recipientCount: total,\n updatedAt: new Date(),\n },\n },\n )\n}\n\n// ---------------------------------------------------------------------------\n// Segment translation\n// ---------------------------------------------------------------------------\n\nfunction toAdapterFilter(seg: SegmentDefinition): AdapterFilter {\n const out: AdapterFilter = {}\n for (const f of seg.filters) {\n switch (f.kind) {\n case 'hasTag':\n out.hasTag = f.tag\n break\n case 'fieldEquals':\n out.fieldEquals = { field: f.field, value: f.value }\n break\n case 'fieldIn':\n out.fieldIn = { field: f.field, values: f.values }\n break\n case 'fieldExists':\n out.fieldExists = f.field\n break\n // notHasTag isn't a single-condition adapter filter, defer to post-filter\n // subscriptionStatus / firedEvent / opened are all mailer-side\n }\n }\n return out\n}\n\nfunction isMailerSide(f: SegmentFilter): boolean {\n return (\n f.kind === 'subscriptionStatus' ||\n f.kind === 'firedEvent' ||\n f.kind === 'notFiredEvent' ||\n f.kind === 'subscribedAfter' ||\n f.kind === 'subscribedBefore' ||\n f.kind === 'opened' ||\n f.kind === 'notOpened' ||\n f.kind === 'notHasTag' ||\n f.kind === 'any' ||\n f.kind === 'not'\n )\n}\n\nasync function applyPostFilters(contacts: Contact[], filters: SegmentFilter[], ctx: RunnerContext): Promise<Contact[]> {\n if (filters.length === 0) return contacts\n const externalIds = contacts.map((c) => c.externalId)\n\n // Cache common lookups in one Mongo round-trip per filter.\n const cache: Record<string, Set<string>> = {}\n for (const f of filters) {\n if (f.kind === 'subscriptionStatus') {\n const docs = await ctx.collections.subscriptions\n .find({ externalId: { $in: externalIds }, status: f.equals })\n .project<{ externalId: string }>({ externalId: 1 })\n .toArray()\n cache[`sub:${f.equals}`] = new Set(docs.map((d) => d.externalId))\n }\n if (f.kind === 'firedEvent' || f.kind === 'notFiredEvent') {\n const query: any = { externalId: { $in: externalIds }, name: f.eventName }\n if (f.withinDays) {\n query.occurredAt = { $gt: new Date(Date.now() - f.withinDays * 86_400_000) }\n }\n const docs = await ctx.collections.events\n .find(query)\n .project<{ externalId: string }>({ externalId: 1 })\n .toArray()\n cache[`evt:${f.eventName}`] = new Set(docs.map((d) => d.externalId))\n }\n }\n\n return contacts.filter((c) => filters.every((f) => filterMatches(c, f, cache)))\n}\n\nfunction filterMatches(c: Contact, f: SegmentFilter, cache: Record<string, Set<string>>): boolean {\n switch (f.kind) {\n case 'subscriptionStatus':\n return cache[`sub:${f.equals}`]?.has(c.externalId) ?? false\n case 'firedEvent':\n return cache[`evt:${f.eventName}`]?.has(c.externalId) ?? false\n case 'notFiredEvent':\n return !cache[`evt:${f.eventName}`]?.has(c.externalId)\n case 'notHasTag':\n return !c.tags.includes(f.tag)\n case 'opened':\n case 'notOpened':\n // V1: not implemented in batch — would need a per-contact send lookup.\n // Treat as pass for now; suppress at dispatch time.\n return true\n case 'subscribedAfter':\n case 'subscribedBefore':\n return true // V2\n case 'any':\n return f.filters.some((sub) => filterMatches(c, sub, cache))\n case 'not':\n return !filterMatches(c, f.filter, cache)\n default:\n return true\n }\n}\n\n// ---------------------------------------------------------------------------\n// Send doc construction\n// ---------------------------------------------------------------------------\n\ninterface BuildResult {\n doc: SendDoc | null\n delayMs: number\n}\n\nasync function buildSendDoc(\n broadcast: BroadcastDoc,\n template: TemplateDoc,\n contact: Contact,\n ctx: RunnerContext,\n scheduledMs: number,\n respectTimezone: boolean,\n): Promise<BuildResult> {\n // Final suppression check before we insert.\n const supp = await isSuppressed(ctx.collections, contact.email, template.kind)\n if (supp.suppressed) return { doc: null, delayMs: 0 }\n\n const sendId = new ObjectId()\n const dedupeKey = `broadcast:${broadcast._id}:${contact.externalId}`\n\n // Per-recipient TZ delay calculation. Anchored to scheduledAt (not enqueue\n // time) so tick lag and backpressure pauses don't drift later batches.\n let delayMs = Math.max(0, scheduledMs - Date.now())\n if (respectTimezone && contact.timezone) {\n const offsetMs = perRecipientOffsetMs(scheduledMs, contact.timezone)\n delayMs = Math.max(0, scheduledMs + offsetMs - Date.now())\n }\n\n const doc: SendDoc = {\n _id: sendId,\n dedupeKey,\n externalId: contact.externalId,\n emailAtSend: contact.email,\n templateId: template._id!,\n templateSlug: template.slug,\n flowRunId: null,\n broadcastId: broadcast._id!,\n manualSendBy: null,\n kind: template.kind,\n provider: template.providerOverride ?? ctx.config.defaultProvider,\n providerMessageId: null,\n fromName: template.fromName,\n fromEmail: template.fromEmail,\n subject: template.subject,\n bodyHash: '',\n status: 'queued',\n errorMessage: null,\n bounceType: null,\n bounceReason: null,\n links: [],\n vars: {},\n openedAt: null,\n openCount: 0,\n firstClickAt: null,\n clickCount: 0,\n clickedLinks: [],\n unsubscribedAt: null,\n complainedAt: null,\n queuedAt: new Date(),\n updatedAt: new Date(),\n sentAt: null,\n deliveredAt: null,\n }\n void sha256Hex\n return { doc, delayMs }\n}\n\n/**\n * Offset to add to `scheduledMs` so the email arrives at the same WALL-CLOCK\n * time in the recipient's timezone.\n *\n * Example: broadcast `scheduledAt` is 10am UTC, contact is in PST (UTC-8).\n * Their 10am is 6pm UTC → offset +8h.\n *\n * Recipients EAST of the schedule's timezone would need a negative offset —\n * their 10am already passed when dispatch starts. Sending \"now\" would land at\n * the wrong local time, so instead the offset is normalized into [0, 24h):\n * they get the NEXT occurrence of the wall-clock slot, i.e. same time\n * tomorrow. (Berlin, UTC+2: raw offset −2h → +22h.)\n */\nfunction perRecipientOffsetMs(scheduledMs: number, timezone: string): number {\n const DAY_MS = 24 * 60 * 60 * 1000\n try {\n // Get the offset between the scheduled UTC instant interpreted as a wall\n // clock and the same wall clock in the recipient's tz.\n const scheduled = new Date(scheduledMs)\n const utc = scheduled.toLocaleString('en-US', { timeZone: 'UTC', hour12: false })\n const local = scheduled.toLocaleString('en-US', { timeZone: timezone, hour12: false })\n\n // Parse both as Date objects in the runner's local tz and take the diff.\n const parse = (s: string) => {\n const m = s.match(/(\\d+)\\/(\\d+)\\/(\\d+),\\s*(\\d+):(\\d+):(\\d+)/)\n if (!m) return 0\n return Date.UTC(+m[3]!, +m[1]! - 1, +m[2]!, +m[4]!, +m[5]!, +m[6]!)\n }\n const utcMs = parse(utc)\n const localMs = parse(local)\n const offsetMs = utcMs - localMs\n\n return ((offsetMs % DAY_MS) + DAY_MS) % DAY_MS\n } catch {\n return 0\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n","/**\n * Soft → hard bounce promotion. Configurable threshold + window:\n *\n * softBouncePromotionThreshold soft bounces for the same email within\n * softBouncePromotionWindowDays → insert a hard suppression + mark\n * the subscription bounced.\n *\n * Runs on each tick. Idempotent: if a hard suppression already exists for\n * that email, we skip.\n */\n\nimport type { TemplateKind } from '../../shared/enums.js'\nimport { sha256Hex } from '../tokens.js'\nimport { recordHealthCounter } from './health.js'\nimport type { RunnerContext } from './index.js'\n\nexport async function promoteSoftBounces(ctx: RunnerContext): Promise<void> {\n const threshold = ctx.config.softBouncePromotionThreshold\n const windowDays = ctx.config.softBouncePromotionWindowDays\n if (threshold <= 0 || windowDays <= 0) return\n\n const cutoff = new Date(Date.now() - windowDays * 86_400_000)\n\n // Aggregate: count soft bounces per emailAtSend since cutoff, hitting the\n // threshold. Bounded limit to keep the tick fast.\n const offenders = await ctx.collections.sends\n .aggregate<{ _id: string; count: number; lastFromEmail: string | null; lastKind: TemplateKind | null }>([\n { $match: { status: 'bounced', bounceType: 'soft', queuedAt: { $gt: cutoff } } },\n { $sort: { queuedAt: 1 } },\n {\n $group: {\n _id: '$emailAtSend',\n count: { $sum: 1 },\n lastFromEmail: { $last: '$fromEmail' },\n lastKind: { $last: '$kind' },\n },\n },\n { $match: { count: { $gte: threshold } } },\n { $limit: 200 },\n ])\n .toArray()\n\n for (const o of offenders) {\n const email = String(o._id ?? '').toLowerCase()\n if (!email) continue\n\n // Skip if already hard-suppressed.\n const existing = await ctx.collections.suppressions.findOne({\n email,\n scope: 'all',\n })\n if (existing) continue\n\n await ctx.collections.suppressions.updateOne(\n { email, scope: 'all' },\n {\n $setOnInsert: {\n email,\n emailHash: sha256Hex(email),\n scope: 'all',\n reason: 'hard_bounce',\n source: 'soft_promotion',\n notes: `${o.count} soft bounces in last ${windowDays} days`,\n addedAt: new Date(),\n expiresAt: null,\n },\n },\n { upsert: true },\n )\n\n await ctx.collections.subscriptions.updateOne(\n { emailAtSubscribe: email },\n { $set: { status: 'bounced', updatedAt: new Date() } },\n )\n\n await recordHealthCounter(\n ctx,\n 'hardBounced',\n o.lastKind ? { fromEmail: o.lastFromEmail, kind: o.lastKind } : null,\n )\n }\n}\n","/**\n * DNSBL monitor. Once a day (or on demand) we DNS-query each configured\n * sender domain against domain block lists (DBLs) and each configured\n * dedicated IP against IP block lists. Results are stored as one doc per\n * (target, list) — the latest result replaces the prior one.\n *\n * No external API. Pure DNS, so it works in any environment that can\n * resolve public hostnames.\n */\n\nimport dns from 'node:dns/promises'\nimport net from 'node:net'\nimport psl from 'psl'\n\nimport type {\n DnsblConfig,\n DnsblListSpec,\n} from '../config.js'\nimport {\n DEFAULT_DOMAIN_DNSBL_LISTS,\n DEFAULT_IP_DNSBL_LISTS,\n} from '../config.js'\nimport type { DnsblCheckDoc, DnsblResult, DnsblTargetKind } from '../models/index.js'\nimport { extractDomain } from '../templates/sender-domain.js'\nimport type { RunnerContext } from './index.js'\n\n/**\n * Lists that expect a registrable domain (eTLD+1) rather than the full\n * FQDN. Querying `mail.foo.example.com.multi.surbl.org` returns NXDOMAIN\n * even when `example.com` is listed.\n */\nconst REGISTRABLE_ONLY_LISTS = new Set(['multi.surbl.org', 'multi.uribl.com'])\n\n/** DNS-query concurrency for parallel lookups. Keep modest to avoid resolver throttling. */\nconst DNS_CONCURRENCY = 8\n\nexport interface Resolver {\n resolve4(hostname: string): Promise<string[]>\n}\n\nconst defaultResolver: Resolver = {\n resolve4: (hostname) => dns.resolve4(hostname),\n}\n\nexport interface RunDnsblOptions {\n /** Override the DNS resolver (used in tests). */\n resolver?: Resolver\n /** When true, ignore the throttle and run all checks immediately. */\n force?: boolean\n}\n\nexport interface RunDnsblResult {\n ran: boolean\n reason?: string\n totalChecks?: number\n listedCount?: number\n}\n\n/**\n * Run DNSBL checks for every (target × list) pair. Idempotent — the latest\n * result for each pair is upserted.\n */\nexport async function runDnsblChecks(\n ctx: RunnerContext,\n opts: RunDnsblOptions = {},\n): Promise<RunDnsblResult> {\n const cfg = ctx.config.dnsbl ?? {}\n const intervalHours = cfg.intervalHours ?? 24\n\n if (!opts.force && intervalHours <= 0) {\n return { ran: false, reason: 'disabled' }\n }\n\n const targets = collectTargets(ctx, cfg)\n if (targets.domains.length === 0 && targets.ips.length === 0) {\n return { ran: false, reason: 'no_targets' }\n }\n\n const resolver = opts.resolver ?? defaultResolver\n const domainLists = cfg.domainLists ?? DEFAULT_DOMAIN_DNSBL_LISTS\n const ipLists = cfg.ipLists ?? DEFAULT_IP_DNSBL_LISTS\n\n const pairs: Array<{\n target: string\n targetKind: DnsblTargetKind\n list: DnsblListSpec\n }> = []\n for (const d of targets.domains) {\n for (const l of domainLists) pairs.push({ target: d, targetKind: 'domain', list: l })\n }\n for (const ip of targets.ips) {\n for (const l of ipLists) pairs.push({ target: ip, targetKind: 'ip', list: l })\n }\n\n // Per-pair throttle: skip pairs whose existing row is fresher than the\n // interval. Force ignores the throttle. This replaces the previous\n // single-most-recent-check gate that blocked the whole suite based on\n // one stale row.\n const throttleCutoff = opts.force ? null : Date.now() - intervalHours * 60 * 60 * 1000\n let duePairs = pairs\n if (throttleCutoff != null) {\n const existing = await ctx.collections.dnsblChecks\n .find(\n {\n $or: pairs.map((p) => ({ target: p.target, list: p.list.host })),\n },\n { projection: { target: 1, list: 1, runAt: 1 } },\n )\n .toArray()\n const fresh = new Set<string>()\n for (const e of existing) {\n if (new Date(e.runAt).getTime() > throttleCutoff) {\n fresh.add(`${e.target}|${e.list}`)\n }\n }\n duePairs = pairs.filter((p) => !fresh.has(`${p.target}|${p.list.host}`))\n if (duePairs.length === 0) {\n return { ran: false, reason: 'not_due', totalChecks: 0, listedCount: 0 }\n }\n }\n\n let listedCount = 0\n\n // Bounded parallelism — DNS lookups are I/O-bound, but blasting all 25+\n // queries at once invites resolver throttling.\n async function processPair(p: typeof pairs[number]) {\n const queryName = buildQueryName(p.target, p.targetKind, p.list.host)\n const lookup = queryName\n ? await queryDnsbl(resolver, queryName)\n : { result: 'error' as DnsblResult, returnCodes: [], errorMessage: 'unsupported target format' }\n // Transient DNS failure: preserve the prior verdict so a momentary\n // resolver hiccup doesn't flip a clean target to 'error' in setup-status.\n if (lookup.transient) return\n if (lookup.result === 'listed') listedCount++\n await ctx.collections.dnsblChecks.updateOne(\n { target: p.target, list: p.list.host },\n {\n $set: {\n target: p.target,\n targetKind: p.targetKind,\n list: p.list.host,\n listLabel: p.list.label,\n result: lookup.result,\n returnCodes: lookup.returnCodes,\n errorMessage: lookup.errorMessage,\n runAt: new Date(),\n },\n },\n { upsert: true },\n )\n }\n\n let idx = 0\n await Promise.all(\n Array.from({ length: Math.min(DNS_CONCURRENCY, duePairs.length) }, async () => {\n while (idx < duePairs.length) {\n const my = idx++\n await processPair(duePairs[my]!)\n }\n }),\n )\n\n return { ran: true, totalChecks: duePairs.length, listedCount }\n}\n\n/**\n * Targets we'll check: every sender domain we know about + any explicitly\n * configured dedicated IPs. Domains come from `senderDomains` registry plus\n * the From defaults so an operator who only set fromDefaults still gets\n * coverage.\n */\nfunction collectTargets(ctx: RunnerContext, cfg: DnsblConfig): { domains: string[]; ips: string[] } {\n const domains = new Set<string>()\n const registry = ctx.config.senderDomains\n if (registry) {\n for (const d of Object.keys(registry)) domains.add(d.toLowerCase())\n }\n const fromDomain = ctx.config.fromDefaults?.email\n ? extractDomain(ctx.config.fromDefaults.email)\n : null\n if (fromDomain) domains.add(fromDomain)\n const txnDomain = ctx.config.transactionalFromDefaults?.email\n ? extractDomain(ctx.config.transactionalFromDefaults.email)\n : null\n if (txnDomain) domains.add(txnDomain)\n\n // Both IPv4 and IPv6 are valid query targets — let the lookup layer handle\n // formatting per RFC 5782. Invalid strings are dropped here so they don't\n // produce a row with errorMessage='unsupported target format' on every run.\n return {\n domains: Array.from(domains),\n ips: (cfg.dedicatedIps ?? []).filter((ip) => net.isIP(ip) !== 0),\n }\n}\n\n/**\n * Compute the DNS name to query for a (target, list) pair, honoring the\n * per-list peculiarities:\n * - IPv4: reverse octets and prepend.\n * - IPv6: reverse nibble-by-nibble per RFC 5782.\n * - Domain on a registrable-only list (SURBL/URIBL): collapse to eTLD+1.\n *\n * Returns null when the target shape isn't supported by the list (e.g.,\n * IPv4-only list given an IPv6 target).\n */\nfunction buildQueryName(target: string, kind: DnsblTargetKind, listHost: string): string | null {\n if (kind === 'ip') {\n const v = net.isIP(target)\n if (v === 4) return `${reverseIPv4(target)}.${listHost}`\n if (v === 6) return `${reverseIPv6Nibbles(target)}.${listHost}`\n return null\n }\n // Domain — collapse to registrable label for lists that demand it.\n const domain = REGISTRABLE_ONLY_LISTS.has(listHost) ? registrableDomain(target) : target\n return `${domain}.${listHost}`\n}\n\ninterface QueryResult {\n /** When true, the underlying DNS query failed transiently (SERVFAIL etc).\n * Caller should leave the existing row in place rather than overwrite it. */\n transient?: boolean\n result: DnsblResult\n returnCodes: string[]\n errorMessage: string | null\n}\n\n// Transient DNS errors we don't want to treat as a \"list error\" — these\n// indicate a resolver problem or rate-limit at the block-list side and\n// should be retried next tick rather than producing a setup-status warn.\nconst TRANSIENT_DNS_CODES = new Set(['ESERVFAIL', 'EREFUSED', 'ETIMEOUT', 'ETIMEDOUT', 'ECONNRESET', 'ECONNREFUSED'])\n\nasync function queryDnsbl(resolver: Resolver, query: string): Promise<QueryResult> {\n try {\n const records = await resolver.resolve4(query)\n return interpretRecords(records)\n } catch (err: any) {\n const code = err?.code\n // NXDOMAIN / no records → not listed.\n if (code === 'ENOTFOUND' || code === 'ENODATA') {\n return { result: 'clean', returnCodes: [], errorMessage: null }\n }\n // Transient: signal the runner to skip the upsert. Spamhaus and friends\n // SERVFAIL when rate-limiting public resolvers; storing those as 'error'\n // produces setup-status warn churn without operator-actionable signal.\n if (code && TRANSIENT_DNS_CODES.has(code)) {\n return {\n transient: true,\n result: 'error',\n returnCodes: [],\n errorMessage: String(err?.message ?? err),\n }\n }\n return {\n result: 'error',\n returnCodes: [],\n errorMessage: String(err?.message ?? err),\n }\n }\n}\n\nexport function interpretRecords(records: string[]): QueryResult {\n if (!records || records.length === 0) {\n return { result: 'clean', returnCodes: [], errorMessage: null }\n }\n // Per Spamhaus convention, 127.255.255.x is reserved for query-error /\n // public-resolver / blocked-by-list signals. Treat those as errors so they\n // don't false-positive a \"listed\" verdict.\n const errorish = records.filter((r) => r.startsWith('127.255.255.'))\n if (errorish.length === records.length) {\n return {\n result: 'error',\n returnCodes: records,\n errorMessage: `list returned reserved code(s): ${records.join(', ')}`,\n }\n }\n const listed = records.filter((r) => r.startsWith('127.') && !r.startsWith('127.255.255.'))\n if (listed.length > 0) {\n return { result: 'listed', returnCodes: records, errorMessage: null }\n }\n return { result: 'clean', returnCodes: records, errorMessage: null }\n}\n\nexport function reverseIPv4(ip: string): string {\n return ip.split('.').reverse().join('.')\n}\n\n/**\n * RFC 5782 §2.4 nibble-reversed form for IPv6. Each hex digit becomes its\n * own label in reverse order. Example:\n * 2001:db8::1\n * → 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2\n *\n * Handles IPv4-mapped form (`::ffff:1.2.3.4`) by converting the embedded\n * dot-octet portion into two hex groups before nibble-expanding.\n */\nexport function reverseIPv6Nibbles(ip: string): string {\n // First convert any embedded IPv4 (\"::ffff:1.2.3.4\" → \"::ffff:0102:0304\").\n const v4Match = /:(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})$/.exec(ip)\n let normalized = ip\n if (v4Match) {\n const octets = v4Match[1]!.split('.').map((o) => Number(o))\n if (octets.length === 4 && octets.every((o) => o >= 0 && o <= 255)) {\n const hi = ((octets[0]! << 8) | octets[1]!).toString(16).padStart(4, '0')\n const lo = ((octets[2]! << 8) | octets[3]!).toString(16).padStart(4, '0')\n normalized = ip.slice(0, v4Match.index) + ':' + hi + ':' + lo\n }\n }\n\n // Expand `::` shorthand and zero-pad each group to 4 chars.\n const sides = normalized.split('::')\n let groups: string[]\n if (sides.length === 1) {\n groups = sides[0]!.split(':')\n } else {\n const left = sides[0]!.split(':').filter(Boolean)\n const right = sides[1]!.split(':').filter(Boolean)\n const missing = 8 - left.length - right.length\n groups = [...left, ...Array(missing).fill('0'), ...right]\n }\n if (groups.length !== 8) {\n throw new Error(`unexpected IPv6 group count for ${ip}: ${groups.length}`)\n }\n const padded = groups.map((g) => g.toLowerCase().padStart(4, '0')).join('')\n return padded.split('').reverse().join('.')\n}\n\n/**\n * Public Suffix List-aware eTLD+1 extraction. Required for SURBL / URIBL\n * which need the registrable domain — `mail.example.co.uk` must collapse to\n * `example.co.uk`, not `co.uk`. Falls back to the original input when PSL\n * can't classify the domain (e.g., a private TLD).\n */\nfunction registrableDomain(domain: string): string {\n const parsed = psl.parse(domain)\n if ('domain' in parsed && parsed.domain) return parsed.domain\n return domain\n}\n","/**\n * Google Postmaster Tools API client + daily puller.\n *\n * - Exchanges the operator-provided OAuth refresh token for short-lived\n * access tokens (cached until ~5 minutes before expiry).\n * - Pulls per-domain TrafficStats for each registered sender domain.\n * - Persists one PostmasterSnapshot per (domain, day).\n * - When a snapshot reports `domainReputation: 'BAD'`, trips the\n * (domain × marketing) health bucket so the runner stops dispatching\n * marketing mail from that domain.\n *\n * Setup is one-time and external — operator creates an OAuth client in their\n * own Google Cloud project, performs the consent flow, and configures the\n * refresh token in MailerConfig.postmaster.\n */\n\nimport type { PostmasterConfig } from '../config.js'\nimport type {\n PostmasterReputation,\n PostmasterSnapshotDoc,\n} from '../models/index.js'\nimport { extractDomain } from '../templates/sender-domain.js'\nimport type { RunnerContext } from './index.js'\nimport { healthBucketId } from '../models/index.js'\n\nconst OAUTH_TOKEN_URL = 'https://oauth2.googleapis.com/token'\nconst POSTMASTER_BASE = 'https://gmailpostmastertools.googleapis.com/v1'\nconst FETCH_TIMEOUT_MS = 15_000\n\nexport type Fetcher = (url: string, init?: RequestInit) => Promise<Response>\n\nasync function fetchWithTimeout(fetcher: Fetcher, url: string, init: RequestInit = {}, timeoutMs = FETCH_TIMEOUT_MS): Promise<Response> {\n const ctl = new AbortController()\n const t = setTimeout(() => ctl.abort(), timeoutMs)\n try {\n return await fetcher(url, { ...init, signal: ctl.signal })\n } finally {\n clearTimeout(t)\n }\n}\n\nexport interface PostmasterClient {\n listDomains(): Promise<Array<{ name: string; createTime?: string }>>\n getLatestTrafficStats(domain: string): Promise<TrafficStat | null>\n}\n\ninterface OAuthResponse {\n access_token: string\n expires_in: number\n scope?: string\n token_type?: string\n}\n\nexport interface TrafficStat {\n /** Resource name, e.g. `domains/example.com/trafficStats/20240101`. */\n name: string\n domainReputation?: PostmasterReputation\n ipReputations?: Array<{ reputation: PostmasterReputation; ipCount: string | number }>\n userReportedSpamRatio?: number\n spfSuccessRatio?: number\n dkimSuccessRatio?: number\n dmarcSuccessRatio?: number\n inboundEncryptionRatio?: number\n outboundEncryptionRatio?: number\n deliveryErrors?: Array<{ errorType: string; errorClass: string; errorRatio: number }>\n spammyFeedbackLoops?: Array<{ id: string; spamRatio: number }>\n}\n\nexport function createPostmasterClient(\n cfg: Pick<PostmasterConfig, 'clientId' | 'clientSecret' | 'refreshToken'>,\n fetcher: Fetcher = globalThis.fetch,\n): PostmasterClient {\n let cached: { accessToken: string; expiresAt: number } | null = null\n\n async function getAccessToken(): Promise<string> {\n if (cached && cached.expiresAt > Date.now() + 5 * 60 * 1000) {\n return cached.accessToken\n }\n const body = new URLSearchParams({\n client_id: cfg.clientId,\n client_secret: cfg.clientSecret,\n refresh_token: cfg.refreshToken,\n grant_type: 'refresh_token',\n })\n const res = await fetchWithTimeout(fetcher, OAUTH_TOKEN_URL, {\n method: 'POST',\n headers: { 'content-type': 'application/x-www-form-urlencoded' },\n body: body.toString(),\n })\n if (!res.ok) {\n throw new Error(`Postmaster OAuth token refresh failed: ${res.status} ${await safeText(res)}`)\n }\n const data = (await res.json()) as OAuthResponse\n cached = {\n accessToken: data.access_token,\n expiresAt: Date.now() + data.expires_in * 1000,\n }\n return cached.accessToken\n }\n\n async function authedGet<T>(path: string): Promise<T> {\n const token = await getAccessToken()\n const res = await fetchWithTimeout(fetcher, `${POSTMASTER_BASE}${path}`, {\n method: 'GET',\n headers: { authorization: `Bearer ${token}` },\n })\n if (!res.ok) {\n throw new Error(`Postmaster GET ${path} failed: ${res.status} ${await safeText(res)}`)\n }\n return (await res.json()) as T\n }\n\n return {\n async listDomains() {\n const data = await authedGet<{ domains?: Array<{ name: string; createTime?: string }> }>('/domains')\n return data.domains ?? []\n },\n\n async getLatestTrafficStats(domain: string) {\n // Postmaster traffic stats are reported with a ~2-day delay. Pull the\n // most recent available; the API returns them in reverse-chronological\n // order when no date range is specified.\n const data = await authedGet<{ trafficStats?: TrafficStat[] }>(\n `/domains/${encodeURIComponent(domain)}/trafficStats?pageSize=1`,\n )\n return data.trafficStats?.[0] ?? null\n },\n }\n}\n\nasync function safeText(res: Response): Promise<string> {\n try {\n return await res.text()\n } catch {\n return '<no body>'\n }\n}\n\n// ---------------------------------------------------------------------------\n// Puller\n// ---------------------------------------------------------------------------\n\nexport interface RunPostmasterOptions {\n client?: PostmasterClient\n fetcher?: Fetcher\n force?: boolean\n}\n\nexport interface RunPostmasterResult {\n ran: boolean\n reason?: string\n fetched?: number\n trippedDomains?: string[]\n}\n\nexport async function runPostmasterPull(\n ctx: RunnerContext,\n opts: RunPostmasterOptions = {},\n): Promise<RunPostmasterResult> {\n const cfg = ctx.config.postmaster\n if (!cfg) return { ran: false, reason: 'not_configured' }\n\n const intervalHours = cfg.intervalHours ?? 24\n if (!opts.force && intervalHours <= 0) {\n return { ran: false, reason: 'disabled' }\n }\n\n const client =\n opts.client ?? createPostmasterClient(cfg, opts.fetcher)\n const allDomains = resolveDomains(ctx, cfg)\n if (allDomains.length === 0) {\n return { ran: false, reason: 'no_domains' }\n }\n\n // Per-domain throttle — fetch only domains whose latest snapshot is\n // older than intervalHours. Previously a single global timestamp across\n // all domains locked unfetched / partially-failed domains out of the\n // next run for a full window.\n let domains = allDomains\n if (!opts.force) {\n const cutoff = Date.now() - intervalHours * 60 * 60 * 1000\n const latest = await ctx.collections.postmasterSnapshots\n .find({ domain: { $in: allDomains } }, { projection: { domain: 1, fetchedAt: 1 } })\n .sort({ fetchedAt: -1 })\n .limit(allDomains.length * 8)\n .toArray()\n const lastByDomain = new Map<string, number>()\n for (const s of latest) {\n const ts = new Date(s.fetchedAt).getTime()\n const cur = lastByDomain.get(s.domain) ?? 0\n if (ts > cur) lastByDomain.set(s.domain, ts)\n }\n domains = allDomains.filter((d) => (lastByDomain.get(d) ?? 0) < cutoff)\n if (domains.length === 0) {\n return { ran: false, reason: 'not_due' }\n }\n }\n\n // Fetch all domains in parallel — they're independent HTTP calls and\n // serial ordering only multiplies tick latency.\n const fetches = await Promise.all(\n domains.map(async (domain) => {\n try {\n const stat = await client.getLatestTrafficStats(domain)\n return { domain, stat, error: null as Error | null }\n } catch (err: any) {\n console.error(`mailery: postmaster fetch failed for ${domain}`, err)\n return { domain, stat: null, error: err as Error }\n }\n }),\n )\n\n let fetched = 0\n const trippedDomains: string[] = []\n for (const { domain, stat } of fetches) {\n if (!stat) continue\n const snapshot = toSnapshot(domain, stat)\n if (!snapshot) continue\n fetched++\n\n await ctx.collections.postmasterSnapshots.updateOne(\n { domain: snapshot.domain, date: snapshot.date },\n { $set: snapshot },\n { upsert: true },\n )\n\n if (snapshot.domainReputation === 'BAD') {\n // Trip every kind the registry says this domain is allowed to send\n // as. If the registry doesn't know this domain at all, skip the\n // auto-trip — we have no signal that the operator wants this domain\n // gated by mailery.\n const kindsToTrip = kindsForDomain(ctx, domain)\n for (const kind of kindsToTrip) {\n const tripped = await tripBucket(ctx, domain, kind, snapshot)\n if (tripped) trippedDomains.push(`${domain}|${kind}`)\n }\n }\n }\n\n return { ran: true, fetched, trippedDomains }\n}\n\nfunction kindsForDomain(ctx: RunnerContext, domain: string): Array<'marketing' | 'transactional'> {\n const registry = ctx.config.senderDomains ?? {}\n const entry = registry[domain.toLowerCase()]\n if (!entry) return []\n if (entry.kind === 'both') return ['marketing', 'transactional']\n return [entry.kind]\n}\n\nfunction resolveDomains(ctx: RunnerContext, cfg: PostmasterConfig): string[] {\n if (cfg.domains && cfg.domains.length > 0) {\n return cfg.domains.map((d) => d.toLowerCase())\n }\n const out = new Set<string>()\n const registry = ctx.config.senderDomains\n if (registry) {\n for (const d of Object.keys(registry)) out.add(d.toLowerCase())\n }\n const f = ctx.config.fromDefaults?.email ? extractDomain(ctx.config.fromDefaults.email) : null\n if (f) out.add(f)\n const t = ctx.config.transactionalFromDefaults?.email\n ? extractDomain(ctx.config.transactionalFromDefaults.email)\n : null\n if (t) out.add(t)\n return Array.from(out)\n}\n\nfunction toSnapshot(domain: string, stat: TrafficStat): PostmasterSnapshotDoc | null {\n // `name` looks like `domains/example.com/trafficStats/20240115`. Bail out\n // when the format isn't recognized rather than overwriting today's snapshot\n // every run — the previous fallback to today's UTC date silently rewrote\n // legitimate data when the API format ever drifted.\n const m = /\\/trafficStats\\/(\\d{8})$/.exec(stat.name ?? '')\n if (!m) {\n console.error(`mailery: postmaster snapshot for ${domain} has unrecognized name \"${stat.name}\" — skipping`)\n return null\n }\n const yyyymmdd = m[1]!\n const date = `${yyyymmdd.slice(0, 4)}-${yyyymmdd.slice(4, 6)}-${yyyymmdd.slice(6, 8)}`\n\n return {\n domain,\n date,\n domainReputation: stat.domainReputation ?? null,\n ipReputations: stat.ipReputations\n ? stat.ipReputations.map((r) => ({\n reputation: r.reputation,\n ipCount: typeof r.ipCount === 'string' ? Number(r.ipCount) : r.ipCount,\n }))\n : null,\n userReportedSpamRatio: stat.userReportedSpamRatio ?? null,\n spfSuccessRatio: stat.spfSuccessRatio ?? null,\n dkimSuccessRatio: stat.dkimSuccessRatio ?? null,\n dmarcSuccessRatio: stat.dmarcSuccessRatio ?? null,\n outboundEncryptionRatio: stat.outboundEncryptionRatio ?? null,\n inboundEncryptionRatio: stat.inboundEncryptionRatio ?? null,\n deliveryErrors: stat.deliveryErrors ?? null,\n spammyFeedbackLoops: stat.spammyFeedbackLoops ?? null,\n fetchedAt: new Date(),\n }\n}\n\n/**\n * Set a (domain × kind) bucket to `tripped` so the dispatcher holds matching\n * sends. The bucket is created on demand if it doesn't exist yet — Postmaster\n * can flag a domain before mailery has ever sent from it.\n */\nasync function tripBucket(\n ctx: RunnerContext,\n domain: string,\n kind: 'marketing' | 'transactional',\n snapshot: PostmasterSnapshotDoc,\n): Promise<boolean> {\n const id = healthBucketId(domain, kind)\n const reason = `Postmaster Tools reports ${domain} reputation = BAD on ${snapshot.date}`\n\n // Only update + alert when the bucket transitions to tripped — otherwise a\n // sustained BAD reputation would fire onCircuitBreakerTrip on every pull.\n const prior = await ctx.collections.health.findOne({ _id: id })\n if (prior?.status === 'tripped') {\n return false\n }\n\n await ctx.collections.health.updateOne(\n { _id: id },\n {\n $set: {\n status: 'tripped',\n trippedAt: new Date(),\n trippedReason: reason,\n updatedAt: new Date(),\n },\n $setOnInsert: {\n _id: id,\n senderDomain: domain,\n kind,\n windowStartedAt: new Date(),\n windowDurationMs: ctx.config.circuitBreaker.windowMinutes * 60 * 1000,\n manuallyResumedAt: null,\n counters: { sent: 0, delivered: 0, bounced: 0, hardBounced: 0, softBounced: 0, complained: 0, failedToSend: 0 },\n rates: { bounceRate: 0, hardBounceRate: 0, complaintRate: 0, failureRate: 0 },\n },\n },\n { upsert: true },\n )\n if (ctx.config.onCircuitBreakerTrip) {\n try {\n await ctx.config.onCircuitBreakerTrip({ reason, rates: { userReportedSpamRatio: snapshot.userReportedSpamRatio ?? 0 } })\n } catch {\n /* swallow */\n }\n }\n return true\n}\n","/**\n * Microsoft SNDS (Smart Network Data Services) puller.\n *\n * https://sendersupport.olc.protection.outlook.com/snds/\n *\n * SNDS reports IP-level Outlook/Hotmail/Live reputation: filter verdict\n * (GREEN/YELLOW/RED), complaint rate, spam-trap hits, and sample HELO /\n * MAIL FROM strings for each activity window. Only meaningful when the\n * operator sends from a dedicated IP — shared-IP senders see nothing\n * meaningful here.\n *\n * Auth is a per-account access key (no OAuth). The data endpoint returns\n * CSV. Snapshots are stored per (ip, activityStart) so historical windows\n * accumulate.\n */\n\nimport type { SndsConfig } from '../config.js'\nimport type { SndsFilterResult, SndsSnapshotDoc } from '../models/index.js'\nimport type { RunnerContext } from './index.js'\n\nconst SNDS_DATA_URL = 'https://postmaster.live.com/snds/data.aspx'\nconst FETCH_TIMEOUT_MS = 30_000\n\nexport type Fetcher = (url: string, init?: RequestInit) => Promise<Response>\n\nexport interface RunSndsOptions {\n fetcher?: Fetcher\n force?: boolean\n}\n\nexport interface RunSndsResult {\n ran: boolean\n reason?: string\n rowsParsed?: number\n rowsPersisted?: number\n}\n\nexport async function runSndsPull(\n ctx: RunnerContext,\n opts: RunSndsOptions = {},\n): Promise<RunSndsResult> {\n const cfg = ctx.config.snds\n if (!cfg?.accessKey) return { ran: false, reason: 'not_configured' }\n\n const intervalHours = cfg.intervalHours ?? 24\n if (!opts.force && intervalHours <= 0) return { ran: false, reason: 'disabled' }\n\n if (!opts.force) {\n const latest = await ctx.collections.sndsSnapshots\n .find({})\n .sort({ fetchedAt: -1 })\n .limit(1)\n .toArray()\n if (latest[0]) {\n const ageMs = Date.now() - new Date(latest[0].fetchedAt).getTime()\n if (ageMs < intervalHours * 60 * 60 * 1000) {\n return { ran: false, reason: 'not_due' }\n }\n }\n }\n\n const fetcher = opts.fetcher ?? globalThis.fetch\n const url = `${SNDS_DATA_URL}?key=${encodeURIComponent(cfg.accessKey)}`\n const ctl = new AbortController()\n const t = setTimeout(() => ctl.abort(), FETCH_TIMEOUT_MS)\n let res: Response\n try {\n res = await fetcher(url, { method: 'GET', signal: ctl.signal })\n } catch (err: any) {\n // Scrub the access key from any error message before it reaches a log.\n throw new Error(`SNDS data fetch failed: ${redactKey(String(err?.message ?? err), cfg.accessKey)}`)\n } finally {\n clearTimeout(t)\n }\n if (!res.ok) {\n throw new Error(`SNDS data fetch failed: ${res.status} ${redactKey(await safeText(res), cfg.accessKey)}`)\n }\n const csv = await res.text()\n const rows = parseSndsCsv(csv)\n\n const ipFilter = cfg.ips?.length ? new Set(cfg.ips) : null\n const now = new Date()\n const ops = rows\n .filter((row) => !ipFilter || ipFilter.has(row.ip))\n .map((row) => ({\n updateOne: {\n filter: { ip: row.ip, activityStart: row.activityStart },\n update: { $set: { ...row, fetchedAt: now } },\n upsert: true,\n },\n }))\n let persisted = 0\n if (ops.length > 0) {\n const r = await ctx.collections.sndsSnapshots.bulkWrite(ops, { ordered: false })\n persisted = (r.modifiedCount ?? 0) + (r.upsertedCount ?? 0)\n }\n\n return { ran: true, rowsParsed: rows.length, rowsPersisted: persisted }\n}\n\nfunction redactKey(s: string, key: string): string {\n if (!key) return s\n return s.split(key).join('<redacted>').split(encodeURIComponent(key)).join('<redacted>')\n}\n\nasync function safeText(res: Response): Promise<string> {\n try { return await res.text() } catch { return '<no body>' }\n}\n\n// ---------------------------------------------------------------------------\n// CSV parsing\n// ---------------------------------------------------------------------------\n\nexport interface ParsedSndsRow {\n ip: string\n activityStart: Date\n activityEnd: Date\n rcptCommands: number\n dataCommands: number\n messageRecipients: number\n filterResult: SndsFilterResult\n complaintRate: number | null\n trapMessageCount: number\n sampleHelo: string | null\n sampleMailFrom: string | null\n}\n\n/**\n * SNDS returns CSV with columns:\n * IP, ActivityStart, ActivityEnd, RCPTCommands, DATACommands,\n * MessageRecipients, FilterResult, ComplaintRate, TrapMessageCount,\n * SampleHELO, SampleMailFrom\n *\n * No header row. Fields may contain commas inside quoted strings (sample\n * HELO / MAIL FROM) — we handle simple double-quote escaping.\n */\nexport function parseSndsCsv(csv: string): ParsedSndsRow[] {\n const out: ParsedSndsRow[] = []\n for (const raw of csv.split(/\\r?\\n/)) {\n if (!raw.trim()) continue\n const fields = splitCsvRow(raw)\n if (fields.length < 7) continue // malformed row\n const parsed = parseRow(fields)\n if (parsed) out.push(parsed)\n }\n return out\n}\n\nfunction splitCsvRow(row: string): string[] {\n const out: string[] = []\n let cur = ''\n let inQuotes = false\n for (let i = 0; i < row.length; i++) {\n const ch = row[i]!\n if (inQuotes) {\n if (ch === '\"') {\n if (row[i + 1] === '\"') {\n cur += '\"'\n i++\n } else {\n inQuotes = false\n }\n } else {\n cur += ch\n }\n } else if (ch === '\"') {\n inQuotes = true\n } else if (ch === ',') {\n out.push(cur)\n cur = ''\n } else {\n cur += ch\n }\n }\n out.push(cur)\n return out.map((f) => f.trim())\n}\n\nfunction parseRow(fields: string[]): ParsedSndsRow | null {\n const [\n ip,\n activityStart,\n activityEnd,\n rcptCommands,\n dataCommands,\n messageRecipients,\n filterResult,\n complaintRate,\n trapMessageCount,\n sampleHelo,\n sampleMailFrom,\n ] = fields\n\n const start = parseSndsDate(activityStart ?? '')\n const end = parseSndsDate(activityEnd ?? '')\n if (!ip || !start || !end) return null\n\n return {\n ip,\n activityStart: start,\n activityEnd: end,\n rcptCommands: toInt(rcptCommands),\n dataCommands: toInt(dataCommands),\n messageRecipients: toInt(messageRecipients),\n filterResult: normalizeFilter(filterResult ?? ''),\n complaintRate: parseComplaintRate(complaintRate ?? ''),\n trapMessageCount: toInt(trapMessageCount),\n sampleHelo: sampleHelo ? sampleHelo : null,\n sampleMailFrom: sampleMailFrom ? sampleMailFrom : null,\n }\n}\n\nfunction toInt(s: string | undefined): number {\n if (!s) return 0\n const n = Number(s.replace(/[^\\d-]/g, ''))\n return Number.isFinite(n) ? n : 0\n}\n\nfunction normalizeFilter(s: string): SndsFilterResult {\n const u = s.toUpperCase().trim()\n if (u === 'GREEN' || u === 'YELLOW' || u === 'RED') return u\n return 'UNKNOWN'\n}\n\n/**\n * SNDS reports complaint rate in the formats: `<0.1%`, `0.1-0.3%`, `0.3-0.5%`,\n * `0.5-1%`, `1-2%`, `2-4%`, `>4%`. We persist the upper bound as a 0-1 fraction.\n */\nexport function parseComplaintRate(s: string): number | null {\n const trimmed = s.trim()\n if (!trimmed || trimmed === '-' || /n\\/?a/i.test(trimmed)) return null\n\n const cleaned = trimmed.replace(/%/g, '')\n // `<X` → X\n let m = /^<\\s*(\\d+(?:\\.\\d+)?)$/.exec(cleaned)\n if (m) return Number(m[1]) / 100\n // `>X` → X (lower bound; treat as the floor of what they're reporting)\n m = /^>\\s*(\\d+(?:\\.\\d+)?)$/.exec(cleaned)\n if (m) return Number(m[1]) / 100\n // `A-B` → B\n m = /^(\\d+(?:\\.\\d+)?)\\s*-\\s*(\\d+(?:\\.\\d+)?)$/.exec(cleaned)\n if (m) return Number(m[2]) / 100\n // Plain number\n m = /^(\\d+(?:\\.\\d+)?)$/.exec(cleaned)\n if (m) return Number(m[1]) / 100\n return null\n}\n\n/**\n * SNDS reports dates as `M/D/YYYY h:mm AM/PM` in Microsoft's Pacific time\n * (PST/PDT) — Microsoft's own docs are silent but community testing\n * consistently shows Pacific. Convert to UTC by applying the offset that\n * was in effect at that local timestamp.\n *\n * Daylight saving in the US runs second-Sunday-of-March → first-Sunday-of-\n * November. We compute the offset based on the parsed local-Pacific\n * timestamp; a fixed -8/-7 offset would be wrong around the boundaries.\n */\nexport function parseSndsDate(s: string): Date | null {\n const trimmed = s.trim()\n if (!trimmed) return null\n const m = /^(\\d{1,2})\\/(\\d{1,2})\\/(\\d{4})\\s+(\\d{1,2}):(\\d{2})(?::(\\d{2}))?\\s*(AM|PM)?$/i.exec(trimmed)\n if (m) {\n const month = Number(m[1]) - 1\n const day = Number(m[2])\n const year = Number(m[3])\n let hour = Number(m[4])\n const minute = Number(m[5])\n const second = Number(m[6] ?? 0)\n const meridiem = m[7]?.toUpperCase()\n if (meridiem === 'PM' && hour < 12) hour += 12\n if (meridiem === 'AM' && hour === 12) hour = 0\n // First place the wall-clock instant in UTC, then add the Pacific\n // offset to convert back to a real UTC moment.\n const wallMs = Date.UTC(year, month, day, hour, minute, second)\n if (!Number.isFinite(wallMs)) return null\n const offsetHours = isUsPacificDst(year, month, day) ? 7 : 8\n return new Date(wallMs + offsetHours * 60 * 60 * 1000)\n }\n // Fallback: ISO-ish strings get parsed as expected by Date.\n const d = new Date(trimmed)\n if (!isNaN(d.getTime())) return d\n return null\n}\n\n/**\n * US daylight saving runs from the second Sunday of March through the\n * first Sunday of November. Pure date math against the wall-clock day —\n * close enough for SNDS export granularity (full-day activity windows).\n */\nfunction isUsPacificDst(year: number, month0: number, day: number): boolean {\n if (month0 > 2 && month0 < 10) return true\n if (month0 < 2 || month0 > 10) return false\n // March: starts on second Sunday.\n if (month0 === 2) {\n const dst = nthSundayOfMonth(year, 2, 2)\n return day >= dst\n }\n // November: ends on first Sunday.\n const dst = nthSundayOfMonth(year, 10, 1)\n return day < dst\n}\n\nfunction nthSundayOfMonth(year: number, month0: number, n: number): number {\n const first = new Date(Date.UTC(year, month0, 1))\n const dayOfWeek = first.getUTCDay()\n const firstSunday = 1 + ((7 - dayOfWeek) % 7)\n return firstSunday + (n - 1) * 7\n}\n","/**\n * DMARC RUA aggregate report ingestion.\n *\n * - extractDmarcXml(buffer, filename) — decompresses .zip / .gz / .xml\n * - parseDmarcReport(xml) — pure RFC 7489 XML → normalized doc + failures\n * - ingestDmarcAttachment(ctx, buffer, filename) — full ingest path:\n * extract → parse → upsert into mailer_dmarc_reports + _dmarc_failures\n *\n * Designed so the same `ingestDmarcAttachment` is used by:\n * - the admin file-upload endpoint\n * - the (future) SendGrid Inbound Parse webhook\n * - the (future) IMAP poller\n * - the `mailery ingest-dmarc` CLI\n */\n\n// `adm-zip` is still loaded lazily — `extractDmarcXmls` is already async, so\n// `await import()` costs nothing and compiles correctly under both output\n// formats.\n//\n// `fast-xml-parser` is NOT lazy. `parseDmarcReport` is synchronous, so the\n// only lazy form available to it was `require()`, and tsup compiles that to\n// esbuild's `__require` shim, which throws unconditionally in the ESM output\n// of a `\"type\": \"module\"` package. That shipped broken in v0.14.0 (see #12).\n// A static import is the one form that is correct in both the esm and cjs\n// bundles. The cost is ~25ms of module init at import time (against ~360ms\n// for the bundle as a whole) for a package that is a hard, non-optional\n// dependency and is therefore always installed anyway.\nimport type AdmZipType from 'adm-zip'\nimport { XMLParser } from 'fast-xml-parser'\n\nimport type {\n DmarcAuthResult,\n DmarcFailureDoc,\n DmarcPolicy,\n DmarcReportDoc,\n} from '../models/index.js'\nimport type { RunnerContext } from './index.js'\n\n/**\n * Hard cap on decompressed bytes. A real RUA aggregate report is well under\n * 1 MB; anything above this is either malformed or an attempted zip bomb.\n */\nconst MAX_DECOMPRESSED_BYTES = 50 * 1024 * 1024\n\n/**\n * Reject zip entry names that would escape the extraction directory if we\n * were writing them to disk, plus null-byte injection. We only ever read\n * the buffer in memory, but defense-in-depth keeps us safe if the storage\n * model changes.\n */\nexport function assertSafeZipEntryName(rawName: string): void {\n if (typeof rawName !== 'string' || rawName.length === 0) {\n throw new Error(`zip entry has unsafe path: <empty>`)\n }\n if (rawName.includes('\\0')) {\n throw new Error(`zip entry has unsafe path: contains null byte`)\n }\n // POSIX absolute (`/etc/passwd`) or Windows-drive (`C:\\…`) paths.\n if (rawName.startsWith('/') || rawName.startsWith('\\\\') || /^[a-zA-Z]:[\\\\/]/.test(rawName)) {\n throw new Error(`zip entry has unsafe path: ${rawName}`)\n }\n const parts = rawName.split(/[/\\\\]/)\n if (parts.some((p) => p === '..')) {\n throw new Error(`zip entry has unsafe path: ${rawName}`)\n }\n}\n\n// ---------------------------------------------------------------------------\n// Extraction\n// ---------------------------------------------------------------------------\n\n/**\n * Pull DMARC XML payload(s) out of an attachment. Receivers send `.zip` or\n * `.gz` (or rarely a bare `.xml`). A multi-file zip returns each entry as a\n * separate string — concatenating them with `\\n` produces invalid XML with\n * two `<feedback>` roots.\n *\n * Defends against:\n * - decompression bombs — caps inflated bytes at MAX_DECOMPRESSED_BYTES\n * - zip-slip path traversal — rejects entries with absolute or `..` paths\n * - empty / malformed archives — throws with a useful message\n */\nexport async function extractDmarcXmls(buffer: Buffer, filename: string): Promise<string[]> {\n const lower = (filename ?? '').toLowerCase()\n const zlib = await import('node:zlib')\n\n if (lower.endsWith('.gz')) {\n const xml = await new Promise<string>((resolve, reject) => {\n const chunks: Buffer[] = []\n let bytes = 0\n const stream = zlib.createGunzip()\n stream.on('data', (chunk: Buffer) => {\n bytes += chunk.length\n if (bytes > MAX_DECOMPRESSED_BYTES) {\n stream.destroy()\n reject(new Error(`DMARC gzip exceeds ${MAX_DECOMPRESSED_BYTES} bytes (decompression bomb?)`))\n return\n }\n chunks.push(chunk)\n })\n stream.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')))\n stream.on('error', reject)\n stream.end(buffer)\n })\n return [xml]\n }\n\n if (lower.endsWith('.zip')) {\n const { default: AdmZip } = await import('adm-zip')\n const zip = new (AdmZip as unknown as typeof AdmZipType)(buffer)\n const entries = zip.getEntries().filter((e) => !e.isDirectory)\n if (entries.length === 0) throw new Error('zip contains no files')\n\n let total = 0\n const pieces: string[] = []\n for (const entry of entries) {\n // Zip-slip defense — adm-zip has had CVE history (CVE-2018-1002204).\n assertSafeZipEntryName(entry.entryName)\n\n // Declared size is the fast-path bail — reject before decompressing\n // when a (truthful) header already exceeds the cap. Reject entries\n // with no declared size at all (DMARC receivers always populate it).\n const declaredSize = (entry.header as any)?.size\n if (typeof declaredSize !== 'number' || declaredSize <= 0) {\n throw new Error(`zip entry ${entry.entryName} has no declared size (refusing to decompress)`)\n }\n if (declaredSize > MAX_DECOMPRESSED_BYTES || total + declaredSize > MAX_DECOMPRESSED_BYTES) {\n throw new Error(`DMARC zip exceeds ${MAX_DECOMPRESSED_BYTES} bytes (decompression bomb?)`)\n }\n\n // Actual decompressed payload — defends against a forged header that\n // claims a tiny size but inflates huge. We pay the inflation cost for\n // this entry, but cap on cumulative real bytes before the next entry.\n const data = entry.getData()\n total += data.length\n if (total > MAX_DECOMPRESSED_BYTES) {\n throw new Error(`DMARC zip decompressed payload exceeds ${MAX_DECOMPRESSED_BYTES} bytes (forged header?)`)\n }\n // Compression-ratio sanity check only kicks in on larger entries —\n // legitimate tiny XML inflates ~64x routinely. The cumulative cap\n // above already covers the real bomb scenarios for small entries.\n if (declaredSize > 10 * 1024 && data.length > declaredSize * 64 + 1024) {\n throw new Error(`DMARC zip entry ${entry.entryName} decompressed size (${data.length}) far exceeds declared (${declaredSize})`)\n }\n pieces.push(data.toString('utf8'))\n }\n return pieces\n }\n\n // Treat as raw XML — still cap by raw buffer size.\n if (buffer.length > MAX_DECOMPRESSED_BYTES) {\n throw new Error(`DMARC payload exceeds ${MAX_DECOMPRESSED_BYTES} bytes`)\n }\n return [buffer.toString('utf8')]\n}\n\n/**\n * Convenience wrapper for callers that handle a single report.\n * @deprecated prefer `extractDmarcXmls` so multi-file zips can be parsed\n * independently. Kept temporarily; remove once all callers migrate.\n */\nexport async function extractDmarcXml(buffer: Buffer, filename: string): Promise<string> {\n const xmls = await extractDmarcXmls(buffer, filename)\n return xmls.join('\\n')\n}\n\n// ---------------------------------------------------------------------------\n// XML parsing\n// ---------------------------------------------------------------------------\n\nexport interface ParsedDmarcReport {\n report: Omit<DmarcReportDoc, 'receivedAt'>\n failures: Array<Omit<DmarcFailureDoc, 'receivedAt'>>\n}\n\n/**\n * Parse RFC 7489 aggregate report XML. Tolerant — receivers vary slightly in\n * casing and field order. Throws if the XML can't be parsed at all or if\n * required identifiers (report_id, domain, date_range) are missing.\n */\nexport function parseDmarcReport(xml: string): ParsedDmarcReport {\n const parser = new XMLParser({\n ignoreAttributes: false,\n parseAttributeValue: false,\n parseTagValue: false,\n trimValues: true,\n // RFC 7489 specifies lowercase snake_case tag names, but some\n // less-careful receivers emit CamelCase. Normalize before lookup.\n transformTagName: (t: string) => t.toLowerCase(),\n })\n const root: any = parser.parse(xml)\n const fb = root?.feedback\n if (!fb) throw new Error('DMARC XML missing <feedback> root')\n\n const meta = fb.report_metadata ?? {}\n const policy = fb.policy_published ?? {}\n\n const reportId = String(meta.report_id ?? '').trim()\n const orgName = String(meta.org_name ?? '').trim()\n const email = String(meta.email ?? '').trim()\n const domain = String(policy.domain ?? '').trim().toLowerCase()\n const policyP = (policy.p ?? 'none') as DmarcPolicy\n const rawPct = Number(policy.pct ?? 100)\n // Use isFinite so pct=0 (legit \"monitor only\" config) survives.\n const policyPct = Number.isFinite(rawPct) ? Math.max(0, Math.min(100, rawPct)) : 100\n\n if (!reportId) throw new Error('DMARC XML missing report_id')\n if (!domain) throw new Error('DMARC XML missing policy_published.domain')\n\n const range = meta.date_range ?? {}\n const begin = secondsToDate(range.begin)\n const end = secondsToDate(range.end)\n if (!begin || !end) throw new Error('DMARC XML missing date_range')\n\n const records = toArray<any>(fb.record)\n const failures: ParsedDmarcReport['failures'] = []\n let totalMessages = 0\n let passCount = 0\n let failCount = 0\n\n // Day bucket = mid-point of the report window.\n const midMs = Math.floor((begin.getTime() + end.getTime()) / 2)\n const day = new Date(midMs).toISOString().slice(0, 10)\n\n for (const rec of records) {\n const row = rec?.row ?? {}\n const count = Number(row.count ?? 0) || 0\n totalMessages += count\n\n const evald = row.policy_evaluated ?? {}\n const dkim = (evald.dkim ?? 'none') as DmarcAuthResult\n const spf = (evald.spf ?? 'none') as DmarcAuthResult\n const aligned = dkim === 'pass' || spf === 'pass'\n\n if (aligned) {\n passCount += count\n continue\n }\n failCount += count\n\n const sourceIp = String(row.source_ip ?? '').trim()\n if (!sourceIp) continue\n const headerFrom = String(rec?.identifiers?.header_from ?? '').toLowerCase()\n const dispositionApplied = String(evald.disposition ?? 'none')\n\n failures.push({\n reportId,\n domain,\n sourceIp,\n count,\n headerFrom,\n dkimResult: dkim,\n spfResult: spf,\n dispositionApplied,\n day,\n })\n }\n\n return {\n report: {\n reportId,\n orgName,\n email,\n domain,\n policyP,\n policyPct,\n rangeStart: begin,\n rangeEnd: end,\n totalMessages,\n passCount,\n failCount,\n },\n failures,\n }\n}\n\nfunction secondsToDate(v: unknown): Date | null {\n if (v === undefined || v === null) return null\n const n = typeof v === 'number' ? v : Number(String(v))\n if (!Number.isFinite(n) || n <= 0) return null\n return new Date(n * 1000)\n}\n\nfunction toArray<T>(v: T | T[] | undefined | null): T[] {\n if (v === undefined || v === null) return []\n return Array.isArray(v) ? v : [v]\n}\n\n// ---------------------------------------------------------------------------\n// Persistence\n// ---------------------------------------------------------------------------\n\nexport interface IngestResult {\n ok: true\n reportId: string\n domain: string\n rangeStart: Date\n rangeEnd: Date\n totalMessages: number\n passCount: number\n failCount: number\n duplicate: boolean\n}\n\nexport interface IngestOptions {\n /**\n * Gate on the report's `<policy_published><domain>`, checked after parsing\n * and before any write.\n *\n * The admin upload leaves this unset: the caller is already a privileged\n * operator who chose the file. The public inbound route\n * (`api/dmarc-inbound.ts`) sets it, because that endpoint authenticates with\n * a shared secret and nothing else — if the secret leaks, this is what keeps\n * the blast radius at \"reports about domains you actually send from\" rather\n * than \"arbitrary rows in your DMARC dashboard\".\n */\n allowDomain?: (domain: string) => boolean\n}\n\n/**\n * Full ingest path: extract attachment → parse each XML payload → upsert\n * into mailer_dmarc_reports + mailer_dmarc_failures. Idempotent on\n * (reportId, orgName) — re-uploading the same report is a no-op. When the\n * attachment is a multi-file zip, each entry is parsed independently and\n * the first ingest result is returned (with `additionalReports` count).\n */\nexport async function ingestDmarcAttachment(\n ctx: RunnerContext,\n buffer: Buffer,\n filename: string,\n opts: IngestOptions = {},\n): Promise<IngestResult & { additionalReports?: number }> {\n const xmls = await extractDmarcXmls(buffer, filename)\n if (xmls.length === 0) throw new Error('attachment contained no XML payload')\n const results: IngestResult[] = []\n let firstError: unknown = null\n for (const xml of xmls) {\n try {\n const parsed = parseDmarcReport(xml)\n if (opts.allowDomain && !opts.allowDomain(parsed.report.domain)) {\n throw new Error(`DMARC report is for domain \"${parsed.report.domain}\", which this deployment does not send from`)\n }\n results.push(await ingestParsedDmarcReport(ctx, parsed))\n } catch (err) {\n if (!firstError) firstError = err\n // Continue ingesting siblings — one malformed report in a multi-file\n // archive shouldn't reject all valid siblings.\n }\n }\n if (results.length === 0) {\n throw firstError ?? new Error('no parseable DMARC reports in attachment')\n }\n return { ...results[0]!, additionalReports: results.length - 1 }\n}\n\nexport async function ingestParsedDmarcReport(\n ctx: RunnerContext,\n parsed: ParsedDmarcReport,\n): Promise<IngestResult> {\n const now = new Date()\n const { report, failures } = parsed\n\n // Race-safe duplicate detection — let the unique index on\n // (reportId, orgName) decide. The prior findOne→insertOne split admitted\n // a window where two concurrent uploads of the same report could both\n // succeed.\n let duplicate = false\n try {\n await ctx.collections.dmarcReports.insertOne({ ...report, receivedAt: now })\n } catch (err: any) {\n if (err?.code === 11000) {\n duplicate = true\n } else {\n throw err\n }\n }\n\n if (!duplicate && failures.length > 0) {\n // Idempotent: unique index on (reportId, sourceIp) — duplicates skipped.\n // BulkWriteError mixes real + duplicate-key errors; inspect each write\n // error and rethrow if any aren't 11000.\n try {\n await ctx.collections.dmarcFailures.insertMany(\n failures.map((f) => ({ ...f, receivedAt: now })),\n { ordered: false },\n )\n } catch (err: any) {\n const writeErrors: Array<{ code?: number }> | undefined = err?.writeErrors\n if (Array.isArray(writeErrors)) {\n const nonDup = writeErrors.find((w) => w?.code !== 11000)\n if (nonDup) throw err\n } else if (err?.code !== 11000) {\n throw err\n }\n }\n }\n\n return {\n ok: true,\n reportId: report.reportId,\n domain: report.domain,\n rangeStart: report.rangeStart,\n rangeEnd: report.rangeEnd,\n totalMessages: report.totalMessages,\n passCount: report.passCount,\n failCount: report.failCount,\n duplicate,\n }\n}\n\n// ---------------------------------------------------------------------------\n// Retention\n// ---------------------------------------------------------------------------\n\n// Throttle DMARC prune so it doesn't fire on every tick (60s default). Once\n// per hour is plenty — failure rows live for retentionDays (default 90).\nlet _lastPruneAt = 0\nconst PRUNE_INTERVAL_MS = 60 * 60 * 1000\n\nexport async function pruneDmarcFailures(ctx: RunnerContext, opts: { force?: boolean } = {}): Promise<number> {\n const cfg = ctx.config.dmarc\n const days = cfg?.retentionDays ?? 90\n if (days <= 0) return 0\n if (!opts.force && Date.now() - _lastPruneAt < PRUNE_INTERVAL_MS) return 0\n _lastPruneAt = Date.now()\n const cutoff = new Date(Date.now() - days * 86_400_000)\n const r = await ctx.collections.dmarcFailures.deleteMany({ receivedAt: { $lt: cutoff } })\n return r.deletedCount ?? 0\n}\n\n// ---------------------------------------------------------------------------\n// Source tags — merge config-defined + db-defined\n// ---------------------------------------------------------------------------\n\nexport interface ResolvedSourceTag {\n ip: string\n label: string\n ignored: boolean\n /** 'config' = read-only (set in MailerConfig), 'db' = mutable from UI. */\n source: 'config' | 'db'\n}\n\nexport async function resolveSourceTags(ctx: RunnerContext): Promise<Map<string, ResolvedSourceTag>> {\n const out = new Map<string, ResolvedSourceTag>()\n for (const t of ctx.config.dmarc?.knownSources ?? []) {\n out.set(t.ip, { ip: t.ip, label: t.label, ignored: !!t.ignored, source: 'config' })\n }\n // DB tags override config tags so the operator can re-label without redeploy.\n const dbTags = await ctx.collections.dmarcSourceTags.find({}).toArray()\n for (const t of dbTags) {\n out.set(t.ip, { ip: t.ip, label: t.label, ignored: t.ignored, source: 'db' })\n }\n return out\n}\n\n// ---------------------------------------------------------------------------\n// Policy progression suggestion\n// ---------------------------------------------------------------------------\n\nexport interface DomainProgression {\n domain: string\n currentPolicy: 'none' | 'quarantine' | 'reject' | null\n currentPct: number | null\n /** null when no suggestion (already at strictest, or insufficient data). */\n suggested: { policy: 'none' | 'quarantine' | 'reject'; pct: number; reason: string } | null\n}\n\n/**\n * Heuristic: walk through the DMARC ramp progression.\n * p=none → suggest p=quarantine pct=10 when last 30d alignment ≥99%\n * from non-ignored sources AND ≥30 reports AND ≥1k messages\n * p=quarantine pct<100 → ramp pct (10→25→50→100) when alignment stays high\n * p=quarantine pct=100 → suggest p=reject when alignment ≥99.9% for 14+ days\n * p=reject → no suggestion (already at strictest)\n *\n * Pure function so it's easy to unit-test.\n */\nexport interface ProgressionInput {\n reports: Array<{ rangeEnd: Date; passCount: number; failCount: number }>\n failures: Array<{ sourceIp: string; count: number; receivedAt: Date }>\n knownSourceIps: Set<string>\n ignoredSourceIps: Set<string>\n currentPolicy: 'none' | 'quarantine' | 'reject' | null\n currentPct: number | null\n}\n\nexport function suggestPolicyProgression(input: ProgressionInput): DomainProgression['suggested'] {\n const { reports, failures, knownSourceIps, ignoredSourceIps, currentPolicy, currentPct } = input\n\n if (currentPolicy === 'reject') return null\n\n const since30 = Date.now() - 30 * 86_400_000\n const recentReports = reports.filter((r) => r.rangeEnd.getTime() >= since30)\n const totalMsgs = recentReports.reduce((acc, r) => acc + r.passCount + r.failCount, 0)\n const totalPass = recentReports.reduce((acc, r) => acc + r.passCount, 0)\n\n if (recentReports.length < 30) return null\n if (totalMsgs < 1000) return null\n\n // Failures from untagged (and non-ignored) sources mean we don't yet know\n // who they are — never tighten policy until they're identified.\n const untaggedFailures = failures.filter(\n (f) => f.receivedAt.getTime() >= since30 && !knownSourceIps.has(f.sourceIp) && !ignoredSourceIps.has(f.sourceIp),\n )\n if (untaggedFailures.length > 0) return null\n\n const alignmentRate = totalMsgs === 0 ? 0 : totalPass / totalMsgs\n\n if (currentPolicy === null || currentPolicy === 'none') {\n if (alignmentRate >= 0.99) {\n return {\n policy: 'quarantine',\n pct: 10,\n reason: `${(alignmentRate * 100).toFixed(2)}% alignment over ${recentReports.length} reports / ${totalMsgs.toLocaleString()} messages, all known sources tagged.`,\n }\n }\n return null\n }\n\n if (currentPolicy === 'quarantine') {\n const pct = currentPct ?? 100\n if (alignmentRate < 0.995) return null\n if (pct < 25) return { policy: 'quarantine', pct: 25, reason: `Alignment held at ${(alignmentRate * 100).toFixed(2)}% — safe to ramp pct from ${pct} to 25.` }\n if (pct < 50) return { policy: 'quarantine', pct: 50, reason: `Alignment held at ${(alignmentRate * 100).toFixed(2)}% — safe to ramp pct from ${pct} to 50.` }\n if (pct < 100) return { policy: 'quarantine', pct: 100, reason: `Alignment held at ${(alignmentRate * 100).toFixed(2)}% — safe to ramp pct from ${pct} to 100.` }\n\n // pct=100 + alignment ≥99.9% for 14+ days → suggest reject\n if (alignmentRate >= 0.999) {\n return { policy: 'reject', pct: 100, reason: `Alignment at ${(alignmentRate * 100).toFixed(3)}% with policy=quarantine pct=100 — safe to move to p=reject.` }\n }\n }\n\n return null\n}\n","/**\n * The pending-unsubscribe journal — the on-disk half of INVARIANT 8.\n *\n * When `POST /m/unsub/:token` cannot reach Mongo, the opt-out is appended here\n * as one JSON object per line, and `runner/pending-unsubs.ts` replays it on a\n * later tick. Until v0.15 the write existed and the replay did not, so a\n * recipient who unsubscribed during a Mongo outage was told \"you are\n * unsubscribed\" and then kept receiving mail. That is a legal failure, not a\n * dropped metric.\n *\n * This module owns only the file: append, rotate, read, delete. It never\n * touches Mongo, so it can be unit tested against a tmpdir with no database.\n *\n * ## Why there is no default path\n *\n * The old default was `/tmp/mailery-pending-unsubs.jsonl`: world-writable\n * directory, cleared on reboot, and — since nothing drained it — write-only.\n * There is no replacement default, because a library mounted into an unknown\n * host cannot pick a directory that is simultaneously writable, durable and\n * private: `/var/lib/...` needs root to create, `$HOME` may not exist in a\n * container, and the working directory may be read-only or ephemeral. On top of\n * that the journal holds recipient email addresses in plaintext outside the\n * database, so choosing a location on the operator's behalf is a data-residency\n * decision the operator has to make.\n *\n * So the journal is opt-in: set `pendingUnsubsPath` in `MailerConfig`. With it\n * unset, a failed Mongo write makes the endpoint answer 503 instead of\n * silently dropping the opt-out (see INVARIANT 8).\n *\n * ## Layout\n *\n * <path> the live journal — appended to by the route\n * <path>.draining.<token> a batch claimed by one drain pass\n *\n * Claiming is done with `rename`, which is atomic on POSIX within a directory:\n * exactly one process can move the live journal to its own `.draining.<token>`\n * name, and a second process racing it gets ENOENT and moves on. That is the\n * whole concurrency story — no lock files, no leases.\n *\n * A drain that crashes leaves its `.draining.<token>` file behind. A later pass\n * adopts any such file older than `ADOPT_AFTER_MS` (again by rename, so only\n * one adopter wins) and replays it. Replaying is idempotent, so adopting a file\n * another process is in fact still working on costs duplicate writes and\n * nothing else.\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { randomBytes } from 'node:crypto'\n\nimport { unsubscribeInputSchema, type UnsubscribeInput } from '../shared/schemas.js'\n\n/** One line of the journal. */\nexport interface PendingUnsubEntry {\n email: string\n scope: 'all' | 'marketing' | 'transactional'\n /** Epoch ms the unsubscribe was received. */\n at: number\n /**\n * How many drain passes have already failed to apply this entry. Absent on\n * entries written by the route; incremented each time the drain writes one\n * back. Purely diagnostic — an entry is never dropped for being old.\n */\n attempts?: number\n}\n\n/** Marker inserted between the journal path and a claim token. */\nconst DRAINING_INFIX = '.draining.'\n\n/**\n * How long a `.draining.<token>` file must sit untouched before another pass\n * treats its owner as dead and adopts it. Matches the stranded-send and\n * stranded-webhook thresholds in `runner/tick.ts`.\n */\nexport const ADOPT_AFTER_MS = 5 * 60 * 1000\n\n/** Beyond this the operator has a real outage and should be told. */\nexport const JOURNAL_WARN_BYTES = 8 * 1024 * 1024\n\n/**\n * `O_NOFOLLOW` where the platform has it (POSIX), 0 elsewhere (Windows).\n * Stops the final path component being swapped for a symlink pointing at\n * something we should not be appending recipient addresses to.\n */\nconst O_NOFOLLOW = (fs.constants as { O_NOFOLLOW?: number }).O_NOFOLLOW ?? 0\n\nconst APPEND_FLAGS =\n fs.constants.O_WRONLY | fs.constants.O_CREAT | fs.constants.O_APPEND | O_NOFOLLOW\n\n// ---------------------------------------------------------------------------\n// Append\n// ---------------------------------------------------------------------------\n\n/**\n * Append one entry to the live journal. Synchronous on purpose: this runs on\n * the failure path of an HTTP request that is holding a compliance obligation,\n * and an `await` there is one more place to lose it.\n *\n * Throws on any failure, including a path that is not a plain private file.\n * The caller (the unsubscribe route) turns a throw into a 503.\n *\n * Concurrency: the parent directory is created 0700 and the file 0600, and the\n * write is a single `O_APPEND` write of a short line, so concurrent appenders\n * from multiple processes interleave at line granularity rather than within a\n * line. A line that does get torn is dropped by the drain as malformed and\n * logged; it is not able to corrupt its neighbours.\n */\nexport function appendPendingUnsub(journalPath: string, entry: PendingUnsubEntry): void {\n fs.mkdirSync(path.dirname(journalPath), { recursive: true, mode: 0o700 })\n\n const fd = fs.openSync(journalPath, APPEND_FLAGS, 0o600)\n try {\n assertPrivateRegularFile(fd, journalPath)\n fs.writeSync(fd, serializeEntry(entry))\n } finally {\n fs.closeSync(fd)\n }\n}\n\n/**\n * Reject anything that is not a regular file we exclusively own.\n *\n * `O_NOFOLLOW` covers a symlink swapped in at the last component; it does not\n * cover a regular file pre-created by someone else in a shared directory, nor\n * a hard link pointing our appends at a file that matters. `nlink > 1` catches\n * the hard link; the `chmod` narrows a file that was created with looser\n * permissions before this version shipped.\n */\nfunction assertPrivateRegularFile(fd: number, journalPath: string): void {\n const st = fs.fstatSync(fd)\n if (!st.isFile()) {\n throw new Error(`pending-unsubscribe journal is not a regular file: ${journalPath}`)\n }\n if (st.nlink > 1) {\n throw new Error(`pending-unsubscribe journal has ${st.nlink} hard links: ${journalPath}`)\n }\n if ((st.mode & 0o077) !== 0) fs.fchmodSync(fd, 0o600)\n}\n\nexport function serializeEntry(entry: PendingUnsubEntry): string {\n return JSON.stringify(entry) + '\\n'\n}\n\n// ---------------------------------------------------------------------------\n// Claiming\n// ---------------------------------------------------------------------------\n\nfunction claimToken(): string {\n return `${Date.now().toString(36)}-${randomBytes(6).toString('hex')}`\n}\n\n/**\n * Move the live journal aside so this pass owns its contents and the route can\n * keep appending to a fresh file. Returns the claimed path, or null when there\n * was nothing to claim (no journal, or another process won the race).\n */\nexport function claimJournal(journalPath: string): string | null {\n const claimed = `${journalPath}${DRAINING_INFIX}${claimToken()}`\n try {\n fs.renameSync(journalPath, claimed)\n } catch (err) {\n if (isMissing(err)) return null\n throw err\n }\n markClaimActive(claimed)\n return claimed\n}\n\n/**\n * Stamp a claim as owned *now*.\n *\n * `rename` preserves mtime, so a journal whose last append was during an\n * outage an hour ago would arrive already looking abandoned, and a second\n * process would adopt it out from under the pass that just claimed it. The\n * touch is what makes `mtime` mean \"this batch has an owner that was alive\n * recently\" rather than \"this is when the last unsubscribe came in\".\n */\nfunction markClaimActive(claimPath: string): void {\n const now = new Date()\n try {\n fs.utimesSync(claimPath, now, now)\n } catch (err) {\n // Not fatal — worst case another pass adopts the batch and applies it\n // twice, which is a no-op.\n if (!isMissing(err)) throw err\n }\n}\n\n/**\n * Find `.draining.*` files left behind by a pass that died, and take ownership\n * of the ones that have been idle longer than `olderThanMs`.\n *\n * Adoption is a rename to a fresh token, so two processes scanning at the same\n * instant cannot both end up owning the same batch.\n */\nexport function adoptAbandonedClaims(\n journalPath: string,\n opts: { olderThanMs?: number; now?: number } = {},\n): string[] {\n const olderThanMs = opts.olderThanMs ?? ADOPT_AFTER_MS\n const now = opts.now ?? Date.now()\n const dir = path.dirname(journalPath)\n const prefix = path.basename(journalPath) + DRAINING_INFIX\n\n let names: string[]\n try {\n names = fs.readdirSync(dir)\n } catch (err) {\n if (isMissing(err)) return []\n throw err\n }\n\n const adopted: string[] = []\n for (const name of names) {\n if (!name.startsWith(prefix)) continue\n const full = path.join(dir, name)\n let st: fs.Stats\n try {\n st = fs.statSync(full)\n } catch (err) {\n if (isMissing(err)) continue\n throw err\n }\n if (!st.isFile()) continue\n if (now - st.mtimeMs < olderThanMs) continue\n\n const mine = `${journalPath}${DRAINING_INFIX}${claimToken()}`\n try {\n fs.renameSync(full, mine)\n markClaimActive(mine)\n adopted.push(mine)\n } catch (err) {\n // Lost the race to another adopter — that is the mechanism working.\n if (!isMissing(err)) throw err\n }\n }\n return adopted\n}\n\n// ---------------------------------------------------------------------------\n// Reading\n// ---------------------------------------------------------------------------\n\nexport interface ReadResult {\n entries: PendingUnsubEntry[]\n /** Lines that were not usable — torn by a crash mid-append, or hand-edited. */\n malformed: Array<{ lineNumber: number; preview: string }>\n bytes: number\n}\n\n/**\n * Read a claimed batch.\n *\n * Every failure mode of a file that is appended to by a process which may be\n * killed at any moment is tolerated here, because the alternative is a drain\n * that aborts and leaves valid opt-outs unapplied:\n *\n * - absent file → empty result\n * - empty file → empty result\n * - truncated final line → that line is malformed, every earlier line is\n * still returned\n * - a malformed line → skipped, reported, neighbours unaffected\n * - a JSON line that is not a valid unsubscribe (bad email, bad scope)\n * → malformed; it can never be applied, so retrying\n * it forever would only pin the journal open\n */\nexport function readClaim(claimPath: string): ReadResult {\n let raw: string\n try {\n raw = fs.readFileSync(claimPath, 'utf8')\n } catch (err) {\n if (isMissing(err)) return { entries: [], malformed: [], bytes: 0 }\n throw err\n }\n\n const entries: PendingUnsubEntry[] = []\n const malformed: ReadResult['malformed'] = []\n\n const lines = raw.split('\\n')\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!\n if (line.trim() === '') continue\n const parsed = parseEntry(line)\n if (parsed) entries.push(parsed)\n else malformed.push({ lineNumber: i + 1, preview: line.slice(0, 120) })\n }\n\n return { entries, malformed, bytes: Buffer.byteLength(raw) }\n}\n\n/**\n * Parse one journal line. Returns null for anything that could not be turned\n * into an applicable unsubscribe.\n */\nexport function parseEntry(line: string): PendingUnsubEntry | null {\n let obj: unknown\n try {\n obj = JSON.parse(line)\n } catch {\n return null\n }\n if (!obj || typeof obj !== 'object' || Array.isArray(obj)) return null\n const o = obj as Record<string, unknown>\n\n // Validated with the same schema the live route uses, so an entry that\n // survives here is one `applyUnsubscribe` can definitely accept.\n const check = unsubscribeInputSchema.safeParse({\n email: o.email,\n scope: o.scope,\n reason: 'user_request',\n source: 'one-click',\n })\n if (!check.success) return null\n\n const at = typeof o.at === 'number' && Number.isFinite(o.at) ? o.at : Date.now()\n const attempts =\n typeof o.attempts === 'number' && Number.isFinite(o.attempts) && o.attempts > 0\n ? Math.floor(o.attempts)\n : undefined\n\n return {\n email: check.data.email,\n scope: check.data.scope,\n at,\n ...(attempts === undefined ? {} : { attempts }),\n }\n}\n\n/** The `UnsubscribeInput` a journal entry replays as. */\nexport function entryToInput(entry: PendingUnsubEntry): UnsubscribeInput {\n return unsubscribeInputSchema.parse({\n email: entry.email,\n scope: entry.scope,\n reason: 'user_request',\n // Distinguishable in `mailer_suppressions.source` from a live one-click,\n // but only on rows the drain actually created (the upsert is\n // `$setOnInsert`, so a row the live path already wrote keeps its own).\n source: 'one-click-drain',\n })\n}\n\n// ---------------------------------------------------------------------------\n// Finishing a batch\n// ---------------------------------------------------------------------------\n\n/**\n * Hand entries this pass could not apply back to the live journal, then drop\n * the claim.\n *\n * Returning them to the live journal rather than leaving them in the claim\n * file is what makes the next tick pick them up immediately instead of waiting\n * out `ADOPT_AFTER_MS`. The order — append first, unlink second — is chosen so\n * a crash in between duplicates entries rather than losing them, and duplicates\n * are free because applying twice is a no-op.\n */\nexport function releaseClaim(\n journalPath: string,\n claimPath: string,\n remaining: PendingUnsubEntry[],\n): void {\n if (remaining.length > 0) {\n fs.mkdirSync(path.dirname(journalPath), { recursive: true, mode: 0o700 })\n const fd = fs.openSync(journalPath, APPEND_FLAGS, 0o600)\n try {\n assertPrivateRegularFile(fd, journalPath)\n fs.writeSync(\n fd,\n remaining.map((e) => serializeEntry({ ...e, attempts: (e.attempts ?? 0) + 1 })).join(''),\n )\n } finally {\n fs.closeSync(fd)\n }\n }\n try {\n fs.unlinkSync(claimPath)\n } catch (err) {\n if (!isMissing(err)) throw err\n }\n}\n\n/** True when the journal (or any claim of it) has anything worth draining. */\nexport function journalExists(journalPath: string): boolean {\n try {\n return fs.statSync(journalPath).isFile()\n } catch (err) {\n if (isMissing(err)) return false\n throw err\n }\n}\n\nfunction isMissing(err: unknown): boolean {\n const code = (err as NodeJS.ErrnoException | undefined)?.code\n return code === 'ENOENT' || code === 'ENOTDIR'\n}\n","/**\n * The pending-unsubscribe drain — the second half of INVARIANT 8.\n *\n * `POST /m/unsub/:token` journals an opt-out to disk when Mongo is unreachable\n * (`src/server/unsub-journal.ts`). This replays those entries. It runs from\n * `runTick`, so it needs no scheduling of its own and inherits the tick's\n * cadence (`tickIntervalSeconds`, default 60) and its per-runner error\n * isolation. It is also exported so a host can run it from a script or a\n * one-shot process.\n *\n * ## Where the drain runs, and why only here\n *\n * The tick, not a CLI command. `src/cli/` is a DNS/provider setup tool: it has\n * no Mongo connection, no contact adapter and no config loader, so a\n * `mailery drain-unsubs` command would have to invent a whole configuration\n * story to reach the database. Every deployment that can journal an opt-out is\n * by definition already running the library, and most run the tick;\n * `drainPendingUnsubscribes` is exported for the ones that don't.\n *\n * ## Guarantees\n *\n * - **Idempotent.** Replay goes through `applyUnsubscribe`, whose suppression\n * write is a `$setOnInsert` upsert and whose subscription write is a `$set`\n * to a terminal state. Draining the same entry twice is indistinguishable\n * from draining it once.\n * - **Nothing is lost to a crash.** A pass claims a batch by renaming the\n * journal aside; if it dies, the claim file stays on disk and a later pass\n * adopts it. Entries it could not apply are appended back to the live\n * journal *before* the claim is unlinked, so the failure window duplicates\n * rather than drops.\n * - **Concurrency-safe.** Claiming and adopting are `rename`, which is atomic\n * within a directory. Two processes draining the same journal cannot both\n * own the same batch.\n * - **Fails soft.** A Mongo write failure aborts the pass immediately — the\n * database being down is exactly why these entries exist, and hammering it\n * with the rest of the batch achieves nothing.\n */\n\nimport {\n adoptAbandonedClaims,\n claimJournal,\n entryToInput,\n journalExists,\n readClaim,\n releaseClaim,\n JOURNAL_WARN_BYTES,\n type PendingUnsubEntry,\n} from '../unsub-journal.js'\nimport { applyUnsubscribe } from '../unsubscribe.js'\nimport type { RunnerContext } from './index.js'\n\n/**\n * Entries applied per pass. A long outage can leave a journal with far more\n * than this; the remainder is written back and picked up by the next tick,\n * which keeps a single tick's latency bounded.\n */\nconst MAX_ENTRIES_PER_PASS = 1000\n\n/**\n * Attempts after which an entry is loud rather than routine. It is never\n * dropped — a stuck opt-out is a compliance problem an operator has to see,\n * not one the library gets to discard.\n */\nconst NOISY_AFTER_ATTEMPTS = 10\n\nexport interface DrainPendingUnsubsResult {\n /** False when no `pendingUnsubsPath` is configured — the journal is opt-in. */\n enabled: boolean\n applied: number\n /** Entries handed back to the journal for a later pass. */\n deferred: number\n /** Lines that could never be applied (torn by a crash, or hand-edited). */\n malformed: number\n /** Claim files processed, including ones adopted from a dead pass. */\n batches: number\n}\n\nexport interface DrainPendingUnsubsOptions {\n /** Overrides `config.pendingUnsubsPath`. Mostly for tests. */\n path?: string\n maxEntries?: number\n /** Structured sink for diagnostics. Defaults to `console`. */\n log?: {\n warn?: (fields: Record<string, unknown>, msg?: string) => void\n error?: (fields: Record<string, unknown>, msg?: string) => void\n }\n}\n\nconst consoleLog = {\n warn: (fields: Record<string, unknown>, msg?: string) => console.warn(msg ?? 'mailery', fields),\n error: (fields: Record<string, unknown>, msg?: string) => console.error(msg ?? 'mailery', fields),\n}\n\nexport async function drainPendingUnsubscribes(\n ctx: RunnerContext,\n opts: DrainPendingUnsubsOptions = {},\n): Promise<DrainPendingUnsubsResult> {\n const journalPath = opts.path ?? ctx.config.pendingUnsubsPath\n const result: DrainPendingUnsubsResult = {\n enabled: Boolean(journalPath),\n applied: 0,\n deferred: 0,\n malformed: 0,\n batches: 0,\n }\n if (!journalPath) return result\n\n const log = opts.log ?? consoleLog\n const budget = opts.maxEntries ?? MAX_ENTRIES_PER_PASS\n\n // Claims left behind by a pass that died mid-drain come first: they are\n // strictly older than anything in the live journal.\n const claims: string[] = []\n try {\n claims.push(...adoptAbandonedClaims(journalPath))\n } catch (err) {\n log.error?.({ err, path: journalPath }, 'mailery: pending-unsub claim adoption failed')\n }\n\n if (journalExists(journalPath)) {\n const claimed = claimJournal(journalPath)\n if (claimed) claims.push(claimed)\n }\n if (claims.length === 0) return result\n\n let remainingBudget = budget\n\n for (const claimPath of claims) {\n result.batches++\n const batch = readClaim(claimPath)\n\n if (batch.bytes > JOURNAL_WARN_BYTES) {\n log.warn?.(\n { path: claimPath, bytes: batch.bytes, entries: batch.entries.length },\n 'mailery: pending-unsubscribe journal is large — Mongo has been unreachable for a while',\n )\n }\n for (const bad of batch.malformed) {\n result.malformed++\n log.warn?.(\n { path: claimPath, lineNumber: bad.lineNumber, preview: bad.preview },\n 'mailery: pending-unsubscribe journal line unusable — skipped',\n )\n }\n\n const deferred: PendingUnsubEntry[] = []\n let stop = false\n\n for (let i = 0; i < batch.entries.length; i++) {\n const entry = batch.entries[i]!\n if (stop || remainingBudget <= 0) {\n deferred.push(entry)\n continue\n }\n try {\n await applyUnsubscribe(ctx.collections, entryToInput(entry))\n result.applied++\n remainingBudget--\n } catch (err) {\n // The database is the reason this file exists. Stop the pass rather\n // than replay the rest of the batch into the same failure.\n stop = true\n deferred.push(entry)\n const attempts = (entry.attempts ?? 0) + 1\n const fields = { err, path: claimPath, attempts, pending: batch.entries.length - i }\n if (attempts >= NOISY_AFTER_ATTEMPTS) {\n log.error?.(\n fields,\n 'mailery: pending unsubscribe still not applied after repeated attempts — investigate',\n )\n } else {\n log.warn?.(fields, 'mailery: pending-unsubscribe replay failed — deferred to next tick')\n }\n }\n }\n\n result.deferred += deferred.length\n // Always release, even after an abort: the entries are back in the live\n // journal, and holding the claim would only make the next pass wait out\n // the adoption threshold before retrying them.\n releaseClaim(journalPath, claimPath, deferred)\n }\n\n return result\n}\n","/**\n * The mailer:tick handler. Orchestrates all the periodic work that doesn't\n * fit a delayed-job model: event-trigger scanning, recovery sweep,\n * scheduled-broadcast dispatch, outbox draining, rollups.\n */\n\nimport { processNewlyFiredEventTriggers } from './triggers.js'\nimport { processWebhookBacklog } from './webhook.js'\nimport { sweepStrandedFlowRuns } from './sweep.js'\nimport { processScheduledBroadcasts as dispatchScheduled, resumeStalledBroadcasts } from './broadcasts.js'\nimport { evaluateHealth } from './health.js'\nimport { promoteSoftBounces } from './bounce-promotion.js'\nimport { runDnsblChecks } from './dnsbl.js'\nimport { runPostmasterPull } from './postmaster.js'\nimport { runSndsPull } from './snds.js'\nimport { pruneDmarcFailures } from './dmarc.js'\nimport { drainPendingUnsubscribes } from './pending-unsubs.js'\nimport { HEALTH_AGG_ID } from '../models/index.js'\nimport type { RunnerContext } from './index.js'\n\n/**\n * Sends that entered the 'sending' state more than this long ago are assumed\n * to have been abandoned mid-dispatch (worker crash, OOM kill, ...). The tick\n * resets them to 'queued' and re-enqueues. Providers should treat the sendId\n * (passed in messageMeta) as an idempotency key to avoid duplicate delivery on\n * the rare case where the original call did reach the provider.\n */\nconst STRANDED_SEND_THRESHOLD_MS = 5 * 60 * 1000\n\n/**\n * Webhook events older than this and still unprocessed are assumed stranded\n * (the ingest-time queue add failed). The tick drains them; fresher rows are\n * left to the webhook worker to avoid racing it in the normal path.\n */\nconst STRANDED_WEBHOOK_THRESHOLD_MS = 5 * 60 * 1000\n\nexport async function runTick(ctx: RunnerContext): Promise<void> {\n // Heartbeat: ensure the aggregate health doc exists with an up-to-date\n // `updatedAt` so the setup-status check can detect \"workers are running.\"\n // Wrapped in try/catch — a Mongo blip should never abort the whole tick.\n try {\n await ctx.collections.health.updateOne(\n { _id: HEALTH_AGG_ID },\n {\n $set: { updatedAt: new Date() },\n $setOnInsert: {\n _id: HEALTH_AGG_ID,\n senderDomain: null,\n kind: null,\n windowStartedAt: new Date(),\n windowDurationMs: ctx.config.circuitBreaker.windowMinutes * 60 * 1000,\n status: 'healthy',\n trippedAt: null,\n trippedReason: null,\n manuallyResumedAt: null,\n counters: { sent: 0, delivered: 0, bounced: 0, hardBounced: 0, softBounced: 0, complained: 0, failedToSend: 0 },\n rates: { bounceRate: 0, hardBounceRate: 0, complaintRate: 0, failureRate: 0 },\n },\n },\n { upsert: true },\n )\n } catch (err) {\n console.error('mailery: heartbeat write failed', err)\n }\n\n // Core runners: order matters (sweep before send dispatch, drain outbox\n // before triggers re-scan, etc). Keep these serial.\n await processNewlyFiredEventTriggers(ctx).catch((err) => {\n console.error('mailery: triggers scan failed', err)\n })\n await sweepStrandedFlowRuns(ctx).catch((err) => {\n console.error('mailery: sweep failed', err)\n })\n await sweepStrandedSends(ctx).catch((err) => {\n console.error('mailery: stranded-send sweep failed', err)\n })\n await drainOutbox(ctx).catch((err) => {\n console.error('mailery: outbox drain failed', err)\n })\n // INVARIANT 8: opt-outs journaled to disk while Mongo was unreachable. Runs\n // early and unconditionally — a pending unsubscribe is a legal obligation,\n // and every send dispatched below re-checks suppression at send time\n // (INVARIANT 3), so applying these first is what stops the next broadcast\n // mailing someone who already opted out.\n await drainPendingUnsubscribes(ctx).catch((err) => {\n console.error('mailery: pending-unsubscribe drain failed', err)\n })\n await processScheduledBroadcasts(ctx).catch((err) => {\n console.error('mailery: broadcast dispatch failed', err)\n })\n await resumeStalledBroadcasts(ctx).catch((err) => {\n console.error('mailery: stalled-broadcast resume failed', err)\n })\n await evaluateHealth(ctx).catch((err) => {\n console.error('mailery: health evaluation failed', err)\n })\n await promoteSoftBounces(ctx).catch((err) => {\n console.error('mailery: soft-bounce promotion failed', err)\n })\n await processWebhookBacklog(ctx, { olderThanMs: STRANDED_WEBHOOK_THRESHOLD_MS }).catch((err) => {\n console.error('mailery: stranded-webhook drain failed', err)\n })\n\n // Independent reputation pollers + housekeeping — run in parallel so tick\n // latency is max() not sum(). Each is already throttled internally and\n // catches its own errors.\n await Promise.all([\n runDnsblChecks(ctx).catch((err) => {\n console.error('mailery: dnsbl checks failed', err)\n }),\n runPostmasterPull(ctx).catch((err) => {\n console.error('mailery: postmaster pull failed', err)\n }),\n runSndsPull(ctx).catch((err) => {\n console.error('mailery: snds pull failed', err)\n }),\n pruneDmarcFailures(ctx).catch((err) => {\n console.error('mailery: dmarc prune failed', err)\n }),\n ])\n}\n\n/**\n * Find sends stuck in 'sending' past the threshold (crashed mid-dispatch) and\n * re-enqueue them. Returning to 'queued' lets `dispatchSend` pick them back up.\n */\nasync function sweepStrandedSends(ctx: RunnerContext): Promise<void> {\n const cutoff = new Date(Date.now() - STRANDED_SEND_THRESHOLD_MS)\n const cursor = ctx.collections.sends.find(\n { status: 'sending', updatedAt: { $lt: cutoff } },\n { projection: { _id: 1 } },\n ).limit(500)\n for await (const row of cursor) {\n const reset = await ctx.collections.sends.updateOne(\n { _id: row._id, status: 'sending', updatedAt: { $lt: cutoff } },\n { $set: { status: 'queued', updatedAt: new Date() } },\n )\n if (reset.modifiedCount === 0) continue\n await ctx.queues.send.add('send', { sendId: String(row._id) }, {\n attempts: ctx.config.sendRetryAttempts,\n backoff: { type: 'exponential', delay: 60_000 },\n })\n }\n}\n\n/**\n * Pull pending outbox rows committed by host transactions and promote them\n * into the real collections (events / subscriptions / suppressions).\n */\nasync function drainOutbox(ctx: RunnerContext): Promise<void> {\n const batch = await ctx.collections.outbox\n .find({ status: 'pending' })\n .sort({ enqueuedAt: 1 })\n .limit(200)\n .toArray()\n\n for (const row of batch) {\n try {\n if (row.payload.type === 'event') {\n try {\n await ctx.collections.events.insertOne({\n externalId: row.payload.data.externalId as string,\n name: row.payload.data.name as string,\n properties: (row.payload.data.properties as Record<string, unknown>) ?? {},\n dedupeKey: row.payload.dedupeKey,\n occurredAt: (row.payload.data.occurredAt as Date | undefined) ?? new Date(),\n createdAt: new Date(),\n })\n } catch (err: any) {\n if (err?.code !== 11000) throw err\n }\n }\n await ctx.collections.outbox.updateOne(\n { _id: row._id },\n { $set: { status: 'processed', processedAt: new Date() } },\n )\n } catch (err: any) {\n await ctx.collections.outbox.updateOne(\n { _id: row._id },\n {\n $set: { lastAttemptAt: new Date(), lastError: String(err?.message ?? err) },\n $inc: { attempts: 1 },\n },\n )\n }\n }\n}\n\n/**\n * Claim broadcasts whose `scheduledAt` has passed and hand their recipient\n * enqueue to an advance job (inline for the noop driver), so a large\n * broadcast never blocks the tick. The dispatch itself streams the segment\n * cursor and bulk-enqueues sends, pausing when the send queue's waiting\n * count exceeds the configured cap (broadcastEnqueueMaxWaiting).\n */\nasync function processScheduledBroadcasts(ctx: RunnerContext): Promise<void> {\n await dispatchScheduled(ctx)\n}\n","/**\n * Mailer — public facade. Hosts call `Mailer.init(config)` and get an object\n * exposing the public API (fire, upsertSubscription, unsubscribe, ...) plus\n * mountable Express routers.\n *\n * See plans/10-public-api.md for the surface.\n */\n\nimport type { Db, ClientSession, ObjectId } from 'mongodb'\nimport { ObjectId as ObjectIdCtor } from 'mongodb'\n\nimport type {\n ContactAdapter,\n MailProvider,\n} from '../shared/types.js'\nimport {\n abortAllFlowsInputSchema,\n abortFlowInputSchema,\n fireInputSchema,\n registerEventSchema,\n sendOneOffInputSchema,\n suppressInputSchema,\n tagInputSchema,\n unsubscribeInputSchema,\n upsertSubscriptionSchema,\n type FireInput,\n type RegisterEventInput,\n type SendOneOffInput,\n type SuppressInput,\n type TagInput,\n type UnsubscribeInput,\n type UpsertSubscriptionInput,\n} from '../shared/schemas.js'\nimport { resolveConfig, type MailerConfig, type ResolvedConfig } from './config.js'\nimport {\n ensureIndexes,\n getCollections,\n} from './models/index.js'\nimport type { Collections } from './models/index.js'\nimport { EventRegistry } from './events.js'\nimport { resolveProvider, registeredProviderNames } from './provider-lookup.js'\nimport { sha256Hex, signDoiToken } from './tokens.js'\nimport { applyUnsubscribe } from './unsubscribe.js'\nimport {\n createQueueDriver,\n type QueueDriver,\n type Queues,\n} from './queues/index.js'\nimport {\n dispatchBroadcastById,\n dispatchSend,\n exitFlowRun,\n processOneRunStep,\n runTick,\n type RunnerContext,\n} from './runner/index.js'\nimport { processWebhookBacklog } from './runner/webhook.js'\n\nexport class Mailer {\n readonly db: Db\n readonly collections: Collections\n readonly adapter: ContactAdapter\n readonly providers: Record<string, MailProvider>\n readonly queues: Queues\n readonly config: ResolvedConfig\n readonly events: EventRegistry\n\n private queueDriver: QueueDriver\n private workersStarted = false\n private runnerContext: RunnerContext\n\n private constructor(args: {\n config: ResolvedConfig\n db: Db\n collections: Collections\n adapter: ContactAdapter\n providers: Record<string, MailProvider>\n queueDriver: QueueDriver\n events: EventRegistry\n }) {\n this.config = args.config\n this.db = args.db\n this.collections = args.collections\n this.adapter = args.adapter\n this.providers = args.providers\n this.queueDriver = args.queueDriver\n this.queues = args.queueDriver.queues\n this.events = args.events\n\n this.runnerContext = {\n db: this.db,\n collections: this.collections,\n adapter: this.adapter,\n varsAdapter: this.config.varsAdapter,\n providers: this.providers,\n queues: this.queues,\n config: this.config,\n handlebarsHelpers: this.config.handlebarsHelpers,\n audit: (entry) => this.audit(entry),\n }\n }\n\n /**\n * Construct a Mailer from environment variables. Reads:\n *\n * MAILER_MONGODB_URI — Mongo connection string (required)\n * MAILER_MONGODB_DB — database name (optional; defaults to the URI default)\n * MAILER_REDIS_URL — Redis connection URL (required)\n * MAILER_QUEUE_PREFIX — namespaces this instance (optional). Bull: Redis key\n * prefix. Agenda: jobs collection suffix.\n * MAILER_PUBLIC_URL — base for tracking/unsub URLs (required)\n * MAILER_UNSUBSCRIBE_SECRET — HMAC key (required)\n * MAILER_SENDER_ADDRESS — postal address for CAN-SPAM (optional)\n * MAILER_FROM_NAME / MAILER_FROM_EMAIL\n * MAILER_DEFAULT_PROVIDER — defaults to 'sendgrid' if SENDGRID_API_KEY is set\n * MAILER_SENDGRID_API_KEY / MAILER_SENDGRID_WEBHOOK_KEY\n * MAILER_SENDGRID_WEBHOOK_TOLERANCE — signed-webhook replay window, seconds\n * (default 300; '0' disables the check).\n * Unparseable values fall back to the\n * default rather than disabling it.\n * MAILER_HOST_USERS_COLLECTION (default 'users')\n * MAILER_HOST_USERS_EMAIL_FIELD (default 'email')\n * MAILER_HOST_USERS_ID_FIELD (default '_id')\n * MAILER_HOST_USERS_TAGS_FIELD\n * MAILER_HOST_USERS_TAGS_WRITABLE — '1' or 'true' to enable\n *\n * For anything beyond this (custom toContact, custom providers, hooks),\n * use the programmatic init.\n */\n static async fromEnv(): Promise<Mailer> {\n const env = process.env\n const required = (k: string) => {\n const v = env[k]\n if (!v) throw new Error(`Mailer.fromEnv: missing env var ${k}`)\n return v\n }\n\n const { MongoClient } = await import('mongodb')\n const mongoClient = await MongoClient.connect(required('MAILER_MONGODB_URI'))\n const db = env.MAILER_MONGODB_DB ? mongoClient.db(env.MAILER_MONGODB_DB) : mongoClient.db()\n\n const { MongoContactAdapter } = await import('./adapters/mongo.js')\n const adapter = new MongoContactAdapter({\n db,\n collection: env.MAILER_HOST_USERS_COLLECTION ?? 'users',\n emailField: env.MAILER_HOST_USERS_EMAIL_FIELD ?? 'email',\n idField: env.MAILER_HOST_USERS_ID_FIELD ?? '_id',\n tagsField: env.MAILER_HOST_USERS_TAGS_FIELD,\n tagsWritable:\n env.MAILER_HOST_USERS_TAGS_WRITABLE === '1' || env.MAILER_HOST_USERS_TAGS_WRITABLE === 'true',\n })\n\n const providers: Record<string, MailProvider> = {}\n if (env.MAILER_SENDGRID_API_KEY) {\n const { SendGridProvider } = await import('./providers/sendgrid.js')\n providers.sendgrid = new SendGridProvider({\n apiKey: env.MAILER_SENDGRID_API_KEY,\n webhookVerificationKey: env.MAILER_SENDGRID_WEBHOOK_KEY,\n // Left undefined when unset/blank so the provider default (300s) applies.\n // resolveWebhookToleranceSeconds() rejects NaN back to the default, so a\n // typo here can never silently switch the replay check off.\n webhookToleranceSeconds: env.MAILER_SENDGRID_WEBHOOK_TOLERANCE\n ? Number(env.MAILER_SENDGRID_WEBHOOK_TOLERANCE)\n : undefined,\n sandbox: env.NODE_ENV !== 'production',\n })\n }\n if (Object.keys(providers).length === 0) {\n throw new Error('Mailer.fromEnv: no provider configured (set MAILER_SENDGRID_API_KEY, ...)')\n }\n\n const defaultProvider = env.MAILER_DEFAULT_PROVIDER ?? Object.keys(providers)[0]!\n\n const driverEnv = env.MAILER_QUEUE_DRIVER ?? 'bull'\n const queue =\n driverEnv === 'agenda'\n ? ({ driver: 'agenda' as const, prefix: env.MAILER_QUEUE_PREFIX })\n : driverEnv === 'noop'\n ? ({ driver: 'noop' as const })\n : ({\n driver: 'bull' as const,\n redis: { url: required('MAILER_REDIS_URL') },\n prefix: env.MAILER_QUEUE_PREFIX,\n })\n\n return Mailer.init({\n db,\n adapter,\n queue,\n providers,\n defaultProvider,\n publicUrl: required('MAILER_PUBLIC_URL'),\n unsubscribeSecret: required('MAILER_UNSUBSCRIBE_SECRET'),\n senderAddress: env.MAILER_SENDER_ADDRESS,\n fromDefaults:\n env.MAILER_FROM_NAME && env.MAILER_FROM_EMAIL\n ? { name: env.MAILER_FROM_NAME, email: env.MAILER_FROM_EMAIL }\n : undefined,\n })\n }\n\n static async init(input: MailerConfig): Promise<Mailer> {\n const config = resolveConfig(input)\n // Both defaults are validated here, through the same guarded lookup the\n // routes and the runner use — a name that resolves to an inherited\n // `Object.prototype` member is not a provider. `defaultTransactionalProvider`\n // was previously unchecked, so a typo in it stayed silent until a\n // transactional send failed at dispatch time, long after startup.\n if (!resolveProvider(config.providers, config.defaultProvider)) {\n throw new Error(\n `defaultProvider \"${config.defaultProvider}\" is not a registered provider. `\n + `Registered: ${registeredProviderNames(config.providers).join(', ') || '(none)'}`,\n )\n }\n if (\n config.defaultTransactionalProvider != null\n && !resolveProvider(config.providers, config.defaultTransactionalProvider)\n ) {\n throw new Error(\n `defaultTransactionalProvider \"${config.defaultTransactionalProvider}\" is not a `\n + `registered provider. `\n + `Registered: ${registeredProviderNames(config.providers).join(', ') || '(none)'}`,\n )\n }\n if (config.varsAdapter) {\n const { assertNoReservedVarKeys } = await import('./adapters/vars.js')\n assertNoReservedVarKeys(config.varsAdapter)\n }\n\n const collections = getCollections(config.db, config.collectionPrefix)\n await ensureIndexes(config.db, config.collectionPrefix)\n\n const queueDriver = await createQueueDriver(config.queue, config.db)\n if (!config.workerless && config.queue.driver !== 'noop') {\n await queueDriver.scheduleRepeatingTick(config.tickIntervalSeconds)\n }\n\n return new Mailer({\n config,\n db: config.db,\n collections,\n adapter: config.adapter,\n providers: config.providers,\n queueDriver,\n events: new EventRegistry(),\n })\n }\n\n // -------------------------------------------------------------------------\n // Event registration + firing\n // -------------------------------------------------------------------------\n\n registerEvent(reg: RegisterEventInput): void {\n const parsed = registerEventSchema.parse(reg)\n this.events.register(parsed)\n }\n\n async fire(\n eventName: string,\n externalId: string,\n properties: Record<string, unknown> = {},\n dedupeKey?: string,\n ): Promise<void> {\n const input = fireInputSchema.parse({ eventName, externalId, properties, dedupeKey })\n const key = this.events.deriveKey(input.eventName, input.externalId, input.dedupeKey, new Date())\n if (!key) {\n throw new Error(\n `fire(\"${input.eventName}\") missing dedupeKey and no policy registered. ` +\n `Call mailer.registerEvent(\"${input.eventName}\", { dedupePolicy }) or pass a key explicitly.`,\n )\n }\n try {\n await this.collections.events.insertOne({\n externalId: input.externalId,\n name: input.eventName,\n properties: input.properties ?? {},\n dedupeKey: key,\n occurredAt: new Date(),\n createdAt: new Date(),\n })\n } catch (err: any) {\n if (err?.code !== 11000) throw err\n // Duplicate dedupeKey — no-op by design.\n }\n }\n\n async fireFromSession(\n session: ClientSession,\n eventName: string,\n externalId: string,\n properties: Record<string, unknown> = {},\n dedupeKey?: string,\n ): Promise<void> {\n const input = fireInputSchema.parse({ eventName, externalId, properties, dedupeKey })\n const key = this.events.deriveKey(input.eventName, input.externalId, input.dedupeKey, new Date())\n if (!key) {\n throw new Error(`fireFromSession(\"${input.eventName}\") missing dedupeKey and no policy registered.`)\n }\n try {\n await this.collections.outbox.insertOne(\n {\n payload: {\n type: 'event',\n data: {\n externalId: input.externalId,\n name: input.eventName,\n properties: input.properties ?? {},\n occurredAt: new Date(),\n },\n dedupeKey: key,\n },\n status: 'pending',\n attempts: 0,\n lastAttemptAt: null,\n lastError: null,\n enqueuedAt: new Date(),\n processedAt: null,\n },\n { session },\n )\n } catch (err: any) {\n if (err?.code !== 11000) throw err\n }\n }\n\n // -------------------------------------------------------------------------\n // Subscription / unsubscribe / tags / suppression\n // -------------------------------------------------------------------------\n\n async upsertSubscription(input: UpsertSubscriptionInput): Promise<void> {\n const parsed = upsertSubscriptionSchema.parse(input)\n const contact = await this.adapter.getById(parsed.externalId)\n if (!contact) throw new Error(`adapter has no contact for externalId ${parsed.externalId}`)\n\n const status = this.config.requireDoubleOptIn ? 'pending_doi' : 'subscribed'\n const now = new Date()\n\n // Generate a DOI token up front when DOI is required. We store its hash\n // (not the raw token) on the subscription doc for audit.\n let doiToken: string | null = null\n let doiTokenHash: string | null = null\n if (status === 'pending_doi') {\n const expiresAt = new Date(now.getTime() + this.config.doiTokenLifetimeDays * 86_400_000)\n doiToken = signDoiToken({ externalId: parsed.externalId, expiresAt }, this.config.unsubscribeSecret)\n doiTokenHash = sha256Hex(doiToken)\n }\n\n await this.collections.subscriptions.updateOne(\n { externalId: parsed.externalId },\n {\n $set: {\n status,\n source: parsed.source,\n emailAtSubscribe: contact.email,\n subscribedAt: status === 'subscribed' ? (parsed.consentTimestamp ?? now) : null,\n updatedAt: now,\n ...(doiTokenHash ? { doiTokenHash, doiRequestedAt: now } : {}),\n },\n $setOnInsert: {\n externalId: parsed.externalId,\n createdAt: now,\n unsubscribedAt: null,\n unsubscribeReason: null,\n doiTokenHash: null,\n doiRequestedAt: null,\n doiConfirmedAt: null,\n doiIp: parsed.consentIp ?? null,\n doiUserAgent: parsed.consentUserAgent ?? null,\n },\n },\n { upsert: true },\n )\n\n // Send the DOI confirmation email (best-effort — failures here don't\n // unwind the subscription; the host can poll pending DOI rows + re-fire).\n if (status === 'pending_doi' && doiToken) {\n const tpl = await this.collections.templates.findOne({ slug: this.config.doiTemplateSlug })\n if (!tpl) {\n console.warn(`mailery: DOI required but template \"${this.config.doiTemplateSlug}\" not found — skipping confirmation email`)\n return\n }\n const dedupeKey = `doi:${parsed.externalId}:${now.toISOString().slice(0, 10)}`\n try {\n await this.sendOneOff({\n templateSlug: tpl.slug,\n externalId: parsed.externalId,\n vars: { confirmDoiUrl: `${this.config.publicUrl}/m/confirm-doi/${doiToken}` },\n dedupeKey,\n })\n } catch (err) {\n console.error('mailery: DOI confirmation send failed', err)\n }\n }\n }\n\n /**\n * The writes live in `server/unsubscribe.ts` so the pending-unsubscribe\n * drain (INVARIANT 8) replays a journaled opt-out through exactly this path\n * without holding a `Mailer` instance.\n */\n async unsubscribe(email: string, opts: Omit<UnsubscribeInput, 'email'>): Promise<void> {\n const parsed = unsubscribeInputSchema.parse({ email, ...opts })\n await applyUnsubscribe(this.collections, parsed)\n }\n\n async suppress(email: string, opts: Omit<SuppressInput, 'email'>): Promise<void> {\n const parsed = suppressInputSchema.parse({ email, ...opts })\n await this.collections.suppressions.updateOne(\n { email: parsed.email, scope: parsed.scope },\n {\n $setOnInsert: {\n email: parsed.email,\n emailHash: sha256Hex(parsed.email),\n scope: parsed.scope,\n reason: parsed.reason,\n source: parsed.source,\n notes: parsed.notes ?? null,\n addedAt: new Date(),\n expiresAt: parsed.expiresAt ?? null,\n },\n },\n { upsert: true },\n )\n }\n\n async tag(externalId: string, tag: string): Promise<void> {\n const parsed = tagInputSchema.parse({ externalId, tag })\n if (this.adapter.addTags) {\n await this.adapter.addTags(parsed.externalId, [parsed.tag])\n } else {\n await this.collections.contactTags.updateOne(\n { externalId: parsed.externalId, tag: parsed.tag },\n {\n $setOnInsert: {\n externalId: parsed.externalId,\n tag: parsed.tag,\n appliedBy: 'admin',\n appliedAt: new Date(),\n },\n },\n { upsert: true },\n )\n }\n }\n\n async untag(externalId: string, tag: string): Promise<void> {\n const parsed = tagInputSchema.parse({ externalId, tag })\n if (this.adapter.removeTags) {\n await this.adapter.removeTags(parsed.externalId, [parsed.tag])\n } else {\n await this.collections.contactTags.deleteOne({ externalId: parsed.externalId, tag: parsed.tag })\n }\n }\n\n // -------------------------------------------------------------------------\n // Flow abort\n // -------------------------------------------------------------------------\n\n /**\n * Abort every active run of one flow for a contact, immediately. Runs parked\n * in a `wait` exit too — their delayed wake-up jobs find the run exited and\n * no-op. Also cancels any of the flow's emails still sitting in the send\n * queue for this contact (queued or awaiting retry), so an abort means no\n * further mail, not just no further steps.\n *\n * No-op (returns zero counts) when nothing is active. Safe to call from the\n * same handler that processes the business event (\"user upgraded\").\n */\n async abortFlow(\n flowSlug: string,\n externalId: string,\n opts: { reason?: string; matchTriggerProperties?: Record<string, unknown> } = {},\n ): Promise<{ abortedRuns: number; cancelledSends: number }> {\n const parsed = abortFlowInputSchema.parse({\n flowSlug,\n externalId,\n reason: opts.reason,\n matchTriggerProperties: opts.matchTriggerProperties,\n })\n const flow = await this.collections.flows.findOne(\n { slug: parsed.flowSlug },\n { projection: { _id: 1 } },\n )\n if (!flow) throw new Error(`abortFlow: unknown flow slug \"${parsed.flowSlug}\"`)\n\n // Dotted paths so the match is against individual trigger properties; a\n // nested-object equality would demand the whole properties bag match.\n const triggerMatch = Object.fromEntries(\n Object.entries(parsed.matchTriggerProperties ?? {}).map(([k, v]) => [\n `triggerEvent.properties.${k}`,\n v,\n ]),\n )\n\n const result = await this.abortActiveRuns(\n { externalId: parsed.externalId, flowId: flow._id!, ...triggerMatch },\n parsed.reason ? `aborted_by_host:${parsed.reason}` : 'aborted_by_host',\n )\n if (result.abortedRuns > 0 || result.cancelledSends > 0) {\n await this.audit({\n actor: 'host',\n action: 'flow.abort',\n resource: { collection: 'mailer_flow_runs', slug: parsed.flowSlug },\n // Record the scope: without it a one-account abort and an abort-every-\n // run-for-this-contact are indistinguishable in the audit trail.\n diffSummary: `abortFlow slug=${parsed.flowSlug} externalId=${parsed.externalId} scope=${\n parsed.matchTriggerProperties ? JSON.stringify(parsed.matchTriggerProperties) : 'all'\n } runs=${result.abortedRuns} sends=${result.cancelledSends}${parsed.reason ? ` reason=${parsed.reason}` : ''}`,\n })\n }\n return result\n }\n\n /**\n * Abort every active flow run for a contact across all flows. Same semantics\n * as `abortFlow` — for \"stop everything\" events (account deleted, churned).\n */\n async abortAllFlows(\n externalId: string,\n opts: { reason?: string } = {},\n ): Promise<{ abortedRuns: number; cancelledSends: number }> {\n const parsed = abortAllFlowsInputSchema.parse({ externalId, reason: opts.reason })\n\n const result = await this.abortActiveRuns(\n { externalId: parsed.externalId },\n parsed.reason ? `aborted_by_host:${parsed.reason}` : 'aborted_by_host',\n )\n if (result.abortedRuns > 0 || result.cancelledSends > 0) {\n await this.audit({\n actor: 'host',\n action: 'flow.abort_all',\n resource: { collection: 'mailer_flow_runs' },\n diffSummary: `abortAllFlows externalId=${parsed.externalId} runs=${result.abortedRuns} sends=${result.cancelledSends}${parsed.reason ? ` reason=${parsed.reason}` : ''}`,\n })\n }\n return result\n }\n\n private async abortActiveRuns(\n // Open-ended extra keys carry caller-supplied dotted paths (e.g.\n // 'triggerEvent.properties.accountId') straight into the run query.\n filter: { externalId: string; flowId?: ObjectId } & Record<string, unknown>,\n exitReason: string,\n ): Promise<{ abortedRuns: number; cancelledSends: number }> {\n const runs = await this.collections.flowRuns\n .find({ ...filter, status: 'active' })\n .toArray()\n if (runs.length === 0) return { abortedRuns: 0, cancelledSends: 0 }\n\n for (const run of runs) {\n await exitFlowRun(run, exitReason, this.runnerContext)\n }\n\n // Exiting the runs stops future steps; this stops mail already produced by\n // past send steps but not yet dispatched (provider retry backoff, tripped\n // circuit breaker, stranded-send sweep). 'failed' is included because the\n // send queue re-dispatches failed sends on retry.\n const cancelled = await this.collections.sends.updateMany(\n { flowRunId: { $in: runs.map((r) => r._id!) }, status: { $in: ['queued', 'failed'] } },\n { $set: { status: 'cancelled', errorMessage: `cancelled: ${exitReason}`, updatedAt: new Date() } },\n )\n\n return { abortedRuns: runs.length, cancelledSends: cancelled.modifiedCount }\n }\n\n /**\n * GDPR right-to-erasure. Hard-deletes the contact's PII and leaves a hashed\n * suppression row to block re-import. INVARIANT 9.\n */\n async forget(externalId: string): Promise<void> {\n const sub = await this.collections.subscriptions.findOne({ externalId })\n const email = sub?.emailAtSubscribe?.toLowerCase()\n\n const collected = await Promise.all([\n this.collections.sends.find({ externalId }).map((s) => s.emailAtSend).toArray(),\n ])\n const emails = new Set<string>()\n if (email) emails.add(email)\n for (const e of collected[0]) if (e) emails.add(e.toLowerCase())\n\n await Promise.all([\n this.collections.events.deleteMany({ externalId }),\n this.collections.flowRuns.deleteMany({ externalId }),\n this.collections.sends.deleteMany({ externalId }),\n this.collections.subscriptions.deleteMany({ externalId }),\n this.collections.contactTags.deleteMany({ externalId }),\n ])\n if (email) {\n await this.collections.leads.deleteMany({ email })\n }\n\n for (const e of emails) {\n await this.collections.suppressions.updateOne(\n { emailHash: sha256Hex(e), scope: 'all' },\n {\n $setOnInsert: {\n email: null,\n emailHash: sha256Hex(e),\n scope: 'all',\n reason: 'gdpr_forget',\n source: 'gdpr_request',\n notes: null,\n addedAt: new Date(),\n expiresAt: null,\n },\n },\n { upsert: true },\n )\n }\n\n await this.audit({\n actor: 'system:gdpr',\n action: 'gdpr.forget',\n resource: { collection: 'mailer_subscriptions', id: sub?._id },\n diffSummary: `forget externalId=${externalId}`,\n })\n }\n\n /** GDPR data export. JSON-serializable. */\n async exportContactData(externalId: string): Promise<Record<string, unknown>> {\n const subscription = await this.collections.subscriptions.findOne({ externalId })\n const [events, flowRuns, sends, suppressions, tags] = await Promise.all([\n this.collections.events.find({ externalId }).toArray(),\n this.collections.flowRuns.find({ externalId }).toArray(),\n this.collections.sends.find({ externalId }).toArray(),\n subscription?.emailAtSubscribe\n ? this.collections.suppressions.find({ email: subscription.emailAtSubscribe }).toArray()\n : Promise.resolve([]),\n this.collections.contactTags.find({ externalId }).toArray(),\n ])\n return { subscription, events, flowRuns, sends, suppressions, tags }\n }\n\n // -------------------------------------------------------------------------\n // One-off transactional send (password reset etc.)\n // -------------------------------------------------------------------------\n\n async sendOneOff(input: SendOneOffInput): Promise<{ sendId: string }> {\n const parsed = sendOneOffInputSchema.parse(input)\n const template = await this.collections.templates.findOne({ slug: parsed.templateSlug })\n if (!template) throw new Error(`template not found: ${parsed.templateSlug}`)\n\n const contact = await this.adapter.getById(parsed.externalId)\n if (!contact) throw new Error(`contact not found: ${parsed.externalId}`)\n\n const dedupeKey = `oneoff:${parsed.dedupeKey}`\n const existing = await this.collections.sends.findOne({ dedupeKey })\n if (existing) return { sendId: String(existing._id) }\n\n const providerName =\n parsed.providerOverride\n ?? template.providerOverride\n ?? (template.kind === 'transactional' ? this.config.defaultTransactionalProvider : null)\n ?? this.config.defaultProvider\n\n const sendId = new ObjectIdCtor()\n try {\n await this.collections.sends.insertOne({\n _id: sendId,\n dedupeKey,\n externalId: parsed.externalId,\n emailAtSend: contact.email,\n templateId: template._id!,\n templateSlug: template.slug,\n flowRunId: null,\n broadcastId: null,\n manualSendBy: 'sendOneOff',\n kind: template.kind,\n provider: providerName,\n providerMessageId: null,\n fromName: template.fromName,\n fromEmail: template.fromEmail,\n subject: template.subject,\n bodyHash: '',\n status: 'queued',\n errorMessage: null,\n bounceType: null,\n bounceReason: null,\n links: [],\n vars: parsed.vars ?? {},\n openedAt: null,\n openCount: 0,\n firstClickAt: null,\n clickCount: 0,\n clickedLinks: [],\n unsubscribedAt: null,\n complainedAt: null,\n queuedAt: new Date(),\n updatedAt: new Date(),\n sentAt: null,\n deliveredAt: null,\n })\n } catch (err: any) {\n // Concurrent call with the same dedupeKey won the insert — return its id.\n if (err?.code !== 11000) throw err\n const winner = await this.collections.sends.findOne({ dedupeKey })\n if (winner) return { sendId: String(winner._id) }\n throw err\n }\n\n await this.queues.send.add(\n 'send',\n { sendId: String(sendId) },\n { attempts: this.config.sendRetryAttempts, backoff: { type: 'exponential', delay: 60_000 } },\n )\n\n return { sendId: String(sendId) }\n }\n\n // -------------------------------------------------------------------------\n // Audit log helper\n // -------------------------------------------------------------------------\n\n async audit(entry: {\n actor: string\n action: string\n resource: { collection: string; id?: string | ObjectId; slug?: string }\n before?: Record<string, unknown> | null\n after?: Record<string, unknown> | null\n diffSummary?: string\n ip?: string\n userAgent?: string\n requestId?: string\n }): Promise<void> {\n await this.collections.auditLog.insertOne({\n actor: entry.actor,\n action: entry.action,\n resource: entry.resource,\n before: entry.before ?? null,\n after: entry.after ?? null,\n diffSummary: entry.diffSummary ?? null,\n ip: entry.ip ?? null,\n userAgent: entry.userAgent ?? null,\n requestId: entry.requestId ?? null,\n occurredAt: new Date(),\n })\n }\n\n // -------------------------------------------------------------------------\n // Workers\n // -------------------------------------------------------------------------\n\n async startWorkers(): Promise<void> {\n if (this.workersStarted) return\n if (this.config.queue.driver === 'noop') {\n throw new Error('startWorkers requires a non-noop queue driver')\n }\n const provider = this.providers[this.config.defaultProvider]\n const sendRate = provider?.sendRatePerSecond ?? this.config.sendRatePerSecond\n\n await this.queueDriver.startWorkers({\n concurrency: { send: this.config.sendConcurrency },\n sendRateLimit: { max: sendRate, durationMs: 1_000 },\n retryAttempts: this.config.sendRetryAttempts,\n handlers: {\n tick: async () => {\n await runTick(this.runnerContext)\n },\n advance: async (data) => {\n if (data.broadcastId) {\n if (!ObjectIdCtor.isValid(data.broadcastId)) return\n await dispatchBroadcastById(new ObjectIdCtor(data.broadcastId), this.runnerContext)\n return\n }\n if (!data.flowRunId || !ObjectIdCtor.isValid(data.flowRunId)) return\n await processOneRunStep(new ObjectIdCtor(data.flowRunId), this.runnerContext)\n },\n send: async (data) => {\n if (!ObjectIdCtor.isValid(data.sendId)) return\n await dispatchSend(new ObjectIdCtor(data.sendId), this.runnerContext)\n },\n webhook: async () => {\n await this.processWebhookBacklog()\n },\n },\n })\n this.workersStarted = true\n }\n\n /** Process unprocessed webhook events in mailer_webhook_events. */\n private async processWebhookBacklog(): Promise<void> {\n await processWebhookBacklog(this.runnerContext)\n }\n\n async stop(): Promise<void> {\n await this.queueDriver.close()\n this.workersStarted = false\n }\n\n /** Used internally by the admin router and tests; not part of the public API. */\n getRunnerContext(): RunnerContext {\n return this.runnerContext\n }\n}\n","/**\n * Public exports for the `mailery` package.\n */\n\ndeclare const __PKG_VERSION__: string | undefined\n\n/**\n * Library version, stamped from package.json at build time (tsup/vitest\n * `define`). 'dev' when the source runs without a bundler define (plain tsx).\n */\nexport const VERSION = typeof __PKG_VERSION__ === 'string' ? __PKG_VERSION__ : 'dev'\n\n// Core\nexport { Mailer } from './mailer.js'\nexport type { MailerConfig, RedisOptions, CircuitBreakerThresholds, BotFilterConfig, SenderDomainConfig, SenderDomainRegistry } from './config.js'\nexport { validateSenderDomain } from './templates/sender-domain.js'\nexport type { SenderDomainValidation } from './templates/sender-domain.js'\n\n// Adapters\nexport { MongoContactAdapter } from './adapters/mongo.js'\nexport type { MongoContactAdapterOptions } from './adapters/mongo.js'\nexport { defineVars, varsJsonSchema, RESERVED_VAR_KEYS } from './adapters/vars.js'\nexport type { VarsAdapter, VarsResolveInfo } from './adapters/vars.js'\n\n// Providers\nexport { NullProvider } from './providers/null.js'\nexport { SendGridProvider } from './providers/sendgrid.js'\nexport type { SendGridProviderOptions } from './providers/sendgrid.js'\n\n// HTTP routers\nexport { createAdminRouter } from './api/admin.js'\nexport type { AdminRouterOptions } from './api/admin.js'\nexport { createPublicRouter } from './api/public.js'\nexport type { PublicRouterOptions } from './api/public.js'\nexport { sendgridInboundParser } from './api/dmarc-inbound.js'\nexport type {\n DmarcInboundOptions,\n InboundAttachment,\n InboundParser,\n} from './api/dmarc-inbound.js'\nexport type { RouteLogger } from './api/wrap.js'\n\n// Templates (host apps may want compile + render directly for previews)\nexport {\n compileTemplate,\n compileMailyTemplate,\n derivePlaintext,\n renderTemplate,\n applyTracking,\n} from './templates/render.js'\n\n// Runner internals — exported so test harnesses and advanced hosts can drive\n// the runner inline. In production let `startWorkers()` invoke these.\nexport {\n runTick,\n processOneRunStep,\n dispatchSend,\n applyWebhookEvent,\n processNewlyFiredEventTriggers,\n sweepStrandedFlowRuns,\n drainPendingUnsubscribes,\n} from './runner/index.js'\nexport type {\n DrainPendingUnsubsOptions,\n DrainPendingUnsubsResult,\n} from './runner/index.js'\n\n// Models (collection helpers, in case hosts need to query directly)\nexport { getCollections, ensureIndexes } from './models/index.js'\nexport type {\n Collections,\n SubscriptionDoc,\n EventDoc,\n FlowDoc,\n FlowRunDoc,\n TemplateDoc,\n SendDoc,\n SuppressionDoc,\n BroadcastDoc,\n AuditLogDoc,\n WebhookEventDoc,\n HealthDoc,\n ContactTagDoc,\n LeadDoc,\n OutboxDoc,\n FlowVersionDoc,\n TemplateVersionDoc,\n} from './models/index.js'\n\n// Token helpers (rarely needed by hosts, useful for tests)\nexport { signUnsubscribeToken, verifyUnsubscribeToken, sha256Hex } from './tokens.js'\nexport {\n signTrackingToken,\n verifyTrackingToken,\n TRACKING_SIG_LENGTH,\n type TrackingScope,\n type TrackingTokenParams,\n} from './tokens.js'\nexport { DEFAULT_BOT_UA_RE } from './runner/predicate.js'\n\n// Shared types\nexport { computeDeliveryTime } from './runner/delivery-window.js'\n\nexport type {\n Contact,\n ContactAdapter,\n AdapterFilter,\n DeliveryWindow,\n MailProvider,\n SendArgs,\n SendResult,\n NormalizedEvent,\n FlowStep,\n Predicate,\n SegmentDefinition,\n SegmentFilter,\n} from '../shared/types.js'\n\nexport type {\n SubscriptionStatus,\n SendStatus,\n TemplateKind,\n SuppressionScope,\n SuppressionReason,\n FlowRunStatus,\n BroadcastStatus,\n HealthStatus,\n FlowGoal,\n} from '../shared/enums.js'\n\n// Option lists for tooling / admin UIs — flow step kinds, predicate kinds,\n// segment filter kinds, dedupe policies.\nexport {\n FLOW_STEP_KINDS,\n defaultFlowStep,\n PREDICATE_KINDS,\n defaultPredicate,\n predicateKind,\n SEGMENT_FILTER_KINDS,\n defaultSegmentFilter,\n DEDUPE_POLICIES,\n} from '../shared/options.js'\nexport type {\n FlowStepKindOption,\n PredicateKindOption,\n PredicateKind,\n SegmentFilterKindOption,\n SegmentFilterKind,\n DedupePolicyOption,\n} from '../shared/options.js'\n","/**\n * NullProvider — in-memory provider for tests and dev. Records every send\n * without dispatching anything. Inspect `.sent` to assert what would have\n * been delivered.\n */\n\nimport type { MailProvider, NormalizedEvent, SendArgs, SendResult } from '../../shared/types.js'\n\nlet counter = 0\n\nexport class NullProvider implements MailProvider {\n readonly name = 'null'\n readonly sendRatePerSecond = 1000\n public readonly sent: SendArgs[] = []\n\n async send(args: SendArgs): Promise<SendResult> {\n this.sent.push(args)\n return {\n providerId: `null-${Date.now()}-${++counter}`,\n status: 'accepted',\n }\n }\n\n /**\n * Fails closed. This provider has no signing key, so it can never establish\n * that an inbound payload is authentic — and a method whose entire job is to\n * reject unauthenticated input must not answer \"yes\" by default. Returning\n * `true` here would mean any unsigned body posted to the webhook route is\n * accepted as genuine whenever the null provider is registered, which is\n * exactly the dev/staging configuration where that is easiest to miss.\n *\n * Nothing is lost: `parseWebhookEvents()` returns `[]`, so there was never\n * any inbound behaviour to preserve. To exercise the inbound half locally,\n * use a provider that actually signs (see `test/README.md`).\n */\n async verifyWebhook(): Promise<boolean> {\n return false\n }\n\n parseWebhookEvents(): NormalizedEvent[] {\n return []\n }\n\n reset(): void {\n this.sent.length = 0\n }\n}\n","/**\n * Content linter for email templates. Pure function — no I/O.\n *\n * const result = lintTemplate(input, { senderDomains })\n * if (result.errors.length) refuse to publish\n *\n * The publish endpoint runs this as a gate. The editor will eventually run it\n * live for inline squiggles (PR10) — same engine, same rules.\n */\n\nimport type { TemplateKind } from '../../shared/enums.js'\nimport type { SenderDomainRegistry } from './sender-domain.js'\nimport { validateSenderDomain } from './sender-domain.js'\n\nexport type LintSeverity = 'error' | 'warning' | 'info'\n\nexport interface LintIssue {\n /** Stable rule identifier, e.g. 'missing_plain_text'. */\n rule: string\n severity: LintSeverity\n message: string\n /** Optional remediation hint shown in tooltips/expanders. */\n hint?: string\n}\n\nexport interface LintResult {\n errors: LintIssue[]\n warnings: LintIssue[]\n infos: LintIssue[]\n}\n\nexport interface LintInput {\n subject: string\n preheader: string\n /** MJML source, when authored that way. Empty string when authored via Maily. */\n mjml: string\n /**\n * Maily editor JSON source, when authored that way. Optional — passing it\n * helps rules that scan for merge tags survive HTML-encoding of braces\n * in body text.\n */\n editorJson?: unknown\n /** Rendered HTML. */\n html: string\n /** Rendered plain-text alternative. */\n plainText: string\n kind: TemplateKind\n fromEmail: string\n}\n\nexport interface LintConfig {\n senderDomains?: SenderDomainRegistry\n /**\n * JSON Schema of the host's varsAdapter (see `varsJsonSchema`). When set,\n * `{{paths}}` in subject/preheader/MJML/editorJson that don't exist in the\n * schema (or the built-in keys) are flagged as `unknown_variable` warnings.\n */\n varsJsonSchema?: Record<string, unknown> | null\n}\n\nconst URL_SHORTENERS = ['bit.ly', 't.co', 'tinyurl.com', 'goo.gl', 'ow.ly']\n\nconst SPAM_PHRASES: Array<{ pattern: RegExp; phrase: string }> = [\n { pattern: /\\bFREE\\b/, phrase: 'FREE' },\n { pattern: /\\bACT NOW\\b/i, phrase: 'ACT NOW' },\n { pattern: /\\b100%\\s+guaranteed\\b/i, phrase: '100% guaranteed' },\n]\n\nconst MARKETING_UNSUBSCRIBE_TAG = /\\{\\{\\s*unsubscribeUrl\\s*\\}\\}/\n\nexport function lintTemplate(rawInput: LintInput, config: LintConfig = {}): LintResult {\n // Coerce missing/undefined fields so downstream `.length` / `.test()`\n // calls don't throw. The publish path can hand us a draft with an\n // undefined subject, and we'd rather lint it (and emit a length warning)\n // than 500.\n const input: LintInput = {\n subject: typeof rawInput.subject === 'string' ? rawInput.subject : '',\n preheader: typeof rawInput.preheader === 'string' ? rawInput.preheader : '',\n mjml: typeof rawInput.mjml === 'string' ? rawInput.mjml : '',\n editorJson: rawInput.editorJson,\n html: typeof rawInput.html === 'string' ? rawInput.html : '',\n plainText: typeof rawInput.plainText === 'string' ? rawInput.plainText : '',\n kind: rawInput.kind === 'marketing' || rawInput.kind === 'transactional' ? rawInput.kind : 'transactional',\n fromEmail: typeof rawInput.fromEmail === 'string' ? rawInput.fromEmail : '',\n }\n const issues: LintIssue[] = []\n\n // 1. Missing plain-text alternative — error\n if (!input.plainText || input.plainText.trim().length === 0) {\n issues.push({\n rule: 'missing_plain_text',\n severity: 'error',\n message: 'Plain-text alternative is empty.',\n hint: 'Email clients and spam filters use the plain-text part. Add visible text content (MJML mj-text blocks, or text content in the Maily editor) — do not strip plain-text to empty.',\n })\n }\n\n // 2. Image-only body — error\n const imageCount = countMatches(input.html, /<img\\b/gi)\n const textLen = input.plainText.trim().length\n if (imageCount >= 1 && textLen < 20) {\n issues.push({\n rule: 'image_only_body',\n severity: 'error',\n message: 'Body is mostly images with little or no text.',\n hint: 'Image-only emails are heavily filtered as spam. Add at least one paragraph of meaningful text.',\n })\n }\n\n // 3. URL shortener — error\n const shortenerLinks = findShortenerLinks(input.html)\n if (shortenerLinks.length > 0) {\n issues.push({\n rule: 'url_shortener',\n severity: 'error',\n message: `Link uses a URL shortener: ${shortenerLinks.join(', ')}.`,\n hint: 'URL shorteners are strongly correlated with spam and are routinely blocked. Use a direct link to your domain.',\n })\n }\n\n // 4. Bare URL in body — warning\n if (hasBareUrlInVisibleText(input.html)) {\n issues.push({\n rule: 'bare_url',\n severity: 'warning',\n message: 'A URL appears in the body text without being wrapped in a link.',\n hint: 'Wrap visible URLs in an anchor tag — bare URLs look like spam template residue and reduce engagement.',\n })\n }\n\n // 5. Spammy phrases — warning (check both subject and plainText)\n const spam = findSpamSignals(`${input.subject}\\n${input.plainText}`)\n if (spam.length > 0) {\n issues.push({\n rule: 'spam_phrases',\n severity: 'warning',\n message: `Content contains spam-flagged phrases: ${spam.join(', ')}.`,\n hint: 'These phrases trigger content filters. Rephrase if possible.',\n })\n }\n\n // 6. All-caps subject — warning\n if (isAllCaps(input.subject)) {\n issues.push({\n rule: 'all_caps_subject',\n severity: 'warning',\n message: 'Subject line is mostly uppercase.',\n hint: 'All-caps subjects are flagged by spam filters and reduce click-through. Use sentence case.',\n })\n }\n\n // 7. Missing unsubscribe merge tag (marketing only) — error.\n // Check the raw mjml + editorJson + compiled HTML. @maily-to/render\n // HTML-encodes the `{{ }}` braces when they're placed in body text\n // (not in href), so checking only the rendered html misses legitimate\n // unsubscribe-tag placements.\n if (input.kind === 'marketing') {\n const sources = [input.mjml ?? '', input.html ?? '', JSON.stringify(input.editorJson ?? null)]\n const hasTag = sources.some((s) => MARKETING_UNSUBSCRIBE_TAG.test(s))\n if (!hasTag) {\n issues.push({\n rule: 'missing_unsubscribe_tag',\n severity: 'error',\n message: 'Marketing template is missing the {{unsubscribeUrl}} merge tag.',\n hint: 'CAN-SPAM, GDPR, and Gmail/Yahoo bulk-sender rules all require a working unsubscribe link. Add {{unsubscribeUrl}} somewhere in the body.',\n })\n }\n }\n\n // 8. From-domain mismatch — error (mirrors the publish-time check)\n const senderCheck = validateSenderDomain(input.fromEmail, input.kind, config.senderDomains)\n if (!senderCheck.ok) {\n issues.push({\n rule: 'sender_domain_invalid',\n severity: 'error',\n message: senderCheck.reason,\n hint: 'Edit the template fromEmail to use a domain declared for this kind in senderDomains, or update the registry.',\n })\n }\n\n // 9. Empty preheader — info\n if (!input.preheader || input.preheader.trim().length === 0) {\n issues.push({\n rule: 'empty_preheader',\n severity: 'info',\n message: 'No preheader set.',\n hint: 'The preheader shows next to the subject in most inbox previews. A good preheader lifts open rate 5-10%.',\n })\n }\n\n // 10. Subject too long — warning\n if (input.subject.length > 60) {\n issues.push({\n rule: 'subject_too_long',\n severity: 'warning',\n message: `Subject is ${input.subject.length} characters; mobile clients truncate around 60.`,\n hint: 'Front-load the important words so the truncated preview still makes sense.',\n })\n }\n\n // 11a. Unknown template variables — warning (only when a vars schema is provided)\n if (config.varsJsonSchema) {\n const sources = [input.subject, input.preheader, input.mjml, JSON.stringify(input.editorJson ?? null)]\n const unknown = findUnknownVariables(sources.join('\\n'), config.varsJsonSchema)\n if (unknown.length > 0) {\n issues.push({\n rule: 'unknown_variable',\n severity: 'warning',\n message: `Template references variable(s) not in the vars schema: ${unknown.join(', ')}.`,\n hint: 'These render as empty strings. Check for typos, or add the key to your varsAdapter schema. Paths inside {{#each}}/{{#with}} blocks are relative and not checked.',\n })\n }\n }\n\n // 12. Off-domain links — warning.\n // Mailbox providers weigh whether link domains line up with the From\n // domain. A stray off-domain link is normal (docs, social); a body whose\n // links mostly point elsewhere reads like a forwarded/spoofed template.\n const offDomain = findOffDomainLinkHosts(input.html, input.fromEmail)\n if (offDomain.majority && offDomain.hosts.length > 0) {\n issues.push({\n rule: 'offdomain_links',\n severity: 'warning',\n message: `Most links point away from the From domain: ${offDomain.hosts.join(', ')}.`,\n hint: 'Link domains that match the sending domain build reputation. Route links through your own domain (or a tracking subdomain of it) where you can.',\n })\n }\n\n // 13. Insecure links — warning.\n // Note: this is a scheme check only. Liveness (200 vs 404) needs network\n // I/O and does not belong in a pure lint pass.\n const insecure = findInsecureLinkHosts(input.html)\n if (insecure.length > 0) {\n issues.push({\n rule: 'insecure_link',\n severity: 'warning',\n message: `Link uses plain http://: ${insecure.join(', ')}.`,\n hint: 'Mixed-content links get rewritten or warned about by some clients, and http:// correlates with stale spam templates. Use https://.',\n })\n }\n\n // 14. Images missing alt text — warning.\n if (countImagesMissingAlt(input.html) > 0) {\n issues.push({\n rule: 'image_missing_alt',\n severity: 'warning',\n message: 'One or more images have no alt text.',\n hint: 'Most clients block images by default on first open. Alt text is what the recipient actually sees, and screen readers need it.',\n })\n }\n\n // 15. Image-only link — warning.\n if (hasImageOnlyLink(input.html)) {\n issues.push({\n rule: 'image_only_link',\n severity: 'warning',\n message: 'A link wraps an image with no accompanying text.',\n hint: 'With images blocked, an image-only call-to-action is invisible and unclickable. Add a text label inside the link.',\n })\n }\n\n // 11. Too many links — warning\n // Match href= with or without surrounding quotes — same shape as\n // extractHrefs above.\n const linkCount = countMatches(input.html, /<a\\s[^>]*\\bhref\\s*=/gi)\n if (linkCount > 10) {\n issues.push({\n rule: 'too_many_links',\n severity: 'warning',\n message: `${linkCount} links in body; promotional content with many links is flagged by content filters.`,\n hint: 'Consolidate calls-to-action. Aim for one primary action plus a footer link or two.',\n })\n }\n\n return splitBySeverity(issues)\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction splitBySeverity(issues: LintIssue[]): LintResult {\n const out: LintResult = { errors: [], warnings: [], infos: [] }\n for (const i of issues) {\n if (i.severity === 'error') out.errors.push(i)\n else if (i.severity === 'warning') out.warnings.push(i)\n else out.infos.push(i)\n }\n return out\n}\n\nfunction countMatches(s: string, re: RegExp): number {\n return (s.match(re) ?? []).length\n}\n\nfunction findShortenerLinks(html: string): string[] {\n const hrefs = extractHrefs(html)\n const hits = new Set<string>()\n for (const href of hrefs) {\n const domain = hostnameOf(href)\n if (!domain) continue\n if (URL_SHORTENERS.includes(domain)) hits.add(domain)\n }\n return Array.from(hits)\n}\n\nfunction extractHrefs(html: string): string[] {\n const out: string[] = []\n // Match href values in any of: double-quoted, single-quoted, or\n // unquoted (terminated by space, `>`, or end of tag). Maily-generated\n // HTML mostly quotes but operator-edited MJML may not.\n const re = /<a\\s[^>]*\\bhref\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)'|([^\\s>]+))/gi\n let m: RegExpExecArray | null\n while ((m = re.exec(html))) {\n const href = m[1] ?? m[2] ?? m[3]\n if (href) out.push(href)\n }\n return out\n}\n\nfunction hostnameOf(url: string): string | null {\n try {\n return new URL(url).hostname.toLowerCase()\n } catch {\n return null\n }\n}\n\n/**\n * Heuristic: strip anchor tags (and their contents), plus `<style>`,\n * `<script>`, and `<head>` blocks before looking for a bare URL. Otherwise\n * URLs in CSS (`@import url(...)`) or scripts trigger a false positive.\n */\nfunction hasBareUrlInVisibleText(html: string): boolean {\n const stripped = html\n .replace(/<a\\b[^>]*>.*?<\\/a>/gis, ' ')\n .replace(/<style\\b[^>]*>.*?<\\/style>/gis, ' ')\n .replace(/<script\\b[^>]*>.*?<\\/script>/gis, ' ')\n .replace(/<head\\b[^>]*>.*?<\\/head>/gis, ' ')\n return /https?:\\/\\/[^\\s<>\"']+/i.test(stripped)\n}\n\n/**\n * Hosts linked in the body that don't belong to the From domain, plus whether\n * they're the majority of resolvable links. Unresolved merge-tag hrefs\n * (`{{unsubscribeUrl}}`), mailto:/tel:, anchors, and relative URLs are\n * ignored — none of them carry a domain to compare.\n */\nfunction findOffDomainLinkHosts(html: string, fromEmail: string): { hosts: string[]; majority: boolean } {\n const fromDomain = fromEmail.split('@')[1]?.toLowerCase()\n if (!fromDomain) return { hosts: [], majority: false }\n\n const hosts = new Set<string>()\n let total = 0\n let off = 0\n for (const href of extractHrefs(html)) {\n if (href.includes('{{')) continue\n const host = hostnameOf(href)\n if (!host) continue\n total++\n if (sameSite(host, fromDomain)) continue\n off++\n hosts.add(host)\n }\n return { hosts: Array.from(hosts), majority: total > 0 && off * 2 > total }\n}\n\n/**\n * Approximate same-site test: exact match, either side a subdomain of the\n * other, or a shared last-two-label suffix (so `mail.example.com` and\n * `www.example.com` match). Deliberately loose — a false \"off-domain\"\n * warning is worse than a missed one, and we don't ship a PSL.\n */\nfunction sameSite(a: string, b: string): boolean {\n if (a === b) return true\n if (a.endsWith(`.${b}`) || b.endsWith(`.${a}`)) return true\n return lastLabels(a) === lastLabels(b)\n}\n\nfunction lastLabels(host: string): string {\n return host.split('.').slice(-2).join('.')\n}\n\nfunction findInsecureLinkHosts(html: string): string[] {\n const hits = new Set<string>()\n for (const href of extractHrefs(html)) {\n if (!/^http:\\/\\//i.test(href)) continue\n const host = hostnameOf(href)\n if (host) hits.add(host)\n }\n return Array.from(hits)\n}\n\nfunction countImagesMissingAlt(html: string): number {\n let missing = 0\n const re = /<img\\b[^>]*>/gi\n let m: RegExpExecArray | null\n while ((m = re.exec(html))) {\n const tag = m[0]\n const alt = /\\balt\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)'|([^\\s>]+))/i.exec(tag)\n const value = alt ? (alt[1] ?? alt[2] ?? alt[3] ?? '') : ''\n if (value.trim().length === 0) missing++\n }\n return missing\n}\n\n/** An anchor whose entire content is one or more images and no visible text. */\nfunction hasImageOnlyLink(html: string): boolean {\n const re = /<a\\b[^>]*>(.*?)<\\/a>/gis\n let m: RegExpExecArray | null\n while ((m = re.exec(html))) {\n const inner = m[1]!\n if (!/<img\\b/i.test(inner)) continue\n const text = inner\n .replace(/<[^>]*>/g, '')\n .replace(/&nbsp;/gi, ' ')\n .trim()\n if (text.length === 0) return true\n }\n return false\n}\n\nfunction findSpamSignals(text: string): string[] {\n const out = new Set<string>()\n for (const { pattern, phrase } of SPAM_PHRASES) {\n if (pattern.test(text)) out.add(phrase)\n }\n if (/!{3,}/.test(text)) out.add('excessive \"!!!\"')\n return Array.from(out)\n}\n\n// --- unknown_variable helpers ----------------------------------------------\n\n/** Render-context keys mailery provides regardless of the host schema. */\nconst BUILTIN_VAR_ROOTS = new Set([\n 'contact',\n 'vars',\n 'event',\n 'unsubscribeUrl',\n 'viewInBrowserUrl',\n 'preferenceCenterUrl',\n 'senderAddress',\n 'this',\n])\n\nconst PATH_TOKEN = /^@?[A-Za-z_][\\w$]*(\\.[A-Za-z_][\\w$]*)*$/\n\n/**\n * Extract `{{ ... }}` expressions and return the dotted paths that cannot be\n * found in the vars JSON Schema. Conservative by design: helper arguments,\n * block-relative paths, and any schema shape we can't confidently walk are\n * treated as valid — a warning here should never be a false alarm the\n * operator has to fight.\n */\nexport function findUnknownVariables(source: string, schema: Record<string, unknown>): string[] {\n // Block helpers introduce relative scopes ({{#each topics}} → {{title}}),\n // so bare single-segment identifiers can't be validated when any exist.\n const hasBlockScopes = /\\{\\{[#^]\\s*(each|with)\\b/.test(source)\n\n const unknown = new Set<string>()\n const re = /\\{\\{\\{?\\s*([^{}]+?)\\s*\\}?\\}\\}/g\n let m: RegExpExecArray | null\n while ((m = re.exec(source))) {\n const expr = m[1]!.trim()\n if (!expr || /^[#^/>!]/.test(expr) || expr === 'else') continue // blocks, partials, comments\n if (expr.includes('(')) continue // subexpressions — too dynamic to check\n\n // Helper call: skip the helper name, validate path-shaped args.\n // Single token: validate it directly.\n const parts = expr.split(/\\s+/)\n const candidates = parts.length > 1 ? parts.slice(1) : parts\n for (const raw of candidates) {\n if (!PATH_TOKEN.test(raw)) continue // quoted strings, numbers, key=val hash args\n if (raw.startsWith('@')) continue // @index, @key, @root\n const segments = raw.split('.')\n if (BUILTIN_VAR_ROOTS.has(segments[0]!)) continue\n if (hasBlockScopes && segments.length === 1) continue // possibly block-relative\n if (!schemaHasPath(schema, segments)) unknown.add(raw)\n }\n }\n return Array.from(unknown)\n}\n\n/**\n * Walk a JSON Schema along `segments`. Returns false only when we positively\n * know the path is absent (an object node with declared properties that lacks\n * the segment and forbids extras). Unions, arrays, open objects → true.\n */\nfunction schemaHasPath(node: unknown, segments: string[]): boolean {\n if (segments.length === 0) return true\n if (!node || typeof node !== 'object') return true // can't tell — accept\n const n = node as Record<string, any>\n\n // Union shapes (zod nullable/optional/union): valid if any branch accepts.\n for (const key of ['anyOf', 'oneOf', 'allOf']) {\n if (Array.isArray(n[key])) {\n return (n[key] as unknown[]).some((branch) => schemaHasPath(branch, segments))\n }\n }\n\n if (Array.isArray(n.type) && n.type.includes('object') && !n.properties) return true\n if (n.type === 'array') {\n if (segments[0] === 'length') return true // {{topics.length}}\n return schemaHasPath(n.items, segments)\n }\n\n const props = n.properties\n if (!props || typeof props !== 'object') return true // not a closed object — accept\n\n const [head, ...rest] = segments\n if (head! in props) return schemaHasPath(props[head!], rest)\n // Segment missing — only reject when the object doesn't allow extras.\n if (n.additionalProperties === undefined || n.additionalProperties === false) return false\n return true\n}\n\nfunction isAllCaps(subject: string): boolean {\n const letters = subject.replace(/[^a-zA-Z]/g, '')\n if (letters.length < 5) return false\n const upper = subject.replace(/[^A-Z]/g, '').length\n return upper / letters.length > 0.5\n}\n","/**\n * Admin router — serves the prebuilt React SPA + REST endpoints the SPA\n * consumes. Mount inside a host Express app, gated by host auth.\n *\n * app.use('/admin/mailer', requireAdmin, createAdminRouter(mailer))\n *\n * REST routes under /api/* are documented in plans/14-admin-api.md.\n */\n\nimport express, { Router, type Request, type Response, type NextFunction } from 'express'\nimport multer from 'multer'\nimport net from 'node:net'\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { ObjectId } from 'mongodb'\n\nimport type { Mailer } from '../mailer.js'\nimport {\n applyTracking,\n compileMailyTemplate,\n compileTemplate,\n renderTemplate,\n} from '../templates/render.js'\nimport { validateSenderDomain } from '../templates/sender-domain.js'\nimport { lintTemplate } from '../templates/linter.js'\nimport { resolveVars, varsJsonSchema, RESERVED_VAR_KEYS } from '../adapters/vars.js'\nimport type { Contact } from '../../shared/types.js'\nimport { TEMPLATE_BODY_FORMATS } from '../../shared/enums.js'\nimport { runSetupChecks } from './setup-status.js'\nimport { sha256Hex, signUnsubscribeToken } from '../tokens.js'\nimport { registeredProviderNames, resolveProvider } from '../provider-lookup.js'\nimport { effectiveOverallStatus } from '../runner/health.js'\nimport { runDnsblChecks } from '../runner/dnsbl.js'\nimport { runPostmasterPull } from '../runner/postmaster.js'\nimport { runSndsPull } from '../runner/snds.js'\nimport { ingestDmarcAttachment, resolveSourceTags, suggestPolicyProgression } from '../runner/dmarc.js'\nimport { computeListHygiene } from '../runner/hygiene.js'\nimport {\n createMailTesterClient,\n evaluateMailTesterGate,\n findCachedScore,\n mailTesterContentKey,\n persistScore,\n type MailTesterClient,\n} from '../runner/mail-tester.js'\nimport { HEALTH_AGG_ID, healthBucketId } from '../models/index.js'\n\nconst __filename = fileURLToPath(import.meta.url)\nconst __dirname = path.dirname(__filename)\n\nfunction defaultSpaDir(): string {\n // After tsup build: dist/index.{js,cjs} + dist/admin/spa/. __dirname = dist/.\n return path.resolve(__dirname, 'admin/spa')\n}\n\nexport interface AdminRouterOptions {\n /** Override path to the built SPA. Defaults to `dist/admin/spa` shipped with the package. */\n spaDir?: string\n /** Resolve actor metadata from a Request. Defaults to `human:${req.user?.email || 'anonymous'}`. */\n getActor?: (req: Request) => string\n /**\n * Inject a Mail-Tester client (tests use a stub). When omitted, a real\n * client is created from `mailer.config.mailTester`.\n */\n mailTesterClient?: MailTesterClient\n}\n\nexport function createAdminRouter(mailer: Mailer, opts: AdminRouterOptions = {}): Router {\n const router = Router()\n const spaDir = opts.spaDir ?? defaultSpaDir()\n const getActor =\n opts.getActor ?? ((req: Request) => `human:${(req as any).user?.email ?? 'anonymous'}`)\n\n // Static assets — long cache, hashed filenames.\n router.use(\n '/_assets',\n express.static(spaDir, {\n maxAge: '1y',\n immutable: true,\n index: false,\n }),\n )\n\n // JSON body parsing for mutating endpoints.\n router.use('/api', express.json({ limit: '1mb' }))\n\n // Inject actor on every API request (read after the host's auth middleware).\n router.use('/api', (req: Request, _res, next: NextFunction) => {\n ;(req as any).actor = getActor(req)\n next()\n })\n\n router.use('/api', apiRouter(mailer, opts))\n\n // SPA shell — any other route returns index.html so client-side routing\n // doesn't 404 on refresh.\n router.get(/.*/, (_req: Request, res: Response) => {\n res.sendFile(path.join(spaDir, 'index.html'))\n })\n\n return router\n}\n\n// ---------------------------------------------------------------------------\n// JSON API\n// ---------------------------------------------------------------------------\n\nfunction apiRouter(mailer: Mailer, opts: AdminRouterOptions = {}): Router {\n const r = Router()\n const c = mailer.collections\n\n // Computed once — the vars schema is fixed for the process lifetime.\n const varsSchema = mailer.config.varsAdapter ? varsJsonSchema(mailer.config.varsAdapter) : null\n\n function getMailTesterClient(): MailTesterClient | null {\n if (opts.mailTesterClient) return opts.mailTesterClient\n const cfg = mailer.config.mailTester\n if (!cfg?.apiKey) return null\n return createMailTesterClient(cfg)\n }\n\n // Vars contract for the template editor — JSON Schema of the host's\n // varsAdapter (null when none configured) plus the mailery-provided\n // built-in keys, so autocomplete/linting have one source of truth.\n r.get(\n '/vars-schema',\n asyncHandler(async (_req, res) => {\n res.json({ schema: varsSchema, builtins: RESERVED_VAR_KEYS })\n }),\n )\n\n r.get(\n '/me',\n asyncHandler(async (req, res) => {\n const [flows, templates, broadcasts, contacts, suppressions, healthDocs] = await Promise.all([\n c.flows.estimatedDocumentCount(),\n c.templates.estimatedDocumentCount(),\n c.broadcasts.estimatedDocumentCount(),\n c.subscriptions.countDocuments({ status: 'subscribed' }),\n c.suppressions.estimatedDocumentCount(),\n c.health.find({}).limit(500).toArray(),\n ])\n res.json({\n actor: (req as any).actor,\n counts: { flows, templates, broadcasts, contacts, suppressions },\n health: { status: effectiveOverallStatus(healthDocs) },\n providers: {\n names: Object.keys(mailer.config.providers),\n default: mailer.config.defaultProvider,\n },\n broadcastConfirmationThreshold: mailer.config.broadcastConfirmationThreshold,\n })\n }),\n )\n\n // ----- Dashboard ----------------------------------------------------------\n r.get(\n '/dashboard',\n asyncHandler(async (_req, res) => {\n const now = Date.now()\n const HOUR = 60 * 60 * 1000\n const since24h = new Date(now - 24 * HOUR)\n const since48h = new Date(now - 48 * HOUR)\n\n const [\n sentTotal, deliveredCount, bouncedCount, openedCount, clickedCount,\n sentPrev, deliveredPrev, openedPrev, clickedPrev,\n hourly,\n ] = await Promise.all([\n c.sends.countDocuments({ queuedAt: { $gt: since24h } }),\n c.sends.countDocuments({ queuedAt: { $gt: since24h }, status: 'delivered' }),\n c.sends.countDocuments({ queuedAt: { $gt: since24h }, status: 'bounced' }),\n c.sends.countDocuments({ queuedAt: { $gt: since24h }, openedAt: { $ne: null } }),\n c.sends.countDocuments({ queuedAt: { $gt: since24h }, firstClickAt: { $ne: null } }),\n c.sends.countDocuments({ queuedAt: { $gt: since48h, $lte: since24h } }),\n c.sends.countDocuments({ queuedAt: { $gt: since48h, $lte: since24h }, status: 'delivered' }),\n c.sends.countDocuments({ queuedAt: { $gt: since48h, $lte: since24h }, openedAt: { $ne: null } }),\n c.sends.countDocuments({ queuedAt: { $gt: since48h, $lte: since24h }, firstClickAt: { $ne: null } }),\n c.sends\n .aggregate<{ _id: number; sends: number; opens: number }>([\n { $match: { queuedAt: { $gt: since24h } } },\n {\n $project: {\n hour: {\n $toInt: {\n $divide: [{ $subtract: [now, { $toLong: '$queuedAt' }] }, HOUR],\n },\n },\n opened: { $cond: [{ $ifNull: ['$openedAt', false] }, 1, 0] },\n },\n },\n { $group: { _id: '$hour', sends: { $sum: 1 }, opens: { $sum: '$opened' } } },\n ])\n .toArray(),\n ])\n\n const sendSeries = new Array(24).fill(0)\n const openSeries = new Array(24).fill(0)\n for (const row of hourly) {\n const idx = 23 - Math.max(0, Math.min(23, row._id))\n sendSeries[idx] = row.sends\n openSeries[idx] = row.opens\n }\n\n const delta = (cur: number, prev: number): number | null => {\n if (prev === 0) return null\n return (cur - prev) / prev\n }\n const rateDelta = (curN: number, curD: number, prevN: number, prevD: number): number | null => {\n if (prevD === 0 || curD === 0) return null\n return curN / curD - prevN / prevD\n }\n\n const healthDocs = await c.health.find({}).limit(500).toArray()\n const healthAgg = healthDocs.find((d) => d._id === HEALTH_AGG_ID) ?? null\n const recentFlowsRaw = await c.flows.find({ enabled: true }).limit(5).toArray()\n const flowStatsMap = await computeFlowStats(mailer)\n const recentFlows = recentFlowsRaw.map((f) => ({ ...f, stats: flowStatsMap.get(f.slug) ?? emptyFlowStats() }))\n const recentSends = await c.sends.find().sort({ queuedAt: -1 }).limit(6).toArray()\n const recentAudit = await c.auditLog.find().sort({ occurredAt: -1 }).limit(5).toArray()\n\n const queueCounts = await collectQueueCounts(mailer)\n const lastSendError = await c.sends\n .findOne({ status: { $in: ['bounced', 'failed'] } }, { sort: { queuedAt: -1 } })\n const lastSendOk = await c.sends\n .findOne({ status: 'delivered' }, { sort: { queuedAt: -1 } })\n const providerOk =\n lastSendOk && lastSendError\n ? new Date(lastSendOk.queuedAt as Date).getTime() >= new Date(lastSendError.queuedAt as Date).getTime()\n : lastSendOk\n ? true\n : lastSendError\n ? false\n : null\n\n res.json({\n kpis: {\n sends: { value: sentTotal, delta: delta(sentTotal, sentPrev) },\n deliveredRate: {\n value: sentTotal === 0 ? null : deliveredCount / sentTotal,\n delta: rateDelta(deliveredCount, sentTotal, deliveredPrev, sentPrev),\n bounced: bouncedCount,\n },\n openRate: {\n value: sentTotal === 0 ? null : openedCount / sentTotal,\n delta: rateDelta(openedCount, sentTotal, openedPrev, sentPrev),\n },\n clickRate: {\n value: sentTotal === 0 ? null : clickedCount / sentTotal,\n delta: rateDelta(clickedCount, sentTotal, clickedPrev, sentPrev),\n },\n },\n series: { hourly: { sends: sendSeries, opens: openSeries } },\n health: {\n status: effectiveOverallStatus(healthDocs),\n rates: healthAgg?.rates ?? null,\n thresholds: {\n hardBounceRatePctTrip: mailer.config.circuitBreaker.hardBounceRatePctTrip,\n complaintRatePctTrip: mailer.config.circuitBreaker.complaintRatePctTrip,\n combinedBounceRatePctTrip: mailer.config.circuitBreaker.combinedBounceRatePctTrip,\n failedToSendRatePctDegrade: mailer.config.circuitBreaker.failedToSendRatePctDegrade,\n },\n },\n queue: {\n inFlight: queueCounts?.inFlight ?? null,\n delayed: queueCounts?.delayed ?? null,\n providerOk,\n providerName: mailer.config.defaultProvider,\n },\n recentFlows,\n recentSends,\n recentAudit,\n })\n }),\n )\n\n // ----- Events registry ----------------------------------------------------\n r.get(\n '/events',\n asyncHandler(async (_req, res) => {\n const registered = mailer.events.list()\n const seenNames = await c.events.distinct('name')\n const known = new Set(registered.map((r) => r.name))\n const unregistered = (seenNames as string[]).filter((n) => n && !known.has(n))\n res.json({\n registered: registered.sort((a, b) => a.name.localeCompare(b.name)),\n seen: unregistered.sort(),\n })\n }),\n )\n\n // ----- Flows --------------------------------------------------------------\n r.get(\n '/flows',\n asyncHandler(async (_req, res) => {\n const flows = await c.flows.find().sort({ updatedAt: -1 }).toArray()\n const stats = await computeFlowStats(mailer)\n res.json(flows.map((f) => ({ ...f, stats: stats.get(f.slug) ?? emptyFlowStats() })))\n }),\n )\n\n r.get(\n '/flows/:slug',\n asyncHandler(async (req, res) => {\n const flow = await c.flows.findOne({ slug: req.params.slug })\n if (!flow) return res.status(404).json({ error: 'not_found' })\n const stats = (await computeFlowStats(mailer, flow.slug)).get(flow.slug) ?? emptyFlowStats()\n return res.json({ ...flow, stats })\n }),\n )\n\n r.post(\n '/flows/:slug/pause',\n asyncHandler(async (req, res) => {\n const before = await c.flows.findOne({ slug: req.params.slug })\n if (!before) return res.status(404).json({ error: 'not_found' })\n await c.flows.updateOne({ _id: before._id }, { $set: { enabled: false, updatedAt: new Date() } })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'flow.pause',\n resource: { collection: 'mailer_flows', id: before._id, slug: before.slug },\n })\n return res.json({ ok: true })\n }),\n )\n\n r.post(\n '/flows/:slug/resume',\n asyncHandler(async (req, res) => {\n const before = await c.flows.findOne({ slug: req.params.slug })\n if (!before) return res.status(404).json({ error: 'not_found' })\n await c.flows.updateOne({ _id: before._id }, { $set: { enabled: true, updatedAt: new Date() } })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'flow.resume',\n resource: { collection: 'mailer_flows', id: before._id, slug: before.slug },\n })\n return res.json({ ok: true })\n }),\n )\n\n // ----- Templates ----------------------------------------------------------\n r.get(\n '/templates',\n asyncHandler(async (_req, res) => {\n const templates = await c.templates.find().sort({ updatedAt: -1 }).toArray()\n const stats = await computeTemplateStats(mailer)\n res.json(templates.map((t) => ({ ...t, stats: stats.get(t.slug) ?? emptyTemplateStats() })))\n }),\n )\n\n r.get(\n '/templates/:slug',\n asyncHandler(async (req, res) => {\n const template = await c.templates.findOne({ slug: req.params.slug })\n if (!template) return res.status(404).json({ error: 'not_found' })\n const stats = (await computeTemplateStats(mailer, template.slug)).get(template.slug) ?? emptyTemplateStats()\n return res.json({ ...template, stats })\n }),\n )\n\n // ----- Broadcasts ---------------------------------------------------------\n r.get(\n '/broadcasts',\n asyncHandler(async (_req, res) => {\n const broadcasts = await c.broadcasts.find().sort({ createdAt: -1 }).toArray()\n const stats = await computeBroadcastStats(mailer)\n res.json(broadcasts.map((b) => ({ ...b, stats: stats.get(String(b._id)) ?? emptyBroadcastStats() })))\n }),\n )\n\n r.get(\n '/broadcasts/:slug',\n asyncHandler(async (req, res) => {\n const broadcast = await c.broadcasts.findOne({ slug: req.params.slug })\n if (!broadcast) return res.status(404).json({ error: 'not_found' })\n const stats = (await computeBroadcastStats(mailer, broadcast._id)).get(String(broadcast._id)) ?? emptyBroadcastStats()\n return res.json({ ...broadcast, stats })\n }),\n )\n\n // ----- Contacts -----------------------------------------------------------\n r.get(\n '/contacts',\n asyncHandler(async (req, res) => {\n const cursor = typeof req.query.cursor === 'string' ? req.query.cursor : undefined\n const limit = Math.min(Number(req.query.limit ?? 50), 200)\n const [{ contacts, nextCursor }, counts] = await Promise.all([\n mailer.adapter.query({}, { limit, cursor }),\n (async () => {\n const rows = await c.subscriptions\n .aggregate<{ _id: string; n: number }>([{ $group: { _id: '$status', n: { $sum: 1 } } }])\n .toArray()\n const out: Record<string, number> = { subscribed: 0, pending_doi: 0, unsubscribed: 0, bounced: 0, complained: 0 }\n let total = 0\n for (const r of rows) {\n if (r._id) out[r._id] = r.n\n total += r.n\n }\n return { ...out, total }\n })(),\n ])\n res.json({ contacts, nextCursor, counts })\n }),\n )\n\n r.get(\n '/contacts/:externalId',\n asyncHandler(async (req, res) => {\n const externalId = String(req.params.externalId)\n const [contact, subscription, recentEvents, recentSends, activeRuns] = await Promise.all([\n mailer.adapter.getById(externalId),\n c.subscriptions.findOne({ externalId }),\n c.events.find({ externalId }).sort({ occurredAt: -1 }).limit(50).toArray(),\n c.sends.find({ externalId }).sort({ queuedAt: -1 }).limit(50).toArray(),\n c.flowRuns.find({ externalId, status: 'active' }).sort({ nextActionAt: 1 }).limit(50).toArray(),\n ])\n if (!contact) return res.status(404).json({ error: 'not_found' })\n return res.json({ contact, subscription, recentEvents, recentSends, activeRuns })\n }),\n )\n\n // ----- Sends --------------------------------------------------------------\n r.get(\n '/sends',\n asyncHandler(async (req, res) => {\n const limit = Math.min(Number(req.query.limit ?? 100), 500)\n const status = typeof req.query.status === 'string' ? req.query.status : undefined\n const filter: any = {}\n if (status) filter.status = status\n const sends = await c.sends.find(filter).sort({ queuedAt: -1 }).limit(limit).toArray()\n res.json(sends)\n }),\n )\n\n r.get(\n '/sends/:id',\n asyncHandler(async (req, res) => {\n const id = String(req.params.id)\n if (!ObjectId.isValid(id)) return res.status(400).json({ error: 'bad_id' })\n const send = await c.sends.findOne({ _id: new ObjectId(id) })\n if (!send) return res.status(404).json({ error: 'not_found' })\n const events = send.providerMessageId\n ? await c.webhookEvents\n .find({ providerMessageId: send.providerMessageId })\n .sort({ receivedAt: -1 })\n .limit(100)\n .toArray()\n : []\n return res.json({ send, webhookEvents: events })\n }),\n )\n\n // ----- Suppressions -------------------------------------------------------\n r.get(\n '/suppressions',\n asyncHandler(async (_req, res) => {\n const rows = await c.suppressions.find().sort({ addedAt: -1 }).limit(500).toArray()\n res.json(rows)\n }),\n )\n\n r.post(\n '/suppressions',\n asyncHandler(async (req, res) => {\n const { email, scope, reason, source, notes } = req.body ?? {}\n await mailer.suppress(email, { scope, reason, source, notes })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'suppression.add',\n resource: { collection: 'mailer_suppressions' },\n diffSummary: `${email} → ${scope}/${reason}`,\n })\n res.json({ ok: true })\n }),\n )\n\n // ----- Audit log ----------------------------------------------------------\n r.get(\n '/audit',\n asyncHandler(async (_req, res) => {\n const rows = await c.auditLog.find().sort({ occurredAt: -1 }).limit(200).toArray()\n res.json(rows)\n }),\n )\n\n // ----- Setup status -------------------------------------------------------\n r.get(\n '/setup-status',\n asyncHandler(async (_req, res) => {\n const status = await runSetupChecks(mailer)\n res.json(status)\n }),\n )\n\n // ----- Health -------------------------------------------------------------\n r.get(\n '/health',\n asyncHandler(async (_req, res) => {\n const cb = mailer.config.circuitBreaker\n const thresholds = {\n hardBounceRatePctTrip: cb.hardBounceRatePctTrip,\n complaintRatePctTrip: cb.complaintRatePctTrip,\n combinedBounceRatePctTrip: cb.combinedBounceRatePctTrip,\n failedToSendRatePctDegrade: cb.failedToSendRatePctDegrade,\n }\n const docs = await c.health.find({}).limit(500).toArray()\n const aggregate = docs.find((d) => d._id === HEALTH_AGG_ID) ?? null\n const buckets = docs.filter((d) => d._id !== HEALTH_AGG_ID)\n const overall = effectiveOverallStatus(docs)\n if (docs.length === 0) {\n // No tick has run yet. UI renders \"—\" / muted dots when status is null.\n res.json({ status: null, rates: null, counters: null, aggregate: null, buckets: [], thresholds })\n return\n }\n // Keep top-level `status` / `rates` for back-compat with consumers that\n // expect a single status (broadcast-new pre-flight, shell pill).\n res.json({\n status: overall,\n rates: aggregate?.rates ?? null,\n counters: aggregate?.counters ?? null,\n aggregate,\n buckets,\n thresholds,\n })\n }),\n )\n\n r.get(\n '/health/trips',\n asyncHandler(async (_req, res) => {\n const rows = await c.auditLog\n .find({ action: { $in: ['health.trip', 'health.resume'] } })\n .sort({ occurredAt: -1 })\n .limit(50)\n .toArray()\n res.json(rows)\n }),\n )\n\n r.post(\n '/health/resume',\n asyncHandler(async (req, res) => {\n const body = (req.body ?? {}) as { senderDomain?: string; kind?: 'marketing' | 'transactional' }\n // Half-specified body (only senderDomain or only kind) is almost\n // certainly an operator error — fail closed rather than silently\n // resume every tripped bucket.\n if ((body.senderDomain != null) !== (body.kind != null)) {\n return res.status(400).json({\n error: 'validation_failed',\n message: 'senderDomain and kind must both be provided to target a single bucket, or both omitted to resume all tripped buckets.',\n })\n }\n if (body.kind && !['marketing', 'transactional'].includes(body.kind)) {\n return res.status(400).json({ error: 'validation_failed', message: 'kind must be \"marketing\" or \"transactional\"' })\n }\n const target = body.senderDomain && body.kind\n ? { _id: healthBucketId(body.senderDomain.toLowerCase(), body.kind) }\n // Explicitly exclude the aggregate doc — it never trips, but guard\n // anyway so a future schema change can't accidentally flip its status.\n : { status: 'tripped' as const, _id: { $ne: HEALTH_AGG_ID } }\n\n const result = await c.health.updateMany(\n target,\n { $set: { status: 'healthy', manuallyResumedAt: new Date(), updatedAt: new Date() } },\n )\n await mailer.audit({\n actor: (req as any).actor,\n action: 'health.resume',\n resource: {\n collection: 'mailer_health',\n id: body.senderDomain && body.kind ? `${body.senderDomain}|${body.kind}` : 'all-tripped',\n },\n })\n res.json({ ok: true, resumed: result.modifiedCount })\n }),\n )\n\n // ----- DNSBL --------------------------------------------------------------\n r.get(\n '/dnsbl',\n asyncHandler(async (_req, res) => {\n const checks = await c.dnsblChecks.find({}).sort({ result: 1, target: 1, list: 1 }).limit(500).toArray()\n const latestRunAt = checks.reduce<Date | null>((acc, d) => {\n const t = new Date(d.runAt)\n return acc && acc.getTime() >= t.getTime() ? acc : t\n }, null)\n res.json({\n checks,\n latestRunAt: latestRunAt ? latestRunAt.toISOString() : null,\n intervalHours: mailer.config.dnsbl?.intervalHours ?? 24,\n })\n }),\n )\n\n r.post(\n '/dnsbl/recheck',\n asyncHandler(async (req, res) => {\n const result = await runDnsblChecks(mailer.getRunnerContext(), { force: true })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'dnsbl.recheck',\n resource: { collection: 'mailer_dnsbl_checks' },\n diffSummary: result.ran\n ? `${result.totalChecks} checks, ${result.listedCount} listed`\n : `not run: ${result.reason}`,\n })\n res.json(result)\n }),\n )\n\n // ----- Postmaster Tools ---------------------------------------------------\n r.get(\n '/postmaster',\n asyncHandler(async (_req, res) => {\n const cfg = mailer.config.postmaster\n const configured = !!cfg?.clientId && !!cfg?.clientSecret && !!cfg?.refreshToken\n const all = await c.postmasterSnapshots.find({}).sort({ domain: 1, date: -1 }).limit(2000).toArray()\n // Group by domain, keep last 30 entries per domain.\n const byDomain = new Map<string, typeof all>()\n for (const s of all) {\n const arr = byDomain.get(s.domain) ?? []\n if (arr.length < 30) arr.push(s)\n byDomain.set(s.domain, arr)\n }\n const domains = Array.from(byDomain.entries()).map(([domain, snapshots]) => ({\n domain,\n latest: snapshots[0] ?? null,\n history: snapshots,\n }))\n res.json({\n configured,\n intervalHours: cfg?.intervalHours ?? 24,\n domains,\n })\n }),\n )\n\n r.post(\n '/postmaster/refresh',\n asyncHandler(async (req, res) => {\n const result = await runPostmasterPull(mailer.getRunnerContext(), { force: true })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'postmaster.refresh',\n resource: { collection: 'mailer_postmaster_snapshots' },\n diffSummary: result.ran\n ? `fetched ${result.fetched ?? 0}, tripped ${(result.trippedDomains ?? []).length}`\n : `not run: ${result.reason}`,\n })\n res.json(result)\n }),\n )\n\n // ----- List Hygiene -------------------------------------------------------\n // The hygiene aggregation iterates every send doc — at scale that's\n // expensive. Cache the result for 60s and serialize concurrent requests\n // so a few rapid-fire dashboard loads can't pile up multiple full scans.\n let hygieneCache: { computedAt: number; report: Awaited<ReturnType<typeof computeListHygiene>> } | null = null\n let hygieneInFlight: Promise<Awaited<ReturnType<typeof computeListHygiene>>> | null = null\n const HYGIENE_CACHE_MS = 60_000\n\n r.get(\n '/hygiene',\n asyncHandler(async (req, res) => {\n const force = req.query.refresh === '1' || req.query.refresh === 'true'\n const now = Date.now()\n if (!force && hygieneCache && now - hygieneCache.computedAt < HYGIENE_CACHE_MS) {\n return res.json(hygieneCache.report)\n }\n if (!hygieneInFlight) {\n hygieneInFlight = (async () => {\n try {\n const report = await computeListHygiene(mailer.getRunnerContext())\n hygieneCache = { computedAt: Date.now(), report }\n return report\n } finally {\n hygieneInFlight = null\n }\n })()\n }\n const report = await hygieneInFlight\n res.json(report)\n }),\n )\n\n // ----- DMARC RUA ingestion ------------------------------------------------\n const dmarcUpload = multer({\n storage: multer.memoryStorage(),\n limits: { fileSize: 10 * 1024 * 1024 }, // 10 MB; reports are typically <100KB\n })\n\n r.post(\n '/dmarc/upload',\n dmarcUpload.single('file'),\n asyncHandler(async (req, res) => {\n const file = (req as any).file as Express.Multer.File | undefined\n if (!file) return res.status(400).json({ error: 'no_file', message: 'expected a \"file\" field' })\n\n try {\n const result = await ingestDmarcAttachment(mailer.getRunnerContext(), file.buffer, file.originalname)\n await mailer.audit({\n actor: (req as any).actor,\n action: 'dmarc.ingest',\n resource: { collection: 'mailer_dmarc_reports', id: result.reportId },\n diffSummary: result.duplicate\n ? `duplicate report ${result.reportId}`\n : `ingested ${result.totalMessages} msgs (${result.passCount} pass / ${result.failCount} fail) for ${result.domain}`,\n })\n return res.json(result)\n } catch (err: any) {\n return res.status(400).json({ error: 'ingest_failed', message: String(err?.message ?? err) })\n }\n }),\n )\n\n r.get(\n '/dmarc',\n asyncHandler(async (_req, res) => {\n const ctx = mailer.getRunnerContext()\n const tagged = await resolveSourceTags(ctx)\n const reports = await c.dmarcReports.find({}).sort({ rangeEnd: -1 }).limit(200).toArray()\n const since30 = new Date(Date.now() - 30 * 86_400_000)\n // Cap at 5k rows — busy domains can easily generate that many failure\n // rows over 30 days. We only consume these for per-domain progression\n // suggestions (untagged-source check); a partial page is fine.\n const recentFailures = await c.dmarcFailures\n .find({ receivedAt: { $gte: since30 } })\n .sort({ receivedAt: -1 })\n .limit(5000)\n .toArray()\n\n const byDomain = new Map<string, { passCount: number; failCount: number; totalMessages: number; reportCount: number; latestRangeEnd: Date | null; latestPolicy: 'none' | 'quarantine' | 'reject' | null; latestPct: number | null; reports: typeof reports }>()\n for (const r of reports) {\n const cur = byDomain.get(r.domain) ?? { passCount: 0, failCount: 0, totalMessages: 0, reportCount: 0, latestRangeEnd: null, latestPolicy: null, latestPct: null, reports: [] }\n cur.passCount += r.passCount\n cur.failCount += r.failCount\n cur.totalMessages += r.totalMessages\n cur.reportCount += 1\n const re = new Date(r.rangeEnd)\n if (!cur.latestRangeEnd || re > cur.latestRangeEnd) {\n cur.latestRangeEnd = re\n cur.latestPolicy = r.policyP\n cur.latestPct = r.policyPct\n }\n cur.reports.push(r)\n byDomain.set(r.domain, cur)\n }\n\n // Build per-day alignment series (last 14 days) per domain for sparklines.\n const since14 = Date.now() - 14 * 86_400_000\n\n const domains = Array.from(byDomain.entries()).map(([domain, s]) => {\n // Sparkline series — pass rate per day from recent reports.\n const dayTotals = new Map<string, { pass: number; total: number }>()\n for (const r of s.reports) {\n if (new Date(r.rangeEnd).getTime() < since14) continue\n const day = new Date(r.rangeEnd).toISOString().slice(0, 10)\n const d = dayTotals.get(day) ?? { pass: 0, total: 0 }\n d.pass += r.passCount\n d.total += r.passCount + r.failCount\n dayTotals.set(day, d)\n }\n const series = Array.from(dayTotals.entries())\n .sort((a, b) => a[0].localeCompare(b[0]))\n .map(([day, d]) => ({ day, alignmentRate: d.total === 0 ? null : d.pass / d.total }))\n\n // Policy progression suggestion.\n const knownIps = new Set(Array.from(tagged.values()).filter((t) => !t.ignored).map((t) => t.ip))\n const ignoredIps = new Set(Array.from(tagged.values()).filter((t) => t.ignored).map((t) => t.ip))\n const suggested = suggestPolicyProgression({\n reports: s.reports.map((r) => ({ rangeEnd: new Date(r.rangeEnd), passCount: r.passCount, failCount: r.failCount })),\n failures: recentFailures.filter((f) => f.domain === domain).map((f) => ({ sourceIp: f.sourceIp, count: f.count, receivedAt: new Date(f.receivedAt) })),\n knownSourceIps: knownIps,\n ignoredSourceIps: ignoredIps,\n currentPolicy: s.latestPolicy,\n currentPct: s.latestPct,\n })\n\n return {\n domain,\n passCount: s.passCount,\n failCount: s.failCount,\n totalMessages: s.totalMessages,\n reportCount: s.reportCount,\n latestRangeEnd: s.latestRangeEnd,\n alignmentRate: s.totalMessages === 0 ? null : s.passCount / s.totalMessages,\n currentPolicy: s.latestPolicy,\n currentPct: s.latestPct,\n progression: suggested\n ? { ...suggested, current: { policy: s.latestPolicy, pct: s.latestPct } }\n : null,\n series,\n }\n })\n\n const topFailures = await c.dmarcFailures\n .aggregate<{ _id: { sourceIp: string; domain: string }; total: number; days: number; lastSeen: Date; sample: any }>([\n { $match: { receivedAt: { $gte: since30 } } },\n {\n $group: {\n _id: { sourceIp: '$sourceIp', domain: '$domain' },\n total: { $sum: '$count' },\n days: { $addToSet: '$day' },\n lastSeen: { $max: '$receivedAt' },\n sample: { $first: '$$ROOT' },\n },\n },\n { $project: { sourceIp: '$_id.sourceIp', domain: '$_id.domain', total: 1, days: { $size: '$days' }, lastSeen: 1, sample: 1 } },\n { $sort: { total: -1 } },\n { $limit: 50 },\n ])\n .toArray()\n\n const sources = topFailures.map((f) => {\n const tag = tagged.get(f._id.sourceIp)\n return {\n sourceIp: f._id.sourceIp,\n domain: f._id.domain,\n totalMessages: f.total,\n daysSeen: f.days,\n lastSeen: f.lastSeen,\n dkimResult: f.sample.dkimResult,\n spfResult: f.sample.spfResult,\n dispositionApplied: f.sample.dispositionApplied,\n label: tag?.label ?? null,\n ignored: !!tag?.ignored,\n tagSource: tag?.source ?? null,\n }\n })\n\n res.json({\n domains,\n sources,\n recentReports: reports.slice(0, 30),\n retentionDays: mailer.config.dmarc?.retentionDays ?? 90,\n })\n }),\n )\n\n // ----- DMARC source tags (mutable from UI) --------------------------------\n r.put(\n '/dmarc/sources/:ip',\n asyncHandler(async (req, res) => {\n const ip = String(req.params.ip ?? '')\n if (!net.isIP(ip)) {\n return res.status(400).json({ error: 'validation_failed', message: 'invalid IP' })\n }\n const body = (req.body ?? {}) as { label?: string; ignored?: boolean }\n if (!body.label || typeof body.label !== 'string') {\n return res.status(400).json({ error: 'validation_failed', message: 'label is required' })\n }\n const label = body.label.trim().slice(0, 200)\n if (!label) {\n return res.status(400).json({ error: 'validation_failed', message: 'label is required' })\n }\n const ignored = !!body.ignored\n await c.dmarcSourceTags.updateOne(\n { ip },\n { $set: { ip, label, ignored, setBy: (req as any).actor ?? 'unknown', setAt: new Date() } },\n { upsert: true },\n )\n await mailer.audit({\n actor: (req as any).actor,\n action: 'dmarc.source_tag.upsert',\n resource: { collection: 'mailer_dmarc_source_tags', id: ip },\n diffSummary: `${ip} → \"${label}\"${ignored ? ' (ignored)' : ''}`,\n })\n res.json({ ok: true })\n }),\n )\n\n r.delete(\n '/dmarc/sources/:ip',\n asyncHandler(async (req, res) => {\n const ip = String(req.params.ip ?? '')\n if (!net.isIP(ip)) {\n return res.status(400).json({ error: 'validation_failed', message: 'invalid IP' })\n }\n const result = await c.dmarcSourceTags.deleteOne({ ip })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'dmarc.source_tag.delete',\n resource: { collection: 'mailer_dmarc_source_tags', id: ip },\n })\n res.json({ ok: true, deleted: result.deletedCount })\n }),\n )\n\n // ----- Microsoft SNDS -----------------------------------------------------\n r.get(\n '/snds',\n asyncHandler(async (_req, res) => {\n const cfg = mailer.config.snds\n const configured = !!cfg?.accessKey\n const all = await c.sndsSnapshots.find({}).sort({ ip: 1, activityStart: -1 }).limit(2000).toArray()\n const byIp = new Map<string, typeof all>()\n for (const s of all) {\n const arr = byIp.get(s.ip) ?? []\n if (arr.length < 30) arr.push(s)\n byIp.set(s.ip, arr)\n }\n const ips = Array.from(byIp.entries()).map(([ip, snapshots]) => ({\n ip,\n latest: snapshots[0] ?? null,\n history: snapshots,\n }))\n res.json({\n configured,\n intervalHours: cfg?.intervalHours ?? 24,\n ips,\n })\n }),\n )\n\n r.post(\n '/snds/refresh',\n asyncHandler(async (req, res) => {\n const result = await runSndsPull(mailer.getRunnerContext(), { force: true })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'snds.refresh',\n resource: { collection: 'mailer_snds_snapshots' },\n diffSummary: result.ran\n ? `parsed ${result.rowsParsed ?? 0}, persisted ${result.rowsPersisted ?? 0}`\n : `not run: ${result.reason}`,\n })\n res.json(result)\n }),\n )\n\n // ----- Flows: create / edit / publish ------------------------------------\n r.post(\n '/flows',\n asyncHandler(async (req, res) => {\n const { slug, name, description, trigger, goal, audience } = req.body ?? {}\n if (!slug || !name || !trigger?.eventName) {\n return res.status(400).json({ error: 'validation_failed', message: 'slug, name, and trigger.eventName required' })\n }\n const now = new Date()\n const doc = {\n slug,\n name,\n description: description ?? '',\n trigger: { type: 'event' as const, eventName: trigger.eventName, once: trigger.once !== false },\n enabled: false,\n steps: [],\n version: 0,\n draft: {\n steps: [],\n notes: 'Initial draft',\n lastModifiedBy: (req as any).actor ?? 'unknown',\n lastModifiedAt: now,\n },\n goal: goal ?? 'activation',\n audience: audience ?? '',\n expectedVolumePerWeek: null,\n stats: { activeRuns: 0, completedRuns: 0, sendsTotal: 0, sendsLast7Days: 0 },\n lastTriggerScanAt: null,\n publishedAt: null,\n publishedBy: null,\n createdAt: now,\n updatedAt: now,\n }\n try {\n await c.flows.insertOne(doc as any)\n } catch (err: any) {\n if (err?.code === 11000) return res.status(409).json({ error: 'slug_taken' })\n throw err\n }\n await mailer.audit({\n actor: (req as any).actor,\n action: 'flow.create',\n resource: { collection: 'mailer_flows', slug },\n })\n return res.json({ ok: true, slug })\n }),\n )\n\n r.patch(\n '/flows/:slug/draft',\n asyncHandler(async (req, res) => {\n const flow = await c.flows.findOne({ slug: req.params.slug })\n if (!flow) return res.status(404).json({ error: 'not_found' })\n const { steps, notes, trigger, name, description, goal, audience } = req.body ?? {}\n\n const set: Record<string, unknown> = {\n 'draft.lastModifiedBy': (req as any).actor,\n 'draft.lastModifiedAt': new Date(),\n updatedAt: new Date(),\n }\n if (Array.isArray(steps)) set['draft.steps'] = steps\n if (typeof notes === 'string') set['draft.notes'] = notes\n if (trigger?.eventName) set.trigger = { type: 'event' as const, eventName: trigger.eventName, once: trigger.once !== false }\n if (typeof name === 'string') set.name = name\n if (typeof description === 'string') set.description = description\n if (typeof goal === 'string') set.goal = goal\n if (typeof audience === 'string') set.audience = audience\n\n await c.flows.updateOne({ _id: flow._id }, { $set: set })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'flow.draft.update',\n resource: { collection: 'mailer_flows', id: flow._id, slug: flow.slug },\n diffSummary: `Updated draft (${steps ? `${steps.length} steps` : 'metadata only'})`,\n })\n return res.json({ ok: true })\n }),\n )\n\n r.post(\n '/flows/:slug/publish',\n asyncHandler(async (req, res) => {\n const flow = await c.flows.findOne({ slug: req.params.slug })\n if (!flow) return res.status(404).json({ error: 'not_found' })\n const draftSteps = flow.draft?.steps ?? flow.steps\n if (!Array.isArray(draftSteps) || draftSteps.length === 0) {\n return res.status(400).json({ error: 'empty_flow', message: 'flow has no steps to publish' })\n }\n const nextVersion = (flow.version ?? 0) + 1\n const now = new Date()\n await c.flowVersions.insertOne({\n flowId: flow._id!,\n version: nextVersion,\n steps: draftSteps,\n trigger: flow.trigger,\n publishedAt: now,\n publishedBy: (req as any).actor,\n })\n await c.flows.updateOne(\n { _id: flow._id },\n {\n $set: {\n steps: draftSteps,\n version: nextVersion,\n enabled: true,\n draft: null,\n publishedAt: now,\n publishedBy: (req as any).actor,\n updatedAt: now,\n },\n },\n )\n await mailer.audit({\n actor: (req as any).actor,\n action: 'flow.publish',\n resource: { collection: 'mailer_flows', id: flow._id, slug: flow.slug },\n diffSummary: `Published v${nextVersion}`,\n })\n return res.json({ ok: true, version: nextVersion })\n }),\n )\n\n r.delete(\n '/flows/:slug',\n asyncHandler(async (req, res) => {\n const flow = await c.flows.findOne({ slug: req.params.slug })\n if (!flow) return res.status(404).json({ error: 'not_found' })\n const everRan = await c.flowRuns.countDocuments({ flowId: flow._id }, { limit: 1 })\n if (everRan > 0) return res.status(409).json({ error: 'has_runs', message: 'flow has runs — pause it instead' })\n await c.flows.deleteOne({ _id: flow._id })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'flow.delete',\n resource: { collection: 'mailer_flows', id: flow._id, slug: flow.slug },\n })\n return res.json({ ok: true })\n }),\n )\n\n // ----- Templates: create / edit / publish --------------------------------\n r.post(\n '/templates',\n asyncHandler(async (req, res) => {\n const { slug, name, kind, subject, preheader, fromName, fromEmail } = req.body ?? {}\n if (!slug || !name || !kind) {\n return res.status(400).json({ error: 'validation_failed', message: 'slug, name, kind required' })\n }\n if (kind !== 'marketing' && kind !== 'transactional') {\n return res.status(400).json({ error: 'validation_failed', message: 'kind must be marketing or transactional' })\n }\n const resolvedFromEmail =\n fromEmail ??\n (kind === 'transactional' ? mailer.config.transactionalFromDefaults?.email : undefined) ??\n mailer.config.fromDefaults?.email ??\n 'noreply@example.com'\n const senderCheck = validateSenderDomain(resolvedFromEmail, kind, mailer.config.senderDomains)\n if (!senderCheck.ok) {\n return res.status(400).json({\n error: 'sender_domain_invalid',\n code: senderCheck.code,\n message: senderCheck.reason,\n })\n }\n const now = new Date()\n try {\n await c.templates.insertOne({\n slug,\n name,\n description: '',\n kind,\n fromName:\n fromName ??\n (kind === 'transactional' ? mailer.config.transactionalFromDefaults?.name : undefined) ??\n mailer.config.fromDefaults?.name ??\n 'Mailery',\n fromEmail: resolvedFromEmail,\n replyTo: null,\n providerOverride: null,\n subject: subject ?? `Untitled — ${name}`,\n preheader: preheader ?? '',\n body: { mjml: '', editorJson: null, html: '', plainText: '', compiledAt: null },\n variablesSchema: {},\n draft: {\n subject: subject ?? `Untitled — ${name}`,\n preheader: preheader ?? '',\n mjml: '',\n editorJson: null,\n notes: 'Initial draft',\n lastModifiedBy: (req as any).actor,\n lastModifiedAt: now,\n },\n tags: [],\n bodyFormat: 'multipart',\n trackOpens: kind === 'marketing',\n trackClicks: kind === 'marketing',\n stats: { sent: 0, delivered: 0, opened: 0, clicked: 0, bounced: 0, complained: 0, unsubscribed: 0, lastSentAt: null },\n publishedAt: null,\n publishedBy: null,\n createdAt: now,\n updatedAt: now,\n } as any)\n } catch (err: any) {\n if (err?.code === 11000) return res.status(409).json({ error: 'slug_taken' })\n throw err\n }\n await mailer.audit({\n actor: (req as any).actor,\n action: 'template.create',\n resource: { collection: 'mailer_templates', slug },\n })\n return res.json({ ok: true, slug })\n }),\n )\n\n r.patch(\n '/templates/:slug/draft',\n asyncHandler(async (req, res) => {\n const tpl = await c.templates.findOne({ slug: req.params.slug })\n if (!tpl) return res.status(404).json({ error: 'not_found' })\n\n const { subject, preheader, mjml, editorJson, notes, name, fromName, fromEmail, replyTo, kind, bodyFormat, trackOpens, trackClicks } = req.body ?? {}\n\n const set: Record<string, unknown> = {\n 'draft.lastModifiedBy': (req as any).actor,\n 'draft.lastModifiedAt': new Date(),\n updatedAt: new Date(),\n }\n if (typeof subject === 'string') set['draft.subject'] = subject\n if (typeof preheader === 'string') set['draft.preheader'] = preheader\n if (typeof mjml === 'string') set['draft.mjml'] = mjml\n if (editorJson !== undefined) set['draft.editorJson'] = editorJson\n if (typeof notes === 'string') set['draft.notes'] = notes\n if (typeof name === 'string') set.name = name\n if (typeof fromName === 'string') set.fromName = fromName\n if (typeof fromEmail === 'string') set.fromEmail = fromEmail\n if (typeof replyTo === 'string' || replyTo === null) set.replyTo = replyTo\n if (kind === 'marketing' || kind === 'transactional') set.kind = kind\n\n // Validate resulting (kind, fromEmail) against the senderDomains registry\n // whenever either field is being touched.\n if (typeof fromEmail === 'string' || kind === 'marketing' || kind === 'transactional') {\n const resultingKind = (set.kind as typeof tpl.kind) ?? tpl.kind\n const resultingFromEmail = (set.fromEmail as string) ?? tpl.fromEmail\n const senderCheck = validateSenderDomain(resultingFromEmail, resultingKind, mailer.config.senderDomains)\n if (!senderCheck.ok) {\n return res.status(400).json({\n error: 'sender_domain_invalid',\n code: senderCheck.code,\n message: senderCheck.reason,\n })\n }\n }\n if (TEMPLATE_BODY_FORMATS.includes(bodyFormat)) set.bodyFormat = bodyFormat\n if (typeof trackOpens === 'boolean') set.trackOpens = trackOpens\n if (typeof trackClicks === 'boolean') set.trackClicks = trackClicks\n\n await c.templates.updateOne({ _id: tpl._id }, { $set: set })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'template.draft.update',\n resource: { collection: 'mailer_templates', id: tpl._id, slug: tpl.slug },\n })\n return res.json({ ok: true })\n }),\n )\n\n // ----- Mail-Tester deliverability check ----------------------------------\n r.get(\n '/templates/:slug/mail-tester',\n asyncHandler(async (req, res) => {\n const cfg = mailer.config.mailTester\n const configured = !!cfg?.apiKey\n const tpl = await c.templates.findOne({ slug: req.params.slug })\n if (!tpl) return res.status(404).json({ error: 'not_found' })\n\n // Cache key must reflect the same fingerprint the check + publish gate\n // use — render the *current* draft if there is one, otherwise the\n // most recent published body. Previously this mixed draft.subject\n // with published body.html, which always missed pre-first-publish\n // and drifted whenever a subject edit followed a publish.\n let bodyHash = ''\n let subject = tpl.subject ?? ''\n if (tpl.draft) {\n try {\n const compiled = tpl.draft.editorJson\n ? await compileMailyTemplate(tpl.draft.editorJson)\n : tpl.draft.mjml\n ? await compileTemplate(tpl.draft.mjml)\n : null\n if (compiled) {\n bodyHash = sha256Hex(compiled.html)\n subject = tpl.draft.subject || subject\n }\n } catch {\n // If the draft no longer compiles, fall back to the published body.\n }\n }\n if (!bodyHash && tpl.body?.html) {\n bodyHash = sha256Hex(tpl.body.html)\n }\n const key = bodyHash ? mailTesterContentKey({ bodyHash, subject, fromEmail: tpl.fromEmail }) : null\n const cached = key ? await findCachedScore(mailer.getRunnerContext(), key) : null\n\n res.json({\n configured,\n minScore: cfg?.minScore ?? 8.0,\n requireScore: !!cfg?.requireScore,\n cacheHours: cfg?.cacheHours ?? 24,\n score: cached,\n })\n }),\n )\n\n r.post(\n '/templates/:slug/mail-tester-check',\n asyncHandler(async (req, res) => {\n const client = getMailTesterClient()\n if (!client) {\n return res.status(400).json({\n error: 'not_configured',\n message: 'Mail-Tester is not configured. Set mailer.config.mailTester.apiKey to enable.',\n })\n }\n\n const tpl = await c.templates.findOne({ slug: req.params.slug })\n if (!tpl) return res.status(404).json({ error: 'not_found' })\n const draft = tpl.draft\n if (!draft) return res.status(400).json({ error: 'no_draft', message: 'Save a draft before running a deliverability check.' })\n\n let compiled: { html: string; plainText: string }\n try {\n if (draft.editorJson) compiled = await compileMailyTemplate(draft.editorJson)\n else if (draft.mjml) compiled = await compileTemplate(draft.mjml)\n else return res.status(400).json({ error: 'empty_draft' })\n } catch (err: any) {\n return res.status(400).json({ error: 'compile_failed', message: String(err?.message ?? err) })\n }\n\n const bodyHash = sha256Hex(compiled.html)\n const contentKey = mailTesterContentKey({ bodyHash, subject: draft.subject, fromEmail: tpl.fromEmail })\n const ctx = mailer.getRunnerContext()\n\n // Cache hit — return without burning a credit.\n const cached = await findCachedScore(ctx, contentKey)\n if (cached) {\n return res.json({ cached: true, status: 'ready', score: cached })\n }\n\n // Resolve the provider *before* provisioning: provisionCheck burns a\n // Mail-Tester credit, and a template pointing at a provider that isn't\n // registered can never get past the send below.\n const provider = resolveProvider(mailer.providers, tpl.providerOverride ?? mailer.config.defaultProvider)\n if (!provider) {\n return res.status(400).json(unknownProviderError(mailer, tpl))\n }\n\n // Provision a new test address and send the rendered draft to it.\n const { checkId, emailAddress } = await client.provisionCheck()\n\n try {\n await provider.send({\n to: emailAddress,\n fromName: tpl.fromName,\n fromEmail: tpl.fromEmail,\n replyTo: tpl.replyTo ?? undefined,\n subject: draft.subject,\n // Match the real send shape — a text_only template's deliverability\n // should be scored on the single-part message it actually sends.\n ...(tpl.bodyFormat === 'text_only' ? {} : { html: compiled.html }),\n text: compiled.plainText,\n headers: {},\n messageMeta: { mailTesterCheckId: checkId },\n })\n } catch (err: any) {\n return res.status(502).json({ error: 'send_failed', message: String(err?.message ?? err) })\n }\n\n await mailer.audit({\n actor: (req as any).actor,\n action: 'mail_tester.check.start',\n resource: { collection: 'mailer_mail_tester_scores', id: contentKey, slug: tpl.slug },\n diffSummary: `Sent draft to ${emailAddress} for Mail-Tester check ${checkId}`,\n })\n\n res.json({\n cached: false,\n status: 'pending',\n checkId,\n contentKey,\n message: 'Test email sent. Poll /mail-tester-result?checkId=...&contentKey=... for the score.',\n })\n }),\n )\n\n r.get(\n '/templates/:slug/mail-tester-result',\n asyncHandler(async (req, res) => {\n const client = getMailTesterClient()\n if (!client) return res.status(400).json({ error: 'not_configured' })\n\n const checkId = String(req.query.checkId ?? '')\n if (!checkId) return res.status(400).json({ error: 'validation_failed', message: 'checkId is required' })\n\n const tpl = await c.templates.findOne({ slug: req.params.slug })\n if (!tpl) return res.status(404).json({ error: 'not_found' })\n const draft = tpl.draft\n if (!draft) return res.status(400).json({ error: 'no_draft', message: 'Draft no longer exists.' })\n\n // Re-derive the content key server-side from the current draft so an\n // attacker can't land a score under an arbitrary fingerprint and game\n // the publish gate. We must recompile to recompute bodyHash.\n let compiled: { html: string; plainText: string }\n try {\n if (draft.editorJson) compiled = await compileMailyTemplate(draft.editorJson)\n else if (draft.mjml) compiled = await compileTemplate(draft.mjml)\n else return res.status(400).json({ error: 'empty_draft' })\n } catch (err: any) {\n return res.status(400).json({ error: 'compile_failed', message: String(err?.message ?? err) })\n }\n const contentKey = mailTesterContentKey({\n bodyHash: sha256Hex(compiled.html),\n subject: draft.subject,\n fromEmail: tpl.fromEmail,\n })\n\n const result = await client.fetchResult(checkId)\n if (!result.ready) {\n return res.json({ status: 'pending', score: null })\n }\n\n const ctx = mailer.getRunnerContext()\n const persisted = await persistScore(ctx, { templateSlug: tpl.slug, contentKey, checkId, result })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'mail_tester.check.complete',\n resource: { collection: 'mailer_mail_tester_scores', id: contentKey, slug: tpl.slug },\n diffSummary: `Score ${result.score.toFixed(1)}`,\n })\n res.json({ status: 'ready', score: persisted })\n }),\n )\n\n r.post(\n '/templates/:slug/lint',\n asyncHandler(async (req, res) => {\n const tpl = await c.templates.findOne({ slug: req.params.slug })\n if (!tpl) return res.status(404).json({ error: 'not_found' })\n\n // Lint against the supplied draft if present, otherwise the saved draft,\n // otherwise the last-published body. Keep this tolerant so the editor\n // can call it without juggling round-trips.\n const body = (req.body ?? {}) as {\n subject?: string\n preheader?: string\n mjml?: string\n editorJson?: Record<string, unknown> | null\n fromEmail?: string\n kind?: 'marketing' | 'transactional'\n }\n\n const subject = body.subject ?? tpl.draft?.subject ?? tpl.subject ?? ''\n const preheader = body.preheader ?? tpl.draft?.preheader ?? tpl.preheader ?? ''\n const mjml = body.mjml ?? tpl.draft?.mjml ?? tpl.body?.mjml ?? ''\n const editorJson = body.editorJson !== undefined ? body.editorJson : (tpl.draft?.editorJson ?? tpl.body?.editorJson ?? null)\n const fromEmail = body.fromEmail ?? tpl.fromEmail\n // Whitelist kind — otherwise body.kind:'foo' bypasses the marketing-\n // only missing_unsubscribe_tag check by hitting neither branch.\n const kind = body.kind === 'marketing' || body.kind === 'transactional' ? body.kind : tpl.kind\n\n let html = ''\n let plainText = ''\n try {\n if (editorJson) {\n const compiled = await compileMailyTemplate(editorJson)\n html = compiled.html\n plainText = compiled.plainText\n } else if (mjml) {\n const compiled = await compileTemplate(mjml)\n html = compiled.html\n plainText = compiled.plainText\n }\n } catch (err: any) {\n return res.status(200).json({\n errors: [{ rule: 'compile_failed', severity: 'error', message: `Compile error: ${String(err?.message ?? err)}` }],\n warnings: [],\n infos: [],\n compileFailed: true,\n })\n }\n\n // Script-seeded templates can have no draft source at all (body.html +\n // body.plainText inserted directly, editorJson/mjml empty). Fall back to\n // the stored body so lint judges what actually sends instead of\n // reporting an empty template.\n if (!html && typeof tpl.body?.html === 'string') html = tpl.body.html\n if (!plainText && typeof tpl.body?.plainText === 'string') plainText = tpl.body.plainText\n\n const lint = lintTemplate(\n { subject, preheader, mjml, editorJson, html, plainText, kind, fromEmail },\n { senderDomains: mailer.config.senderDomains, varsJsonSchema: varsSchema },\n )\n res.json({ ...lint, compileFailed: false })\n }),\n )\n\n r.post(\n '/templates/:slug/publish',\n asyncHandler(async (req, res) => {\n const tpl = await c.templates.findOne({ slug: req.params.slug })\n if (!tpl) return res.status(404).json({ error: 'not_found' })\n const draft = tpl.draft\n if (!draft) return res.status(400).json({ error: 'no_draft' })\n\n // Short-circuit sender-domain check — preserves the pre-linter 400\n // sender_domain_invalid contract so external callers (and the SPA's\n // own publish modal) can key on it without conflating with lint errors.\n const senderCheck = validateSenderDomain(tpl.fromEmail, tpl.kind, mailer.config.senderDomains)\n if (!senderCheck.ok) {\n return res.status(400).json({\n error: 'sender_domain_invalid',\n code: senderCheck.code,\n message: senderCheck.reason,\n })\n }\n\n let compiled: { html: string; plainText: string; errors: any[] }\n try {\n if (draft.editorJson) {\n compiled = await compileMailyTemplate(draft.editorJson)\n } else if (draft.mjml) {\n compiled = await compileTemplate(draft.mjml)\n } else {\n return res.status(400).json({ error: 'empty_draft', message: 'draft has no MJML or editorJson content' })\n }\n } catch (err: any) {\n // Same shape as the lint endpoint's compileFailed branch so the UI\n // can surface compile errors uniformly with lint errors.\n return res.status(422).json({\n error: 'compile_failed',\n message: String(err?.message ?? err),\n lint: {\n errors: [{ rule: 'compile_failed', severity: 'error', message: `Compile error: ${String(err?.message ?? err)}` }],\n warnings: [],\n infos: [],\n },\n })\n }\n\n const lint = lintTemplate(\n {\n subject: draft.subject,\n preheader: draft.preheader,\n mjml: draft.mjml ?? '',\n editorJson: draft.editorJson,\n html: compiled.html,\n plainText: compiled.plainText,\n kind: tpl.kind,\n fromEmail: tpl.fromEmail,\n },\n { senderDomains: mailer.config.senderDomains, varsJsonSchema: varsSchema },\n )\n\n if (lint.errors.length > 0) {\n return res.status(422).json({\n error: 'lint_failed',\n message: `Template publish blocked by ${lint.errors.length} content issue(s).`,\n lint,\n })\n }\n\n // Mail-Tester gate. Blocks when a cached score for this exact content is\n // below minScore, and — when `requireScore` is configured — when no score\n // for this content exists at all. Operator can override either with\n // `bypassMailTester: true` in the request body.\n const bypass = Boolean(req.body?.bypassMailTester)\n if (!bypass) {\n const gate = await evaluateMailTesterGate(mailer.getRunnerContext(), {\n bodyHash: sha256Hex(compiled.html),\n subject: draft.subject,\n fromEmail: tpl.fromEmail,\n })\n if (!gate.allowed) {\n return res.status(422).json({\n error: 'mail_tester_blocked',\n code: gate.code,\n message: gate.reason,\n score: gate.score,\n hint:\n gate.code === 'no_score'\n ? 'POST to `/templates/:slug/mail-tester-check`, poll `/mail-tester-result`, then publish — or POST `bypassMailTester: true` to publish anyway.'\n : 'Re-run the deliverability check after fixing the feedback, or POST `bypassMailTester: true` to publish anyway.',\n })\n }\n }\n\n const now = new Date()\n const nextVersion = await c.templateVersions.countDocuments({ templateId: tpl._id }) + 1\n await c.templateVersions.insertOne({\n templateId: tpl._id!,\n version: nextVersion,\n mjml: draft.mjml,\n html: compiled.html,\n plainText: compiled.plainText,\n subject: draft.subject,\n preheader: draft.preheader,\n publishedAt: now,\n publishedBy: (req as any).actor,\n })\n\n await c.templates.updateOne(\n { _id: tpl._id },\n {\n $set: {\n subject: draft.subject,\n preheader: draft.preheader,\n body: {\n mjml: draft.mjml,\n editorJson: draft.editorJson,\n html: compiled.html,\n plainText: compiled.plainText,\n compiledAt: now,\n },\n draft: null,\n publishedAt: now,\n publishedBy: (req as any).actor,\n updatedAt: now,\n },\n },\n )\n await mailer.audit({\n actor: (req as any).actor,\n action: 'template.publish',\n resource: { collection: 'mailer_templates', id: tpl._id, slug: tpl.slug },\n diffSummary: `Published v${nextVersion}`,\n })\n return res.json({\n ok: true,\n version: nextVersion,\n warnings: compiled.errors,\n lint, // warnings + infos for UI\n })\n }),\n )\n\n r.post(\n '/templates/:slug/preview',\n asyncHandler(async (req, res) => {\n const tpl = await c.templates.findOne({ slug: req.params.slug })\n if (!tpl) return res.status(404).json({ error: 'not_found' })\n\n const useDraft = req.body?.useDraft !== false\n let html = ''\n let plainText = ''\n if (useDraft && tpl.draft) {\n const compiled = tpl.draft.editorJson\n ? await compileMailyTemplate(tpl.draft.editorJson)\n : await compileTemplate(tpl.draft.mjml || '<mjml><mj-body></mj-body></mjml>')\n html = compiled.html\n plainText = compiled.plainText\n } else {\n if (!tpl.body?.html) {\n return res.status(409).json({ error: 'not_published', message: 'Template has not been published yet.' })\n }\n html = tpl.body.html\n plainText = tpl.body.plainText\n }\n\n // Preview as a real contact when contactId is given — pulls the actual\n // contact through the adapter and runs the host's varsAdapter, so the\n // preview shows exactly what that person would receive.\n let contact: Contact\n const contactId = typeof req.body?.contactId === 'string' ? req.body.contactId : null\n if (contactId) {\n const found = await mailer.adapter.getById(contactId)\n if (!found) return res.status(404).json({ error: 'contact_not_found', contactId })\n contact = found\n } else {\n contact = req.body?.sampleContact ?? {\n externalId: 'preview-contact',\n email: 'preview@example.com',\n tags: [],\n fields: { firstName: 'Alex' },\n }\n }\n\n // Optional simulated trigger-event properties, so account/topic-scoped\n // templates ({{event.*}} or resolver branching) preview realistically.\n const eventProperties =\n req.body?.eventProperties && typeof req.body.eventProperties === 'object'\n ? (req.body.eventProperties as Record<string, unknown>)\n : undefined\n\n let resolved: Record<string, unknown> = {}\n try {\n resolved = await resolveVars(mailer.config.varsAdapter, contact, {\n reason: 'preview',\n templateSlug: tpl.slug,\n eventProperties,\n })\n } catch (err: any) {\n return res.status(502).json({\n error: 'vars_resolve_failed',\n message: `varsAdapter.resolve threw: ${String(err?.message ?? err)}`,\n })\n }\n\n const renderCtx = {\n ...resolved,\n contact,\n vars: req.body?.vars ?? {},\n event: eventProperties ?? {},\n unsubscribeUrl: `${mailer.config.publicUrl}/m/unsub/preview`,\n senderAddress: mailer.config.senderAddress,\n }\n\n const previewTpl = { ...tpl, body: { ...tpl.body, html, plainText } }\n const rendered = await renderTemplate(previewTpl as any, renderCtx, { helpers: mailer.config.handlebarsHelpers })\n return res.json({\n subject: rendered.subject,\n preheader: rendered.preheader,\n html: rendered.html,\n plainText: rendered.plainText,\n contact: { externalId: contact.externalId, email: contact.email },\n })\n }),\n )\n\n r.post(\n '/templates/:slug/send-test',\n asyncHandler(async (req, res) => {\n const { to, sampleData, contactId, eventProperties } = req.body ?? {}\n if (!to) return res.status(400).json({ error: 'to_required' })\n const tpl = await c.templates.findOne({ slug: req.params.slug })\n if (!tpl) return res.status(404).json({ error: 'not_found' })\n\n // Render as a real contact when contactId is given (vars included),\n // but always deliver to the operator-typed address.\n let contact: Contact\n if (typeof contactId === 'string' && contactId) {\n const found = await mailer.adapter.getById(contactId)\n if (!found) return res.status(404).json({ error: 'contact_not_found', contactId })\n contact = { ...found, email: to }\n } else {\n contact = sampleData?.contact ?? {\n externalId: 'test-recipient',\n email: to,\n tags: [],\n fields: { firstName: 'Test' },\n }\n contact.email = to\n }\n\n const evProps =\n eventProperties && typeof eventProperties === 'object'\n ? (eventProperties as Record<string, unknown>)\n : undefined\n\n let resolved: Record<string, unknown> = {}\n try {\n resolved = await resolveVars(mailer.config.varsAdapter, contact, {\n reason: 'test',\n templateSlug: tpl.slug,\n eventProperties: evProps,\n })\n } catch (err: any) {\n return res.status(502).json({\n error: 'vars_resolve_failed',\n message: `varsAdapter.resolve threw: ${String(err?.message ?? err)}`,\n })\n }\n\n const renderCtx = {\n ...resolved,\n contact,\n vars: sampleData?.vars ?? {},\n event: evProps ?? {},\n unsubscribeUrl: `${mailer.config.publicUrl}/m/unsub/test`,\n senderAddress: mailer.config.senderAddress,\n }\n const rendered = await renderTemplate(tpl as any, renderCtx, { helpers: mailer.config.handlebarsHelpers })\n const tracking = applyTracking(rendered.html, {\n sendId: `test-${Date.now()}`,\n publicUrl: mailer.config.publicUrl,\n trackOpens: false,\n trackClicks: false,\n })\n\n const provider = resolveProvider(mailer.providers, tpl.providerOverride ?? mailer.config.defaultProvider)\n if (!provider) {\n return res.status(400).json(unknownProviderError(mailer, tpl))\n }\n const result = await provider.send({\n to,\n fromName: rendered.fromName,\n fromEmail: rendered.fromEmail,\n subject: `[TEST] ${rendered.subject}`,\n // Match the real send shape, or a test of a text_only template would\n // arrive as HTML and hide exactly what the author is checking.\n ...(tpl.bodyFormat === 'text_only' ? {} : { html: tracking.html }),\n text: rendered.plainText,\n })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'template.send-test',\n resource: { collection: 'mailer_templates', slug: tpl.slug },\n diffSummary: `to=${to}`,\n })\n // Avoid unused — sign helper is exposed for future preview routes.\n void signUnsubscribeToken\n return res.json({ ok: true, providerId: result.providerId })\n }),\n )\n\n // ----- Broadcasts: create / patch / schedule / cancel --------------------\n r.post(\n '/broadcasts',\n asyncHandler(async (req, res) => {\n const { slug, name, templateSlug, segmentDefinition } = req.body ?? {}\n if (!slug || !name || !templateSlug) {\n return res.status(400).json({ error: 'validation_failed', message: 'slug, name, templateSlug required' })\n }\n const now = new Date()\n try {\n await c.broadcasts.insertOne({\n slug,\n name,\n templateSlug,\n segmentDefinition: segmentDefinition ?? { filters: [{ kind: 'subscriptionStatus', equals: 'subscribed' }] },\n status: 'draft',\n scheduledAt: null,\n startedAt: null,\n completedAt: null,\n confirmationRequired: true,\n confirmedCount: null,\n confirmedAt: null,\n confirmedBy: null,\n recipientCount: null,\n stats: { sent: 0, delivered: 0, opened: 0, clicked: 0, bounced: 0, complained: 0, unsubscribed: 0 },\n createdAt: now,\n createdBy: (req as any).actor,\n updatedAt: now,\n } as any)\n } catch (err: any) {\n if (err?.code === 11000) return res.status(409).json({ error: 'slug_taken' })\n throw err\n }\n await mailer.audit({\n actor: (req as any).actor,\n action: 'broadcast.create',\n resource: { collection: 'mailer_broadcasts', slug },\n })\n return res.json({ ok: true, slug })\n }),\n )\n\n r.patch(\n '/broadcasts/:slug',\n asyncHandler(async (req, res) => {\n const b = await c.broadcasts.findOne({ slug: req.params.slug })\n if (!b) return res.status(404).json({ error: 'not_found' })\n if (b.status !== 'draft') return res.status(409).json({ error: 'not_draft' })\n const { name, templateSlug, segmentDefinition } = req.body ?? {}\n const set: Record<string, unknown> = { updatedAt: new Date() }\n if (typeof name === 'string') set.name = name\n if (typeof templateSlug === 'string') set.templateSlug = templateSlug\n if (segmentDefinition) set.segmentDefinition = segmentDefinition\n await c.broadcasts.updateOne({ _id: b._id }, { $set: set })\n return res.json({ ok: true })\n }),\n )\n\n r.post(\n '/broadcasts/:slug/segment/count',\n asyncHandler(async (req, res) => {\n const segmentDefinition = req.body?.segmentDefinition\n if (!segmentDefinition?.filters) return res.status(400).json({ error: 'segment_required' })\n const t0 = Date.now()\n // V1: only host-side filter translation. Mailer-side filters\n // (subscription status, fired events, etc.) and the suppression check\n // are applied at dispatch time over the streamed cursor, so the live\n // counter would have to scan-and-filter the full audience to be\n // precise. We return the upper-bound count and tell the UI it's an\n // estimate. When richer estimation lands, swap this for a sampled\n // pass that includes mailer-side filters + suppression.\n const hostFilter: any = {}\n for (const f of segmentDefinition.filters) {\n if (f.kind === 'hasTag') hostFilter.hasTag = f.tag\n if (f.kind === 'fieldEquals') hostFilter.fieldEquals = { field: f.field, value: f.value }\n }\n const hasMailerFilters = segmentDefinition.filters.some((f: any) =>\n ['subscriptionStatus', 'firedEvent', 'notFiredEvent', 'notHasTag', 'opened', 'notOpened', 'subscribedAfter', 'subscribedBefore'].includes(f.kind),\n )\n const upperBound = await mailer.adapter.count(hostFilter)\n return res.json({\n upperBound,\n approximate: hasMailerFilters,\n computedMs: Date.now() - t0,\n })\n }),\n )\n\n r.post(\n '/broadcasts/:slug/schedule',\n asyncHandler(async (req, res) => {\n const b = await c.broadcasts.findOne({ slug: req.params.slug })\n if (!b) return res.status(404).json({ error: 'not_found' })\n if (b.status !== 'draft') return res.status(409).json({ error: 'not_draft' })\n const { scheduledAt, confirmedCount, respectRecipientTimezone } = req.body ?? {}\n if (!scheduledAt) return res.status(400).json({ error: 'scheduledAt_required' })\n const scheduled = new Date(scheduledAt)\n if (Number.isNaN(scheduled.getTime())) return res.status(400).json({ error: 'bad_scheduledAt' })\n\n const threshold = mailer.config.broadcastConfirmationThreshold\n if (typeof confirmedCount !== 'number') {\n return res.status(400).json({ error: 'confirmedCount_required' })\n }\n\n const set: Record<string, unknown> = {\n status: 'scheduled',\n scheduledAt: scheduled,\n confirmedCount,\n confirmedAt: new Date(),\n confirmedBy: (req as any).actor,\n updatedAt: new Date(),\n }\n if (respectRecipientTimezone) set.respectRecipientTimezone = true\n\n await c.broadcasts.updateOne({ _id: b._id }, { $set: set })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'broadcast.schedule',\n resource: { collection: 'mailer_broadcasts', id: b._id, slug: b.slug },\n diffSummary: `scheduled at ${scheduled.toISOString()} · confirmedCount=${confirmedCount} · threshold=${threshold}`,\n })\n return res.json({ ok: true })\n }),\n )\n\n r.post(\n '/broadcasts/:slug/cancel',\n asyncHandler(async (req, res) => {\n const b = await c.broadcasts.findOne({ slug: req.params.slug })\n if (!b) return res.status(404).json({ error: 'not_found' })\n await c.broadcasts.updateOne({ _id: b._id }, { $set: { status: 'cancelled', updatedAt: new Date() } })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'broadcast.cancel',\n resource: { collection: 'mailer_broadcasts', id: b._id, slug: b.slug },\n })\n return res.json({ ok: true })\n }),\n )\n\n // Catch-all 404 for /api.\n r.use((_req, res) => res.status(404).json({ error: 'not_found' }))\n\n return r\n}\n\ntype AsyncHandler = (req: Request, res: Response, next: NextFunction) => Promise<unknown>\nfunction asyncHandler(fn: AsyncHandler) {\n return (req: Request, res: Response, next: NextFunction) => {\n fn(req, res, next).catch(next)\n }\n}\n\n/**\n * Body for the 4xx a route returns when a template's effective provider name\n * doesn't resolve (see `resolveProvider`).\n *\n * These routes are behind the host's admin gate, and the name comes from\n * `providerOverride` on a stored template or from `defaultProvider` in config —\n * never from the request. So this is a misconfiguration report, not a security\n * boundary: 400 rather than 500 because the server is fine and the *stored*\n * input is what's wrong, and it names both the unresolved provider and the\n * registered alternatives, which is the whole difference between an operator\n * fixing the template and an operator reading a stack trace.\n */\nfunction unknownProviderError(\n mailer: Mailer,\n tpl: { slug?: string; providerOverride?: string | null },\n): { error: string; message: string; provider: string; registeredProviders: string[] } {\n const override = tpl.providerOverride ?? null\n const name = override ?? mailer.config.defaultProvider\n const known = registeredProviderNames(mailer.providers)\n const source = override\n ? `template \"${tpl.slug ?? '?'}\" overrides the provider to \"${name}\"`\n : `the configured defaultProvider is \"${name}\"`\n return {\n error: 'provider_unknown',\n message:\n `${source}, but no such provider is registered. ` +\n `Registered providers: ${known.length ? known.join(', ') : '(none)'}.`,\n provider: name,\n registeredProviders: known,\n }\n}\n\n/**\n * Sum inFlight and delayed across every queue the driver exposes. Returns\n * `null` for either count when the driver doesn't implement that accessor\n * (e.g. Agenda/Noop), so the UI can render \"—\" instead of a misleading 0.\n */\nasync function collectQueueCounts(\n mailer: Mailer,\n): Promise<{ inFlight: number | null; delayed: number | null }> {\n const qs = Object.values(mailer.queues) as Array<{\n getInFlightCount?: () => Promise<number | null>\n getDelayedCount?: () => Promise<number | null>\n }>\n const sum = async (key: 'getInFlightCount' | 'getDelayedCount'): Promise<number | null> => {\n let total = 0\n let supported = false\n for (const q of qs) {\n const fn = q[key]\n if (!fn) continue\n try {\n const v = await fn.call(q)\n if (v == null) continue\n total += v\n supported = true\n } catch {\n // Treat one queue's failure as \"unknown\" — surface as null upstream.\n return null\n }\n }\n return supported ? total : null\n }\n const [inFlight, delayed] = await Promise.all([sum('getInFlightCount'), sum('getDelayedCount')])\n return { inFlight, delayed }\n}\n\n// ---------------------------------------------------------------------------\n// Live stats aggregation\n//\n// The flow / template / broadcast list endpoints used to return zeros for\n// every metric because no rollup ever wrote to `stats.*` on those docs. We\n// now compute them on-the-fly from the canonical `sends` and `flowRuns`\n// collections. Optional slug/id filters keep single-resource reads cheap.\n// ---------------------------------------------------------------------------\n\ninterface FlowStats {\n activeRuns: number\n completedRuns: number\n sendsLast7Days: number\n sendsTotal: number\n}\nfunction emptyFlowStats(): FlowStats {\n return { activeRuns: 0, completedRuns: 0, sendsLast7Days: 0, sendsTotal: 0 }\n}\n\nasync function computeFlowStats(mailer: Mailer, slugFilter?: string): Promise<Map<string, FlowStats>> {\n const out = new Map<string, FlowStats>()\n const match = slugFilter ? { flowSlug: slugFilter } : {}\n\n const runRows = await mailer.collections.flowRuns\n .aggregate<{ _id: { flowSlug: string; status: string }; count: number }>([\n { $match: match },\n { $group: { _id: { flowSlug: '$flowSlug', status: '$status' }, count: { $sum: 1 } } },\n ])\n .toArray()\n for (const row of runRows) {\n const slug = row._id.flowSlug\n if (!slug) continue\n const cur = out.get(slug) ?? emptyFlowStats()\n if (row._id.status === 'active') cur.activeRuns += row.count\n else if (row._id.status === 'completed') cur.completedRuns += row.count\n out.set(slug, cur)\n }\n\n const sevenDaysAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000)\n const sendRows = await mailer.collections.sends\n .aggregate<{ _id: string; total: number; last7: number }>([\n { $match: { flowRunId: { $ne: null } } },\n {\n $lookup: {\n from: mailer.collections.flowRuns.collectionName,\n localField: 'flowRunId',\n foreignField: '_id',\n as: 'run',\n pipeline: slugFilter\n ? [{ $match: { flowSlug: slugFilter } }, { $project: { flowSlug: 1 } }]\n : [{ $project: { flowSlug: 1 } }],\n },\n },\n { $unwind: '$run' },\n {\n $group: {\n _id: '$run.flowSlug',\n total: { $sum: 1 },\n last7: { $sum: { $cond: [{ $gte: ['$queuedAt', sevenDaysAgo] }, 1, 0] } },\n },\n },\n ])\n .toArray()\n for (const row of sendRows) {\n if (!row._id) continue\n const cur = out.get(row._id) ?? emptyFlowStats()\n cur.sendsTotal = row.total\n cur.sendsLast7Days = row.last7\n out.set(row._id, cur)\n }\n\n return out\n}\n\ninterface TemplateStats {\n sent: number\n opened: number\n clicked: number\n bounced: number\n sentLast7Days: number\n lastSentAt: Date | null\n}\nfunction emptyTemplateStats(): TemplateStats {\n return { sent: 0, opened: 0, clicked: 0, bounced: 0, sentLast7Days: 0, lastSentAt: null }\n}\n\nasync function computeTemplateStats(mailer: Mailer, slugFilter?: string): Promise<Map<string, TemplateStats>> {\n const out = new Map<string, TemplateStats>()\n const match: Record<string, unknown> = {}\n if (slugFilter) match.templateSlug = slugFilter\n const sevenDaysAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000)\n\n const rows = await mailer.collections.sends\n .aggregate<{\n _id: string\n sent: number\n opened: number\n clicked: number\n bounced: number\n sentLast7Days: number\n lastSentAt: Date | null\n }>([\n { $match: match },\n {\n $group: {\n _id: '$templateSlug',\n sent: { $sum: 1 },\n opened: { $sum: { $cond: [{ $ifNull: ['$openedAt', false] }, 1, 0] } },\n clicked: { $sum: { $cond: [{ $ifNull: ['$firstClickAt', false] }, 1, 0] } },\n bounced: { $sum: { $cond: [{ $eq: ['$status', 'bounced'] }, 1, 0] } },\n sentLast7Days: { $sum: { $cond: [{ $gte: ['$queuedAt', sevenDaysAgo] }, 1, 0] } },\n lastSentAt: { $max: '$queuedAt' },\n },\n },\n ])\n .toArray()\n for (const row of rows) {\n if (!row._id) continue\n out.set(row._id, {\n sent: row.sent,\n opened: row.opened,\n clicked: row.clicked,\n bounced: row.bounced,\n sentLast7Days: row.sentLast7Days,\n lastSentAt: row.lastSentAt ?? null,\n })\n }\n return out\n}\n\ninterface BroadcastStats {\n delivered: number\n opened: number\n clicked: number\n bounced: number\n}\nfunction emptyBroadcastStats(): BroadcastStats {\n return { delivered: 0, opened: 0, clicked: 0, bounced: 0 }\n}\n\nasync function computeBroadcastStats(\n mailer: Mailer,\n idFilter?: ObjectId,\n): Promise<Map<string, BroadcastStats>> {\n const out = new Map<string, BroadcastStats>()\n const match: Record<string, unknown> = { broadcastId: { $ne: null } }\n if (idFilter) match.broadcastId = idFilter\n\n const rows = await mailer.collections.sends\n .aggregate<{\n _id: ObjectId\n delivered: number\n opened: number\n clicked: number\n bounced: number\n }>([\n { $match: match },\n {\n $group: {\n _id: '$broadcastId',\n delivered: { $sum: { $cond: [{ $eq: ['$status', 'delivered'] }, 1, 0] } },\n opened: { $sum: { $cond: [{ $ifNull: ['$openedAt', false] }, 1, 0] } },\n clicked: { $sum: { $cond: [{ $ifNull: ['$firstClickAt', false] }, 1, 0] } },\n bounced: { $sum: { $cond: [{ $eq: ['$status', 'bounced'] }, 1, 0] } },\n },\n },\n ])\n .toArray()\n for (const row of rows) {\n if (!row._id) continue\n out.set(String(row._id), {\n delivered: row.delivered,\n opened: row.opened,\n clicked: row.clicked,\n bounced: row.bounced,\n })\n }\n return out\n}\n","/**\n * Shared enums — string-literal unions for status fields and other discriminators.\n * Kept separate from types.ts so the client can import these without pulling in\n * server-shaped interfaces.\n */\n\nexport type SubscriptionStatus = 'subscribed' | 'pending_doi' | 'unsubscribed' | 'bounced' | 'complained'\n\nexport type SendStatus =\n | 'queued'\n | 'sending'\n | 'sent'\n | 'delivered'\n | 'bounced'\n | 'complained'\n | 'failed'\n | 'suppressed'\n | 'cancelled'\n\nexport type TemplateKind = 'transactional' | 'marketing'\n\n/**\n * How a template's body goes on the wire.\n *\n * multipart — HTML + plain-text alternative (the default, and what almost\n * every template wants).\n * text_only — plain text alone, no HTML part at all. For mail that should\n * read as if it were typed by a person. Open tracking is\n * impossible without an HTML part to carry the pixel, and click\n * tracking is skipped too (rewriting bare URLs in text produces\n * the opaque redirect links this format exists to avoid), so a\n * text_only send reports no opens and no clicks — by design.\n */\nexport type TemplateBodyFormat = 'multipart' | 'text_only'\nexport const TEMPLATE_BODY_FORMATS: readonly TemplateBodyFormat[] = ['multipart', 'text_only'] as const\n\nexport type SuppressionScope = 'all' | 'marketing' | 'transactional'\n\nexport type SuppressionReason =\n | 'unsubscribed'\n | 'hard_bounce'\n | 'complaint'\n | 'manual'\n | 'list_cleaning'\n | 'gdpr_forget'\n\nexport type FlowRunStatus = 'active' | 'completed' | 'exited' | 'failed'\n\nexport type BroadcastStatus = 'draft' | 'scheduled' | 'sending' | 'sent' | 'cancelled' | 'failed'\n\nexport type HealthStatus = 'healthy' | 'degraded' | 'tripped'\n\nexport type FlowGoal = 'activation' | 'conversion' | 'retention' | 'reactivation' | 'transactional' | 'broadcast'\n","/**\n * Setup-status: a small suite of synchronous checks the admin dashboard\n * surfaces as a banner. Each check returns an `ok | warn | error` verdict\n * with a short message and optional hint. The endpoint exists to catch the\n * \"silent misconfiguration that breaks sends\" class of bug — missing DOI\n * template, workers not running, fromDefaults on a domain that doesn't pass\n * the senderDomains registry, etc.\n */\n\nimport type { Mailer } from '../mailer.js'\nimport { validateSenderDomain } from '../templates/sender-domain.js'\nimport { resolveSourceTags } from '../runner/dmarc.js'\nimport { HEALTH_AGG_ID } from '../models/index.js'\n\nexport type CheckSeverity = 'ok' | 'warn' | 'error'\n\nexport interface SetupCheck {\n /** Stable identifier, e.g. 'mongo', 'workers_heartbeat'. */\n name: string\n /** Human-readable label, e.g. \"MongoDB connection\". */\n label: string\n severity: CheckSeverity\n message: string\n /** Optional remediation hint shown when the user expands the row. */\n hint?: string\n}\n\nexport interface SetupStatus {\n overall: CheckSeverity\n generatedAt: string\n checks: SetupCheck[]\n}\n\nexport async function runSetupChecks(mailer: Mailer): Promise<SetupStatus> {\n const checks: SetupCheck[] = []\n\n checks.push(await checkMongo(mailer))\n checks.push(await checkQueue(mailer))\n // Run the heartbeat check even in a workerless process: in a web/worker\n // split the workerless web process is the one WITH the admin UI, so it is\n // exactly where an operator will look for \"are the workers alive\". The\n // heartbeat lives in Mongo, which both processes share, so the check works\n // from either side — only the remediation wording differs.\n if (mailer.config.queue.driver !== 'noop') {\n checks.push(await checkWorkersHeartbeat(mailer))\n }\n checks.push(await checkCircuitBreaker(mailer))\n checks.push(await checkDnsbl(mailer))\n checks.push(await checkPostmaster(mailer))\n checks.push(await checkSnds(mailer))\n const jmrp = checkJmrp(mailer)\n if (jmrp) checks.push(jmrp)\n checks.push(await checkDmarc(mailer))\n checks.push(...checkFromDefaultsAgainstRegistry(mailer))\n checks.push(...(await checkPublishedTemplates(mailer)))\n checks.push(await checkPostalAddress(mailer))\n checks.push(await checkDoiTemplate(mailer))\n\n const overall: CheckSeverity = checks.some((c) => c.severity === 'error')\n ? 'error'\n : checks.some((c) => c.severity === 'warn')\n ? 'warn'\n : 'ok'\n\n return {\n overall,\n generatedAt: new Date().toISOString(),\n checks,\n }\n}\n\nasync function checkMongo(mailer: Mailer): Promise<SetupCheck> {\n try {\n await mailer.db.admin().ping()\n return { name: 'mongo', label: 'MongoDB connection', severity: 'ok', message: 'reachable' }\n } catch (err) {\n return {\n name: 'mongo',\n label: 'MongoDB connection',\n severity: 'error',\n message: `MongoDB ping failed: ${(err as Error)?.message ?? err}`,\n hint: 'Mailery is configured against an unreachable Mongo. Sends, flow advancement, and admin reads will all fail.',\n }\n }\n}\n\nasync function checkQueue(mailer: Mailer): Promise<SetupCheck> {\n const driver = mailer.config.queue.driver\n if (driver === 'noop') {\n return {\n name: 'queue',\n label: 'Queue driver',\n severity: 'ok',\n message: 'driver: noop (synchronous-only mode)',\n }\n }\n try {\n await mailer.queues.send.getWaitingCount()\n return { name: 'queue', label: 'Queue driver', severity: 'ok', message: `driver: ${driver}` }\n } catch (err) {\n return {\n name: 'queue',\n label: 'Queue driver',\n severity: 'error',\n message: `${driver} queue is not responding: ${(err as Error)?.message ?? err}`,\n hint:\n driver === 'bull'\n ? 'Check Redis connectivity (queue.redis.url).'\n : 'Check the @hokify/agenda + Mongo connection.',\n }\n }\n}\n\nasync function checkWorkersHeartbeat(mailer: Mailer): Promise<SetupCheck> {\n // The aggregate doc's updatedAt is touched on every counter increment and\n // on every evaluate tick, so it's the canonical worker-heartbeat marker.\n const h = await mailer.collections.health.findOne(\n {},\n { sort: { updatedAt: -1 } },\n )\n const tickIntervalMs = mailer.config.tickIntervalSeconds * 1000\n const staleAfterMs = Math.max(tickIntervalMs * 3, 30_000) // tolerate a couple missed ticks\n\n // This process may not run the workers itself (web/worker split) — keep the\n // verdicts identical either way, but point the operator at the right place.\n const workerless = mailer.config.workerless\n\n if (!h) {\n return {\n name: 'workers_heartbeat',\n label: 'Background workers',\n severity: 'warn',\n message: workerless ? 'no tick has run yet (workers run in another process)' : 'no tick has run yet',\n hint: workerless\n ? 'This process is workerless; the heartbeat comes from your separate worker process. If that process is started, the heartbeat will appear within one tick interval — a fresh install legitimately has none yet.'\n : 'If your separate worker process is started, the heartbeat will appear within one tick interval. If you forgot to run `mailer.startWorkers()`, sends will sit queued indefinitely.',\n }\n }\n\n const ageMs = Date.now() - new Date(h.updatedAt).getTime()\n if (ageMs > staleAfterMs) {\n return {\n name: 'workers_heartbeat',\n label: 'Background workers',\n severity: 'error',\n message: `last tick ${humanDuration(ageMs)} ago (expected within ${humanDuration(tickIntervalMs)})`,\n hint: workerless\n ? 'Workers run in another process, and that process appears to be down. Sends and flow advancement are halted. Restart the process that calls `mailer.startWorkers()`.'\n : 'Workers appear to be down. Sends and flow advancement are halted. Restart your worker process (`mailer.startWorkers()`).',\n }\n }\n return {\n name: 'workers_heartbeat',\n label: 'Background workers',\n severity: 'ok',\n message: `last tick ${humanDuration(ageMs)} ago${workerless ? ' (worker process)' : ''}`,\n }\n}\n\nasync function checkCircuitBreaker(mailer: Mailer): Promise<SetupCheck> {\n const docs = await mailer.collections.health.find({}).toArray()\n const buckets = docs.filter((d) => d._id !== HEALTH_AGG_ID)\n\n if (buckets.length === 0) {\n // No telemetry yet (heartbeat-only state, no sends recorded). Claiming\n // \"healthy\" misleads — there's nothing to base it on.\n return {\n name: 'circuit_breaker',\n label: 'Circuit breaker',\n severity: 'ok',\n message: 'no telemetry yet',\n hint: 'The breaker tracks bounce / complaint rates per (sender domain × kind) and starts evaluating once enough sends have been recorded. Send some mail to populate.',\n }\n }\n\n const tripped = buckets.filter((d) => d.status === 'tripped')\n if (tripped.length > 0) {\n const summary = tripped\n .map((d) => `${d.senderDomain ?? '_unknown'}/${d.kind}`)\n .join(', ')\n return {\n name: 'circuit_breaker',\n label: 'Circuit breaker',\n severity: 'error',\n message: `tripped: ${summary}`,\n hint: 'Marketing sends are held for the listed bucket(s). Investigate the underlying bounce / complaint cause, then POST /api/health/resume (with optional senderDomain + kind to resume one bucket).',\n }\n }\n\n const degraded = buckets.filter((d) => d.status === 'degraded')\n if (degraded.length > 0) {\n const summary = degraded\n .map((d) => `${d.senderDomain ?? '_unknown'}/${d.kind}`)\n .join(', ')\n return {\n name: 'circuit_breaker',\n label: 'Circuit breaker',\n severity: 'warn',\n message: `degraded: ${summary}`,\n hint: 'Marketing sends still flow but failure rate is above the degraded threshold for the listed bucket(s). Investigate provider errors before they escalate to tripped.',\n }\n }\n\n return { name: 'circuit_breaker', label: 'Circuit breaker', severity: 'ok', message: 'healthy' }\n}\n\nasync function checkDnsbl(mailer: Mailer): Promise<SetupCheck> {\n const docs = await mailer.collections.dnsblChecks.find({}).toArray()\n if (docs.length === 0) {\n return {\n name: 'dnsbl',\n label: 'DNS block-list checks',\n severity: 'ok',\n message: 'no checks run yet',\n hint: 'Checks run automatically once per dnsbl.intervalHours (default 24h). To run now, POST /api/dnsbl/recheck.',\n }\n }\n const listed = docs.filter((d) => d.result === 'listed')\n if (listed.length > 0) {\n const summary = listed\n .map((d) => `${d.target} on ${d.listLabel}`)\n .slice(0, 3)\n .join('; ')\n const more = listed.length > 3 ? ` (+${listed.length - 3} more)` : ''\n return {\n name: 'dnsbl',\n label: 'DNS block-list checks',\n severity: 'error',\n message: `${listed.length} listing(s): ${summary}${more}`,\n hint: 'A sender domain or IP is listed on a public DNSBL. Investigate the listing source — most lists publish a removal procedure on their website. Mail to the affected (domain, kind) bucket will likely land in spam until delisted.',\n }\n }\n const errored = docs.filter((d) => d.result === 'error')\n if (errored.length === docs.length) {\n return {\n name: 'dnsbl',\n label: 'DNS block-list checks',\n severity: 'warn',\n message: `all ${docs.length} checks errored`,\n hint: 'Lookups against block lists are failing — usually a DNS-resolution problem on the host running mailery, or a list rate-limiting your public resolver. Verify outbound DNS works.',\n }\n }\n return {\n name: 'dnsbl',\n label: 'DNS block-list checks',\n severity: 'ok',\n message: `clean (${docs.length} checks)`,\n }\n}\n\nasync function checkPostmaster(mailer: Mailer): Promise<SetupCheck> {\n const cfg = mailer.config.postmaster\n if (!cfg?.clientId || !cfg?.clientSecret || !cfg?.refreshToken) {\n // Postmaster is opt-in (needs OAuth setup) and only meaningful at >100/day\n // to Gmail. Treat \"not configured\" as ok so it doesn't spam every operator\n // with a permanent warning banner.\n return {\n name: 'postmaster',\n label: 'Google Postmaster Tools',\n severity: 'ok',\n message: 'not configured (optional)',\n hint: 'Set mailer.config.postmaster with an OAuth client + refresh token to pull authoritative Gmail reputation data. Only meaningful at >100 sends/day to Gmail.',\n }\n }\n\n const snapshots = await mailer.collections.postmasterSnapshots.find({}).sort({ fetchedAt: -1 }).toArray()\n if (snapshots.length === 0) {\n return {\n name: 'postmaster',\n label: 'Google Postmaster Tools',\n severity: 'warn',\n message: 'configured but no data yet',\n hint: 'A pull runs once per postmaster.intervalHours (default 24h). To run now, POST /api/postmaster/refresh. Postmaster only reports for domains with >100 messages/day to Gmail; smaller senders see empty responses.',\n }\n }\n\n // Find the latest snapshot per domain (snapshots are already sorted by fetchedAt desc).\n const latestByDomain = new Map<string, typeof snapshots[number]>()\n for (const s of snapshots) {\n if (!latestByDomain.has(s.domain)) latestByDomain.set(s.domain, s)\n }\n const bad: string[] = []\n const low: string[] = []\n for (const s of latestByDomain.values()) {\n if (s.domainReputation === 'BAD') bad.push(s.domain)\n else if (s.domainReputation === 'LOW') low.push(s.domain)\n }\n\n if (bad.length > 0) {\n return {\n name: 'postmaster',\n label: 'Google Postmaster Tools',\n severity: 'error',\n message: `BAD reputation on ${bad.join(', ')}`,\n hint: 'Gmail considers these domains spammy. Most mail to Gmail addresses will land in spam folder. Marketing breaker has been tripped for affected domains. See docs/guide/warming.md §6 for recovery.',\n }\n }\n if (low.length > 0) {\n return {\n name: 'postmaster',\n label: 'Google Postmaster Tools',\n severity: 'warn',\n message: `LOW reputation on ${low.join(', ')}`,\n hint: 'Reputation has slipped below Medium. Review recent complaint + bounce activity, slow down marketing volume, and re-engage your most active segment only.',\n }\n }\n return {\n name: 'postmaster',\n label: 'Google Postmaster Tools',\n severity: 'ok',\n // Includes REPUTATION_CATEGORY_UNSPECIFIED (\"no data yet\") domains —\n // surface that explicitly so the operator isn't misled.\n message: (() => {\n const tiers = new Set(Array.from(latestByDomain.values()).map((d) => d.domainReputation))\n const hasUnspec = tiers.has('REPUTATION_CATEGORY_UNSPECIFIED' as any)\n return `${latestByDomain.size} domain(s) tracked${hasUnspec ? ' (some have no reputation data yet)' : ', all High/Medium'}`\n })(),\n }\n}\n\n/**\n * JMRP enrolment is a manual one-time setup on the Microsoft sender-support\n * portal — there's no API to confirm completion. We surface a persistent\n * info-level reminder whenever the operator has configured a dedicated IP,\n * regardless of whether SNDS itself is set up. Operators can suppress this\n * by setting `dnsbl.dedicatedIps = []` once they've confirmed enrolment in\n * their runbook.\n */\nfunction checkJmrp(mailer: Mailer): SetupCheck | null {\n const hasDedicatedIp = (mailer.config.dnsbl?.dedicatedIps?.length ?? 0) > 0\n if (!hasDedicatedIp) return null\n return {\n name: 'snds_jmrp',\n label: 'Microsoft JMRP enrolment',\n severity: 'ok',\n message: 'manual setup — confirm in your runbook',\n hint: 'Outlook spam complaints only land in mailery if you enrol each sending IP in JMRP. Visit https://sendersupport.olc.protection.outlook.com/snds/JMRP.aspx and complete the form for each IP. There is no API to verify completion; mailery shows this reminder whenever dedicatedIps is non-empty.',\n }\n}\n\nasync function checkSnds(mailer: Mailer): Promise<SetupCheck> {\n const cfg = mailer.config.snds\n const hasDedicatedIp = (mailer.config.dnsbl?.dedicatedIps?.length ?? 0) > 0\n\n if (!cfg?.accessKey) {\n if (!hasDedicatedIp) {\n return {\n name: 'snds',\n label: 'Microsoft SNDS',\n severity: 'ok',\n message: 'not applicable (no dedicated IP)',\n hint: 'SNDS reports IP-level Outlook/Hotmail reputation. Only meaningful when you send from a dedicated IP. Skip unless you do.',\n }\n }\n return {\n name: 'snds',\n label: 'Microsoft SNDS',\n severity: 'warn',\n message: 'dedicated IP configured but SNDS access key not set',\n hint: 'Sign in at https://sendersupport.olc.protection.outlook.com/snds/ , request access for your IP(s), then set mailer.config.snds.accessKey to enable daily pulls. Also enrol in JMRP at https://sendersupport.olc.protection.outlook.com/snds/JMRP.aspx so Outlook complaints flow back to your suppression list.',\n }\n }\n\n const snapshots = await mailer.collections.sndsSnapshots.find({}).sort({ fetchedAt: -1 }).toArray()\n if (snapshots.length === 0) {\n return {\n name: 'snds',\n label: 'Microsoft SNDS',\n severity: 'warn',\n message: 'configured but no data yet',\n hint: 'A pull runs every snds.intervalHours (default 24h). To run now, POST /api/snds/refresh. If you just enrolled, SNDS data can take 1-2 days to populate.',\n }\n }\n\n const latestByIp = new Map<string, typeof snapshots[number]>()\n for (const s of snapshots) {\n if (!latestByIp.has(s.ip)) latestByIp.set(s.ip, s)\n }\n const red: string[] = []\n const yellow: string[] = []\n for (const s of latestByIp.values()) {\n if (s.filterResult === 'RED') red.push(s.ip)\n else if (s.filterResult === 'YELLOW') yellow.push(s.ip)\n }\n\n if (red.length > 0) {\n return {\n name: 'snds',\n label: 'Microsoft SNDS',\n severity: 'error',\n message: `RED filter on ${red.join(', ')}`,\n hint: 'Outlook/Hotmail is filtering mail from these IPs as spam. Reduce volume, audit recent complaints / trap hits, fix any auth alignment problems, and wait for reputation to recover (typically 1-2 weeks).',\n }\n }\n if (yellow.length > 0) {\n return {\n name: 'snds',\n label: 'Microsoft SNDS',\n severity: 'warn',\n message: `YELLOW filter on ${yellow.join(', ')}`,\n hint: 'Outlook is putting some mail from these IPs in the junk folder. Investigate recent complaint rate and trap hits before reputation slips to RED.',\n }\n }\n return {\n name: 'snds',\n label: 'Microsoft SNDS',\n severity: 'ok',\n message: `${latestByIp.size} IP(s) tracked, all GREEN`,\n }\n}\n\nasync function checkDmarc(mailer: Mailer): Promise<SetupCheck> {\n const reportCount = await mailer.collections.dmarcReports.estimatedDocumentCount()\n if (reportCount === 0) {\n return {\n name: 'dmarc',\n label: 'DMARC RUA reports',\n severity: 'ok',\n message: 'no reports ingested yet',\n hint: 'Publish DMARC `rua=mailto:<your-mailbox>` in DNS, then upload received reports via /admin/mailer/api/dmarc/upload (or drag-drop in the Health screen). RUA tells you who is sending mail as your domain — both legitimate sources and spoofers.',\n }\n }\n\n const since = new Date(Date.now() - 7 * 86_400_000)\n const recent = await mailer.collections.dmarcReports.find({ rangeEnd: { $gte: since } }).toArray()\n if (recent.length === 0) {\n return {\n name: 'dmarc',\n label: 'DMARC RUA reports',\n severity: 'warn',\n message: `no reports in the last 7 days (${reportCount} total)`,\n hint: 'Receivers email RUA reports daily. A gap suggests inbound delivery is broken or the rua= mailbox is no longer monitored. Check inbound mail flow.',\n }\n }\n\n // Merge config-defined tags with DB-defined tags so operator tags set via\n // the admin UI count. Both labeled (non-ignored) and ignored sources are\n // treated as \"known\" — operator already triaged them.\n const tagged = await resolveSourceTags(mailer.getRunnerContext())\n const known = new Set(Array.from(tagged.keys()))\n const since30 = new Date(Date.now() - 30 * 86_400_000)\n const failures = await mailer.collections.dmarcFailures.find({ receivedAt: { $gte: since30 } }).toArray()\n const unknownFailing = failures.filter((f) => !known.has(f.sourceIp))\n\n if (unknownFailing.length === 0) {\n return {\n name: 'dmarc',\n label: 'DMARC RUA reports',\n severity: 'ok',\n message: `${recent.length} report(s) this week, no failing unknown sources`,\n }\n }\n\n const totalFailing = unknownFailing.reduce((acc, f) => acc + f.count, 0)\n const ips = Array.from(new Set(unknownFailing.map((f) => f.sourceIp))).slice(0, 3)\n const more = unknownFailing.length > 3 ? ` (+${unknownFailing.length - 3} more)` : ''\n return {\n name: 'dmarc',\n label: 'DMARC RUA reports',\n severity: 'warn',\n message: `${totalFailing} failing message(s) from ${ips.join(', ')}${more}`,\n hint: 'These IPs sent mail claiming to be from your domain that failed DMARC alignment. Tag known-legit sources in mailer.config.dmarc.knownSources to silence them. Untagged sources are likely either forgotten SaaS tools or active spoofing.',\n }\n}\n\nfunction checkFromDefaultsAgainstRegistry(mailer: Mailer): SetupCheck[] {\n const registry = mailer.config.senderDomains\n if (!registry || Object.keys(registry).length === 0) return []\n\n const out: SetupCheck[] = []\n const from = mailer.config.fromDefaults?.email\n const tx = mailer.config.transactionalFromDefaults?.email\n\n if (from) {\n const r = validateSenderDomain(from, 'marketing', registry)\n if (!r.ok) {\n out.push({\n name: 'from_defaults_marketing',\n label: 'fromDefaults vs senderDomains',\n severity: 'error',\n message: r.reason,\n hint: 'New marketing templates that fall back to fromDefaults will fail to publish.',\n })\n }\n }\n\n if (tx) {\n const r = validateSenderDomain(tx, 'transactional', registry)\n if (!r.ok) {\n out.push({\n name: 'transactional_from_defaults',\n label: 'transactionalFromDefaults vs senderDomains',\n severity: 'error',\n message: r.reason,\n hint: 'New transactional templates that fall back to transactionalFromDefaults will fail to publish.',\n })\n }\n } else if (from) {\n // No transactional defaults set; transactional creates will fall back to\n // fromDefaults. Check whether that fallback is valid for transactional.\n const r = validateSenderDomain(from, 'transactional', registry)\n if (!r.ok) {\n out.push({\n name: 'transactional_fallback',\n label: 'Transactional fallback',\n severity: 'warn',\n message: `transactionalFromDefaults is unset and fromDefaults (${from}) is invalid for transactional templates`,\n hint: 'Set transactionalFromDefaults to a transactional-kind domain, or set senderDomains entry for the existing one to \"both\".',\n })\n }\n }\n\n return out\n}\n\nasync function checkPublishedTemplates(mailer: Mailer): Promise<SetupCheck[]> {\n const registry = mailer.config.senderDomains\n if (!registry || Object.keys(registry).length === 0) return []\n\n const published = await mailer.collections.templates\n .find({ publishedAt: { $ne: null } }, { projection: { slug: 1, kind: 1, fromEmail: 1 } })\n .toArray()\n\n const broken: Array<{ slug: string; reason: string }> = []\n for (const tpl of published) {\n const r = validateSenderDomain(tpl.fromEmail, tpl.kind, registry)\n if (!r.ok) broken.push({ slug: tpl.slug, reason: r.reason })\n }\n\n if (broken.length === 0) return []\n const list = broken.slice(0, 5).map((b) => `${b.slug} (${b.reason})`).join('; ')\n const more = broken.length > 5 ? ` …and ${broken.length - 5} more` : ''\n return [\n {\n name: 'published_template_domains',\n label: 'Published templates',\n severity: 'error',\n message: `${broken.length} published template${broken.length === 1 ? '' : 's'} use a fromEmail that no longer matches senderDomains: ${list}${more}`,\n hint: 'These templates will still send with their stored fromEmail until re-published. Edit each template and republish to surface the validation, or update senderDomains.',\n },\n ]\n}\n\nasync function checkPostalAddress(mailer: Mailer): Promise<SetupCheck> {\n if (mailer.config.senderAddress) {\n return { name: 'postal_address', label: 'CAN-SPAM postal address', severity: 'ok', message: 'set' }\n }\n const marketingCount = await mailer.collections.templates.countDocuments({\n kind: 'marketing',\n publishedAt: { $ne: null },\n })\n if (marketingCount === 0) {\n return { name: 'postal_address', label: 'CAN-SPAM postal address', severity: 'ok', message: 'no published marketing templates yet' }\n }\n return {\n name: 'postal_address',\n label: 'CAN-SPAM postal address',\n severity: 'warn',\n message: `${marketingCount} published marketing template${marketingCount === 1 ? '' : 's'} but senderAddress is unset`,\n hint: 'CAN-SPAM requires a postal address in marketing emails. Set `senderAddress` in your Mailer config and reference the `{{senderAddress}}` render variable in your templates.',\n }\n}\n\nasync function checkDoiTemplate(mailer: Mailer): Promise<SetupCheck> {\n if (!mailer.config.requireDoubleOptIn) {\n return { name: 'doi_template', label: 'DOI template', severity: 'ok', message: 'DOI not required' }\n }\n const tpl = await mailer.collections.templates.findOne({\n slug: mailer.config.doiTemplateSlug,\n publishedAt: { $ne: null },\n })\n if (tpl) {\n return { name: 'doi_template', label: 'DOI template', severity: 'ok', message: `template \"${tpl.slug}\" published` }\n }\n return {\n name: 'doi_template',\n label: 'DOI template',\n severity: 'error',\n message: `requireDoubleOptIn is true but no published template with slug \"${mailer.config.doiTemplateSlug}\"`,\n hint: 'New subscriptions will silently fail to send confirmation emails. Create and publish a template with this slug, or unset requireDoubleOptIn.',\n }\n}\n\nfunction humanDuration(ms: number): string {\n if (ms < 1000) return `${ms}ms`\n if (ms < 60_000) return `${Math.round(ms / 1000)}s`\n if (ms < 3_600_000) return `${Math.round(ms / 60_000)}m`\n return `${Math.round(ms / 3_600_000)}h`\n}\n","/**\n * List hygiene aggregations. Reports the engagement health of the\n * subscriber list: how many contacts engaged recently, how many are\n * stale, and what the bounce/complaint impact of sunsetting the stale\n * cohort would be.\n *\n * Pure read — no writes. Caller decides when to run.\n */\n\nimport type { RunnerContext } from './index.js'\n\nconst DAY_MS = 86_400_000\n\nexport const HYGIENE_BUCKETS = [\n { label: 'Engaged (last 30 days)', maxDays: 30 },\n { label: 'Engaged (31-60 days)', minDays: 30, maxDays: 60 },\n { label: 'Engaged (61-90 days)', minDays: 60, maxDays: 90 },\n { label: 'Engaged (91-180 days)', minDays: 90, maxDays: 180 },\n { label: 'Inactive (>180 days)', minDays: 180 },\n { label: 'Never engaged', neverEngaged: true },\n] as const\n\nexport interface HygieneBucket {\n label: string\n /** Lower bound of \"days since last engagement\" inclusive. Null for never-engaged. */\n minDays?: number | null\n /** Upper bound of \"days since last engagement\" exclusive. Null = unbounded. */\n maxDays?: number | null\n /** True for the \"never engaged\" bucket (sent but no open/click ever). */\n neverEngaged?: boolean\n count: number\n pctOfTotal: number\n}\n\nexport interface HygieneReport {\n totalSubscribers: number\n totalWithSends: number\n buckets: HygieneBucket[]\n sunsetCandidate: {\n /** Cohort: subscribed contacts whose lastEngagedAt is >180 days ago, or who have never engaged after >180 days of being subscribed. */\n count: number\n pctOfTotal: number\n /** Lifetime metrics for the cohort, when data exists. */\n cohortLifetime: {\n totalSends: number\n bouncedRate: number\n hardBouncedRate: number\n complaintRate: number\n } | null\n /** Projected impact: how recent (90d) rates would change if this cohort were sunset. */\n projectedImpact: {\n recentTotalSends: number\n recentBounced: number\n recentComplained: number\n cohortRecentSends: number\n cohortRecentBounced: number\n cohortRecentComplained: number\n currentOverallBounceRate: number\n projectedBounceRate: number\n currentOverallComplaintRate: number\n projectedComplaintRate: number\n } | null\n }\n computedAt: string\n}\n\nexport interface ComputeHygieneOptions {\n /** Override now() for tests. */\n now?: number\n /** Days of inactivity considered \"stale\" enough to sunset. Default 180. */\n sunsetThresholdDays?: number\n /** Window for projected-impact calculations. Default 90. */\n recentWindowDays?: number\n}\n\nexport async function computeListHygiene(\n ctx: RunnerContext,\n opts: ComputeHygieneOptions = {},\n): Promise<HygieneReport> {\n const now = opts.now ?? Date.now()\n const sunsetDays = opts.sunsetThresholdDays ?? 180\n const recentDays = opts.recentWindowDays ?? 90\n const recentCutoff = new Date(now - recentDays * DAY_MS)\n\n const totalSubscribers = await ctx.collections.subscriptions.countDocuments({ status: 'subscribed' })\n\n // Restrict the engagement aggregation to currently-subscribed contacts.\n // We materialize the subscriber externalId set in memory (one short\n // string per row). At ~10M subscribers this would be ~hundreds of MB —\n // a real concern at that scale. Below ~1M it's negligible. If list\n // sizes ever push past that, move to a server-side $lookup join inside\n // the sends aggregation.\n const subscribedIds = new Set<string>()\n {\n const cursor = ctx.collections.subscriptions\n .find({ status: 'subscribed' }, { projection: { externalId: 1 } })\n for await (const s of cursor) subscribedIds.add(s.externalId)\n }\n\n type EngagementRow = {\n _id: string\n lastOpened: Date | null\n lastClicked: Date | null\n firstSent: Date | null\n totalSends: number\n bounced: number\n hardBounced: number\n complained: number\n recentSends: number\n recentBounced: number\n recentComplained: number\n }\n\n // Single aggregation: group by externalId, computing engagement + lifetime\n // counts + recent-window counts in one pass. Cursor iteration avoids\n // loading the full per-contact map at once; allowDiskUse keeps Mongo from\n // OOMing on the $group stage at scale.\n const cursor = ctx.collections.sends.aggregate<EngagementRow>(\n [\n {\n $group: {\n _id: '$externalId',\n lastOpened: { $max: '$openedAt' },\n lastClicked: { $max: '$firstClickAt' },\n firstSent: { $min: '$queuedAt' },\n totalSends: { $sum: 1 },\n bounced: { $sum: { $cond: [{ $eq: ['$status', 'bounced'] }, 1, 0] } },\n hardBounced: {\n $sum: {\n $cond: [\n { $and: [{ $eq: ['$status', 'bounced'] }, { $eq: ['$bounceType', 'hard'] }] },\n 1,\n 0,\n ],\n },\n },\n complained: { $sum: { $cond: [{ $ne: ['$complainedAt', null] }, 1, 0] } },\n recentSends: { $sum: { $cond: [{ $gte: ['$queuedAt', recentCutoff] }, 1, 0] } },\n recentBounced: {\n $sum: {\n $cond: [\n { $and: [{ $eq: ['$status', 'bounced'] }, { $gte: ['$queuedAt', recentCutoff] }] },\n 1,\n 0,\n ],\n },\n },\n recentComplained: {\n $sum: {\n $cond: [\n { $and: [{ $ne: ['$complainedAt', null] }, { $gte: ['$queuedAt', recentCutoff] }] },\n 1,\n 0,\n ],\n },\n },\n },\n },\n ],\n { allowDiskUse: true },\n )\n\n const buckets: HygieneBucket[] = HYGIENE_BUCKETS.map((b) => ({\n label: b.label,\n minDays: 'minDays' in b ? b.minDays : null,\n maxDays: 'maxDays' in b ? b.maxDays : null,\n neverEngaged: 'neverEngaged' in b && b.neverEngaged,\n count: 0,\n pctOfTotal: 0,\n }))\n\n let totalWithSends = 0\n let sunsetCount = 0\n\n const cohortLifetimeAcc = { totalSends: 0, bounced: 0, hardBounced: 0, complained: 0 }\n const cohortRecentAcc = { totalSends: 0, bounced: 0, complained: 0 }\n\n for await (const row of cursor) {\n if (!subscribedIds.has(row._id)) continue\n totalWithSends++\n\n const lastOpened = row.lastOpened ? new Date(row.lastOpened).getTime() : null\n const lastClicked = row.lastClicked ? new Date(row.lastClicked).getTime() : null\n const lastEngaged = lastOpened == null && lastClicked == null\n ? null\n : Math.max(lastOpened ?? 0, lastClicked ?? 0)\n\n let isSunset = false\n if (lastEngaged == null) {\n const firstSent = row.firstSent ? new Date(row.firstSent).getTime() : null\n buckets[5]!.count++\n if (firstSent != null && now - firstSent > sunsetDays * DAY_MS) {\n isSunset = true\n }\n } else {\n const daysSince = (now - lastEngaged) / DAY_MS\n if (daysSince <= 30) buckets[0]!.count++\n else if (daysSince <= 60) buckets[1]!.count++\n else if (daysSince <= 90) buckets[2]!.count++\n else if (daysSince <= 180) buckets[3]!.count++\n else {\n buckets[4]!.count++\n isSunset = true\n }\n }\n\n if (isSunset) {\n sunsetCount++\n cohortLifetimeAcc.totalSends += row.totalSends\n cohortLifetimeAcc.bounced += row.bounced\n cohortLifetimeAcc.hardBounced += row.hardBounced\n cohortLifetimeAcc.complained += row.complained\n cohortRecentAcc.totalSends += row.recentSends\n cohortRecentAcc.bounced += row.recentBounced\n cohortRecentAcc.complained += row.recentComplained\n }\n }\n\n for (const b of buckets) {\n b.pctOfTotal = totalSubscribers === 0 ? 0 : b.count / totalSubscribers\n }\n\n const cohortLifetime: HygieneReport['sunsetCandidate']['cohortLifetime'] =\n cohortLifetimeAcc.totalSends > 0\n ? {\n totalSends: cohortLifetimeAcc.totalSends,\n bouncedRate: cohortLifetimeAcc.bounced / cohortLifetimeAcc.totalSends,\n hardBouncedRate: cohortLifetimeAcc.hardBounced / cohortLifetimeAcc.totalSends,\n complaintRate: cohortLifetimeAcc.complained / cohortLifetimeAcc.totalSends,\n }\n : null\n\n // Recent-window overall stats are bounded by the date window and small at\n // any realistic volume.\n let projectedImpact: HygieneReport['sunsetCandidate']['projectedImpact'] = null\n const recentAll = await ctx.collections.sends\n .aggregate<{ totalSends: number; bounced: number; complained: number }>([\n { $match: { queuedAt: { $gte: recentCutoff } } },\n {\n $group: {\n _id: null,\n totalSends: { $sum: 1 },\n bounced: { $sum: { $cond: [{ $eq: ['$status', 'bounced'] }, 1, 0] } },\n complained: { $sum: { $cond: [{ $ne: ['$complainedAt', null] }, 1, 0] } },\n },\n },\n ])\n .toArray()\n\n if (recentAll[0] && recentAll[0].totalSends > 0) {\n const all = recentAll[0]\n const cohort = cohortRecentAcc\n const currentBounceRate = all.bounced / all.totalSends\n const currentComplaintRate = all.complained / all.totalSends\n const remainingSends = all.totalSends - cohort.totalSends\n const remainingBounces = all.bounced - cohort.bounced\n const remainingComplaints = all.complained - cohort.complained\n const projectedBounceRate = remainingSends > 0 ? remainingBounces / remainingSends : 0\n const projectedComplaintRate = remainingSends > 0 ? remainingComplaints / remainingSends : 0\n\n projectedImpact = {\n recentTotalSends: all.totalSends,\n recentBounced: all.bounced,\n recentComplained: all.complained,\n cohortRecentSends: cohort.totalSends,\n cohortRecentBounced: cohort.bounced,\n cohortRecentComplained: cohort.complained,\n currentOverallBounceRate: currentBounceRate,\n projectedBounceRate,\n currentOverallComplaintRate: currentComplaintRate,\n projectedComplaintRate,\n }\n }\n\n return {\n totalSubscribers,\n totalWithSends,\n buckets,\n sunsetCandidate: {\n count: sunsetCount,\n pctOfTotal: totalSubscribers === 0 ? 0 : sunsetCount / totalSubscribers,\n cohortLifetime,\n projectedImpact,\n },\n computedAt: new Date(now).toISOString(),\n }\n}\n","/**\n * Mail-Tester deliverability check.\n *\n * 1. Operator clicks \"Run deliverability check\" in the template editor.\n * 2. Mailery provisions a check (gets a unique test address from Mail-Tester).\n * 3. Mailery sends the rendered draft to that address via the operator's\n * default provider.\n * 4. Mailery polls Mail-Tester for the score (typically arrives 10-30s after\n * receipt) and caches it keyed on a content fingerprint.\n * 5. If the score is below `minScore` the publish endpoint refuses unless\n * the operator passes `bypassMailTester: true` in the publish request.\n *\n * The client interface is pluggable so tests inject a stub. Real\n * implementation hits https://mail-tester.com/api/.\n */\n\nimport crypto from 'node:crypto'\n\nimport type { MailTesterConfig } from '../config.js'\nimport type { MailTesterFeedback, MailTesterScoreDoc } from '../models/index.js'\nimport type { RunnerContext } from './index.js'\n\nexport type Fetcher = (url: string, init?: RequestInit) => Promise<Response>\n\nexport interface ProvisionedCheck {\n checkId: string\n emailAddress: string\n}\n\nexport interface MailTesterResult {\n ready: boolean\n score: number\n feedback: MailTesterFeedback[]\n rawSummary: string | null\n}\n\nexport interface MailTesterClient {\n provisionCheck(): Promise<ProvisionedCheck>\n fetchResult(checkId: string): Promise<MailTesterResult>\n}\n\nconst FETCH_TIMEOUT_MS = 15_000\n\nexport function createMailTesterClient(\n cfg: MailTesterConfig,\n fetcher: Fetcher = globalThis.fetch,\n): MailTesterClient {\n const base = cfg.baseUrl ?? 'https://mail-tester.com/api'\n\n function sanitize(s: string): string {\n if (!cfg.apiKey) return s\n return s.split(cfg.apiKey).join('<redacted>').split(encodeURIComponent(cfg.apiKey)).join('<redacted>')\n }\n\n async function call(method: string, path: string, body?: unknown): Promise<any> {\n const ctl = new AbortController()\n const t = setTimeout(() => ctl.abort(), FETCH_TIMEOUT_MS)\n let res: Response\n try {\n res = await fetcher(`${base}/${encodeURIComponent(cfg.apiKey)}${path}`, {\n method,\n headers: { 'content-type': 'application/json' },\n body: body ? JSON.stringify(body) : undefined,\n signal: ctl.signal,\n })\n } catch (err: any) {\n throw new Error(`Mail-Tester ${method} ${sanitize(path)} failed: ${sanitize(String(err?.message ?? err))}`)\n } finally {\n clearTimeout(t)\n }\n if (!res.ok) {\n const text = await safeText(res)\n throw new Error(`Mail-Tester ${method} ${sanitize(path)} → ${res.status}: ${sanitize(text)}`)\n }\n return res.json()\n }\n\n return {\n async provisionCheck() {\n const data = await call('POST', '/new')\n const checkId = String(data.check_id ?? data.checkId ?? '')\n const emailAddress = String(data.email_address ?? data.email ?? '')\n if (!checkId || !emailAddress) throw new Error('Mail-Tester /new returned an unexpected shape')\n return { checkId, emailAddress }\n },\n async fetchResult(checkId) {\n const data = await call('GET', `/${encodeURIComponent(checkId)}`)\n // Ready is decided independently from score finiteness so a malformed\n // score number can't accidentally surface as `score: 0` and trip the\n // publish gate.\n const ready = Boolean(data.ready ?? data.complete ?? data.score != null)\n const scoreRaw = Number(data.score)\n const score = Number.isFinite(scoreRaw) ? scoreRaw : 0\n const feedback: MailTesterFeedback[] = Array.isArray(data.feedback)\n ? data.feedback.map(normalizeFeedback)\n : []\n const rawSummary = typeof data.summary === 'string' ? data.summary : null\n return { ready: ready && Number.isFinite(scoreRaw), score, feedback, rawSummary }\n },\n }\n}\n\nfunction normalizeFeedback(raw: any): MailTesterFeedback {\n const severity = String(raw.severity ?? 'info').toLowerCase()\n return {\n category: String(raw.category ?? 'other'),\n severity: severity === 'error' || severity === 'warning' || severity === 'info' ? severity : 'info',\n message: String(raw.message ?? ''),\n }\n}\n\nasync function safeText(res: Response): Promise<string> {\n try { return await res.text() } catch { return '<no body>' }\n}\n\n// ---------------------------------------------------------------------------\n// Content fingerprint + cache lookups\n// ---------------------------------------------------------------------------\n\nexport function mailTesterContentKey(input: { bodyHash: string; subject: string; fromEmail: string }): string {\n return crypto\n .createHash('sha256')\n .update(`${input.bodyHash}|${input.subject}|${input.fromEmail}`)\n .digest('hex')\n}\n\nexport async function findCachedScore(\n ctx: RunnerContext,\n contentKey: string,\n): Promise<MailTesterScoreDoc | null> {\n const doc = await ctx.collections.mailTesterScores.findOne({ contentKey })\n if (!doc) return null\n if (new Date(doc.expiresAt).getTime() < Date.now()) return null\n return doc\n}\n\nexport async function persistScore(\n ctx: RunnerContext,\n input: {\n templateSlug: string\n contentKey: string\n checkId: string\n result: MailTesterResult\n },\n): Promise<MailTesterScoreDoc> {\n const cfg = ctx.config.mailTester\n const hours = cfg?.cacheHours ?? 24\n const now = new Date()\n const expiresAt = new Date(now.getTime() + hours * 60 * 60 * 1000)\n const doc: MailTesterScoreDoc = {\n templateSlug: input.templateSlug,\n contentKey: input.contentKey,\n checkId: input.checkId,\n score: input.result.score,\n feedback: input.result.feedback,\n rawSummary: input.result.rawSummary,\n fetchedAt: now,\n expiresAt,\n }\n await ctx.collections.mailTesterScores.updateOne(\n { contentKey: input.contentKey },\n { $set: doc },\n { upsert: true },\n )\n return doc\n}\n\n// ---------------------------------------------------------------------------\n// Publish gate\n// ---------------------------------------------------------------------------\n\nexport interface MailTesterGateResult {\n allowed: boolean\n /** Reason for blocking. Null when allowed. */\n reason: string | null\n /** The cached score (if one exists for the content being published). */\n score: MailTesterScoreDoc | null\n /**\n * Why the gate blocked, for callers that render different guidance:\n * - 'low_score' — a score exists and is below minScore\n * - 'no_score' — requireScore is on and this content was never checked\n * Null when allowed.\n */\n code: 'low_score' | 'no_score' | null\n}\n\n/**\n * Check whether a publish is allowed under the Mail-Tester gate.\n *\n * Default mode (`requireScore` unset/false) blocks only content already known\n * to score below `minScore`. That is a ratchet on known-bad content, not a\n * gate: the content key covers body + subject + fromEmail, so any edit misses\n * the cache and publishes freely — a failing score is one whitespace change\n * away from irrelevant.\n *\n * With `requireScore: true`, a cache miss blocks too, so every publish is\n * backed by a score for that exact content. Costs one Mail-Tester credit per\n * content revision. Either mode is overridable per-request with\n * `bypassMailTester: true`.\n *\n * We never auto-trigger a check at publish time — that would send mail as a\n * side effect of a publish request.\n */\nexport async function evaluateMailTesterGate(\n ctx: RunnerContext,\n input: { bodyHash: string; subject: string; fromEmail: string },\n): Promise<MailTesterGateResult> {\n const cfg = ctx.config.mailTester\n if (!cfg?.apiKey) return { allowed: true, reason: null, score: null, code: null }\n\n const minScore = cfg.minScore ?? 8.0\n const key = mailTesterContentKey(input)\n const cached = await findCachedScore(ctx, key)\n\n if (!cached) {\n if (cfg.requireScore) {\n return {\n allowed: false,\n reason:\n 'No Mail-Tester score for this exact content. Run a deliverability check before publishing.',\n score: null,\n code: 'no_score',\n }\n }\n return { allowed: true, reason: null, score: null, code: null }\n }\n\n if (cached.score < minScore) {\n return {\n allowed: false,\n reason: `Mail-Tester score ${cached.score.toFixed(1)} is below minimum ${minScore.toFixed(1)}`,\n score: cached,\n code: 'low_score',\n }\n }\n return { allowed: true, reason: null, score: cached, code: null }\n}\n","/**\n * Async handler wrapper for the *public* router.\n *\n * The admin router's `asyncHandler` (`api/admin.ts`) is a plain `.catch(next)`,\n * which is right there: every admin handler computes first and responds last, so\n * a rejection always arrives before any header is written and Express can turn\n * it into a clean JSON 500.\n *\n * The public router cannot use that. `/open`, `/click` and `/webhooks` respond\n * *first* and do their work after — never make a mail client or a provider\n * wait on our database. By the time those handlers can reject,\n * `res.headersSent` is already true, and forwarding post-headers makes Express\n * destroy the socket underneath a response the client has already been\n * promised.\n *\n * (`POST /unsub` used to be in that list. It now awaits its write before\n * answering, because a response sent first can only ever report success —\n * see INVARIANT 8 and the route's own comment. It still needs this wrapper for\n * the pre-headers branch.)\n *\n * So this is a log-and-swallow wrapper, ported from featureboard's\n * `src/server/routes/wrap.js`, with one deliberate difference: featureboard\n * forwards with `next(err)` on the `headersSent` branch, and here that branch\n * only logs. See issue #5 — every public route is unauthenticated, and the\n * failure mode being fixed is precisely \"a rejected promise in a public route\n * takes down the host process\".\n */\n\nimport type { NextFunction, Request, RequestHandler, Response } from 'express'\n\n/**\n * Minimal structured-logger shape, compatible with pino/bunyan-style loggers\n * (`logger.error(fields, message)`). Every method is optional, so `{}` is a\n * valid silent logger and a bare `console` is not accidentally accepted with\n * mismatched argument order.\n */\nexport interface RouteLogger {\n error?: (fields: Record<string, unknown>, msg?: string) => void\n warn?: (fields: Record<string, unknown>, msg?: string) => void\n /**\n * Routine, high-volume telemetry — currently only \"an unsigned (pre-signing)\n * tracking URL was accepted in grace mode\", which is one line per legacy open\n * and is not a fault. Kept off `warn` deliberately so it can be routed or\n * dropped separately from things that are.\n */\n info?: (fields: Record<string, unknown>, msg?: string) => void\n}\n\n/**\n * Default logger — preserves the `console.error('mailery: …', details)` output\n * this package emitted before the `logger` option existed, so hosts that don't\n * pass one see no change.\n */\nexport const consoleRouteLogger: RouteLogger = {\n error(fields, msg) {\n console.error(msg ?? 'mailery: request failed', fields)\n },\n warn(fields, msg) {\n console.warn(msg ?? 'mailery: request warning', fields)\n },\n info(fields, msg) {\n console.info(msg ?? 'mailery: request', fields)\n },\n}\n\nexport type AsyncRouteHandler = (\n req: Request,\n res: Response,\n next: NextFunction,\n) => unknown | Promise<unknown>\n\n/**\n * Wrap a public route handler so a rejection can never become an unhandled\n * promise rejection (which, under Node's default `--unhandled-rejections=throw`,\n * takes the whole host application down — an unauthenticated DoS).\n *\n * Rejection handling:\n * - always log, with the request path\n * - headers already sent → swallow; the client has its response already\n * - otherwise → a plain 500\n */\nexport function wrap(logger: RouteLogger, handler: AsyncRouteHandler): RequestHandler {\n return async (req: Request, res: Response, next: NextFunction) => {\n try {\n await handler(req, res, next)\n } catch (err) {\n logger.error?.({ err, path: req.originalUrl }, 'mailery: request failed')\n if (res.headersSent) return\n res.status(500).json({ error: 'internal_error' })\n }\n }\n}\n","/**\n * Inbound DMARC aggregate-report webhook.\n *\n * DMARC RUA reports arrive as email. The usual way to turn that email into an\n * HTTP request is SendGrid Inbound Parse, and until v0.15 the documented setup\n * pointed Inbound Parse at `/admin/mailer/api/dmarc/upload` — a route behind\n * the host's `requireAdmin` guard, which Inbound Parse cannot satisfy. So the\n * documented setup either did not work, or worked because somebody removed the\n * guard from an admin router. This route replaces that advice.\n *\n * ## Read this before enabling it\n *\n * **Inbound Parse does not sign its payloads.** The SendGrid *Event Webhook*\n * does — see `providers/sendgrid.ts`, where signature verification and the\n * replay window live — but Inbound Parse is a different product and offers no\n * signature, no HMAC and no verifiable identity. There is nothing to verify.\n *\n * So this is, structurally, an unauthenticated file-accepting endpoint on a\n * public router, and the design has to own that rather than dress it up:\n *\n * 1. **Off unless configured.** No `dmarcInbound.secret`, no route — not a\n * 404 handler, no route registered at all. An endpoint like this appearing\n * on an upgrade because someone shipped a default would be indefensible.\n * 2. **A shared secret, checked first.** The secret is compared with\n * `timingSafeEqual` before multer is allowed to read a single byte of the\n * body, so an unauthenticated caller cannot make us buffer 10MB.\n * 3. **Hard size and count limits**, matching the admin upload's shape.\n * 4. **A domain cross-check.** A report whose `<policy_published><domain>` is\n * not a domain this deployment sends from is rejected. If the secret leaks,\n * the attacker gets to inject rows about *your* domains, which is bounded\n * and visible, instead of arbitrary garbage.\n * 5. **The existing parser.** `runner/dmarc.ts` already caps decompressed\n * bytes, validates declared-vs-actual sizes, checks compression ratio and\n * guards zip-slip. This route does not parse anything itself.\n *\n * ## Why a shared secret, and where it goes\n *\n * The three options that don't need a signature:\n *\n * - **Source IP allowlist.** Rejected as the primary control. SendGrid does\n * not publish a stable Inbound Parse egress range, and behind a proxy\n * `req.ip` is the proxy's address unless the host has set `trust proxy`\n * correctly — which this library cannot verify and must not assume. An\n * allowlist that silently matches the wrong address either locks out the\n * real sender or admits everyone. Put an allowlist in your ingress if you\n * want one; it is a good second layer and a bad only layer.\n * - **Secret in the path.** Works, and is the fallback, but a URL path is\n * logged by every proxy, load balancer and access log between SendGrid and\n * you. Supported implicitly: nothing stops you making `path` unguessable.\n * - **Secret in the `Authorization` header.** The default and the\n * recommendation. Inbound Parse cannot set custom headers, but its\n * destination URL accepts embedded basic-auth credentials\n * (`https://mailery:SECRET@example.com/m/inbound/dmarc`), which travel as an\n * `Authorization` header rather than in the request line. `Bearer` is\n * accepted too, for hosts forwarding from something other than SendGrid.\n *\n * A leaked secret gets an attacker exactly one capability: inserting DMARC\n * report rows for domains you already send from. No mail is sent, no contact\n * data is touched, nothing is deleted. Rotate it by changing the config value\n * and the Inbound Parse destination URL.\n */\n\nimport { createHash, timingSafeEqual } from 'node:crypto'\nimport type { Request, Response, Router } from 'express'\nimport multer from 'multer'\n\nimport { ingestDmarcAttachment } from '../runner/dmarc.js'\nimport type { Mailer } from '../mailer.js'\nimport { wrap, type RouteLogger } from './wrap.js'\n\n/** One attachment lifted off an inbound request by a `parseInbound` seam. */\nexport interface InboundAttachment {\n filename: string\n buffer: Buffer\n}\n\n/**\n * Pull DMARC attachments out of a provider's inbound-email payload.\n *\n * The seam exists so Mailgun's and Postmark's inbound routes can be added\n * without touching this route's auth, limits or ingest path. Only the SendGrid\n * shape is implemented today.\n */\nexport type InboundParser = (req: Request) => InboundAttachment[]\n\nexport interface DmarcInboundOptions {\n /**\n * Shared secret the caller must present. **Absent or empty → the route is\n * not mounted at all.**\n *\n * Accepted as HTTP Basic (any username; the password is compared) or as\n * `Authorization: Bearer <secret>`. Basic is the one to use with SendGrid\n * Inbound Parse, since it can be embedded in the destination URL and so\n * stays out of access logs.\n */\n secret?: string\n /** Sub-path on the public router. Default `/inbound/dmarc`. */\n path?: string\n /** Per-file cap. Default 10MB, matching the admin upload. */\n maxFileSizeBytes?: number\n /** Attachments accepted per request. Default 10. */\n maxFiles?: number\n /**\n * Domains whose reports are accepted. Defaults to every domain in\n * `senderDomains` plus the `fromDefaults` / `transactionalFromDefaults`\n * addresses. Reports for anything else are rejected.\n *\n * If none of those are configured there is nothing to check against, and the\n * route mounts with the domain gate disabled and a warning — configure\n * `senderDomains` to get it back.\n */\n allowedDomains?: string[]\n /** Override the inbound payload shape. Defaults to SendGrid Inbound Parse. */\n parseInbound?: InboundParser\n}\n\n/** Extensions a DMARC receiver actually sends. */\nconst ALLOWED_EXTENSIONS = ['.zip', '.gz', '.xml']\n\nconst DEFAULT_PATH = '/inbound/dmarc'\nconst DEFAULT_MAX_FILE_BYTES = 10 * 1024 * 1024\nconst DEFAULT_MAX_FILES = 10\n\n/**\n * Mount the inbound route, if it is configured. Returns the mounted path, or\n * null when nothing was mounted — which is the default.\n */\nexport function mountDmarcInbound(\n router: Router,\n mailer: Mailer,\n opts: DmarcInboundOptions | undefined,\n logger: RouteLogger,\n): string | null {\n const secret = opts?.secret\n if (!opts || typeof secret !== 'string' || secret.length === 0) return null\n\n const routePath = opts.path ?? DEFAULT_PATH\n const parseInbound = opts.parseInbound ?? sendgridInboundParser\n const allowedDomains = normalizeDomains(opts.allowedDomains ?? deriveSenderDomains(mailer))\n\n if (allowedDomains.size === 0) {\n logger.warn?.(\n { path: routePath },\n 'mailery: DMARC inbound route mounted without a domain allowlist — set senderDomains (or dmarcInbound.allowedDomains) so a leaked secret cannot inject reports for arbitrary domains',\n )\n }\n\n const upload = multer({\n storage: multer.memoryStorage(),\n limits: {\n fileSize: opts.maxFileSizeBytes ?? DEFAULT_MAX_FILE_BYTES,\n files: opts.maxFiles ?? DEFAULT_MAX_FILES,\n // Inbound Parse sends the whole email as form fields (headers, text,\n // html, ...). We read none of them, but they still have to be bounded.\n fields: 40,\n fieldSize: 1024 * 1024,\n },\n })\n\n // Order is the security control: authenticate, *then* let multer read the\n // body. Reversed, an anonymous caller could make the process buffer the full\n // upload limit per request.\n router.post(\n routePath,\n wrap(logger, (req: Request, res: Response, next) => {\n if (!isAuthorized(req, secret)) {\n logger.warn?.(\n { path: routePath, ip: req.ip },\n 'mailery: DMARC inbound request rejected — bad or missing shared secret',\n )\n // 401 with no WWW-Authenticate challenge: this is a machine endpoint,\n // and prompting a browser for credentials helps nobody.\n res.status(401).json({ error: 'unauthorized' })\n return\n }\n next()\n }),\n (req: Request, res: Response, next: (err?: unknown) => void) => {\n upload.any()(req, res, (err: unknown) => {\n if (!err) return next()\n const code = (err as { code?: string })?.code\n const status = code === 'LIMIT_FILE_SIZE' || code === 'LIMIT_FILE_COUNT' ? 413 : 400\n logger.warn?.({ err, path: routePath }, 'mailery: DMARC inbound upload rejected')\n res.status(status).json({ error: 'upload_rejected', message: String(code ?? 'malformed_multipart') })\n })\n },\n wrap(logger, async (req: Request, res: Response) => {\n let attachments: InboundAttachment[]\n try {\n attachments = parseInbound(req)\n } catch (err) {\n logger.warn?.({ err, path: routePath }, 'mailery: DMARC inbound payload unreadable')\n return res.status(400).json({ error: 'bad_payload' })\n }\n\n const candidates = attachments.filter((a) => hasAllowedExtension(a.filename))\n if (candidates.length === 0) {\n // A RUA mailbox also receives ordinary mail — auto-replies, a human\n // asking a question. Nothing to ingest is not an error, and answering\n // 4xx would make the provider retry it.\n logger.info?.(\n { path: routePath, attachments: attachments.length },\n 'mailery: DMARC inbound message carried no report attachment — ignored',\n )\n return res.status(200).json({ ok: true, ingested: 0, ignored: attachments.length })\n }\n\n const ctx = mailer.getRunnerContext()\n const allowDomain =\n allowedDomains.size === 0 ? undefined : (d: string) => allowedDomains.has(d.toLowerCase())\n\n const ingested: Array<{ reportId: string; domain: string; duplicate: boolean }> = []\n const rejected: Array<{ filename: string; message: string }> = []\n\n for (const file of candidates) {\n try {\n const result = await ingestDmarcAttachment(ctx, file.buffer, file.filename, { allowDomain })\n ingested.push({ reportId: result.reportId, domain: result.domain, duplicate: result.duplicate })\n } catch (err: unknown) {\n const message = String((err as Error)?.message ?? err)\n rejected.push({ filename: file.filename, message })\n logger.warn?.(\n { path: routePath, filename: file.filename, err },\n 'mailery: DMARC inbound attachment rejected',\n )\n }\n }\n\n if (ingested.length === 0) {\n // Nothing usable in a message that claimed to carry a report. 400 so\n // the failure is visible in the provider's activity log rather than\n // disappearing into a 200.\n return res.status(400).json({ error: 'ingest_failed', rejected })\n }\n return res.status(200).json({ ok: true, ingested, rejected })\n }),\n )\n\n return routePath\n}\n\n// ---------------------------------------------------------------------------\n// Authentication\n// ---------------------------------------------------------------------------\n\n/**\n * Constant-time shared-secret check over the `Authorization` header.\n *\n * `timingSafeEqual` throws on a length mismatch, which would itself leak the\n * secret's length, so both sides are hashed to a fixed width first — the same\n * shape the token helpers use.\n */\nexport function isAuthorized(req: Request, secret: string): boolean {\n const presented = extractPresentedSecret(req)\n if (presented === null) return false\n return constantTimeEquals(presented, secret)\n}\n\nfunction extractPresentedSecret(req: Request): string | null {\n const header = req.headers.authorization\n if (typeof header !== 'string') return null\n\n const [scheme, ...rest] = header.split(' ')\n const value = rest.join(' ').trim()\n if (!scheme || value === '') return null\n\n switch (scheme.toLowerCase()) {\n case 'basic': {\n let decoded: string\n try {\n decoded = Buffer.from(value, 'base64').toString('utf8')\n } catch {\n return null\n }\n const sep = decoded.indexOf(':')\n // The username is deliberately ignored: SendGrid's destination URL needs\n // *a* username, and pinning one only adds a way to misconfigure it.\n return sep === -1 ? null : decoded.slice(sep + 1)\n }\n case 'bearer':\n return value\n default:\n return null\n }\n}\n\nfunction constantTimeEquals(a: string, b: string): boolean {\n // sha256 both sides so the comparison is over equal-length buffers no matter\n // what was presented.\n const ha = createHash('sha256').update(a, 'utf8').digest()\n const hb = createHash('sha256').update(b, 'utf8').digest()\n return timingSafeEqual(ha, hb)\n}\n\n// ---------------------------------------------------------------------------\n// Provider payload shapes\n// ---------------------------------------------------------------------------\n\n/**\n * SendGrid Inbound Parse: `multipart/form-data` with the message's fields\n * (`headers`, `from`, `subject`, `text`, ...) plus one file part per\n * attachment, named `attachment1`, `attachment2`, and so on.\n *\n * Read through `multer.any()`, so the field names are not trusted — every file\n * part is a candidate and the extension gate below decides.\n */\nexport const sendgridInboundParser: InboundParser = (req) => {\n const files = (req as unknown as { files?: unknown }).files\n if (!Array.isArray(files)) return []\n return files\n .filter((f): f is Express.Multer.File => Boolean(f) && Buffer.isBuffer((f as Express.Multer.File).buffer))\n .map((f) => ({ filename: safeFilename(f.originalname), buffer: f.buffer }))\n}\n\n/**\n * A provider-supplied filename only ever reaches `extractDmarcXmls`, which\n * reads its extension and nothing else — but it is also logged, so strip path\n * separators and control characters before it goes anywhere.\n */\nfunction safeFilename(raw: unknown): string {\n if (typeof raw !== 'string') return ''\n // eslint-disable-next-line no-control-regex\n return raw.replace(/[\\u0000-\\u001f\\u007f]/g, '').replace(/[\\\\/]/g, '_').slice(0, 255)\n}\n\nfunction hasAllowedExtension(filename: string): boolean {\n const lower = filename.toLowerCase()\n return ALLOWED_EXTENSIONS.some((ext) => lower.endsWith(ext))\n}\n\n// ---------------------------------------------------------------------------\n// Domain allowlist\n// ---------------------------------------------------------------------------\n\nfunction normalizeDomains(domains: Iterable<string>): Set<string> {\n const out = new Set<string>()\n for (const d of domains) {\n if (typeof d !== 'string') continue\n const trimmed = d.trim().toLowerCase().replace(/^\\.+/, '')\n if (trimmed) out.add(trimmed)\n }\n return out\n}\n\n/**\n * Domains this deployment sends from: the `senderDomains` registry plus the\n * From defaults. DMARC reports are published per organizational domain, so a\n * deployment sending from `news.example.com` receives reports whose\n * `policy_published.domain` may be either that or `example.com` — both are\n * included.\n */\nfunction deriveSenderDomains(mailer: Mailer): string[] {\n const out: string[] = []\n const push = (domain: string | undefined) => {\n if (!domain) return\n out.push(domain)\n // The organizational domain the subdomain's DMARC policy is inherited\n // from. Approximated as the last two labels, which is right for\n // `example.com` and over-permissive for a multi-label public suffix like\n // `example.co.uk` — set `dmarcInbound.allowedDomains` explicitly there.\n const labels = domain.split('.')\n if (labels.length > 2) out.push(labels.slice(-2).join('.'))\n }\n\n for (const domain of Object.keys(mailer.config.senderDomains ?? {})) push(domain.toLowerCase())\n push(emailDomain(mailer.config.fromDefaults?.email))\n push(emailDomain(mailer.config.transactionalFromDefaults?.email))\n push(emailDomain(mailer.config.senderAddress))\n return out\n}\n\nfunction emailDomain(email: string | undefined): string | undefined {\n if (typeof email !== 'string') return undefined\n const at = email.lastIndexOf('@')\n if (at === -1) return undefined\n const domain = email.slice(at + 1).trim().toLowerCase()\n return domain || undefined\n}\n","/**\n * Public router — endpoints that must be reachable by email clients and\n * provider webhooks. Mount under your tracking base path (default `/m`).\n *\n * app.use('/m', createPublicRouter(mailer))\n *\n * Routes:\n * GET /open/:sendId.:sig.png — open pixel (records open, returns 1×1 PNG)\n * GET /click/:sendId/:linkId/:sig — click redirect (records click, 302 → target)\n * GET /unsub/:token — confirmation page (one-click POST link)\n * POST /unsub/:token — RFC 8058 one-click unsubscribe\n * POST /webhooks/:provider — inbound provider event webhook\n * POST /inbound/dmarc — inbound DMARC report (opt-in; see below)\n *\n * Every route here is unauthenticated by necessity — mail clients and provider\n * webhook servers cannot present credentials. The one exception is\n * `/inbound/dmarc`, which is **not mounted at all** unless a shared secret is\n * configured; see `api/dmarc-inbound.ts`.\n *\n * `:sig` is a 12-character truncated HMAC issued by `applyTracking`. It is\n * syntactically optional on both tracking routes so that mail delivered before\n * signing existed keeps working — see `checkTrackingSignature`.\n */\n\nimport express, { Router, type Request, type Response } from 'express'\nimport { ObjectId } from 'mongodb'\n\nimport {\n sha256Hex,\n verifyUnsubscribeToken,\n verifyDoiToken,\n verifyTrackingToken,\n type TrackingScope,\n type TrackingTokenParams,\n} from '../tokens.js'\nimport type { Mailer } from '../mailer.js'\nimport type { SendDoc } from '../models/index.js'\nimport { resolveProvider } from '../provider-lookup.js'\nimport { appendPendingUnsub } from '../unsub-journal.js'\nimport { mountDmarcInbound, type DmarcInboundOptions } from './dmarc-inbound.js'\nimport { consoleRouteLogger, wrap, type RouteLogger } from './wrap.js'\n\nexport interface PublicRouterOptions {\n /**\n * Overrides `MailerConfig.pendingUnsubsPath` for this router only.\n *\n * @deprecated Set `pendingUnsubsPath` in `MailerConfig` instead. The tick\n * drain (`drainPendingUnsubscribes`) reads the *config* value, so a path set\n * only here is written but never replayed — which is precisely the bug\n * INVARIANT 8 was carrying. Setting it here without also setting it in\n * config logs a warning at construction time.\n */\n pendingUnsubsPath?: string\n /**\n * Structured logger for public-route failures, pino-style\n * (`logger.error(fields, message)`).\n *\n * Defaults to a `console`-backed logger that reproduces the output this\n * package emitted before the option existed. Pass `{}` to silence.\n */\n logger?: RouteLogger\n /**\n * Inbound DMARC aggregate-report webhook (SendGrid Inbound Parse and\n * friends). **Off unless `secret` is set** — see `api/dmarc-inbound.ts` for\n * why an endpoint that accepts unsigned file uploads must never appear on an\n * upgrade by itself.\n */\n dmarcInbound?: DmarcInboundOptions\n}\n\n// 1×1 transparent PNG (43 bytes)\nconst PIXEL = Buffer.from(\n 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=',\n 'base64',\n)\n\nexport function createPublicRouter(mailer: Mailer, opts: PublicRouterOptions = {}): Router {\n const router = Router()\n const logger = opts.logger ?? consoleRouteLogger\n\n // INVARIANT 8. No filesystem default: see `MailerConfig.pendingUnsubsPath`\n // for why a library cannot pick one, and what happens when it is unset.\n const pendingUnsubsPath = opts.pendingUnsubsPath ?? mailer.config.pendingUnsubsPath ?? null\n if (opts.pendingUnsubsPath && !mailer.config.pendingUnsubsPath) {\n logger.warn?.(\n { path: opts.pendingUnsubsPath },\n 'mailery: pendingUnsubsPath set on the public router but not in MailerConfig — the tick drain will not replay this journal',\n )\n }\n if (!pendingUnsubsPath) {\n logger.warn?.(\n {},\n 'mailery: no pendingUnsubsPath configured — POST /unsub answers 503 when Mongo is unreachable instead of journaling the opt-out',\n )\n }\n\n // Inbound DMARC reports. Mounted only when a secret is configured; the\n // route's own module explains why that is not negotiable. Registered before\n // the body parsers below so nothing consumes its multipart stream, and\n // `mounted` is logged so an operator can see it exists.\n const dmarcInboundPath = mountDmarcInbound(router, mailer, opts.dmarcInbound, logger)\n if (dmarcInboundPath) {\n logger.info?.(\n { path: dmarcInboundPath },\n 'mailery: DMARC inbound route mounted (shared-secret auth; SendGrid Inbound Parse does not sign payloads)',\n )\n }\n\n // Parse JSON for webhooks — capture raw body for signature verification.\n router.use(\n '/webhooks',\n express.json({\n limit: '5mb',\n verify: (req: any, _res, buf) => {\n req.rawBody = buf\n },\n }),\n )\n\n // Pre-parsed JSON for the POST one-click unsubscribe path (RFC 8058 sends a\n // small form/JSON body; we accept either by reading the URL only).\n router.use('/unsub', express.urlencoded({ extended: false }))\n\n // -------------------------------------------------------------------------\n // GET /open/:sendId.png\n // -------------------------------------------------------------------------\n router.get('/open/:sendId.png', wrap(logger, async (req: Request, res: Response) => {\n // The pixel is returned unconditionally, before anything is validated. A\n // rejected signature must look exactly like an accepted one on the wire:\n // any difference (404, empty body, slower response) is an oracle that tells\n // an attacker when a guessed sendId is real.\n res.setHeader('Content-Type', 'image/png')\n res.setHeader('Content-Length', String(PIXEL.length))\n res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0')\n res.status(200).end(PIXEL)\n\n // Async update — never block the response.\n const parsed = splitOpenParam((req.params as any).sendId as string)\n if (!parsed) return\n const { id, sig } = parsed\n if (!ObjectId.isValid(id)) return\n const sendId = new ObjectId(id)\n\n const verdict = checkTrackingSignature({\n scope: 'open',\n params: { sendId: id },\n sig,\n secret: mailer.config.unsubscribeSecret,\n requireSigned: mailer.config.requireSignedTrackingUrls,\n logger,\n fields: { sendId: id },\n })\n if (verdict === 'rejected') return\n\n try {\n const send = await mailer.collections.sends.findOne(\n { _id: sendId },\n { projection: { openedAt: 1, queuedAt: 1 } },\n )\n if (!send) return\n if (isTrackingExpired(send, mailer.config.trackingUrlLifetimeDays)) {\n logger.warn?.({ sendId: id }, 'mailery: open ignored — tracking URL past trackingUrlLifetimeDays')\n return\n }\n const now = new Date()\n await mailer.collections.sends.updateOne(\n { _id: sendId },\n {\n $set: {\n openedAt: send.openedAt ?? now,\n status: 'delivered' as const,\n },\n $inc: { openCount: 1 },\n // Per-open user agent, so `hasOpenedExcludingBots` has a signal to\n // filter on. Capped: an open pixel can be re-fetched indefinitely\n // (every time the recipient re-opens the mail) and an unbounded\n // array would eventually run the send document into the 16MB limit.\n $push: {\n opens: {\n $each: [{ openedAt: now, userAgent: requestUserAgent(req) }],\n $slice: -MAX_TRACKED_OPENS,\n },\n },\n },\n )\n } catch (err) {\n logger.error?.({ err, sendId: id }, 'mailery: open pixel update failed')\n }\n }))\n\n // -------------------------------------------------------------------------\n // GET /click/:sendId/:linkId\n // -------------------------------------------------------------------------\n router.get('/click/:sendId/:linkId{/:sig}', wrap(logger, async (req: Request, res: Response) => {\n const { sendId: sendIdStr, linkId, sig } = req.params as {\n sendId: string\n linkId: string\n sig?: string\n }\n if (!ObjectId.isValid(sendIdStr)) return res.status(400).end()\n const sendId = new ObjectId(sendIdStr)\n\n // A bad signature is answered with the same 404 an unknown send gets. Any\n // distinct status would confirm \"this sendId exists, keep guessing\".\n const verdict = checkTrackingSignature({\n scope: 'click',\n params: { sendId: sendIdStr, linkId },\n sig,\n secret: mailer.config.unsubscribeSecret,\n requireSigned: mailer.config.requireSignedTrackingUrls,\n logger,\n fields: { sendId: sendIdStr, linkId },\n })\n if (verdict === 'rejected') return res.status(404).end()\n\n const send = await mailer.collections.sends.findOne(\n { _id: sendId },\n { projection: { links: 1, firstClickAt: 1, queuedAt: 1 } },\n )\n if (!send) return res.status(404).end()\n\n if (isTrackingExpired(send, mailer.config.trackingUrlLifetimeDays)) {\n logger.warn?.(\n { sendId: sendIdStr, linkId },\n 'mailery: click rejected — tracking URL past trackingUrlLifetimeDays',\n )\n return res.status(404).end()\n }\n\n const link = (send.links ?? []).find((l) => l.linkId === linkId)\n if (!link) return res.status(404).end()\n\n // Never redirect to a scheme we didn't sanction. The rejected URL is logged\n // but deliberately kept out of the response body — echoing it back would\n // reflect attacker-controlled content from the sending domain's origin.\n if (!isSafeRedirectTarget(link.url)) {\n logger.warn?.(\n { sendId: sendIdStr, linkId, url: link.url },\n 'mailery: click redirect blocked — disallowed URL scheme',\n )\n return res\n .status(400)\n .type('html')\n .send('<!doctype html><html><body><p>This link cannot be opened.</p></body></html>')\n }\n\n res.redirect(302, link.url)\n\n try {\n await mailer.collections.sends.updateOne(\n { _id: sendId },\n {\n $set: { firstClickAt: send.firstClickAt ?? new Date() },\n $inc: { clickCount: 1 },\n $push: {\n clickedLinks: {\n url: link.url,\n linkId,\n clickedAt: new Date(),\n // The bot filter has always read `clickedLinks[].userAgent`; until\n // now nothing ever wrote it, so every click scored as human.\n userAgent: requestUserAgent(req),\n },\n },\n },\n )\n } catch (err) {\n logger.error?.({ err, sendId: sendIdStr, linkId }, 'mailery: click recording failed')\n }\n }))\n\n // -------------------------------------------------------------------------\n // GET + POST /unsub/:token\n // -------------------------------------------------------------------------\n router.get('/unsub/:token', wrap(logger, (req: Request, res: Response) => {\n const decoded = verifyUnsubscribeToken((req.params as any).token, mailer.config.unsubscribeSecret)\n if (!decoded) return sendUnsubError(res, 'Invalid or expired link.')\n\n res.status(200).type('html').send(`<!doctype html>\n<html><head>\n <meta charset=\"utf-8\" />\n <title>Unsubscribe</title>\n <style>body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;max-width:480px;margin:48px auto;padding:0 16px;color:#1c1917;line-height:1.5}h1{font-size:20px}button{padding:10px 18px;background:#dc2626;color:#fff;border:0;border-radius:6px;font-size:14px;cursor:pointer}</style>\n</head><body>\n <h1>Confirm unsubscribe</h1>\n <p>Click the button below to unsubscribe <strong>${escapeHtml(decoded.email)}</strong>${decoded.scope === 'all' ? ' from everything' : ' from marketing emails'}.</p>\n <form method=\"POST\" action=\"${escapeHtml(req.originalUrl)}\">\n <button type=\"submit\">Unsubscribe</button>\n </form>\n</body></html>`)\n }))\n\n /**\n * RFC 8058 one-click unsubscribe.\n *\n * This is the one public route that does *not* answer before doing its work,\n * and INVARIANT 8 is why. \"Return 200 quickly\" and \"never silently drop an\n * opt-out\" are both in that invariant, and answering first can only satisfy\n * the former: the response is already on the wire by the time we learn the\n * write failed, so the recipient is told they are unsubscribed and then\n * keeps receiving mail. Through v0.14 that is exactly what happened, and the\n * 503 the invariant describes was unreachable.\n *\n * So: durability first, within a budget.\n *\n * Mongo write succeeds (typically sub-millisecond) → 200\n * Mongo fails or exceeds `unsubscribeWriteTimeoutMs` → journal → 200\n * no journal configured, or the journal write fails → 503\n *\n * A 503 is not a worse outcome than the old unconditional 200 — it is the\n * same failure, told honestly. The caller (a mail client's one-click\n * infrastructure, or a human on the confirmation page) can retry, and\n * nothing has claimed an unsubscribe that does not exist.\n */\n router.post('/unsub/:token', wrap(logger, async (req: Request, res: Response) => {\n const decoded = verifyUnsubscribeToken((req.params as any).token, mailer.config.unsubscribeSecret)\n if (!decoded) {\n res.status(200).end() // never 5xx; let provider stop retrying\n return\n }\n\n const write = mailer.unsubscribe(decoded.email, {\n scope: decoded.scope,\n reason: 'user_request',\n source: 'one-click',\n })\n\n let dbError: unknown = null\n try {\n await withTimeout(write, mailer.config.unsubscribeWriteTimeoutMs)\n } catch (err) {\n dbError = err ?? new Error('unsubscribe write failed')\n // The write may still land after the timeout. Nothing here depends on\n // whether it does — the journal replay is idempotent — but an unobserved\n // rejection would take the host process down.\n void write.catch(() => {})\n }\n\n if (dbError) {\n if (!pendingUnsubsPath) {\n logger.error?.(\n { err: dbError },\n 'mailery: unsubscribe write failed and no pendingUnsubsPath is configured — answering 503',\n )\n return sendUnsubUnavailable(res)\n }\n try {\n appendPendingUnsub(pendingUnsubsPath, {\n email: decoded.email,\n scope: decoded.scope,\n at: Date.now(),\n })\n logger.warn?.(\n { err: dbError, path: pendingUnsubsPath },\n 'mailery: unsubscribe journaled to disk — will be replayed by the tick drain',\n )\n } catch (diskErr) {\n logger.error?.(\n { err: dbError, diskErr, path: pendingUnsubsPath },\n 'mailery: unsub disk fallback failed — answering 503',\n )\n return sendUnsubUnavailable(res)\n }\n }\n\n res.status(200).type('html').send('<!doctype html><html><body><p>You are unsubscribed.</p></body></html>')\n }))\n\n // -------------------------------------------------------------------------\n // GET /confirm-doi/:token\n // -------------------------------------------------------------------------\n router.get('/confirm-doi/:token', wrap(logger, async (req: Request, res: Response) => {\n const token = (req.params as any).token as string\n const decoded = verifyDoiToken(token, mailer.config.unsubscribeSecret)\n if (!decoded) {\n return res.status(400).type('html').send('<!doctype html><html><body><p>Confirmation link is invalid or expired.</p></body></html>')\n }\n const now = new Date()\n const result = await mailer.collections.subscriptions.updateOne(\n { externalId: decoded.externalId, status: 'pending_doi' },\n {\n $set: {\n status: 'subscribed',\n subscribedAt: now,\n doiConfirmedAt: now,\n doiIp: req.ip ?? null,\n doiUserAgent: (req.headers['user-agent'] as string | undefined) ?? null,\n updatedAt: now,\n },\n },\n )\n if (result.matchedCount === 0) {\n return res.status(200).type('html').send('<!doctype html><html><body><p>Already confirmed. Thanks.</p></body></html>')\n }\n try {\n await mailer.fire('subscription.confirmed', decoded.externalId, {}, `doi-confirmed:${decoded.externalId}`)\n } catch {\n /* swallow — subscription is confirmed regardless */\n }\n return res.status(200).type('html').send('<!doctype html><html><body><p>Thanks — you\\'re subscribed.</p></body></html>')\n }))\n\n // -------------------------------------------------------------------------\n // POST /webhooks/:provider\n // -------------------------------------------------------------------------\n router.post('/webhooks/:provider', wrap(logger, async (req: Request, res: Response) => {\n const providerName = (req.params as any).provider as string\n const provider = resolveProvider(mailer.providers, providerName)\n if (!provider) return res.status(404).end()\n\n const rawBody = (req as any).rawBody as Buffer | undefined\n if (!rawBody) return res.status(400).end()\n\n const headers = lowercaseHeaders(req.headers)\n const valid = await provider.verifyWebhook(rawBody, headers)\n if (!valid) return res.status(401).end()\n\n const events = provider.parseWebhookEvents(req.body, headers)\n\n // Always 200 fast — fail-open, retry inbound is wasted bandwidth.\n res.status(200).end()\n\n // Preserve the original provider payload alongside each normalized event so the\n // audit trail isn't reduced to just our extracted fields. The raw body is the\n // full provider response array; we record it once per parsed event for clarity.\n const rawBodyRef = req.body as unknown\n for (const evt of events) {\n try {\n await mailer.collections.webhookEvents.updateOne(\n { provider: providerName, providerEventId: evt.providerEventId },\n {\n $setOnInsert: {\n provider: providerName,\n providerEventId: evt.providerEventId,\n eventType: evt.type,\n normalizedType: evt.type,\n providerMessageId: evt.providerMessageId,\n email: evt.email,\n occurredAt: evt.occurredAt,\n receivedAt: new Date(),\n processed: false,\n raw: { normalized: evt, providerBody: rawBodyRef },\n },\n },\n { upsert: true },\n )\n } catch (err) {\n logger.error?.(\n { err, provider: providerName, providerEventId: evt.providerEventId },\n 'mailery: webhook dedupe insert failed',\n )\n }\n }\n\n if (events.length > 0) {\n try {\n await mailer.queues.webhook.add('webhook', { provider: providerName })\n } catch {\n /* will be picked up by next tick */\n }\n }\n }))\n\n return router\n}\n\n// ---------------------------------------------------------------------------\n// Tracking-URL verification\n// ---------------------------------------------------------------------------\n\n/** Most recent opens kept per send. See `SendDoc.opens`. */\nconst MAX_TRACKED_OPENS = 50\n\n/** User agents are stored for bot classification only; the tail carries nothing. */\nconst MAX_UA_LENGTH = 256\n\nfunction requestUserAgent(req: Request): string | null {\n const ua = req.headers['user-agent']\n if (typeof ua !== 'string' || ua.trim() === '') return null\n return ua.slice(0, MAX_UA_LENGTH)\n}\n\n/**\n * Split the `:sendId.png` path parameter into id and optional signature.\n *\n * Express hands us everything before the literal `.png`, so a signed pixel\n * arrives as `<objectId>.<sig>` and a legacy one as `<objectId>`. Anything with\n * more dots than that was not produced by `applyTracking` and is dropped\n * outright rather than guessed at.\n */\nfunction splitOpenParam(raw: unknown): { id: string; sig?: string } | null {\n if (typeof raw !== 'string') return null\n const parts = raw.split('.')\n if (parts.length === 1) return { id: parts[0]! }\n if (parts.length === 2) return { id: parts[0]!, sig: parts[1]! }\n return null\n}\n\ntype TrackingVerdict = 'signed' | 'legacy' | 'rejected'\n\n/**\n * Decide whether a tracking hit may be counted.\n *\n * Three cases, and the middle one is the whole backward-compatibility story:\n *\n * signature present + valid → 'signed'\n * signature present + wrong → 'rejected', always, in every mode\n * signature absent → 'rejected' if `requireSignedTrackingUrls`,\n * otherwise 'legacy' — counted, and logged\n *\n * Grace mode exists because mail already in inboxes carries unsigned URLs and\n * will keep being opened for years; hard-rejecting it would silently zero the\n * tracking for every send that predates this change. The per-hit warn is the\n * operator's instrument: watch the legacy rate decay, then set\n * `requireSignedTrackingUrls: true`.\n *\n * A wrong signature is never graced. Grace covers \"this URL predates signing\",\n * not \"this URL was signed by someone who does not have the key\".\n */\nfunction checkTrackingSignature(args: {\n scope: TrackingScope\n params: TrackingTokenParams\n sig: string | undefined\n secret: string\n requireSigned: boolean\n logger: RouteLogger\n fields: Record<string, unknown>\n}): TrackingVerdict {\n const { sig, logger, fields, scope } = args\n\n if (sig === undefined || sig === '') {\n if (args.requireSigned) {\n logger.warn?.(\n { ...fields, scope },\n 'mailery: unsigned tracking URL rejected (requireSignedTrackingUrls)',\n )\n return 'rejected'\n }\n // `info`, not `warn`: in grace mode this fires once per legacy open, which\n // is telemetry rather than a fault. It is the operator's readout for\n // \"has legacy traffic stopped yet?\" — when this line goes quiet, flipping\n // `requireSignedTrackingUrls` to true is safe.\n logger.info?.(\n { ...fields, scope },\n 'mailery: unsigned tracking URL accepted — legacy grace mode',\n )\n return 'legacy'\n }\n\n if (!verifyTrackingToken(sig, scope, args.params, args.secret)) {\n logger.warn?.({ ...fields, scope }, 'mailery: tracking URL signature invalid')\n return 'rejected'\n }\n return 'signed'\n}\n\n/**\n * True when the send is older than `trackingUrlLifetimeDays`.\n *\n * The deadline is derived from the send row rather than embedded in the token:\n * it costs no URL bytes, and changing the config takes effect immediately for\n * mail that has already gone out. A send with no usable `queuedAt` is never\n * treated as expired — losing a real open to a missing timestamp is worse than\n * counting a stale one.\n */\nfunction isTrackingExpired(send: Pick<SendDoc, 'queuedAt'>, lifetimeDays: number, now: Date = new Date()): boolean {\n if (!lifetimeDays || lifetimeDays <= 0) return false\n const queuedAt = send.queuedAt\n if (!(queuedAt instanceof Date) || Number.isNaN(queuedAt.getTime())) return false\n return now.getTime() - queuedAt.getTime() > lifetimeDays * 24 * 60 * 60 * 1000\n}\n\nfunction sendUnsubError(res: Response, msg: string): Response {\n return res.status(400).type('html').send(`<!doctype html><html><body><p>${escapeHtml(msg)}</p></body></html>`)\n}\n\n/**\n * The 503 INVARIANT 8 describes: neither Mongo nor the journal could record\n * the opt-out. `Retry-After` is set because the honest answer to a one-click\n * client is \"come back\", not \"done\".\n */\nfunction sendUnsubUnavailable(res: Response): Response {\n return res\n .status(503)\n .set('Retry-After', '60')\n .type('html')\n .send(\n '<!doctype html><html><body><p>We could not record your unsubscribe right now, ' +\n 'so you are <strong>not</strong> unsubscribed yet. Please try again in a minute.</p></body></html>',\n )\n}\n\n/**\n * Resolve `p`, or reject once `ms` has elapsed.\n *\n * A rejected `p` still settles the race normally; the timer exists for the\n * case that matters here, a Mongo client that is neither resolving nor\n * rejecting because the server it is waiting on is gone. `unref()` keeps a\n * pending timer from holding the process open.\n */\nfunction withTimeout<T>(p: Promise<T>, ms: number): Promise<T> {\n if (!Number.isFinite(ms) || ms <= 0) return p\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => {\n reject(new Error(`timed out after ${ms}ms`))\n }, ms)\n if (typeof timer.unref === 'function') timer.unref()\n p.then(\n (v) => {\n clearTimeout(timer)\n resolve(v)\n },\n (err) => {\n clearTimeout(timer)\n reject(err)\n },\n )\n })\n}\n\nfunction escapeHtml(s: string): string {\n return s\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#39;')\n}\n\n/** Schemes we are willing to bounce a click through. */\nconst ALLOWED_REDIRECT_PROTOCOLS = new Set(['http:', 'https:'])\n\n/**\n * Guard for the click-tracking redirect target.\n *\n * Stored link URLs come out of `applyTracking`, which harvests `href` values\n * from *rendered* HTML — i.e. after Handlebars substitution — so a template\n * that interpolates a variable into an href position can put an arbitrary\n * scheme into the stored URL. Redirecting to it would launch `javascript:` or\n * `data:` from the sending domain's own origin, with the sender's reputation\n * behind it.\n *\n * Parsed with `new URL()` rather than string matching: the URL parser strips\n * tab/newline and lowercases the scheme, so `java\\tscript:` and `JavaScript:`\n * normalize to the same rejected protocol. A protocol-relative `//evil.com`\n * has no scheme and no base here, so parsing throws and it is rejected too.\n */\nfunction isSafeRedirectTarget(raw: unknown): raw is string {\n if (typeof raw !== 'string') return false\n const trimmed = raw.trim()\n if (trimmed === '') return false\n let parsed: URL\n try {\n parsed = new URL(trimmed)\n } catch {\n return false\n }\n return ALLOWED_REDIRECT_PROTOCOLS.has(parsed.protocol)\n}\n\nfunction lowercaseHeaders(h: any): Record<string, string> {\n const out: Record<string, string> = {}\n for (const k of Object.keys(h)) {\n const v = h[k]\n out[k.toLowerCase()] = Array.isArray(v) ? v.join(',') : String(v ?? '')\n }\n return out\n}\n\n// silence unused\nvoid sha256Hex\n","/**\n * Enumerable option lists for the union types in `./types.ts`. Used by the\n * admin client to render dropdowns + by tooling to enumerate the surface.\n *\n * Kept in `shared/` so the client and server agree on the canonical labels +\n * default constructors. Pure data + pure functions — no React, no DOM.\n */\n\nimport type { FlowStep, Predicate, SegmentFilter } from './types.js'\n\n// ---------------------------------------------------------------------------\n// Flow step types\n// ---------------------------------------------------------------------------\n\nexport interface FlowStepKindOption {\n value: FlowStep['type']\n label: string\n /** Icon name from the client's icon set (lookup at render time). */\n icon: string\n /** Visual class on the canvas chip. */\n iconClass: string\n /** One-line description for tooltips / docs generation. */\n description: string\n}\n\nexport const FLOW_STEP_KINDS: readonly FlowStepKindOption[] = [\n { value: 'wait', label: 'Wait', icon: 'Clock', iconClass: 'wait', description: 'Pause the run for a duration before continuing.' },\n { value: 'condition', label: 'Condition', icon: 'Branch', iconClass: 'condition', description: 'Evaluate a predicate. Exit or skip on false.' },\n { value: 'branch', label: 'Branch', icon: 'Branch', iconClass: 'condition', description: 'Evaluate a predicate. Recurse into one of two sub-lists.' },\n { value: 'send', label: 'Send', icon: 'Mail', iconClass: 'send', description: 'Send a template to the contact.' },\n { value: 'tag', label: 'Tag', icon: 'Tag', iconClass: 'tag', description: 'Add or remove tags on the contact.' },\n { value: 'fire_event', label: 'Fire event', icon: 'Activity', iconClass: 'send', description: 'Insert a synthetic event (cross-flow handoff).' },\n { value: 'webhook', label: 'Webhook', icon: 'Webhook', iconClass: 'tag', description: 'POST to an external URL.' },\n { value: 'exit', label: 'Exit', icon: 'Exit', iconClass: 'exit', description: 'End the run with an optional reason.' },\n] as const\n\nexport function defaultFlowStep(type: FlowStep['type']): FlowStep {\n switch (type) {\n case 'wait': return { type: 'wait', value: 1, unit: 'days' }\n case 'condition': return { type: 'condition', test: { hasTag: 'engaged' }, ifFalse: 'exit' }\n case 'branch': return { type: 'branch', test: { hasTag: 'vip' }, ifTrueSteps: [], ifFalseSteps: [] }\n case 'send': return { type: 'send', templateSlug: '' }\n case 'tag': return { type: 'tag', addTags: [], removeTags: [] }\n case 'fire_event': return { type: 'fire_event', eventName: '' }\n case 'webhook': return { type: 'webhook', url: '', method: 'POST' }\n case 'exit': return { type: 'exit' }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Predicate kinds (the union variants of Predicate, minus composites)\n// ---------------------------------------------------------------------------\n\nexport type PredicateKind =\n | 'hasTag'\n | 'notHasTag'\n | 'fieldEquals'\n | 'fieldExists'\n | 'triggerPropertyEquals'\n | 'triggerPropertyTruthy'\n | 'hasFiredEvent'\n | 'notHasFiredEvent'\n | 'subscriptionStatus'\n | 'hasOpened'\n | 'hasClicked'\n | 'hasOpenedExcludingBots'\n | 'hasClickedExcludingBots'\n | 'openedAtLeastN'\n | 'clickedAtLeastN'\n\nexport interface PredicateKindOption {\n value: PredicateKind\n label: string\n /** True when this predicate's signal is noisy (Apple MPP, bot prefetch). */\n noisy?: boolean\n}\n\nexport const PREDICATE_KINDS: readonly PredicateKindOption[] = [\n { value: 'hasTag', label: 'has tag' },\n { value: 'notHasTag', label: 'does NOT have tag' },\n { value: 'fieldEquals', label: 'field equals' },\n { value: 'fieldExists', label: 'field exists' },\n { value: 'triggerPropertyEquals', label: 'trigger property equals' },\n { value: 'triggerPropertyTruthy', label: 'trigger property is set' },\n { value: 'hasFiredEvent', label: 'fired event' },\n { value: 'notHasFiredEvent', label: 'has NOT fired event' },\n { value: 'subscriptionStatus', label: 'subscription status' },\n { value: 'hasOpened', label: 'opened', noisy: true },\n { value: 'hasClicked', label: 'clicked', noisy: true },\n { value: 'hasOpenedExcludingBots', label: 'opened (excl. bots)' },\n { value: 'hasClickedExcludingBots', label: 'clicked (excl. bots)' },\n { value: 'openedAtLeastN', label: 'opened at least N' },\n { value: 'clickedAtLeastN', label: 'clicked at least N' },\n] as const\n\n/** Identify which kind of predicate this object is (or null for composites/unknown). */\nexport function predicateKind(p: Predicate | null | undefined): PredicateKind | null {\n if (!p) return null\n for (const k of PREDICATE_KINDS) {\n if (k.value in (p as object)) return k.value\n }\n return null\n}\n\nexport function defaultPredicate(kind: PredicateKind): Predicate {\n switch (kind) {\n case 'hasTag': return { hasTag: 'engaged' }\n case 'notHasTag': return { notHasTag: 'cold' }\n case 'fieldEquals': return { fieldEquals: { field: 'tier', value: 'Pro' } }\n case 'fieldExists': return { fieldExists: 'tier' }\n case 'triggerPropertyEquals': return { triggerPropertyEquals: { key: 'plan', value: 'pro' } }\n case 'triggerPropertyTruthy': return { triggerPropertyTruthy: 'wasReferred' }\n case 'hasFiredEvent': return { hasFiredEvent: 'Activated app' }\n case 'notHasFiredEvent': return { notHasFiredEvent: 'Cancelled' }\n case 'subscriptionStatus': return { subscriptionStatus: 'subscribed' }\n case 'hasOpened': return { hasOpened: { sinceFlowStart: true } }\n case 'hasClicked': return { hasClicked: { sinceFlowStart: true } }\n case 'hasOpenedExcludingBots': return { hasOpenedExcludingBots: { sinceFlowStart: true } }\n case 'hasClickedExcludingBots': return { hasClickedExcludingBots: { sinceFlowStart: true } }\n case 'openedAtLeastN': return { openedAtLeastN: { count: 1, withinDays: 7 } }\n case 'clickedAtLeastN': return { clickedAtLeastN: { count: 1, withinDays: 7 } }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Segment filter kinds\n// ---------------------------------------------------------------------------\n\nexport type SegmentFilterKind = SegmentFilter['kind']\n\nexport interface SegmentFilterKindOption {\n value: SegmentFilterKind\n label: string\n /** Where the filter is evaluated: host-side via adapter, or mailer-side post-filter. */\n side: 'host' | 'mailer' | 'composite'\n}\n\nexport const SEGMENT_FILTER_KINDS: readonly SegmentFilterKindOption[] = [\n { value: 'subscriptionStatus', label: 'Subscription status', side: 'mailer' },\n { value: 'hasTag', label: 'Has tag', side: 'host' },\n { value: 'notHasTag', label: 'Does NOT have tag', side: 'host' },\n { value: 'fieldEquals', label: 'Field equals', side: 'host' },\n { value: 'fieldIn', label: 'Field in list', side: 'host' },\n { value: 'fieldExists', label: 'Field exists', side: 'host' },\n { value: 'firedEvent', label: 'Fired event', side: 'mailer' },\n { value: 'notFiredEvent', label: 'Has NOT fired event', side: 'mailer' },\n { value: 'subscribedAfter', label: 'Subscribed after', side: 'mailer' },\n { value: 'subscribedBefore', label: 'Subscribed before', side: 'mailer' },\n { value: 'opened', label: 'Opened', side: 'mailer' },\n { value: 'notOpened', label: 'Did NOT open', side: 'mailer' },\n { value: 'any', label: 'Any of (OR)', side: 'composite' },\n { value: 'not', label: 'NOT', side: 'composite' },\n] as const\n\nexport function defaultSegmentFilter(kind: SegmentFilterKind): SegmentFilter {\n switch (kind) {\n case 'subscriptionStatus': return { kind: 'subscriptionStatus', equals: 'subscribed' }\n case 'hasTag': return { kind: 'hasTag', tag: '' }\n case 'notHasTag': return { kind: 'notHasTag', tag: '' }\n case 'fieldEquals': return { kind: 'fieldEquals', field: '', value: '' }\n case 'fieldIn': return { kind: 'fieldIn', field: '', values: [] }\n case 'fieldExists': return { kind: 'fieldExists', field: '' }\n case 'firedEvent': return { kind: 'firedEvent', eventName: '', withinDays: 30 }\n case 'notFiredEvent': return { kind: 'notFiredEvent', eventName: '', withinDays: 90 }\n case 'subscribedAfter': return { kind: 'subscribedAfter', date: new Date(Date.now() - 30 * 86_400_000) }\n case 'subscribedBefore': return { kind: 'subscribedBefore', date: new Date() }\n case 'opened': return { kind: 'opened', withinDays: 14 }\n case 'notOpened': return { kind: 'notOpened', withinDays: 14 }\n case 'any': return { kind: 'any', filters: [] }\n case 'not': return { kind: 'not', filter: { kind: 'hasTag', tag: '' } }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Dedupe policies for event registration\n// ---------------------------------------------------------------------------\n\nexport interface DedupePolicyOption {\n value: 'once-per-contact' | 'once-per-day' | 'every-time'\n label: string\n description: string\n derivedKeyShape: string\n}\n\nexport const DEDUPE_POLICIES: readonly DedupePolicyOption[] = [\n {\n value: 'once-per-contact',\n label: 'Once per contact',\n description: 'Lifecycle markers (Created, Activated)',\n derivedKeyShape: '${externalId}:${eventName}',\n },\n {\n value: 'once-per-day',\n label: 'Once per day',\n description: 'Daily behaviors (Viewed Storyboard)',\n derivedKeyShape: '${externalId}:${eventName}:${YYYY-MM-DD}',\n },\n {\n value: 'every-time',\n label: 'Every time',\n description: 'True every-occurrence events (Imported)',\n derivedKeyShape: '${externalId}:${eventName}:${UUIDv4}',\n },\n] as const\n"]}
1
+ {"version":3,"sources":["../src/server/adapters/vars.ts","../src/server/adapters/mongo.ts","../src/server/providers/webhook-tolerance.ts","../src/server/providers/sendgrid.ts","../src/shared/schemas.ts","../src/server/config.ts","../src/server/models/index.ts","../src/server/events.ts","../src/server/provider-lookup.ts","../src/server/tokens.ts","../src/server/unsubscribe.ts","../src/server/queues/bull.ts","../src/server/queues/agenda.ts","../src/server/queues/noop.ts","../src/server/queues/index.ts","../src/server/runner/triggers.ts","../src/server/templates/sender-domain.ts","../src/server/runner/health.ts","../src/server/runner/webhook.ts","../src/server/runner/predicate.ts","../src/server/runner/delivery-window.ts","../src/server/templates/render.ts","../src/server/runner/send.ts","../src/server/runner/suppression.ts","../src/server/runner/step.ts","../src/server/runner/sweep.ts","../src/server/runner/broadcasts.ts","../src/server/runner/bounce-promotion.ts","../src/server/runner/dnsbl.ts","../src/server/runner/postmaster.ts","../src/server/runner/snds.ts","../src/server/runner/dmarc.ts","../src/server/unsub-journal.ts","../src/server/runner/pending-unsubs.ts","../src/server/runner/tick.ts","../src/server/mailer.ts","../src/server/index.ts","../src/server/providers/null.ts","../src/server/templates/linter.ts","../src/server/api/admin.ts","../src/shared/enums.ts","../src/server/api/setup-status.ts","../src/server/runner/hygiene.ts","../src/server/runner/mail-tester.ts","../src/server/api/wrap.ts","../src/server/api/agent.ts","../src/server/runner/arm.ts","../src/server/runner/simulate.ts","../src/server/api/dmarc-inbound.ts","../src/server/api/public.ts","../src/shared/options.ts"],"names":["RESERVED_VAR_KEYS","z","MongoContactAdapter","ObjectId","SendGridProvider","sgMail","crypto","IORedis","QUEUE_NAMES","counter","mjml2html","htmlToText","Handlebars","branchKey","DAY_MS","dns","net","psl","path","FETCH_TIMEOUT_MS","safeText","dst","XMLParser","fs","randomBytes","processScheduledBroadcasts","assertNoReservedVarKeys","ObjectIdCtor","cursor","__filename","fileURLToPath","__dirname","Router","express","r","report","multer","unitToMs","wrap","sleep","rendered","links","createHash","timingSafeEqual","VERSION"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * VarsAdapter — host-provided template variables, resolved at render time.\n *\n * The host declares a zod schema (the contract templates can rely on) plus a\n * `resolve` function that loads those values from the host's own database for\n * a given contact. Resolved keys are merged into the render context root, so\n * a schema key `user` is referenced in templates as `{{user.name}}`.\n *\n * The schema does double duty: it is exposed to the admin SPA as JSON Schema\n * (GET /vars-schema) to drive editor autocomplete, and the content linter\n * uses it to flag `{{paths}}` that don't exist.\n */\n\nimport { z } from 'zod'\n\nimport type { Contact } from '../../shared/types.js'\n\nexport interface VarsResolveInfo {\n /** Why the vars are being resolved. Previews and tests should be side-effect free. */\n reason: 'send' | 'preview' | 'test'\n /** Slug of the template being rendered, when known. */\n templateSlug?: string\n /** Slug of the flow the send belongs to, when the render is part of a flow run. */\n flowSlug?: string\n /** Name of the event that triggered the flow run, when applicable. */\n eventName?: string\n /**\n * Properties of the triggering event (`mailer.fire(name, id, properties)`).\n * This is how a resolver scopes lookups for account/topic flows:\n * `info.eventProperties?.accountId` tells it WHICH account the run is about.\n * Also available raw in templates as `{{event.*}}`.\n */\n eventProperties?: Record<string, unknown>\n}\n\nexport interface VarsAdapter<S extends z.ZodType = z.ZodType> {\n /** Contract for what `resolve` returns. Root keys become root template variables. */\n schema: S\n /** Load the variables for one contact from the host's data. */\n resolve(contact: Contact, info: VarsResolveInfo): Promise<z.infer<S>> | z.infer<S>\n}\n\n/**\n * Identity helper that pins `resolve`'s return type to `z.infer<schema>` —\n * without it, TypeScript widens the schema generic and the return type is\n * unchecked.\n *\n * const varsAdapter = defineVars({\n * schema: z.object({ user: z.object({ name: z.string() }) }),\n * async resolve(contact) {\n * return { user: { name: await lookupName(contact.externalId) } }\n * },\n * })\n */\nexport function defineVars<S extends z.ZodType>(adapter: VarsAdapter<S>): VarsAdapter<S> {\n return adapter\n}\n\n/**\n * Render-context keys mailery owns. Resolved vars never override these — a\n * schema that declares one is rejected at Mailer.init.\n */\nexport const RESERVED_VAR_KEYS = [\n 'contact',\n 'vars',\n 'event',\n 'unsubscribeUrl',\n 'viewInBrowserUrl',\n 'preferenceCenterUrl',\n 'senderAddress',\n] as const\n\n/**\n * Throw if the schema's root keys collide with reserved render-context keys.\n * Called once at Mailer.init — fail fast, not per send.\n */\nexport function assertNoReservedVarKeys(adapter: VarsAdapter): void {\n const json = varsJsonSchema(adapter)\n const props = json && typeof json === 'object' ? (json as any).properties : undefined\n if (!props) return\n const clashes = RESERVED_VAR_KEYS.filter((k) => k in props)\n if (clashes.length > 0) {\n throw new Error(\n `varsAdapter schema declares reserved key(s): ${clashes.join(', ')}. ` +\n `These names are provided by mailery itself — rename them in your schema.`,\n )\n }\n}\n\n/** JSON Schema for the adapter's zod schema (wire format for the admin SPA + linter). */\nexport function varsJsonSchema(adapter: VarsAdapter): Record<string, unknown> {\n return z.toJSONSchema(adapter.schema, { io: 'output' }) as Record<string, unknown>\n}\n\n/**\n * Resolve vars for a contact, or `{}` when no adapter is configured.\n * Errors propagate to the caller — send paths let the queue retry, preview\n * paths surface the message to the operator.\n */\nexport async function resolveVars(\n adapter: VarsAdapter | undefined,\n contact: Contact,\n info: VarsResolveInfo,\n): Promise<Record<string, unknown>> {\n if (!adapter) return {}\n const resolved = await adapter.resolve(contact, info)\n if (!resolved || typeof resolved !== 'object') return {}\n // Belt-and-braces: drop reserved keys even if the init-time assert was\n // bypassed (e.g. a hand-built adapter object with a lying schema).\n const out: Record<string, unknown> = { ...(resolved as Record<string, unknown>) }\n for (const k of RESERVED_VAR_KEYS) delete out[k]\n return out\n}\n","/**\n * MongoContactAdapter — reads contacts directly from the host's `users`\n * collection (read-mostly; optional narrow tag writes). Mailer never\n * duplicates identity data — the host is the source of truth.\n */\n\nimport type { Collection, Db, Filter } from 'mongodb'\nimport { ObjectId } from 'mongodb'\n\nimport type {\n AdapterFilter,\n Contact,\n ContactAdapter,\n} from '../../shared/types.js'\n\nexport interface MongoContactAdapterOptions {\n db: Db\n collection: string\n emailField?: string\n idField?: string\n /** Path to the tags array on the user document. */\n tagsField?: string\n /** When true, mailer writes tags via `$addToSet` / `$pull` on the user doc. */\n tagsWritable?: boolean\n /** 'strings' = ['vip','beta'], 'objects' = [{ name: 'vip' }]. */\n tagsArrayShape?: 'strings' | 'objects'\n /** Customize the projection mailer sees. Defaults pick up email + tags + a few common fields. */\n toContact?: (userDoc: any) => Contact\n /** Customize how AdapterFilter becomes a Mongo query. */\n translateFilter?: (filter: AdapterFilter) => Filter<any>\n /** Per-call default for query() limit. */\n batchSize?: number\n}\n\nexport class MongoContactAdapter implements ContactAdapter {\n private readonly col: Collection<any>\n private readonly emailField: string\n private readonly idField: string\n private readonly tagsField: string | null\n private readonly tagsWritable: boolean\n private readonly tagsArrayShape: 'strings' | 'objects'\n private readonly toContactFn: (doc: any) => Contact\n private readonly translateFilterFn: (filter: AdapterFilter) => Filter<any>\n private readonly batchSize: number\n\n constructor(opts: MongoContactAdapterOptions) {\n this.col = opts.db.collection(opts.collection)\n this.emailField = opts.emailField ?? 'email'\n this.idField = opts.idField ?? '_id'\n this.tagsField = opts.tagsField ?? null\n this.tagsWritable = !!opts.tagsWritable\n this.tagsArrayShape = opts.tagsArrayShape ?? 'strings'\n this.toContactFn = opts.toContact ?? this.defaultToContact.bind(this)\n this.translateFilterFn = opts.translateFilter ?? this.defaultTranslateFilter.bind(this)\n this.batchSize = opts.batchSize ?? 500\n\n // Only expose tag write methods if the host opted in.\n if (this.tagsWritable && this.tagsField) {\n this.addTags = this.addTagsImpl.bind(this)\n this.removeTags = this.removeTagsImpl.bind(this)\n }\n }\n\n async getById(externalId: string): Promise<Contact | null> {\n const filter = this.idFilter(externalId)\n const doc = await this.col.findOne(filter)\n return doc ? this.toContactFn(doc) : null\n }\n\n async getByEmail(email: string): Promise<Contact | null> {\n const doc = await this.col.findOne({ [this.emailField]: email.toLowerCase() })\n return doc ? this.toContactFn(doc) : null\n }\n\n async getBatch(externalIds: string[]): Promise<Map<string, Contact>> {\n if (externalIds.length === 0) return new Map()\n const tryObjectId = externalIds.every(canBeObjectId)\n const ids: any[] = tryObjectId ? externalIds.map((s) => new ObjectId(s)) : externalIds\n const docs = await this.col.find({ [this.idField]: { $in: ids } }).toArray()\n const out = new Map<string, Contact>()\n for (const doc of docs) {\n const c = this.toContactFn(doc)\n out.set(c.externalId, c)\n }\n return out\n }\n\n async query(\n filter: AdapterFilter,\n opts: { limit: number; cursor?: string },\n ): Promise<{ contacts: Contact[]; nextCursor?: string }> {\n const query = this.translateFilterFn(filter)\n const limit = Math.min(opts.limit, this.batchSize)\n\n // Cursor is an ObjectId-or-externalId encoded as a string; we use it as a >\n // bound on the idField for stable pagination ordered by id.\n if (opts.cursor) {\n const cursorVal = canBeObjectId(opts.cursor) ? new ObjectId(opts.cursor) : opts.cursor\n ;(query as any)[this.idField] = { ...((query as any)[this.idField] ?? {}), $gt: cursorVal }\n }\n\n const docs = await this.col\n .find(query)\n .sort({ [this.idField]: 1 })\n .limit(limit + 1)\n .toArray()\n\n const hasMore = docs.length > limit\n const slice = hasMore ? docs.slice(0, limit) : docs\n const contacts = slice.map((d) => this.toContactFn(d))\n const last = slice[slice.length - 1]\n const nextCursor = hasMore && last ? String((last as any)[this.idField]) : undefined\n return { contacts, nextCursor }\n }\n\n async count(filter: AdapterFilter): Promise<number> {\n const query = this.translateFilterFn(filter)\n return await this.col.countDocuments(query)\n }\n\n addTags?: (externalId: string, tags: string[]) => Promise<void>\n removeTags?: (externalId: string, tags: string[]) => Promise<void>\n\n // -------------------------------------------------------------------------\n // Private helpers\n // -------------------------------------------------------------------------\n\n private idFilter(externalId: string): Filter<any> {\n if (this.idField === '_id' && canBeObjectId(externalId)) {\n return { _id: new ObjectId(externalId) } as Filter<any>\n }\n return { [this.idField]: externalId }\n }\n\n private defaultToContact(doc: any): Contact {\n const tagsRaw = this.tagsField ? doc[this.tagsField] ?? [] : []\n const tags: string[] =\n this.tagsArrayShape === 'objects'\n ? (Array.isArray(tagsRaw) ? tagsRaw : []).map((t: any) => String(t.name ?? t))\n : (Array.isArray(tagsRaw) ? tagsRaw : []).map((t: any) => String(t))\n\n const externalId = String(doc[this.idField] ?? '')\n const email = String(doc[this.emailField] ?? '').toLowerCase()\n\n // Default projection: everything that's not _id / email / tags becomes a field.\n const fields: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(doc)) {\n if (k === this.idField || k === this.emailField || k === this.tagsField) continue\n fields[k] = v\n }\n\n return {\n externalId,\n email,\n tags,\n fields,\n timezone: typeof doc.timezone === 'string' ? doc.timezone : undefined,\n locale: typeof doc.locale === 'string' ? doc.locale : undefined,\n }\n }\n\n private defaultTranslateFilter(filter: AdapterFilter): Filter<any> {\n const q: Record<string, unknown> = {}\n\n if (filter.emailIn && filter.emailIn.length > 0) {\n q[this.emailField] = { $in: filter.emailIn.map((e) => e.toLowerCase()) }\n }\n if (filter.externalIdIn && filter.externalIdIn.length > 0) {\n const tryObjectId = filter.externalIdIn.every(canBeObjectId)\n q[this.idField] = {\n $in: tryObjectId ? filter.externalIdIn.map((s) => new ObjectId(s)) : filter.externalIdIn,\n }\n }\n if (filter.fieldEquals) {\n q[filter.fieldEquals.field] = filter.fieldEquals.value\n }\n if (filter.fieldIn) {\n q[filter.fieldIn.field] = { $in: filter.fieldIn.values }\n }\n if (filter.fieldExists) {\n q[filter.fieldExists] = { $exists: true }\n }\n if (filter.createdAfter || filter.createdBefore) {\n const r: any = {}\n if (filter.createdAfter) r.$gte = filter.createdAfter\n if (filter.createdBefore) r.$lte = filter.createdBefore\n q.createdAt = r\n }\n if (this.tagsField) {\n if (filter.hasTag) {\n q[this.tagsField] = filter.hasTag\n }\n if (filter.hasTagIn && filter.hasTagIn.length > 0) {\n q[this.tagsField] = { $in: filter.hasTagIn }\n }\n }\n return q\n }\n\n private async addTagsImpl(externalId: string, tags: string[]): Promise<void> {\n if (!this.tagsField || tags.length === 0) return\n const value =\n this.tagsArrayShape === 'objects'\n ? tags.map((name) => ({ name }))\n : tags\n await this.col.updateOne(this.idFilter(externalId), {\n $addToSet: { [this.tagsField]: { $each: value } } as any,\n })\n }\n\n private async removeTagsImpl(externalId: string, tags: string[]): Promise<void> {\n if (!this.tagsField || tags.length === 0) return\n const value =\n this.tagsArrayShape === 'objects'\n ? { $in: tags.map((name) => ({ name })) }\n : { $in: tags }\n await this.col.updateOne(this.idFilter(externalId), {\n $pull: { [this.tagsField]: value } as any,\n })\n }\n}\n\nfunction canBeObjectId(s: string): boolean {\n return typeof s === 'string' && /^[a-f0-9]{24}$/i.test(s)\n}\n","/**\n * Replay-window helpers shared by provider webhook verification.\n *\n * A signature proves a payload came from the provider. It does not prove the\n * payload is *current* — a captured request replays forever unless the signed\n * timestamp is also checked for recency. Every provider that signs\n * `timestamp + body` (SendGrid today; Postmark/SES/Mailgun when they land)\n * needs the same window logic, so it lives here rather than in one adapter.\n *\n * Policy, per the maintainer's direction: on by default, overridable per\n * provider, explicitly disable-able for hosts whose proxy delays delivery.\n */\n\n/**\n * Default replay window, in seconds, applied when a provider is constructed\n * without an explicit tolerance.\n *\n * 300s (5 minutes) is the conventional value — it's what Stripe's SDKs use as\n * their default tolerance, and it is comfortably wider than any plausible\n * NTP-synced clock drift or provider retry jitter while still shrinking a\n * \"replayable forever\" window down to a five-minute one.\n */\nexport const DEFAULT_WEBHOOK_TOLERANCE_SECONDS = 300\n\n/**\n * Per-provider tolerance option: seconds, or `0` / `false` to disable the\n * freshness check entirely.\n */\nexport type WebhookToleranceOption = number | false\n\n/**\n * Normalize the constructor option into a number of seconds, where `0` means\n * \"disabled\".\n *\n * Anything nonsensical (negative, NaN, Infinity) falls back to the default\n * rather than being read as \"disabled\" — a typo in config should not silently\n * turn the replay window off.\n */\nexport function resolveWebhookToleranceSeconds(\n option?: WebhookToleranceOption,\n): number {\n if (option === false || option === 0) return 0\n if (option === undefined || option === null) return DEFAULT_WEBHOOK_TOLERANCE_SECONDS\n if (typeof option !== 'number' || !Number.isFinite(option) || option < 0) {\n return DEFAULT_WEBHOOK_TOLERANCE_SECONDS\n }\n return option\n}\n\n/**\n * Is a provider-supplied unix-seconds timestamp inside the replay window?\n *\n * Rejects in both directions: too old (the replay case) and too far in the\n * future (a forged or badly-skewed clock). Clock skew cuts both ways, so the\n * window is symmetric.\n *\n * Fails closed — a missing, empty, or non-integer timestamp is not fresh.\n * Returns a plain boolean so callers can fold it into an existing\n * \"valid / not valid\" decision without leaking *why* through an error.\n */\nexport function isWebhookTimestampFresh(\n rawTimestamp: string | undefined,\n toleranceSeconds: number,\n now: Date = new Date(),\n): boolean {\n // Disabled: the caller opted out of the window. The signature still had to\n // cover this timestamp to get here, so nothing else is weakened.\n if (toleranceSeconds === 0) return true\n if (!rawTimestamp) return false\n\n // Strict digits-only parse. `Number()`/`parseInt` would happily accept\n // ' 12 ', '1e12', '0x10', or '12abc' — none of which a provider sends, and\n // each of which widens what an attacker can put in the signed prefix.\n if (!/^\\d{1,15}$/.test(rawTimestamp)) return false\n\n const timestampMs = Number(rawTimestamp) * 1000\n if (!Number.isFinite(timestampMs)) return false\n\n const deltaMs = Math.abs(now.getTime() - timestampMs)\n return deltaMs <= toleranceSeconds * 1000\n}\n","/**\n * SendGridProvider — sends mail through @sendgrid/mail, verifies the Event\n * Webhook signature with the ECDSA public key configured in SendGrid, and\n * normalizes inbound event payloads into our shared shape.\n *\n * Setup steps required on the SendGrid side (one-time):\n * 1. Authenticate sender domain (SPF, DKIM, DMARC).\n * 2. Configure event webhook → POST to https://your.host/m/webhooks/sendgrid\n * 3. Enable: delivered, open, click, bounce, dropped, spamreport, unsubscribe\n * 4. Generate Signed Event Webhook key → store as webhookVerificationKey\n */\n\nimport crypto from 'node:crypto'\nimport sgMail from '@sendgrid/mail'\n\nimport type {\n MailProvider,\n NormalizedEvent,\n SendArgs,\n SendResult,\n} from '../../shared/types.js'\nimport {\n isWebhookTimestampFresh,\n resolveWebhookToleranceSeconds,\n type WebhookToleranceOption,\n} from './webhook-tolerance.js'\n\nexport interface SendGridProviderOptions {\n apiKey: string\n /** ECDSA public key (PEM) from SendGrid → Settings → Mail Settings → Signed Event Webhook. */\n webhookVerificationKey?: string\n /**\n * Replay window for the signed webhook timestamp, in seconds.\n * Defaults to 300 (5 minutes). A signed payload older — or more than this\n * far in the future — than the window is rejected, so a captured request\n * can't be replayed indefinitely.\n *\n * Set `0` or `false` to disable the check, for hosts whose proxy or queue\n * legitimately delays webhook delivery past the window.\n */\n webhookToleranceSeconds?: WebhookToleranceOption\n /** Send-rate cap per second (BullMQ group limiter consults this). */\n sendRatePerSecond?: number\n /** Sandbox mode bypasses actual delivery — useful in dev/test. */\n sandbox?: boolean\n}\n\nconst SG_SIG_HEADER = 'x-twilio-email-event-webhook-signature'\nconst SG_TS_HEADER = 'x-twilio-email-event-webhook-timestamp'\n\nexport class SendGridProvider implements MailProvider {\n readonly name = 'sendgrid'\n readonly sendRatePerSecond: number\n /** Resolved replay window in seconds; `0` means the check is disabled. */\n readonly webhookToleranceSeconds: number\n\n constructor(private readonly opts: SendGridProviderOptions) {\n sgMail.setApiKey(opts.apiKey)\n this.sendRatePerSecond = opts.sendRatePerSecond ?? 10\n this.webhookToleranceSeconds = resolveWebhookToleranceSeconds(opts.webhookToleranceSeconds)\n }\n\n async send(args: SendArgs): Promise<SendResult> {\n const msg: sgMail.MailDataRequired = {\n to: args.to,\n from: { name: args.fromName, email: args.fromEmail },\n replyTo: args.replyTo,\n subject: args.subject,\n text: args.text,\n // Omit the key entirely rather than sending `html: undefined` — a\n // text_only template must produce a single-part text/plain message, and\n // an explicit undefined can still serialize into an empty HTML part.\n ...(args.html ? { html: args.html } : {}),\n headers: args.headers,\n customArgs: args.messageMeta,\n trackingSettings: {\n // We do our own click/open tracking — let provider stay out of it.\n clickTracking: { enable: false, enableText: false },\n openTracking: { enable: false },\n },\n mailSettings: {\n sandboxMode: { enable: this.opts.sandbox ?? false },\n },\n }\n\n const [response] = await sgMail.send(msg)\n const providerId =\n (response.headers['x-message-id'] as string | undefined) ?? `sg-${Date.now()}`\n return {\n providerId,\n status: response.statusCode < 300 ? 'accepted' : 'rejected',\n raw: response,\n }\n }\n\n async verifyWebhook(rawBody: Buffer, headers: Record<string, string>): Promise<boolean> {\n if (!this.opts.webhookVerificationKey) return false\n const sig = headers[SG_SIG_HEADER]\n const ts = headers[SG_TS_HEADER]\n if (!sig || !ts) return false\n\n const payload = Buffer.concat([Buffer.from(ts, 'utf8'), rawBody])\n try {\n const verifier = crypto.createVerify('sha256')\n verifier.update(payload)\n if (!verifier.verify(this.opts.webhookVerificationKey, sig, 'base64')) return false\n } catch {\n return false\n }\n\n // Signature checks out, so the timestamp is authentic — but authentic is\n // not the same as current. Reject outside the replay window (both stale\n // and implausibly future) so a captured request has a five-minute life,\n // not an unbounded one. Signature first, freshness second, mirroring the\n // verify-then-expiry order in ../tokens.ts.\n return isWebhookTimestampFresh(ts, this.webhookToleranceSeconds)\n }\n\n parseWebhookEvents(payload: unknown): NormalizedEvent[] {\n if (!Array.isArray(payload)) return []\n return payload\n .map((raw) => normalizeSendGridEvent(raw))\n .filter((e): e is NormalizedEvent => e !== null)\n }\n}\n\nfunction normalizeSendGridEvent(e: any): NormalizedEvent | null {\n const type = mapEventType(e.event)\n if (!type) return null\n return {\n type,\n providerEventId: String(e.sg_event_id ?? e['smtp-id'] ?? `${e.event}-${e.timestamp}-${e.email}`),\n providerMessageId: String(e.sg_message_id ?? e['smtp-id'] ?? ''),\n email: String(e.email ?? '').toLowerCase(),\n occurredAt: new Date(Number(e.timestamp) * 1000),\n details: {\n bounceType:\n e.event === 'bounce' ? (e.type === 'bounce' ? 'hard' : 'soft') : undefined,\n bounceReason: e.reason,\n clickedUrl: e.url,\n userAgent: e.useragent,\n ipAddress: e.ip,\n },\n }\n}\n\nfunction mapEventType(sgEvent: string): NormalizedEvent['type'] | null {\n switch (sgEvent) {\n case 'delivered':\n return 'delivered'\n case 'open':\n return 'open'\n case 'click':\n return 'click'\n case 'bounce':\n case 'dropped':\n return 'bounce'\n case 'spamreport':\n return 'spam_report'\n case 'unsubscribe':\n case 'group_unsubscribe':\n return 'unsubscribe'\n default:\n return null\n }\n}\n","/**\n * Zod schemas for runtime validation at write boundaries — public API entry\n * points (fire, upsertSubscription, suppress, sendOneOff, scheduleBroadcast)\n * and REST handler bodies.\n *\n * Domain TypeScript types live in `./types.ts`; these schemas overlap with\n * those types deliberately so we get both compile-time and runtime checking\n * at the surfaces that need it.\n */\n\nimport { z } from 'zod'\n\n// ---------------------------------------------------------------------------\n// Primitive helpers\n// ---------------------------------------------------------------------------\n\nexport const externalIdSchema = z.string().min(1).max(256)\nexport const emailSchema = z.string().email().toLowerCase().trim()\nexport const slugSchema = z\n .string()\n .min(1)\n .max(128)\n .regex(/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/, 'must be kebab-case slug')\n\n// ---------------------------------------------------------------------------\n// Public API inputs\n// ---------------------------------------------------------------------------\n\nexport const fireInputSchema = z.object({\n eventName: z.string().min(1).max(128),\n externalId: externalIdSchema,\n properties: z.record(z.string(), z.unknown()).optional(),\n dedupeKey: z.string().min(1).max(512).optional(),\n})\nexport type FireInput = z.infer<typeof fireInputSchema>\n\nexport const registerEventSchema = z.object({\n name: z.string().min(1).max(128),\n dedupePolicy: z.enum(['once-per-contact', 'once-per-day', 'every-time']),\n})\nexport type RegisterEventInput = z.infer<typeof registerEventSchema>\n\nexport const upsertSubscriptionSchema = z.object({\n externalId: externalIdSchema,\n source: z.string().min(1).max(256),\n consentTimestamp: z.date().optional(),\n consentIp: z.string().optional(),\n consentUserAgent: z.string().optional(),\n})\nexport type UpsertSubscriptionInput = z.infer<typeof upsertSubscriptionSchema>\n\nexport const unsubscribeScopeSchema = z.enum(['all', 'marketing', 'transactional'])\nexport const unsubscribeReasonSchema = z.enum([\n 'user_request',\n 'hard_bounce',\n 'complaint',\n 'manual',\n 'gdpr_forget',\n 'list_cleaning',\n])\n\nexport const unsubscribeInputSchema = z.object({\n email: emailSchema,\n scope: unsubscribeScopeSchema,\n reason: unsubscribeReasonSchema.default('user_request'),\n source: z.string().max(256).default('manual'),\n notes: z.string().max(1024).optional(),\n})\nexport type UnsubscribeInput = z.infer<typeof unsubscribeInputSchema>\n\nexport const suppressInputSchema = z.object({\n email: emailSchema,\n scope: unsubscribeScopeSchema,\n reason: z.enum(['unsubscribed', 'hard_bounce', 'complaint', 'manual', 'list_cleaning', 'gdpr_forget']),\n source: z.string().max(256).default('manual'),\n notes: z.string().max(1024).optional(),\n expiresAt: z.date().optional(),\n})\nexport type SuppressInput = z.infer<typeof suppressInputSchema>\n\nexport const tagInputSchema = z.object({\n externalId: externalIdSchema,\n tag: z.string().min(1).max(128),\n})\nexport type TagInput = z.infer<typeof tagInputSchema>\n\nexport const abortFlowInputSchema = z.object({\n flowSlug: slugSchema,\n externalId: externalIdSchema,\n reason: z.string().min(1).max(200).optional(),\n /**\n * Restrict the abort to runs whose trigger event carried these properties —\n * e.g. `{ accountId }` to cancel one account's series while the same\n * contact's other accounts keep running. Omit to abort every active run for\n * the contact on this flow.\n *\n * Keys and values are both constrained because these go straight into a\n * Mongo query. Values are primitives only: an object value like\n * `{ $ne: null }` would reach the query as an OPERATOR and match every\n * scoped run, turning a one-account abort into abort-everything. Hosts\n * typically pass an id from a request body, so treat it as untrusted. The\n * key regex likewise blocks `$`-prefixed keys and dots (a dot would silently\n * extend the path and change match semantics).\n */\n matchTriggerProperties: z\n .record(\n z.string().regex(/^[A-Za-z0-9_]+$/),\n z.union([z.string(), z.number(), z.boolean(), z.null()]),\n )\n .optional(),\n})\nexport type AbortFlowInput = z.infer<typeof abortFlowInputSchema>\n\nexport const abortAllFlowsInputSchema = abortFlowInputSchema.omit({ flowSlug: true })\nexport type AbortAllFlowsInput = z.infer<typeof abortAllFlowsInputSchema>\n\nexport const sendOneOffInputSchema = z.object({\n templateSlug: slugSchema,\n externalId: externalIdSchema,\n vars: z.record(z.string(), z.unknown()).optional(),\n providerOverride: z.string().optional(),\n dedupeKey: z.string().min(1).max(512),\n})\nexport type SendOneOffInput = z.infer<typeof sendOneOffInputSchema>\n\n// ---------------------------------------------------------------------------\n// Flow step + predicate schemas (mirror types.ts)\n// ---------------------------------------------------------------------------\n\nexport const flowStepSchema: z.ZodType<unknown> = z.lazy(() =>\n z.discriminatedUnion('type', [\n z.object({\n type: z.literal('wait'),\n value: z.number().int().positive(),\n unit: z.enum(['minutes', 'hours', 'days', 'weeks']),\n }),\n z.object({\n type: z.literal('condition'),\n test: predicateSchema,\n ifFalse: z.enum(['continue', 'exit']),\n }),\n z.object({\n type: z.literal('branch'),\n test: predicateSchema,\n ifTrueSteps: z.array(flowStepSchema),\n ifFalseSteps: z.array(flowStepSchema),\n }),\n z.object({\n type: z.literal('send'),\n templateSlug: slugSchema,\n providerOverride: z.string().optional(),\n vars: z.record(z.string(), z.unknown()).optional(),\n delivery: z\n .object({\n weekdaysOnly: z.boolean().optional(),\n timeOfDay: z.string().regex(/^([01]\\d|2[0-3]):[0-5]\\d$/, 'expected HH:mm').optional(),\n useContactTimezone: z.boolean().optional(),\n timezone: z.string().optional(),\n })\n .optional(),\n }),\n z.object({\n type: z.literal('tag'),\n addTags: z.array(z.string()).optional(),\n removeTags: z.array(z.string()).optional(),\n }),\n z.object({\n type: z.literal('fire_event'),\n eventName: z.string().min(1).max(128),\n properties: z.record(z.string(), z.unknown()).optional(),\n }),\n z.object({\n type: z.literal('webhook'),\n // `url` is validated for shape only and is deliberately never templated —\n // see the comment on handleWebhookStep in src/server/runner/step.ts, and\n // INVARIANT 16. Rendering contact/event data into this field would turn an\n // admin-authored flow into a server-side request forgery primitive.\n url: z.string().url(),\n method: z.enum(['POST', 'PUT']).optional(),\n payload: z.record(z.string(), z.unknown()).optional(),\n failureMode: z.enum(['soft', 'fail_run']).optional(),\n }),\n z.object({\n type: z.literal('exit'),\n reason: z.string().optional(),\n }),\n ]),\n)\n\nexport const predicateSchema: z.ZodType<unknown> = z.lazy(() =>\n z.union([\n z.object({ hasTag: z.string() }),\n z.object({ notHasTag: z.string() }),\n z.object({ fieldEquals: z.object({ field: z.string(), value: z.unknown() }) }),\n z.object({ fieldExists: z.string() }),\n z.object({\n triggerPropertyEquals: z.object({\n key: z.string().min(1),\n value: z.union([z.string(), z.number(), z.boolean(), z.null()]),\n }),\n }),\n z.object({ triggerPropertyTruthy: z.string().min(1) }),\n z.object({\n hasFiredEvent: z.string(),\n sinceFlowStart: z.boolean().optional(),\n withinDays: z.number().int().positive().optional(),\n }),\n z.object({\n notHasFiredEvent: z.string(),\n withinDays: z.number().int().positive().optional(),\n }),\n z.object({\n subscriptionStatus: z.enum(['subscribed', 'unsubscribed', 'pending_doi', 'bounced', 'complained']),\n }),\n z.object({\n hasOpened: z.object({\n templateSlug: slugSchema.optional(),\n sinceFlowStart: z.boolean().optional(),\n withinDays: z.number().int().positive().optional(),\n }),\n }),\n z.object({\n hasClicked: z.object({\n templateSlug: slugSchema.optional(),\n sinceFlowStart: z.boolean().optional(),\n withinDays: z.number().int().positive().optional(),\n }),\n }),\n z.object({\n hasOpenedExcludingBots: z.object({\n templateSlug: slugSchema.optional(),\n sinceFlowStart: z.boolean().optional(),\n withinDays: z.number().int().positive().optional(),\n }),\n }),\n z.object({\n hasClickedExcludingBots: z.object({\n templateSlug: slugSchema.optional(),\n sinceFlowStart: z.boolean().optional(),\n withinDays: z.number().int().positive().optional(),\n }),\n }),\n z.object({\n openedAtLeastN: z.object({ count: z.number().int().positive(), withinDays: z.number().int().positive() }),\n }),\n z.object({\n clickedAtLeastN: z.object({ count: z.number().int().positive(), withinDays: z.number().int().positive() }),\n }),\n z.object({ all: z.array(predicateSchema) }),\n z.object({ any: z.array(predicateSchema) }),\n z.object({ not: predicateSchema }),\n ]),\n)\n","/**\n * Mailer configuration shape. Required + optional surfaces with sane defaults.\n */\n\nimport type { Db } from 'mongodb'\nimport type Handlebars from 'handlebars'\nimport type {\n ContactAdapter,\n MailProvider,\n} from '../shared/types.js'\nimport type { QueueDriverConfig } from './queues/types.js'\nimport type { SenderDomainRegistry } from './templates/sender-domain.js'\nimport type { VarsAdapter } from './adapters/vars.js'\n\nexport type { SenderDomainConfig, SenderDomainRegistry } from './templates/sender-domain.js'\n\nexport interface RedisOptions {\n host?: string\n port?: number\n password?: string\n url?: string\n db?: number\n username?: string\n tls?: boolean\n}\n\nexport interface DnsblListSpec {\n /** DNS suffix to query, e.g. `'dbl.spamhaus.org'`. */\n host: string\n /** Display label for the UI, e.g. `'Spamhaus DBL'`. */\n label: string\n}\n\nexport interface DnsblConfig {\n /** Domain block lists (DBLs) — queried as `<domain>.<host>`. */\n domainLists?: DnsblListSpec[]\n /** IP block lists — queried as `<reversed-octets>.<host>`. */\n ipLists?: DnsblListSpec[]\n /** Dedicated sending IPs to check. Most operators on shared ESPs leave empty. */\n dedicatedIps?: string[]\n /** Hours between automatic runs. Default 24. Set to 0 to disable scheduled runs. */\n intervalHours?: number\n}\n\nexport const DEFAULT_DOMAIN_DNSBL_LISTS: DnsblListSpec[] = [\n { host: 'dbl.spamhaus.org', label: 'Spamhaus DBL' },\n { host: 'multi.surbl.org', label: 'SURBL' },\n { host: 'multi.uribl.com', label: 'URIBL' },\n]\n\nexport const DEFAULT_IP_DNSBL_LISTS: DnsblListSpec[] = [\n { host: 'zen.spamhaus.org', label: 'Spamhaus ZEN' },\n { host: 'b.barracudacentral.org', label: 'Barracuda' },\n { host: 'dnsbl.sorbs.net', label: 'SORBS' },\n { host: 'bl.spamcop.net', label: 'SpamCop' },\n]\n\nexport interface MailTesterConfig {\n /** API key from your Mail-Tester paid plan. */\n apiKey: string\n /** Minimum score (0-10) below which publish is blocked. Default 8.0. */\n minScore?: number\n /**\n * When true, publishing content that has no cached score is blocked too —\n * the operator must run a deliverability check for that exact content first.\n * Default false, which only blocks content already known to score below\n * `minScore`; in that mode any edit (even whitespace) changes the content\n * key, misses the cache, and publishes freely.\n */\n requireScore?: boolean\n /**\n * How long a successful score remains cached for the same content. Default 24.\n * Re-publishing the same body within the window does not burn a credit.\n */\n cacheHours?: number\n /** API base URL. Defaults to `https://mail-tester.com/api`. Override for staging or alternate provider. */\n baseUrl?: string\n}\n\nexport interface DmarcSourceTag {\n /** Source IP, e.g. `'149.72.45.10'`. */\n ip: string\n /** Operator-provided label, e.g. `'SendGrid (transactional)'` or `'Hubspot'`. */\n label: string\n /** When true, ignore failures from this source in the alignment-trend headline. */\n ignored?: boolean\n}\n\nexport interface DmarcConfig {\n /**\n * Operator-tagged sources. After RUA reports start arriving, the operator\n * marks each source IP as known/legit (with a label) or rogue. Tagged\n * sources are excluded from the headline failure count, surfacing only\n * unknown senders.\n */\n knownSources?: DmarcSourceTag[]\n /**\n * How many days of failure rows to retain. Default 90. Older rows are\n * trimmed by the daily tick to keep the collection bounded.\n */\n retentionDays?: number\n}\n\nexport interface SndsConfig {\n /**\n * SNDS automated-access key. Obtained per-account from the SNDS portal at\n * https://sendersupport.olc.protection.outlook.com/snds/ once each\n * sending IP has been added and verified.\n */\n accessKey: string\n /**\n * Optional IP filter — when set, only rows for these IPs are persisted.\n * Useful when an SNDS account covers a wider IP pool than this mailery\n * deployment uses. Defaults to keeping all rows the API returns.\n */\n ips?: string[]\n /** Hours between automatic pulls. Default 24. Set to 0 to disable scheduled pulls. */\n intervalHours?: number\n}\n\nexport interface PostmasterConfig {\n /** OAuth client ID from a Google Cloud project with Postmaster Tools API enabled. */\n clientId: string\n clientSecret: string\n /**\n * A refresh token obtained via the OAuth consent flow with scope\n * `https://www.googleapis.com/auth/postmaster.readonly` for the user that\n * verified the domain(s) in Postmaster Tools. See\n * docs/guide/deliverability.md → \"Google Postmaster Tools\" for the\n * one-time setup procedure.\n */\n refreshToken: string\n /**\n * Domains to pull data for. When omitted, mailery uses every domain from the\n * senderDomains registry plus the From defaults. Each must be verified in\n * Postmaster Tools under the same Google account.\n */\n domains?: string[]\n /** Hours between automatic pulls. Default 24. Set to 0 to disable scheduled pulls. */\n intervalHours?: number\n}\n\nexport interface CircuitBreakerThresholds {\n /** Trip when last-hour hard-bounce rate >= this percent (e.g. 2 = 2%). */\n hardBounceRatePctTrip: number\n complaintRatePctTrip: number\n combinedBounceRatePctTrip: number\n failedToSendRatePctDegrade: number\n windowMinutes: number\n minSendsBeforeEval: number\n}\n\nexport interface BotFilterConfig {\n /**\n * User agents matching this pattern are treated as automated. Applied to\n * recorded open and click user agents alike.\n *\n * Default: `/Mimecast|SafeLinks|proofpoint|HeadlessChrome|Googlebot|bingbot/i`\n * (`DEFAULT_BOT_UA_RE`). Replace it to cover your own corporate scanners;\n * extend rather than replace if you want to keep the built-ins.\n */\n userAgentPattern?: RegExp\n /**\n * Opens recorded within this many milliseconds of the send being queued are\n * treated as automated regardless of user agent — corporate scanners and\n * gateway prefetchers fetch the pixel within seconds of delivery, and a\n * human cannot.\n *\n * Default `0` — disabled. It is off by default because it is a heuristic\n * with a real false-positive tail (a recipient already reading their inbox\n * when the mail lands) and because enabling it silently changes the counts\n * every existing flow branches on. `10000` (10s) is the value worth trying\n * first if your open counts look implausible.\n */\n minOpenDelayMs?: number\n}\n\nexport interface MailerConfig {\n // ---- Storage --------------------------------------------------------------\n db: Db\n collectionPrefix?: string\n adapter: ContactAdapter\n /**\n * Optional host-provided template variables. `resolve(contact)` runs at\n * send/preview/test render time; its result is merged into the template\n * context root (schema key `user` → `{{user.name}}`). The zod schema\n * drives admin-editor autocomplete and the `unknown_variable` lint rule.\n * Build one with `defineVars({ schema, resolve })`.\n */\n varsAdapter?: VarsAdapter<any>\n\n // ---- Queue ----------------------------------------------------------------\n /**\n * Queue driver selection. One of:\n * - `{ driver: 'bull', redis: ... }` — BullMQ (default for prod; requires Redis)\n * - `{ driver: 'agenda' }` — @hokify/agenda using this Mongo (no Redis required, single-process)\n * - `{ driver: 'noop' }` — no background workers (tests, synchronous-only hosts)\n */\n queue: QueueDriverConfig\n\n // ---- Providers ------------------------------------------------------------\n providers: Record<string, MailProvider>\n defaultProvider: string\n defaultTransactionalProvider?: string\n\n // ---- Identity / URLs ------------------------------------------------------\n publicUrl: string\n unsubscribeSecret: string\n senderAddress?: string\n fromDefaults?: { name: string; email: string }\n transactionalFromDefaults?: { name: string; email: string }\n /**\n * Optional registry of sender domains by kind. When set, mailery enforces at\n * template publish time that a template's `fromEmail` domain is declared and\n * matches the template's `kind`. Used to keep marketing reputation isolated\n * from transactional reputation by sending from separate verified domains.\n *\n * Domains are case-insensitive. If unset, no enforcement happens.\n */\n senderDomains?: SenderDomainRegistry\n\n // ---- Compliance -----------------------------------------------------------\n requireDoubleOptIn?: boolean\n unsubscribeTokenLifetimeDays?: number\n transactionalRespectUnsubscribe?: boolean\n /**\n * Absolute path to the pending-unsubscribe journal (INVARIANT 8).\n *\n * When `POST /m/unsub/:token` cannot reach Mongo, the opt-out is appended\n * here as JSONL and replayed by the tick drain\n * (`drainPendingUnsubscribes`). The file is created 0600 inside a 0700\n * directory and opened `O_NOFOLLOW`.\n *\n * **There is no default, and that is deliberate.** The journal holds\n * recipient email addresses in plaintext outside the database, and a library\n * mounted into an unknown host cannot pick a directory that is at once\n * writable, durable and private — which is how the previous default ended up\n * being `/tmp` (world-writable, wiped on reboot, and never read back).\n *\n * With this unset the endpoint answers **503** when Mongo is unreachable,\n * rather than promising an unsubscribe it has nowhere to record. Set it to a\n * durable, private, node-local path to get the journal instead — e.g.\n * `/var/lib/mailery/pending-unsubs.jsonl` (systemd: `StateDirectory=mailery`).\n *\n * Must not be on a shared network filesystem: claiming a batch relies on\n * `rename` being atomic within the directory.\n */\n pendingUnsubsPath?: string\n /**\n * How long `POST /m/unsub/:token` waits for the Mongo write before falling\n * back to the journal. Default 5000ms.\n *\n * The tension is INVARIANT 8's own: the response must be fast (clients are\n * impatient, providers retry) *and* must not claim an unsubscribe that was\n * never recorded. A healthy write is sub-millisecond, so this budget is only\n * ever spent during an outage, and spending it is what makes the difference\n * between a truthful 200 and a lie.\n */\n unsubscribeWriteTimeoutMs?: number\n /** Slug of the transactional template sent for DOI confirmation. Defaults to 'doi-confirmation'. */\n doiTemplateSlug?: string\n /** How long the DOI token stays valid. Default 7 days. */\n doiTokenLifetimeDays?: number\n\n // ---- Circuit breaker ------------------------------------------------------\n circuitBreaker?: Partial<CircuitBreakerThresholds>\n\n // ---- DNSBL monitoring -----------------------------------------------------\n /**\n * Daily DNS-based block-list checks on sender domains and (optionally) any\n * dedicated sending IPs. Results surface in setup-status and on the Health\n * screen. No external API needed — plain DNS lookups.\n */\n dnsbl?: DnsblConfig\n\n // ---- Google Postmaster Tools ---------------------------------------------\n /**\n * Pulls daily reputation tiers + spam ratio + auth pass rates from Google\n * Postmaster Tools. Trips the (domain × marketing) circuit breaker when a\n * domain falls to reputation `BAD`. Only meaningful at >100/day to Gmail.\n */\n postmaster?: PostmasterConfig\n\n // ---- Microsoft SNDS ------------------------------------------------------\n /**\n * Pulls daily Outlook/Hotmail/Live IP reputation from Microsoft's Smart\n * Network Data Services. IP-level rather than domain-level — only useful\n * if you send from a dedicated IP. Visibility-only: RED filter results\n * surface as a setup-status error, no auto-trip.\n */\n snds?: SndsConfig\n\n // ---- Mail-Tester deliverability check ------------------------------------\n /**\n * Optional Mail-Tester integration. When set, the template editor exposes\n * a \"Run deliverability check\" button that sends a copy of the rendered\n * draft to a Mail-Tester address and polls for a score (0-10) covering\n * SpamAssassin verdict, auth alignment, content red flags, and link\n * reputation. Score < minScore blocks publish until re-run or overridden.\n */\n mailTester?: MailTesterConfig\n\n // ---- DMARC aggregate report ingestion ------------------------------------\n /**\n * DMARC RUA aggregate reports tell you who is sending mail that claims to\n * be from your domain — both legitimate sources and spoofers. Mailery\n * decompresses, parses, and surfaces alignment failures + unknown senders.\n *\n * Two ways in:\n * - the operator uploads attachments in the admin UI\n * (`POST /admin/mailer/api/dmarc/upload`, behind your admin guard)\n * - the inbound webhook, for SendGrid Inbound Parse and friends:\n * `createPublicRouter(mailer, { dmarcInbound: { secret } })`. Off unless\n * that secret is set. Do **not** point Inbound Parse at the admin\n * upload route — it sits behind the host's `requireAdmin` guard, which\n * Inbound Parse cannot satisfy. (Versions before 0.15 recommended\n * exactly that, and it never worked.)\n */\n dmarc?: DmarcConfig\n\n // ---- Broadcast safety + throughput ---------------------------------------\n broadcastConfirmationThreshold?: number\n broadcastEnqueueBatchSize?: number\n broadcastEnqueueMaxWaiting?: number\n\n // ---- Worker behavior ------------------------------------------------------\n workerless?: boolean\n tickIntervalSeconds?: number\n sendConcurrency?: number\n sendRatePerSecond?: number\n softBouncePromotionThreshold?: number\n softBouncePromotionWindowDays?: number\n webhookRetryAttempts?: number\n sendRetryAttempts?: number\n\n // ---- Tracking -------------------------------------------------------------\n trackOpens?: boolean\n trackClicks?: boolean\n storeTrackingIp?: boolean\n storeRenderedBody?: boolean\n /**\n * Reject `/m/open` and `/m/click` hits that carry no signature.\n *\n * Default `false` — grace mode. Newly rendered mail is always signed; this\n * flag only decides what happens to the *unsigned* URLs sitting in mail that\n * was already delivered. In grace mode they are still counted and each one is\n * logged (`mailery: unsigned tracking URL accepted`) so the operator can watch\n * the legacy rate fall to zero and then flip this to `true`.\n *\n * A signature that is *present but wrong* is always rejected, in both modes.\n */\n requireSignedTrackingUrls?: boolean\n /**\n * How long a tracking URL stays valid, in days, measured from the send's\n * `queuedAt`. Default `0` — never expires.\n *\n * Never-expire is the right default: an email sits in an inbox for years and\n * a legitimate open six months later is real data, not an attack. The\n * signature already proves the caller was handed the URL. Operators with a\n * data-retention policy can set a window; because the deadline is derived\n * from the send row rather than baked into the token, changing this value\n * takes effect immediately for already-delivered mail and costs no URL bytes.\n */\n trackingUrlLifetimeDays?: number\n /**\n * Tuning for `hasOpenedExcludingBots` / `hasClickedExcludingBots` /\n * `openedAtLeastN` / `clickedAtLeastN`. See `BotFilterConfig`.\n */\n botFilter?: BotFilterConfig\n\n // ---- Hooks ----------------------------------------------------------------\n getAdminActor?: (req: any) => string\n onCircuitBreakerTrip?: (info: { reason: string; rates: Record<string, number> }) => Promise<void> | void\n onSendFailure?: (info: { send: any; error: Error }) => Promise<void> | void\n handlebarsHelpers?: Record<string, Handlebars.HelperDelegate>\n}\n\nexport type ResolvedConfig = Required<\n Pick<\n MailerConfig,\n | 'collectionPrefix'\n | 'requireDoubleOptIn'\n | 'unsubscribeTokenLifetimeDays'\n | 'transactionalRespectUnsubscribe'\n | 'unsubscribeWriteTimeoutMs'\n | 'doiTemplateSlug'\n | 'doiTokenLifetimeDays'\n | 'broadcastConfirmationThreshold'\n | 'broadcastEnqueueBatchSize'\n | 'broadcastEnqueueMaxWaiting'\n | 'workerless'\n | 'tickIntervalSeconds'\n | 'sendConcurrency'\n | 'sendRatePerSecond'\n | 'softBouncePromotionThreshold'\n | 'softBouncePromotionWindowDays'\n | 'webhookRetryAttempts'\n | 'sendRetryAttempts'\n | 'trackOpens'\n | 'trackClicks'\n | 'storeTrackingIp'\n | 'storeRenderedBody'\n | 'requireSignedTrackingUrls'\n | 'trackingUrlLifetimeDays'\n >\n> & {\n circuitBreaker: CircuitBreakerThresholds\n} & MailerConfig\n\nexport const DEFAULTS = {\n collectionPrefix: 'mailer_',\n requireDoubleOptIn: false,\n unsubscribeTokenLifetimeDays: 90,\n transactionalRespectUnsubscribe: false,\n unsubscribeWriteTimeoutMs: 5000,\n doiTemplateSlug: 'doi-confirmation',\n doiTokenLifetimeDays: 7,\n broadcastConfirmationThreshold: 1000,\n broadcastEnqueueBatchSize: 1000,\n broadcastEnqueueMaxWaiting: 5000,\n workerless: false,\n tickIntervalSeconds: 60,\n sendConcurrency: 5,\n sendRatePerSecond: 10,\n softBouncePromotionThreshold: 3,\n softBouncePromotionWindowDays: 30,\n webhookRetryAttempts: 3,\n sendRetryAttempts: 4,\n trackOpens: true,\n trackClicks: true,\n storeTrackingIp: false,\n storeRenderedBody: false,\n requireSignedTrackingUrls: false,\n trackingUrlLifetimeDays: 0,\n} as const\n\nexport const CIRCUIT_BREAKER_DEFAULTS: CircuitBreakerThresholds = {\n hardBounceRatePctTrip: 2,\n complaintRatePctTrip: 0.3,\n combinedBounceRatePctTrip: 5,\n failedToSendRatePctDegrade: 10,\n windowMinutes: 60,\n minSendsBeforeEval: 100,\n}\n\nexport function resolveConfig(c: MailerConfig): ResolvedConfig {\n return {\n ...c,\n collectionPrefix: c.collectionPrefix ?? DEFAULTS.collectionPrefix,\n requireDoubleOptIn: c.requireDoubleOptIn ?? DEFAULTS.requireDoubleOptIn,\n unsubscribeTokenLifetimeDays: c.unsubscribeTokenLifetimeDays ?? DEFAULTS.unsubscribeTokenLifetimeDays,\n transactionalRespectUnsubscribe: c.transactionalRespectUnsubscribe ?? DEFAULTS.transactionalRespectUnsubscribe,\n unsubscribeWriteTimeoutMs: c.unsubscribeWriteTimeoutMs ?? DEFAULTS.unsubscribeWriteTimeoutMs,\n doiTemplateSlug: c.doiTemplateSlug ?? DEFAULTS.doiTemplateSlug,\n doiTokenLifetimeDays: c.doiTokenLifetimeDays ?? DEFAULTS.doiTokenLifetimeDays,\n broadcastConfirmationThreshold: c.broadcastConfirmationThreshold ?? DEFAULTS.broadcastConfirmationThreshold,\n broadcastEnqueueBatchSize: c.broadcastEnqueueBatchSize ?? DEFAULTS.broadcastEnqueueBatchSize,\n broadcastEnqueueMaxWaiting: c.broadcastEnqueueMaxWaiting ?? DEFAULTS.broadcastEnqueueMaxWaiting,\n workerless: c.workerless ?? DEFAULTS.workerless,\n tickIntervalSeconds: c.tickIntervalSeconds ?? DEFAULTS.tickIntervalSeconds,\n sendConcurrency: c.sendConcurrency ?? DEFAULTS.sendConcurrency,\n sendRatePerSecond: c.sendRatePerSecond ?? DEFAULTS.sendRatePerSecond,\n softBouncePromotionThreshold: c.softBouncePromotionThreshold ?? DEFAULTS.softBouncePromotionThreshold,\n softBouncePromotionWindowDays: c.softBouncePromotionWindowDays ?? DEFAULTS.softBouncePromotionWindowDays,\n webhookRetryAttempts: c.webhookRetryAttempts ?? DEFAULTS.webhookRetryAttempts,\n sendRetryAttempts: c.sendRetryAttempts ?? DEFAULTS.sendRetryAttempts,\n trackOpens: c.trackOpens ?? DEFAULTS.trackOpens,\n trackClicks: c.trackClicks ?? DEFAULTS.trackClicks,\n storeTrackingIp: c.storeTrackingIp ?? DEFAULTS.storeTrackingIp,\n storeRenderedBody: c.storeRenderedBody ?? DEFAULTS.storeRenderedBody,\n requireSignedTrackingUrls: c.requireSignedTrackingUrls ?? DEFAULTS.requireSignedTrackingUrls,\n trackingUrlLifetimeDays: c.trackingUrlLifetimeDays ?? DEFAULTS.trackingUrlLifetimeDays,\n circuitBreaker: { ...CIRCUIT_BREAKER_DEFAULTS, ...(c.circuitBreaker ?? {}) },\n }\n}\n","/**\n * Mongo collection helpers + indexes for every mailer-owned collection.\n *\n * The single source of truth for `mailer_*` schemas lives in\n * `plans/02-data-model.md`. The TS interfaces here track that doc.\n *\n * const collections = getCollections(db)\n * await ensureIndexes(db)\n * await collections.events.insertOne({ ... })\n */\n\nimport type { Db, Collection, ObjectId } from 'mongodb'\n\nimport type {\n SubscriptionStatus,\n SendStatus,\n TemplateKind,\n TemplateBodyFormat,\n SuppressionScope,\n SuppressionReason,\n FlowRunStatus,\n BroadcastStatus,\n HealthStatus,\n FlowGoal,\n} from '../../shared/enums.js'\nimport type { FlowStep, SegmentDefinition } from '../../shared/types.js'\n\n// ---------------------------------------------------------------------------\n// Document interfaces (per collection)\n// ---------------------------------------------------------------------------\n\nexport interface SubscriptionDoc {\n _id?: ObjectId\n externalId: string\n status: SubscriptionStatus\n subscribedAt: Date | null\n unsubscribedAt: Date | null\n unsubscribeReason: string | null\n doiTokenHash: string | null\n doiRequestedAt: Date | null\n doiConfirmedAt: Date | null\n doiIp: string | null\n doiUserAgent: string | null\n source: string\n emailAtSubscribe: string\n createdAt: Date\n updatedAt: Date\n}\n\nexport interface LeadDoc {\n _id?: ObjectId\n email: string\n source: string\n capturedFields: Record<string, unknown>\n status: 'lead' | 'promoted' | 'rejected'\n promotedToExternalId: string | null\n promotedAt: Date | null\n consentedAt: Date | null\n consentIp: string | null\n unsubscribedAt: Date | null\n createdAt: Date\n updatedAt: Date\n}\n\nexport interface EventDoc {\n _id?: ObjectId\n externalId: string\n name: string\n properties: Record<string, unknown>\n dedupeKey: string\n occurredAt: Date\n createdAt: Date\n}\n\nexport interface FlowTrigger {\n type: 'event' | 'segment_enter' | 'cron'\n eventName?: string\n segmentDefinition?: SegmentDefinition\n cronExpression?: string\n once: boolean\n}\n\nexport interface FlowDraft {\n steps: FlowStep[]\n notes: string\n lastModifiedBy: string\n lastModifiedAt: Date\n}\n\nexport interface FlowDoc {\n _id?: ObjectId\n slug: string\n name: string\n description: string\n trigger: FlowTrigger\n enabled: boolean\n steps: FlowStep[]\n version: number\n draft: FlowDraft | null\n goal: FlowGoal\n audience: string\n expectedVolumePerWeek: number | null\n stats: {\n activeRuns: number\n completedRuns: number\n sendsTotal: number\n sendsLast7Days: number\n }\n lastTriggerScanAt: Date | null\n publishedAt: Date | null\n publishedBy: string | null\n createdAt: Date\n updatedAt: Date\n}\n\nexport interface FlowVersionDoc {\n _id?: ObjectId\n flowId: ObjectId\n version: number\n steps: FlowStep[]\n trigger: FlowTrigger\n publishedAt: Date\n publishedBy: string\n}\n\nexport interface FlowRunHistoryEntry {\n stepIndex: number\n action:\n | 'entered'\n | 'wait_started'\n | 'wait_completed'\n | 'condition_evaluated'\n | 'branch_taken'\n | 'sent'\n | 'send_skipped'\n | 'send_deferred'\n | 'tagged'\n | 'event_fired'\n | 'webhook_called'\n | 'exited'\n | 'failed'\n at: Date\n details?: Record<string, unknown>\n}\n\nexport interface FlowRunDoc {\n _id?: ObjectId\n externalId: string\n flowId: ObjectId\n flowSlug: string\n flowVersion: number\n emailAtEntry: string\n /**\n * Snapshot of the event that triggered this run. Properties surface in\n * templates as `{{event.*}}` and in `varsAdapter.resolve` via\n * `info.eventProperties` — this is how account/topic-scoped flows know\n * which account or topic the run is about. Null for non-event entries.\n */\n triggerEvent?: { name: string; properties: Record<string, unknown>; occurredAt: Date } | null\n /**\n * Dedupe key of the triggering event. Unique per flow (partial index) so the\n * trigger scan's overlap window can re-read an event without creating a\n * second run. Null for non-event entries (manual/API).\n */\n triggerDedupeKey?: string | null\n enteredAt: Date\n status: FlowRunStatus\n currentStepIndex: number\n currentBranchPath: Array<number | 'true' | 'false'>\n nextActionAt: Date\n attemptsForCurrentStep: number\n history: FlowRunHistoryEntry[]\n exitedAt: Date | null\n exitReason: string | null\n createdAt: Date\n updatedAt: Date\n}\n\nexport interface TemplateDraft {\n subject: string\n preheader: string\n /** MJML source (when template is authored as MJML). Empty string if Maily-authored. */\n mjml: string\n /** Maily editor JSON (when template is authored via the WYSIWYG editor). null otherwise. */\n editorJson: Record<string, unknown> | null\n notes: string\n lastModifiedBy: string\n lastModifiedAt: Date\n}\n\nexport interface TemplateDoc {\n _id?: ObjectId\n slug: string\n name: string\n description: string\n kind: TemplateKind\n fromName: string\n fromEmail: string\n replyTo: string | null\n providerOverride: string | null\n subject: string\n preheader: string\n body: {\n /** MJML source (set when published from MJML). */\n mjml: string\n /** Maily editor JSON (set when published from the WYSIWYG editor). null otherwise. */\n editorJson: Record<string, unknown> | null\n html: string\n plainText: string\n compiledAt: Date | null\n }\n variablesSchema: Record<\n string,\n {\n type: 'string' | 'number' | 'boolean' | 'date' | 'url'\n required: boolean\n description?: string\n defaultValue?: unknown\n }\n >\n draft: TemplateDraft | null\n tags: string[]\n /** Wire format for the body. Absent on documents written before 0.11. */\n bodyFormat?: TemplateBodyFormat\n trackOpens: boolean\n trackClicks: boolean\n stats: {\n sent: number\n delivered: number\n opened: number\n clicked: number\n bounced: number\n complained: number\n unsubscribed: number\n lastSentAt: Date | null\n }\n publishedAt: Date | null\n publishedBy: string | null\n createdAt: Date\n updatedAt: Date\n}\n\nexport interface TemplateVersionDoc {\n _id?: ObjectId\n templateId: ObjectId\n version: number\n mjml: string\n html: string\n plainText: string\n subject: string\n preheader: string\n publishedAt: Date\n publishedBy: string\n}\n\nexport interface SendDoc {\n _id?: ObjectId\n dedupeKey: string\n externalId: string\n emailAtSend: string\n templateId: ObjectId\n templateSlug: string\n flowRunId: ObjectId | null\n broadcastId: ObjectId | null\n manualSendBy: string | null\n kind: TemplateKind\n provider: string\n providerMessageId: string | null\n fromName: string\n fromEmail: string\n subject: string\n bodyHash: string\n status: SendStatus\n errorMessage: string | null\n bounceType: 'hard' | 'soft' | null\n bounceReason: string | null\n /** Pre-send map: every rewritten link's linkId → original URL. Lookup target on click. */\n links: Array<{ linkId: string; url: string }>\n /** Render-time vars from the flow step or one-off send. Re-applied at dispatch. */\n vars: Record<string, unknown>\n openedAt: Date | null\n openCount: number\n /**\n * Per-open history, capped at the most recent `MAX_TRACKED_OPENS`. Exists so\n * the bot filter (`hasOpenedExcludingBots`) has something to filter on —\n * `openCount` alone cannot distinguish a scanner from a reader.\n *\n * `userAgent` is null when the requesting client sent no `User-Agent`, which\n * is common for image fetches; see `predicate.ts` for how unknown is scored.\n * Absent entirely on sends recorded before the field existed.\n */\n opens?: Array<{ openedAt: Date; userAgent: string | null }>\n firstClickAt: Date | null\n clickCount: number\n /** History of actual clicks (a linkId may appear multiple times). */\n clickedLinks: Array<{ url: string; linkId: string; clickedAt: Date; userAgent?: string | null }>\n unsubscribedAt: Date | null\n complainedAt: Date | null\n queuedAt: Date\n /** Last time the row was mutated; used by the stranded-send sweep. */\n updatedAt: Date\n sentAt: Date | null\n deliveredAt: Date | null\n}\n\nexport interface SuppressionDoc {\n _id?: ObjectId\n email: string | null\n emailHash: string\n scope: SuppressionScope\n reason: SuppressionReason\n source: string\n notes: string | null\n addedAt: Date\n expiresAt: Date | null\n}\n\nexport interface BroadcastDoc {\n _id?: ObjectId\n slug: string\n name: string\n templateSlug: string\n segmentDefinition: SegmentDefinition\n status: BroadcastStatus\n scheduledAt: Date | null\n startedAt: Date | null\n completedAt: Date | null\n confirmationRequired: boolean\n confirmedCount: number | null\n confirmedAt: Date | null\n confirmedBy: string | null\n recipientCount: number | null\n /** When true, dispatch fires each recipient at their local-timezone equivalent of `scheduledAt`. */\n respectRecipientTimezone?: boolean\n stats: {\n sent: number\n delivered: number\n opened: number\n clicked: number\n bounced: number\n complained: number\n unsubscribed: number\n }\n createdAt: Date\n createdBy: string\n updatedAt: Date\n}\n\nexport interface OutboxDoc {\n _id?: ObjectId\n payload: {\n type: 'event' | 'upsert_subscription' | 'unsubscribe'\n data: Record<string, unknown>\n dedupeKey: string\n }\n status: 'pending' | 'processed' | 'failed' | 'duplicate'\n attempts: number\n lastAttemptAt: Date | null\n lastError: string | null\n enqueuedAt: Date\n processedAt: Date | null\n}\n\nexport interface AuditLogDoc {\n _id?: ObjectId\n actor: string\n action: string\n resource: { collection: string; id?: ObjectId | string; slug?: string }\n before: Record<string, unknown> | null\n after: Record<string, unknown> | null\n diffSummary: string | null\n ip: string | null\n userAgent: string | null\n requestId: string | null\n occurredAt: Date\n}\n\nexport interface WebhookEventDoc {\n _id?: ObjectId\n provider: string\n providerEventId: string\n eventType: string\n normalizedType: 'delivered' | 'open' | 'click' | 'bounce' | 'complaint' | 'unsubscribe' | 'spam_report'\n providerMessageId: string\n email: string\n occurredAt: Date\n receivedAt: Date\n processed: boolean\n raw: unknown\n}\n\n/**\n * Health bucket. One doc per (senderDomain, kind) pair plus a single aggregate\n * doc with _id='agg' that rolls up everything.\n *\n * _id: 'agg' // cross-domain, cross-kind roll-up\n * _id: 'd:<senderDomain>|k:<kind>' // per-bucket\n *\n * The aggregate is informational only — it never trips. Trips live on\n * buckets so one subdomain tanking doesn't hold mail for the others.\n */\nexport interface HealthDoc {\n _id: string\n /** null on the aggregate doc, set on bucket docs. */\n senderDomain: string | null\n /** null on the aggregate doc, set on bucket docs. */\n kind: TemplateKind | null\n windowStartedAt: Date\n windowDurationMs: number\n counters: {\n sent: number\n delivered: number\n bounced: number\n hardBounced: number\n softBounced: number\n complained: number\n failedToSend: number\n }\n rates: {\n bounceRate: number\n hardBounceRate: number\n complaintRate: number\n failureRate: number\n }\n status: HealthStatus\n trippedAt: Date | null\n trippedReason: string | null\n manuallyResumedAt: Date | null\n updatedAt: Date\n}\n\nexport const HEALTH_AGG_ID = 'agg'\n\nexport function healthBucketId(senderDomain: string | null, kind: TemplateKind): string {\n return `d:${senderDomain ?? '_unknown'}|k:${kind}`\n}\n\nexport type PostmasterReputation = 'HIGH' | 'MEDIUM' | 'LOW' | 'BAD' | 'REPUTATION_CATEGORY_UNSPECIFIED'\n\n/**\n * One day's traffic stats for a domain from Google Postmaster Tools.\n * Stored per (domain, date) so we can chart trends.\n */\nexport interface PostmasterSnapshotDoc {\n _id?: ObjectId\n domain: string\n /** Reporting date in YYYY-MM-DD per Postmaster's stat day. */\n date: string\n domainReputation: PostmasterReputation | null\n ipReputations: Array<{ reputation: PostmasterReputation; ipCount: number }> | null\n userReportedSpamRatio: number | null\n spfSuccessRatio: number | null\n dkimSuccessRatio: number | null\n dmarcSuccessRatio: number | null\n outboundEncryptionRatio: number | null\n inboundEncryptionRatio: number | null\n deliveryErrors: Array<{ errorType: string; errorClass: string; errorRatio: number }> | null\n spammyFeedbackLoops: Array<{ id: string; spamRatio: number }> | null\n fetchedAt: Date\n}\n\nexport interface MailTesterFeedback {\n category: string\n severity: 'info' | 'warning' | 'error'\n message: string\n}\n\n/**\n * Cached Mail-Tester deliverability score for a given (template content)\n * fingerprint. Operators don't burn a credit re-running on identical\n * content within cacheHours.\n */\nexport interface MailTesterScoreDoc {\n _id?: ObjectId\n templateSlug: string\n /** Hash of bodyHash + subject + fromEmail — the cache key. */\n contentKey: string\n checkId: string\n score: number\n feedback: MailTesterFeedback[]\n rawSummary: string | null\n fetchedAt: Date\n expiresAt: Date\n}\n\nexport type DmarcPolicy = 'none' | 'quarantine' | 'reject'\nexport type DmarcAuthResult = 'pass' | 'fail' | 'softfail' | 'neutral' | 'temperror' | 'permerror' | 'none' | 'unknown'\n\n/**\n * One DMARC RUA aggregate report. Receivers (Google, Yahoo, Microsoft, etc.)\n * email one per day per sending domain. We store one DmarcReportDoc per\n * incoming report, plus one DmarcFailureDoc per non-aligned record row.\n */\nexport interface DmarcReportDoc {\n _id?: ObjectId\n reportId: string\n /** Reporting org, e.g. 'google.com', 'enterprise.protection.outlook.com'. */\n orgName: string\n /** Reporter contact email from <report_metadata>. */\n email: string\n /** The domain we publish DMARC for, from <policy_published><domain>. */\n domain: string\n policyP: DmarcPolicy\n /** % of mail subject to the policy (1-100). */\n policyPct: number\n /** Activity window the report covers. */\n rangeStart: Date\n rangeEnd: Date\n /** Sum of <count> across all records. */\n totalMessages: number\n /** Messages that passed DMARC (DKIM aligned OR SPF aligned). */\n passCount: number\n failCount: number\n receivedAt: Date\n}\n\n/**\n * One alignment-failing source × day. Composite key `(sourceIp, domain, day)`\n * lets us roll up \"this IP sent N misaligned messages over the past week.\"\n * Failures from multiple reports for the same key get counted once per\n * report (we de-dupe on reportId × sourceIp).\n */\nexport interface DmarcFailureDoc {\n _id?: ObjectId\n reportId: string\n domain: string\n sourceIp: string\n count: number\n headerFrom: string\n dkimResult: DmarcAuthResult\n spfResult: DmarcAuthResult\n dispositionApplied: 'none' | 'quarantine' | 'reject' | string\n /** YYYY-MM-DD bucket derived from the reporting window's mid-point. */\n day: string\n receivedAt: Date\n}\n\n/**\n * Operator-set DMARC source tag. Created/updated/deleted from the admin UI\n * so operators can mark \"this IP is our SendGrid\", \"this is Hubspot\", etc.\n * Merged with `MailerConfig.dmarc.knownSources` at read time — the config\n * version is read-only baseline, the collection is mutable runtime state.\n */\nexport interface DmarcSourceTagDoc {\n _id?: ObjectId\n ip: string\n label: string\n ignored: boolean\n setBy: string\n setAt: Date\n}\n\nexport type SndsFilterResult = 'GREEN' | 'YELLOW' | 'RED' | 'UNKNOWN'\n\n/**\n * One row from a Microsoft SNDS data export covering a single activity\n * window for one sending IP. Stored unique per (ip, activityStart) so\n * historical windows accumulate without re-writing.\n */\nexport interface SndsSnapshotDoc {\n _id?: ObjectId\n ip: string\n activityStart: Date\n activityEnd: Date\n rcptCommands: number\n dataCommands: number\n messageRecipients: number\n filterResult: SndsFilterResult\n /** 0-1 fraction. SNDS reports as \"<0.1%\", \"0.1-0.3%\", etc; we store the upper bound. null when unknown. */\n complaintRate: number | null\n trapMessageCount: number\n sampleHelo: string | null\n sampleMailFrom: string | null\n fetchedAt: Date\n}\n\nexport type DnsblResult = 'clean' | 'listed' | 'error'\nexport type DnsblTargetKind = 'domain' | 'ip'\n\n/**\n * Latest DNSBL check result per (target, list). Replaced in-place on each run\n * so the collection stays small. History (if needed later) lives in audit_log.\n */\nexport interface DnsblCheckDoc {\n _id?: ObjectId\n /** Domain (e.g. `mkt.example.com`) or dotted-quad IP (e.g. `203.0.113.5`). */\n target: string\n targetKind: DnsblTargetKind\n /** DNS suffix queried (e.g. `dbl.spamhaus.org`). */\n list: string\n /** Display label for the UI (e.g. `Spamhaus DBL`). */\n listLabel: string\n result: DnsblResult\n /** A records returned by the lookup, when listed. */\n returnCodes: string[]\n /** When result is 'error', the message; otherwise null. */\n errorMessage: string | null\n runAt: Date\n}\n\nexport interface ContactTagDoc {\n _id?: ObjectId\n externalId: string\n tag: string\n appliedBy: 'flow' | 'admin' | 'script' | 'import'\n appliedAt: Date\n}\n\n// ---------------------------------------------------------------------------\n// Collection factory\n// ---------------------------------------------------------------------------\n\nexport interface Collections {\n subscriptions: Collection<SubscriptionDoc>\n leads: Collection<LeadDoc>\n events: Collection<EventDoc>\n flows: Collection<FlowDoc>\n flowVersions: Collection<FlowVersionDoc>\n flowRuns: Collection<FlowRunDoc>\n templates: Collection<TemplateDoc>\n templateVersions: Collection<TemplateVersionDoc>\n sends: Collection<SendDoc>\n suppressions: Collection<SuppressionDoc>\n broadcasts: Collection<BroadcastDoc>\n outbox: Collection<OutboxDoc>\n auditLog: Collection<AuditLogDoc>\n webhookEvents: Collection<WebhookEventDoc>\n health: Collection<HealthDoc>\n contactTags: Collection<ContactTagDoc>\n dnsblChecks: Collection<DnsblCheckDoc>\n postmasterSnapshots: Collection<PostmasterSnapshotDoc>\n sndsSnapshots: Collection<SndsSnapshotDoc>\n dmarcReports: Collection<DmarcReportDoc>\n dmarcFailures: Collection<DmarcFailureDoc>\n dmarcSourceTags: Collection<DmarcSourceTagDoc>\n mailTesterScores: Collection<MailTesterScoreDoc>\n}\n\nexport function getCollections(db: Db, prefix = 'mailer_'): Collections {\n return {\n subscriptions: db.collection<SubscriptionDoc>(`${prefix}subscriptions`),\n leads: db.collection<LeadDoc>(`${prefix}leads`),\n events: db.collection<EventDoc>(`${prefix}events`),\n flows: db.collection<FlowDoc>(`${prefix}flows`),\n flowVersions: db.collection<FlowVersionDoc>(`${prefix}flow_versions`),\n flowRuns: db.collection<FlowRunDoc>(`${prefix}flow_runs`),\n templates: db.collection<TemplateDoc>(`${prefix}templates`),\n templateVersions: db.collection<TemplateVersionDoc>(`${prefix}template_versions`),\n sends: db.collection<SendDoc>(`${prefix}sends`),\n suppressions: db.collection<SuppressionDoc>(`${prefix}suppressions`),\n broadcasts: db.collection<BroadcastDoc>(`${prefix}broadcasts`),\n outbox: db.collection<OutboxDoc>(`${prefix}outbox`),\n auditLog: db.collection<AuditLogDoc>(`${prefix}audit_log`),\n webhookEvents: db.collection<WebhookEventDoc>(`${prefix}webhook_events`),\n health: db.collection<HealthDoc>(`${prefix}health`),\n contactTags: db.collection<ContactTagDoc>(`${prefix}contact_tags`),\n dnsblChecks: db.collection<DnsblCheckDoc>(`${prefix}dnsbl_checks`),\n postmasterSnapshots: db.collection<PostmasterSnapshotDoc>(`${prefix}postmaster_snapshots`),\n sndsSnapshots: db.collection<SndsSnapshotDoc>(`${prefix}snds_snapshots`),\n dmarcReports: db.collection<DmarcReportDoc>(`${prefix}dmarc_reports`),\n dmarcFailures: db.collection<DmarcFailureDoc>(`${prefix}dmarc_failures`),\n dmarcSourceTags: db.collection<DmarcSourceTagDoc>(`${prefix}dmarc_source_tags`),\n mailTesterScores: db.collection<MailTesterScoreDoc>(`${prefix}mail_tester_scores`),\n }\n}\n\n// ---------------------------------------------------------------------------\n// Index ensurer\n// ---------------------------------------------------------------------------\n\nexport async function ensureIndexes(db: Db, prefix = 'mailer_'): Promise<void> {\n const c = getCollections(db, prefix)\n\n await Promise.all([\n c.subscriptions.createIndexes([\n { key: { externalId: 1 }, unique: true },\n { key: { status: 1, unsubscribedAt: -1 } },\n ]),\n c.leads.createIndexes([\n { key: { email: 1 }, unique: true },\n { key: { status: 1, createdAt: -1 } },\n ]),\n c.events.createIndexes([\n { key: { dedupeKey: 1 }, unique: true },\n { key: { externalId: 1, occurredAt: -1 } },\n { key: { name: 1, occurredAt: -1 } },\n { key: { name: 1, createdAt: 1 } },\n { key: { externalId: 1, name: 1 } },\n ]),\n c.flows.createIndexes([\n { key: { slug: 1 }, unique: true },\n { key: { enabled: 1, 'trigger.type': 1, 'trigger.eventName': 1 } },\n ]),\n c.flowVersions.createIndexes([{ key: { flowId: 1, version: 1 }, unique: true }]),\n c.flowRuns.createIndexes([\n { key: { status: 1, nextActionAt: 1 } },\n { key: { externalId: 1, flowId: 1 } },\n { key: { flowId: 1, status: 1 } },\n {\n key: { flowId: 1, triggerDedupeKey: 1 },\n unique: true,\n partialFilterExpression: { triggerDedupeKey: { $type: 'string' } },\n },\n ]),\n c.templates.createIndexes([\n { key: { slug: 1 }, unique: true },\n { key: { tags: 1 } },\n { key: { kind: 1 } },\n ]),\n c.templateVersions.createIndexes([{ key: { templateId: 1, version: 1 }, unique: true }]),\n c.sends.createIndexes([\n { key: { dedupeKey: 1 }, unique: true },\n { key: { externalId: 1, sentAt: -1 } },\n { key: { templateId: 1, sentAt: -1 } },\n { key: { flowRunId: 1 }, sparse: true },\n { key: { broadcastId: 1 }, sparse: true },\n { key: { providerMessageId: 1 }, sparse: true },\n { key: { status: 1, queuedAt: 1 } },\n { key: { status: 1, updatedAt: 1 } },\n ]),\n c.suppressions.createIndexes([\n { key: { email: 1, scope: 1 }, unique: true, partialFilterExpression: { email: { $type: 'string' } } },\n { key: { emailHash: 1 } },\n { key: { addedAt: -1 } },\n ]),\n c.broadcasts.createIndexes([\n { key: { slug: 1 }, unique: true },\n { key: { status: 1, scheduledAt: 1 } },\n ]),\n c.outbox.createIndexes([\n { key: { status: 1, enqueuedAt: 1 } },\n { key: { 'payload.dedupeKey': 1 }, unique: true },\n ]),\n c.auditLog.createIndexes([\n { key: { occurredAt: -1 } },\n { key: { 'resource.collection': 1, 'resource.id': 1, occurredAt: -1 } },\n { key: { actor: 1, occurredAt: -1 } },\n ]),\n c.webhookEvents.createIndexes([\n { key: { provider: 1, providerEventId: 1 }, unique: true },\n { key: { providerMessageId: 1 } },\n { key: { processed: 1, receivedAt: 1 } },\n ]),\n c.contactTags.createIndexes([\n { key: { externalId: 1, tag: 1 }, unique: true },\n { key: { tag: 1 } },\n ]),\n c.health.createIndexes([\n { key: { senderDomain: 1, kind: 1 } },\n { key: { status: 1 } },\n // setup-status reads the most-recently-touched health doc as a heartbeat.\n { key: { updatedAt: -1 } },\n ]),\n c.dnsblChecks.createIndexes([\n { key: { target: 1, list: 1 }, unique: true },\n // Supports the admin /dnsbl GET sort: result asc, then target asc, list asc.\n { key: { result: 1, target: 1, list: 1 } },\n // TTL — stale rows for targets the operator removed disappear after\n // 60 days without manual cleanup. The puller refreshes runAt on\n // every active target so existing targets stay indefinitely.\n { key: { runAt: 1 }, expireAfterSeconds: 60 * 24 * 60 * 60 },\n ]),\n c.postmasterSnapshots.createIndexes([\n { key: { domain: 1, date: 1 }, unique: true },\n { key: { domain: 1, fetchedAt: -1 } },\n { key: { domainReputation: 1 } },\n ]),\n c.sndsSnapshots.createIndexes([\n { key: { ip: 1, activityStart: 1 }, unique: true },\n { key: { ip: 1, fetchedAt: -1 } },\n { key: { filterResult: 1 } },\n ]),\n c.dmarcReports.createIndexes([\n { key: { reportId: 1, orgName: 1 }, unique: true },\n { key: { domain: 1, rangeEnd: -1 } },\n // Cross-domain \"most recent reports\" queries scan a lot without this.\n { key: { rangeEnd: -1 } },\n { key: { receivedAt: -1 } },\n ]),\n c.dmarcFailures.createIndexes([\n { key: { reportId: 1, sourceIp: 1 }, unique: true },\n { key: { domain: 1, day: -1 } },\n { key: { sourceIp: 1, day: -1 } },\n { key: { receivedAt: 1 } }, // for retention pruning\n ]),\n c.dmarcSourceTags.createIndexes([\n { key: { ip: 1 }, unique: true },\n ]),\n c.mailTesterScores.createIndexes([\n { key: { contentKey: 1 }, unique: true },\n { key: { templateSlug: 1, fetchedAt: -1 } },\n // TTL — Mongo auto-deletes expired scores so we never serve stale data.\n { key: { expiresAt: 1 }, expireAfterSeconds: 0 },\n ]),\n ])\n\n // One-shot migrations — run after indexes are in place so any DELETE\n // plan can use them. Idempotent at MongoDB level (returns 0 when\n // nothing is there).\n await c.health.deleteOne({ _id: 'singleton' as any }).catch(() => {})\n}\n","/**\n * Event registry + dedupe-key policy. INVARIANT 1: every `mailer_events` row\n * has a unique dedupeKey. Callers either pass one or `mailer.registerEvent`\n * declares a policy and we derive it.\n */\n\nimport crypto from 'node:crypto'\n\nexport type DedupePolicy = 'once-per-contact' | 'once-per-day' | 'every-time'\n\nexport interface EventRegistration {\n name: string\n dedupePolicy: DedupePolicy\n}\n\nexport class EventRegistry {\n private readonly policies = new Map<string, DedupePolicy>()\n\n register(reg: EventRegistration): void {\n this.policies.set(reg.name, reg.dedupePolicy)\n }\n\n has(name: string): boolean {\n return this.policies.has(name)\n }\n\n policy(name: string): DedupePolicy | undefined {\n return this.policies.get(name)\n }\n\n list(): EventRegistration[] {\n return Array.from(this.policies, ([name, dedupePolicy]) => ({ name, dedupePolicy }))\n }\n\n /**\n * Derive a dedupeKey for an event call. Returns null when no policy is\n * registered AND no key was passed — caller should throw.\n */\n deriveKey(\n name: string,\n externalId: string,\n passedKey: string | undefined,\n now: Date,\n ): string | null {\n if (passedKey) return passedKey\n const policy = this.policies.get(name)\n if (!policy) return null\n\n switch (policy) {\n case 'once-per-contact':\n return `${externalId}:${name}`\n case 'once-per-day':\n return `${externalId}:${name}:${isoDay(now)}`\n case 'every-time':\n return `${externalId}:${name}:${randomId()}`\n }\n }\n}\n\nfunction isoDay(d: Date): string {\n return d.toISOString().slice(0, 10)\n}\n\nfunction randomId(): string {\n return crypto.randomBytes(8).toString('hex')\n}\n","/**\n * Guarded lookup into the provider map.\n *\n * `Mailer.providers` is a plain object literal (`Record<string, MailProvider>`),\n * so a bare `providers[name]` also resolves inherited `Object.prototype`\n * members: `constructor`, `toString`, `valueOf` and friends all return\n * something truthy, sail past an `if (!provider)` guard, and reach\n * `provider.send(...)` / `provider.verifyWebhook(...)` as a non-provider.\n * `__proto__` resolves to the prototype object itself.\n *\n * Two gates, because either alone is incomplete: `Object.hasOwn` rejects\n * inherited keys, and the shape check rejects an own key whose value was never\n * a provider (a host building the map from untyped JSON, say).\n *\n * The shape check requires the *whole* `MailProvider` method surface rather\n * than just the methods a given call site is about to use. The map is typed\n * `Record<string, MailProvider>`; a value missing any of them was never a\n * provider, and having one lookup answer the same way everywhere is worth more\n * than letting a half-built object through on the routes that happen not to\n * touch its missing half.\n *\n * Lives here — a leaf module next to `mailer.ts`, importing nothing but a type\n * — so the public router, the admin router and the send runner can all share\n * it without any of them importing each other and without a cycle through\n * `mailer.ts` (which imports the runner).\n */\n\nimport type { MailProvider } from '../shared/types.js'\n\n/** Methods that make a value a `MailProvider` rather than an arbitrary object. */\nconst PROVIDER_METHODS = ['send', 'verifyWebhook', 'parseWebhookEvents'] as const\n\nfunction isMailProvider(candidate: unknown): candidate is MailProvider {\n if (!candidate || typeof candidate !== 'object') return false\n const p = candidate as Partial<Record<(typeof PROVIDER_METHODS)[number], unknown>>\n return PROVIDER_METHODS.every((m) => typeof p[m] === 'function')\n}\n\n/**\n * Resolve `name` against `providers`, or `null` when it does not name a\n * registered provider. Never throws, and never returns something that isn't a\n * provider — callers can go straight to a method call on a non-null result.\n */\nexport function resolveProvider(\n providers: Record<string, MailProvider>,\n name: unknown,\n): MailProvider | null {\n if (typeof name !== 'string' || !Object.hasOwn(providers, name)) return null\n const candidate: unknown = providers[name]\n return isMailProvider(candidate) ? candidate : null\n}\n\n/**\n * Names that `resolveProvider` would actually resolve, sorted. For error\n * messages on admin-gated routes, where telling the operator what *is*\n * registered is the difference between a fixable report and a dead end.\n */\nexport function registeredProviderNames(providers: Record<string, MailProvider>): string[] {\n return Object.keys(providers)\n .filter((name) => resolveProvider(providers, name) !== null)\n .sort()\n}\n","/**\n * HMAC-signed tokens for unsubscribe + preference-center URLs.\n *\n * Format: base64url(payload) '.' base64url(hmac)\n * payload = JSON.stringify({ e: email, s: scope, x: expiresAtMs })\n * hmac = HMAC-SHA256(secret, payload)\n *\n * Tokens expire because long-lived signed URLs are a liability.\n */\n\nimport crypto from 'node:crypto'\nimport type { SuppressionScope } from '../shared/enums.js'\n\nexport interface UnsubscribeTokenPayload {\n email: string\n scope: SuppressionScope\n expiresAt: Date\n}\n\nexport function signUnsubscribeToken(\n payload: UnsubscribeTokenPayload,\n secret: string,\n): string {\n const body = JSON.stringify({\n e: payload.email.toLowerCase(),\n s: payload.scope,\n x: payload.expiresAt.getTime(),\n })\n const bodyB64 = b64url(Buffer.from(body, 'utf8'))\n const hmac = crypto.createHmac('sha256', secret).update(bodyB64).digest()\n return `${bodyB64}.${b64url(hmac)}`\n}\n\nexport function verifyUnsubscribeToken(\n token: string,\n secret: string,\n now: Date = new Date(),\n): UnsubscribeTokenPayload | null {\n const parts = token.split('.')\n if (parts.length !== 2) return null\n const [bodyB64, sigB64] = parts as [string, string]\n\n const expected = crypto.createHmac('sha256', secret).update(bodyB64).digest()\n let actual: Buffer\n try {\n actual = b64urlDecode(sigB64)\n } catch {\n return null\n }\n if (expected.length !== actual.length) return null\n if (!crypto.timingSafeEqual(expected, actual)) return null\n\n let body: { e?: string; s?: string; x?: number }\n try {\n body = JSON.parse(b64urlDecode(bodyB64).toString('utf8'))\n } catch {\n return null\n }\n if (!body.e || !body.s || typeof body.x !== 'number') return null\n if (body.x < now.getTime()) return null\n if (body.s !== 'all' && body.s !== 'marketing' && body.s !== 'transactional') return null\n\n return {\n email: body.e,\n scope: body.s,\n expiresAt: new Date(body.x),\n }\n}\n\n// ---------------------------------------------------------------------------\n// Tracking-URL signatures\n// ---------------------------------------------------------------------------\n\n/**\n * Scopes a tracking signature can be issued for. An allowlist, mirroring the\n * `k: 'doi'` discriminator on the DOI token: the scope is part of the signed\n * message, so an `/m/open` signature cannot be replayed as an `/m/click` one\n * even for the same send.\n */\nexport type TrackingScope = 'open' | 'click'\n\nconst TRACKING_SCOPES: readonly string[] = ['open', 'click']\n\n/**\n * Signature length in base64url characters. 12 chars = 72 bits of the\n * HMAC-SHA256 digest.\n *\n * Truncation is deliberate. These signatures are embedded in every link of\n * every email, and the pixel URL in particular is parsed by mail clients with\n * their own length quirks, so bytes are not free. 72 bits is far beyond what an\n * online forgery attack can reach: an attacker gets no oracle beyond \"the open\n * was counted\", each guess is a live HTTP request, and there is no offline\n * verification step. Nothing here is a bearer credential for anything except\n * \"this recipient was sent this mail\".\n */\nexport const TRACKING_SIG_LENGTH = 12\n\nexport interface TrackingTokenParams {\n sendId: string\n /** Present for `click` scope, absent for `open`. */\n linkId?: string\n}\n\n/**\n * The signed message. Versioned so a future format change (longer signature,\n * different digest) can be distinguished rather than silently mis-verified.\n * Components are joined with `:`, a character that appears in neither an\n * ObjectId hex string nor a `shortHash` linkId, so the encoding is unambiguous.\n */\nfunction trackingMessage(scope: TrackingScope, params: TrackingTokenParams): string {\n const tail = params.linkId === undefined ? '' : `:${params.linkId}`\n return `mailery.track.v1:${scope}:${params.sendId}${tail}`\n}\n\n/**\n * Sign a tracking URL. Returns `TRACKING_SIG_LENGTH` base64url characters.\n *\n * Keyed with `unsubscribeSecret` — the same secret the unsubscribe and DOI\n * tokens use, so there is exactly one secret to provision\n * (`MAILER_UNSUBSCRIBE_SECRET`) and one to rotate. The scope prefix keeps the\n * key domains separate.\n */\nexport function signTrackingToken(\n scope: TrackingScope,\n params: TrackingTokenParams,\n secret: string,\n): string {\n if (!TRACKING_SCOPES.includes(scope)) {\n throw new Error(`signTrackingToken: unknown scope ${String(scope)}`)\n }\n const mac = crypto.createHmac('sha256', secret).update(trackingMessage(scope, params)).digest()\n return b64url(mac).slice(0, TRACKING_SIG_LENGTH)\n}\n\n/**\n * Verify a tracking-URL signature in constant time.\n *\n * The length pre-check before `timingSafeEqual` is required, not defensive:\n * `crypto.timingSafeEqual` throws on mismatched lengths, and a thrown\n * verification is a rejection that leaks length through a different channel.\n * Same shape as `verifyUnsubscribeToken`.\n */\nexport function verifyTrackingToken(\n token: unknown,\n scope: TrackingScope,\n params: TrackingTokenParams,\n secret: string,\n): boolean {\n if (typeof token !== 'string') return false\n if (!TRACKING_SCOPES.includes(scope)) return false\n if (token.length !== TRACKING_SIG_LENGTH) return false\n const expected = Buffer.from(signTrackingToken(scope, params, secret), 'utf8')\n const actual = Buffer.from(token, 'utf8')\n if (expected.length !== actual.length) return false\n return crypto.timingSafeEqual(expected, actual)\n}\n\nfunction b64url(buf: Buffer): string {\n return buf.toString('base64').replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '')\n}\n\nfunction b64urlDecode(s: string): Buffer {\n const padded = s.replace(/-/g, '+').replace(/_/g, '/') + '==='.slice((s.length + 3) % 4)\n return Buffer.from(padded, 'base64')\n}\n\n/**\n * sha256 hex digest, used for storing email hashes (GDPR forget) and dedup helpers.\n */\nexport function sha256Hex(input: string): string {\n return crypto.createHash('sha256').update(input).digest('hex')\n}\n\n// ---------------------------------------------------------------------------\n// Double opt-in tokens\n// ---------------------------------------------------------------------------\n\nexport interface DoiTokenPayload {\n externalId: string\n expiresAt: Date\n}\n\n/**\n * Sign a DOI confirmation token. Same shape as the unsubscribe token, but\n * scoped to \"this externalId confirmed their subscription.\"\n */\nexport function signDoiToken(payload: DoiTokenPayload, secret: string): string {\n const body = JSON.stringify({\n i: payload.externalId,\n x: payload.expiresAt.getTime(),\n k: 'doi',\n })\n const bodyB64 = b64url(Buffer.from(body, 'utf8'))\n const hmac = crypto.createHmac('sha256', secret).update(bodyB64).digest()\n return `${bodyB64}.${b64url(hmac)}`\n}\n\nexport function verifyDoiToken(token: string, secret: string, now: Date = new Date()): DoiTokenPayload | null {\n const parts = token.split('.')\n if (parts.length !== 2) return null\n const [bodyB64, sigB64] = parts as [string, string]\n\n const expected = crypto.createHmac('sha256', secret).update(bodyB64).digest()\n let actual: Buffer\n try {\n actual = b64urlDecode(sigB64)\n } catch {\n return null\n }\n if (expected.length !== actual.length) return null\n if (!crypto.timingSafeEqual(expected, actual)) return null\n\n let body: { i?: string; x?: number; k?: string }\n try {\n body = JSON.parse(b64urlDecode(bodyB64).toString('utf8'))\n } catch {\n return null\n }\n if (!body.i || typeof body.x !== 'number' || body.k !== 'doi') return null\n if (body.x < now.getTime()) return null\n\n return { externalId: body.i, expiresAt: new Date(body.x) }\n}\n","/**\n * The one place an unsubscribe is written.\n *\n * Extracted from `Mailer.unsubscribe` so the tick drain\n * (`runner/pending-unsubs.ts`) can replay a journaled opt-out through exactly\n * the same two writes. A second copy of this logic is how a replayed\n * unsubscribe quietly stops matching the real one.\n *\n * Both writes are idempotent, which is what makes the drain safe to re-run:\n * - the suppression is a `$setOnInsert` upsert keyed on (email, scope), so\n * re-applying never rewrites `addedAt`/`source` of the original opt-out\n * - the subscription update is a `$set` to a terminal state\n */\n\nimport type { Collections } from './models/index.js'\nimport type { UnsubscribeInput } from '../shared/schemas.js'\nimport { sha256Hex } from './tokens.js'\n\n/**\n * Apply an unsubscribe: suppression row + subscription status.\n *\n * `input` must already be parsed by `unsubscribeInputSchema` — the caller owns\n * validation so this stays a pure write.\n */\nexport async function applyUnsubscribe(\n collections: Collections,\n input: UnsubscribeInput,\n now: Date = new Date(),\n): Promise<void> {\n const normalized = input.email\n\n await collections.suppressions.updateOne(\n { email: normalized, scope: input.scope },\n {\n $setOnInsert: {\n email: normalized,\n emailHash: sha256Hex(normalized),\n scope: input.scope,\n // mailer_suppressions canonical reason — see plans/02-data-model.md.\n reason: 'unsubscribed' as const,\n source: input.source,\n notes: input.notes ?? null,\n addedAt: now,\n expiresAt: null,\n },\n },\n { upsert: true },\n )\n\n await collections.subscriptions.updateOne(\n { emailAtSubscribe: normalized },\n {\n $set: {\n status: 'unsubscribed' as const,\n unsubscribedAt: now,\n unsubscribeReason: input.reason,\n updatedAt: now,\n },\n },\n )\n}\n","/**\n * BullMQ driver. Four named queues backed by Redis. Job-level `attempts`,\n * `backoff`, `delay`, and `jobId` pass through to BullMQ's native semantics.\n * Send rate limit is enforced via BullMQ's `limiter` option (Redis Lua script).\n */\n\nimport type { Queue, Worker } from 'bullmq'\nimport IORedis, { type RedisOptions as IORedisOptions } from 'ioredis'\n\nimport type { RedisOptions } from '../config.js'\nimport type {\n AddOptions,\n QueueAPI,\n QueueDriver,\n Queues,\n WorkerStartOptions,\n} from './types.js'\n\ninterface BullQueues {\n tick: Queue\n advance: Queue\n send: Queue\n webhook: Queue\n}\n\ninterface BullModule {\n Queue: typeof Queue\n Worker: typeof Worker\n}\n\nconst QUEUE_NAMES = {\n tick: 'mailer-tick',\n advance: 'mailer-advance',\n send: 'mailer-send',\n webhook: 'mailer-webhook',\n} as const\n\nexport class BullDriver implements QueueDriver {\n readonly queues: Queues\n private redis: IORedis\n private bullQueues: BullQueues\n private workers: { tick: Worker; advance: Worker; send: Worker; webhook: Worker } | null = null\n private bull: BullModule\n\n static async create(redisConfig: RedisOptions | IORedis, prefix?: string): Promise<BullDriver> {\n let bull: BullModule\n try {\n bull = (await import('bullmq')) as unknown as BullModule\n } catch {\n throw new Error(\n \"mailery: queue driver 'bull' requires the 'bullmq' peer dependency. Run `npm install bullmq ioredis`.\",\n )\n }\n if (prefix?.includes(':')) {\n throw new Error(\n `mailery: queue prefix \"${prefix}\" must not contain ':' — BullMQ uses it as the Redis key separator.`,\n )\n }\n const redis = isRedisLike(redisConfig) ? (redisConfig as IORedis) : connect(redisConfig as RedisOptions)\n return new BullDriver(bull, redis, prefix)\n }\n\n private prefix?: string\n\n private constructor(bull: BullModule, redis: IORedis, prefix?: string) {\n this.bull = bull\n this.redis = redis\n this.prefix = prefix\n // Bounded retention: completed/failed jobs must not accumulate in Redis\n // forever. Completed jobs also need to leave promptly so jobId-based\n // idempotent re-adds aren't dropped against a stale completed job.\n const opts = {\n connection: redis,\n prefix,\n defaultJobOptions: {\n removeOnComplete: { age: 24 * 3600, count: 1000 },\n removeOnFail: { age: 7 * 24 * 3600 },\n },\n }\n this.bullQueues = {\n tick: new bull.Queue(QUEUE_NAMES.tick, opts),\n advance: new bull.Queue(QUEUE_NAMES.advance, opts),\n send: new bull.Queue(QUEUE_NAMES.send, opts),\n webhook: new bull.Queue(QUEUE_NAMES.webhook, opts),\n }\n this.queues = {\n tick: adaptBullQueue(this.bullQueues.tick),\n advance: adaptBullQueue(this.bullQueues.advance),\n send: adaptBullQueue(this.bullQueues.send),\n webhook: adaptBullQueue(this.bullQueues.webhook),\n }\n }\n\n async scheduleRepeatingTick(intervalSeconds: number): Promise<void> {\n await (this.bullQueues.tick as any).upsertJobScheduler(\n 'mailer-tick-repeat',\n { every: intervalSeconds * 1000 },\n {\n name: 'tick',\n data: {},\n opts: { removeOnComplete: { count: 20 }, removeOnFail: { count: 50 } },\n },\n )\n }\n\n async startWorkers(opts: WorkerStartOptions): Promise<void> {\n if (this.workers) return\n // Workers must share the queues' prefix or they'd poll different keys.\n const base = { connection: this.redis, prefix: this.prefix }\n const { Worker } = this.bull\n\n const tick = new Worker(\n QUEUE_NAMES.tick,\n async (job: any) => opts.handlers.tick(job.data),\n { ...base, concurrency: 1 },\n )\n const advance = new Worker(\n QUEUE_NAMES.advance,\n async (job: any) => opts.handlers.advance(job.data),\n { ...base, concurrency: 10 },\n )\n const send = new Worker(\n QUEUE_NAMES.send,\n async (job: any) => opts.handlers.send(job.data),\n {\n ...base,\n concurrency: opts.concurrency.send,\n limiter: opts.sendRateLimit\n ? { max: opts.sendRateLimit.max, duration: opts.sendRateLimit.durationMs }\n : undefined,\n },\n )\n const webhook = new Worker(\n QUEUE_NAMES.webhook,\n async (job: any) => opts.handlers.webhook(job.data),\n { ...base, concurrency: 4 },\n )\n\n this.workers = { tick, advance, send, webhook }\n }\n\n async stopWorkers(): Promise<void> {\n if (!this.workers) return\n await Promise.all([\n this.workers.tick.close(),\n this.workers.advance.close(),\n this.workers.send.close(),\n this.workers.webhook.close(),\n ])\n this.workers = null\n }\n\n async close(): Promise<void> {\n await this.stopWorkers()\n await Promise.all([\n this.bullQueues.tick.close(),\n this.bullQueues.advance.close(),\n this.bullQueues.send.close(),\n this.bullQueues.webhook.close(),\n ])\n }\n}\n\nfunction adaptBullQueue(q: Queue): QueueAPI {\n return {\n add: (name, data, opts) => q.add(name, data as any, opts as any),\n getWaitingCount: () => q.getWaitingCount(),\n getInFlightCount: async () => {\n const [active, waiting] = await Promise.all([q.getActiveCount(), q.getWaitingCount()])\n return active + waiting\n },\n getDelayedCount: () => q.getDelayedCount(),\n close: () => q.close(),\n }\n}\n\nfunction isRedisLike(x: unknown): boolean {\n return !!x && typeof x === 'object' && typeof (x as any).get === 'function' && typeof (x as any).set === 'function'\n}\n\nfunction connect(opts: RedisOptions): IORedis {\n const config: IORedisOptions = {\n maxRetriesPerRequest: null, // BullMQ requirement\n enableReadyCheck: false,\n }\n if (opts.url) return new IORedis(opts.url, config)\n return new IORedis({\n ...config,\n host: opts.host ?? '127.0.0.1',\n port: opts.port ?? 6379,\n password: opts.password,\n db: opts.db,\n username: opts.username,\n tls: opts.tls ? {} : undefined,\n })\n}\n\n// Re-exports needed by the broader queue surface\nexport type { AddOptions }\n","/**\n * Agenda driver. Backed by the same MongoDB instance the rest of mailery uses,\n * so no Redis is required. Uses `agenda` + `@agendajs/mongo-backend`.\n *\n * Single-process only: send rate limit is enforced via an in-memory Bottleneck\n * wrapped around the send handler. Multi-process Agenda deployments would\n * fan-out beyond the rate cap — out of scope.\n *\n * Retry/backoff: applied per-definition via Agenda's built-in\n * `backoffStrategies.exponential`. Per-call `attempts` from add() is ignored;\n * the driver uses the shared config-level `sendRetryAttempts`.\n *\n * Idempotency: per-call `jobId` is stored as `data.__jobId`. Before scheduling\n * we look for a pending (not-yet-run, not-finished) job with the same key.\n *\n * Retention: Agenda keeps every job document forever by default, which for a\n * mailer means one doc per send/advance/webhook accumulating in Mongo without\n * bound. Succeeded one-shot jobs are removed on completion (`removeOnComplete`);\n * failed ones are swept on an interval, since Agenda's auto-remove only fires\n * on success. The repeating tick is a single document whose `nextRunAt` is\n * recomputed in place, so it is never a source of growth — and the sweep\n * explicitly skips repeating jobs so it can't delete it.\n */\n\nimport type { Db } from 'mongodb'\nimport type { Agenda, Job } from 'agenda'\nimport type Bottleneck from 'bottleneck'\n\nimport type {\n AddOptions,\n QueueAPI,\n QueueDriver,\n Queues,\n WorkerStartOptions,\n} from './types.js'\n\ninterface AgendaModule {\n Agenda: typeof Agenda\n backoffStrategies: { exponential: (opts: { delay: number; maxRetries: number; factor?: number }) => any }\n}\n\ninterface MongoBackendModule {\n MongoBackend: new (cfg: { mongo: Db; collection?: string; ensureIndex?: boolean }) => any\n}\n\ninterface BottleneckCtor {\n new (opts: { minTime?: number; maxConcurrent?: number }): Bottleneck\n}\n\nconst QUEUE_NAMES = {\n tick: 'mailer-tick',\n advance: 'mailer-advance',\n send: 'mailer-send',\n webhook: 'mailer-webhook',\n} as const\n\n/** Default jobs collection. Kept as-is when no prefix is configured. */\nconst DEFAULT_COLLECTION = '_mailerJobs'\n\n/** How long a failed job document is kept before the sweep deletes it. */\nconst DEFAULT_FAILED_RETENTION_DAYS = 7\n\n/** How often the failed-job sweep runs. */\nconst FAILED_SWEEP_INTERVAL_MS = 60 * 60 * 1000\n\nexport interface AgendaDriverOptions {\n db: Db\n processEverySeconds?: number\n lockLifetimeSeconds?: number\n collectionName?: string\n /**\n * Namespaces the jobs collection so multiple mailery instances can share one\n * Mongo database — the Agenda counterpart to the Bull driver's Redis key\n * prefix. Ignored when `collectionName` is given explicitly.\n */\n prefix?: string\n /** Days to keep failed job documents. 0 disables the sweep. */\n failedJobRetentionDays?: number\n}\n\nexport class AgendaDriver implements QueueDriver {\n readonly queues: Queues\n private agenda: Agenda\n private agendaMod: AgendaModule\n private sendLimiter: Bottleneck | null = null\n private started = false\n\n static async create(opts: AgendaDriverOptions): Promise<AgendaDriver> {\n let agendaMod: AgendaModule\n let backendMod: MongoBackendModule\n try {\n agendaMod = (await import('agenda')) as unknown as AgendaModule\n backendMod = (await import('@agendajs/mongo-backend')) as unknown as MongoBackendModule\n } catch {\n throw new Error(\n \"mailery: queue driver 'agenda' requires the 'agenda' and '@agendajs/mongo-backend' peer dependencies. Run `npm install agenda @agendajs/mongo-backend bottleneck`.\",\n )\n }\n\n const collectionName = opts.collectionName ?? collectionFor(opts.prefix)\n const backend = new backendMod.MongoBackend({\n mongo: opts.db,\n collection: collectionName,\n })\n\n const agenda = new agendaMod.Agenda({\n backend,\n processEvery: `${opts.processEverySeconds ?? 5} seconds`,\n defaultLockLifetime: (opts.lockLifetimeSeconds ?? 10 * 60) * 1000,\n maxConcurrency: 50,\n defaultConcurrency: 5,\n // Drop succeeded one-shot jobs instead of retaining them forever.\n // Agenda guards this on `!nextRunAt`, so repeating jobs survive.\n removeOnComplete: true,\n } as any)\n\n const retentionDays = opts.failedJobRetentionDays ?? DEFAULT_FAILED_RETENTION_DAYS\n\n // The sweep filters on failedAt; without an index it's a collection scan\n // every hour. Non-fatal — a driver that can't index still works.\n try {\n await opts.db.collection(collectionName).createIndex({ failedAt: 1 }, { sparse: true })\n } catch (err) {\n console.error('mailery: could not index the Agenda jobs collection on failedAt', err)\n }\n\n return new AgendaDriver(agenda, agendaMod, opts.db, collectionName, retentionDays)\n }\n\n private db: Db\n private collName: string\n private failedRetentionDays: number\n private sweepTimer: ReturnType<typeof setInterval> | null = null\n\n private constructor(\n agenda: Agenda,\n agendaMod: AgendaModule,\n db: Db,\n collectionName: string,\n failedRetentionDays: number,\n ) {\n this.agenda = agenda\n this.agendaMod = agendaMod\n this.db = db\n this.collName = collectionName\n this.failedRetentionDays = failedRetentionDays\n this.queues = {\n tick: this.makeQueueAPI(QUEUE_NAMES.tick),\n advance: this.makeQueueAPI(QUEUE_NAMES.advance),\n send: this.makeQueueAPI(QUEUE_NAMES.send),\n webhook: this.makeQueueAPI(QUEUE_NAMES.webhook),\n }\n }\n\n private makeQueueAPI(name: string): QueueAPI {\n return {\n add: async (_jobName: string, data: unknown, opts?: AddOptions) => {\n const payload: Record<string, unknown> = { ...(data as object) }\n if (opts?.jobId) {\n payload.__jobId = opts.jobId\n if (await this.findPending(name, opts.jobId)) return\n }\n const job = this.agenda.create(name, payload as any)\n if (opts?.delay) job.schedule(new Date(Date.now() + opts.delay))\n await job.save()\n },\n getWaitingCount: async () => {\n return this.jobsCollection().countDocuments({\n name,\n $or: [{ lockedAt: null }, { lockedAt: { $exists: false } }],\n nextRunAt: { $lte: new Date() },\n })\n },\n close: async () => {},\n }\n }\n\n /** Direct access to the Mongo collection Agenda persists jobs into. */\n private jobsCollection() {\n return this.db.collection(this.collName)\n }\n\n private async findPending(name: string, jobId: string): Promise<unknown> {\n return this.jobsCollection().findOne({\n name,\n 'data.__jobId': jobId,\n $or: [{ lastFinishedAt: null }, { lastFinishedAt: { $exists: false } }],\n })\n }\n\n async scheduleRepeatingTick(intervalSeconds: number): Promise<void> {\n // Persist the repeating job only — do NOT start Agenda here. Starting with\n // a placeholder tick handler would let a process that never calls\n // startWorkers (API-only process in a web/worker split) lock and complete\n // tick jobs as no-ops, silently swallowing real ticks. Agenda starts in\n // startWorkers, after the real handlers are defined.\n await this.agenda.every(`${intervalSeconds} seconds`, QUEUE_NAMES.tick)\n }\n\n async startWorkers(opts: WorkerStartOptions): Promise<void> {\n const exp = this.agendaMod.backoffStrategies.exponential\n\n if (opts.sendRateLimit) {\n try {\n const Bottleneck = (await import('bottleneck')).default as unknown as BottleneckCtor\n this.sendLimiter = new Bottleneck({\n minTime: Math.ceil(opts.sendRateLimit.durationMs / opts.sendRateLimit.max),\n maxConcurrent: opts.concurrency.send,\n })\n } catch {\n throw new Error(\n \"mailery: queue driver 'agenda' with sendRateLimit requires the 'bottleneck' peer dependency. Run `npm install bottleneck`.\",\n )\n }\n }\n\n const retryBackoff = exp({ delay: 60_000, maxRetries: Math.max(0, opts.retryAttempts - 1), factor: 2 })\n\n this.agenda.define(QUEUE_NAMES.tick, async (job: Job) => {\n await opts.handlers.tick(job.attrs.data)\n }, { concurrency: 1 })\n\n this.agenda.define(QUEUE_NAMES.advance, async (job: Job) => {\n await opts.handlers.advance(job.attrs.data as any)\n }, { concurrency: 10, backoff: retryBackoff })\n\n this.agenda.define(QUEUE_NAMES.send, async (job: Job) => {\n const data = job.attrs.data as any\n if (this.sendLimiter) {\n await this.sendLimiter.schedule(() => opts.handlers.send(data))\n } else {\n await opts.handlers.send(data)\n }\n }, { concurrency: opts.concurrency.send, backoff: retryBackoff })\n\n this.agenda.define(QUEUE_NAMES.webhook, async (job: Job) => {\n await opts.handlers.webhook(job.attrs.data as any)\n }, { concurrency: 4, backoff: retryBackoff })\n\n if (!this.started) {\n await this.agenda.start()\n this.started = true\n this.startFailedJobSweep()\n }\n }\n\n /**\n * Agenda's auto-remove only fires on success, so failed documents would\n * otherwise be retained forever. Runs once on worker start, then hourly.\n */\n private startFailedJobSweep(): void {\n if (this.failedRetentionDays <= 0 || this.sweepTimer) return\n void this.sweepFailedJobs()\n this.sweepTimer = setInterval(() => void this.sweepFailedJobs(), FAILED_SWEEP_INTERVAL_MS)\n // Don't hold the event loop open on an otherwise-idle process.\n this.sweepTimer.unref?.()\n }\n\n /** Delete failed, fully-retired job documents older than the retention window. */\n async sweepFailedJobs(): Promise<number> {\n const cutoff = new Date(Date.now() - this.failedRetentionDays * 24 * 3600 * 1000)\n try {\n const res = await this.jobsCollection().deleteMany({\n failedAt: { $lt: cutoff },\n // Never touch the repeating tick.\n repeatInterval: { $in: [null, undefined] },\n // Leave anything still scheduled for a retry, and anything a worker\n // currently holds a lock on.\n $and: [\n { $or: [{ nextRunAt: null }, { nextRunAt: { $exists: false } }, { nextRunAt: { $lt: cutoff } }] },\n { $or: [{ lockedAt: null }, { lockedAt: { $exists: false } }, { lockedAt: { $lt: cutoff } }] },\n ],\n })\n return res.deletedCount ?? 0\n } catch (err) {\n console.error('mailery: failed-job sweep failed', err)\n return 0\n }\n }\n\n async stopWorkers(): Promise<void> {\n if (this.sweepTimer) {\n clearInterval(this.sweepTimer)\n this.sweepTimer = null\n }\n if (!this.started) return\n await this.agenda.stop()\n this.started = false\n if (this.sendLimiter) {\n await this.sendLimiter.stop({ dropWaitingJobs: true }).catch(() => {})\n this.sendLimiter = null\n }\n }\n\n async close(): Promise<void> {\n await this.stopWorkers()\n }\n}\n\n/**\n * Resolve the jobs collection from an optional prefix. No prefix keeps the\n * historical `_mailerJobs` name — changing that default would strand queued\n * jobs in the old collection on upgrade.\n */\nexport function collectionFor(prefix?: string): string {\n if (!prefix) return DEFAULT_COLLECTION\n if (!/^[A-Za-z0-9_-]+$/.test(prefix)) {\n throw new Error(\n `mailery: queue prefix \"${prefix}\" must contain only letters, digits, '_' or '-' — it becomes part of a MongoDB collection name.`,\n )\n }\n return `${DEFAULT_COLLECTION}_${prefix}`\n}\n","/**\n * No-op queue driver. Used by tests and by hosts that drive the runner\n * synchronously (no background workers, no Redis, no Agenda). `add()` is a\n * no-op; the caller is expected to invoke runner functions directly.\n */\n\nimport type {\n QueueAPI,\n QueueDriver,\n Queues,\n WorkerStartOptions,\n} from './types.js'\n\nfunction noopQueueAPI(): QueueAPI {\n return {\n add: async () => undefined,\n getWaitingCount: async () => 0,\n close: async () => undefined,\n }\n}\n\nexport class NoopDriver implements QueueDriver {\n readonly queues: Queues = {\n tick: noopQueueAPI(),\n advance: noopQueueAPI(),\n send: noopQueueAPI(),\n webhook: noopQueueAPI(),\n }\n\n async scheduleRepeatingTick(_intervalSeconds: number): Promise<void> {\n /* noop */\n }\n\n async startWorkers(_opts: WorkerStartOptions): Promise<void> {\n /* noop */\n }\n\n async stopWorkers(): Promise<void> {\n /* noop */\n }\n\n async close(): Promise<void> {\n /* noop */\n }\n}\n","/**\n * Queue subsystem entry point. Exports the driver interface, the three\n * built-in drivers (Bull, Agenda, Noop), and a factory that resolves a\n * `QueueDriverConfig` to a concrete driver.\n */\n\nimport type { Db } from 'mongodb'\n\nimport { BullDriver } from './bull.js'\nimport { AgendaDriver } from './agenda.js'\nimport { NoopDriver } from './noop.js'\nimport type { QueueDriver, QueueDriverConfig } from './types.js'\n\nexport { BullDriver } from './bull.js'\nexport { AgendaDriver } from './agenda.js'\nexport { NoopDriver } from './noop.js'\nexport type {\n AddOptions,\n QueueAPI,\n QueueDriver,\n QueueDriverConfig,\n QueueHandlers,\n Queues,\n WorkerStartOptions,\n} from './types.js'\n\nexport async function createQueueDriver(\n config: QueueDriverConfig,\n fallbackDb: Db,\n): Promise<QueueDriver> {\n switch (config.driver) {\n case 'bull':\n return BullDriver.create(config.redis, config.prefix)\n case 'agenda':\n return AgendaDriver.create({\n db: config.db ?? fallbackDb,\n processEverySeconds: config.processEverySeconds,\n lockLifetimeSeconds: config.lockLifetimeSeconds,\n collectionName: config.collectionName,\n prefix: config.prefix,\n failedJobRetentionDays: config.failedJobRetentionDays,\n })\n case 'noop':\n return new NoopDriver()\n default: {\n const _exhaustive: never = config\n void _exhaustive\n throw new Error(`mailery: unknown queue driver`)\n }\n }\n}\n","/**\n * Event-trigger scan. Finds new event firings since each flow's\n * lastTriggerScanAt watermark, creates flow_runs for matching contacts,\n * enqueues immediate-advance jobs.\n */\n\nimport type { RunnerContext } from './index.js'\nimport type { FlowDoc, EventDoc } from '../models/index.js'\n\nconst BATCH_SIZE = 1000\n\n/**\n * Re-scan window. The watermark advances on `createdAt` (insert time), but a\n * concurrent `fire()` can commit a row with a createdAt slightly before the\n * scan's read. Re-reading this much history every pass closes that race; the\n * unique (flowId, triggerDedupeKey) index makes re-reads harmless.\n */\nexport const SCAN_OVERLAP_MS = 30_000\n\nexport async function processNewlyFiredEventTriggers(ctx: RunnerContext): Promise<void> {\n const flows = await ctx.collections.flows.find({ enabled: true, 'trigger.type': 'event' }).toArray()\n for (const flow of flows) {\n await processFlowTriggers(flow, ctx)\n }\n}\n\nasync function processFlowTriggers(flow: FlowDoc, ctx: RunnerContext): Promise<void> {\n const eventName = flow.trigger.eventName\n if (!eventName) return\n // Watermark on createdAt, not occurredAt: occurredAt can lag insert time\n // (outbox-drained events carry the host-transaction timestamp), so an\n // occurredAt watermark permanently skips any event that lands \"in the past.\"\n // createdAt only ever moves forward with inserts.\n const since = flow.lastTriggerScanAt ?? flow.createdAt\n const scanFrom = new Date(since.getTime() - SCAN_OVERLAP_MS)\n\n const events = await ctx.collections.events\n .find({ name: eventName, createdAt: { $gt: scanFrom } })\n .sort({ createdAt: 1 })\n .limit(BATCH_SIZE)\n .toArray()\n\n if (events.length === 0) return\n\n for (const event of events) {\n await tryEnterFlow(flow, event, ctx)\n }\n\n const newestCreatedAt = events[events.length - 1]!.createdAt\n if (newestCreatedAt.getTime() > since.getTime()) {\n await ctx.collections.flows.updateOne(\n { _id: flow._id },\n { $set: { lastTriggerScanAt: newestCreatedAt, updatedAt: new Date() } },\n )\n }\n}\n\nasync function tryEnterFlow(flow: FlowDoc, event: EventDoc, ctx: RunnerContext): Promise<void> {\n if (flow.trigger.once) {\n const existing = await ctx.collections.flowRuns.findOne(\n { externalId: event.externalId, flowId: flow._id },\n { projection: { _id: 1 } },\n )\n if (existing) return\n }\n\n // Flow entry requires an active subscription — flows are marketing-scope.\n // Transactional mail for not-subscribed contacts goes through sendOneOff.\n const sub = await ctx.collections.subscriptions.findOne({ externalId: event.externalId })\n if (!sub || sub.status !== 'subscribed') return\n\n let result\n try {\n result = await ctx.collections.flowRuns.insertOne({\n externalId: event.externalId,\n flowId: flow._id!,\n flowSlug: flow.slug,\n flowVersion: flow.version,\n emailAtEntry: sub.emailAtSubscribe,\n triggerEvent: { name: event.name, properties: event.properties ?? {}, occurredAt: event.occurredAt },\n triggerDedupeKey: event.dedupeKey,\n enteredAt: new Date(),\n status: 'active',\n currentStepIndex: 0,\n currentBranchPath: [],\n nextActionAt: new Date(),\n attemptsForCurrentStep: 0,\n history: [{ stepIndex: -1, action: 'entered', at: new Date(), details: { eventDedupeKey: event.dedupeKey } }],\n exitedAt: null,\n exitReason: null,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n } catch (err: any) {\n // Event already entered this flow (overlap-window re-read) — no-op.\n if (err?.code !== 11000) throw err\n return\n }\n\n await ctx.queues.advance.add('advance', { flowRunId: String(result.insertedId) })\n}\n","/**\n * Sender-domain validator.\n *\n * Hosts may declare a `senderDomains` registry mapping a domain to which kind\n * of email is allowed to send from it. Used to isolate marketing reputation\n * from transactional reputation:\n *\n * senderDomains: {\n * 'news.example.com': { kind: 'marketing' },\n * 'mail.example.com': { kind: 'transactional' },\n * 'tools.example.com': { kind: 'both' }, // OK for either kind\n * }\n *\n * The check runs at template publish time. If a template's `fromEmail` domain\n * isn't declared, or is declared for the wrong kind, publish fails with a\n * descriptive 400. Hosts who don't set `senderDomains` get no enforcement —\n * back-compat default.\n */\n\nimport type { TemplateKind } from '../../shared/enums.js'\n\nexport interface SenderDomainConfig {\n /** Which template `kind` may use this domain as a From address. */\n kind: 'marketing' | 'transactional' | 'both'\n}\n\nexport type SenderDomainRegistry = Record<string, SenderDomainConfig>\n\nexport type SenderDomainValidation =\n | { ok: true }\n | { ok: false; code: 'invalid_email' | 'unregistered_domain' | 'wrong_kind'; reason: string }\n\nexport function validateSenderDomain(\n fromEmail: string,\n templateKind: TemplateKind,\n registry: SenderDomainRegistry | undefined,\n): SenderDomainValidation {\n if (!registry || Object.keys(registry).length === 0) return { ok: true }\n\n const domain = extractDomain(fromEmail)\n if (!domain) {\n return {\n ok: false,\n code: 'invalid_email',\n reason: `invalid fromEmail \"${fromEmail}\" — expected \"name@domain\"`,\n }\n }\n\n const entry = registry[domain]\n if (!entry) {\n const known = Object.keys(registry).join(', ')\n return {\n ok: false,\n code: 'unregistered_domain',\n reason: `sender domain \"${domain}\" is not declared in senderDomains (allowed: ${known})`,\n }\n }\n\n if (entry.kind === 'both') return { ok: true }\n if (entry.kind !== templateKind) {\n return {\n ok: false,\n code: 'wrong_kind',\n reason: `sender domain \"${domain}\" is configured for ${entry.kind} email, but this template's kind is ${templateKind}`,\n }\n }\n\n return { ok: true }\n}\n\nexport function extractDomain(email: string): string | null {\n if (typeof email !== 'string') return null\n const at = email.lastIndexOf('@')\n if (at <= 0 || at === email.length - 1) return null\n return email.slice(at + 1).toLowerCase().trim()\n}\n","/**\n * Circuit breaker. Tracks rolling counters in mailer_health per\n * (senderDomain, kind) bucket plus a single aggregate roll-up. Computes rates\n * on each tick and trips individual buckets when thresholds are exceeded.\n *\n * status: 'healthy' — normal\n * 'degraded' — non-blocking warnings (e.g. high failed-to-send rate)\n * 'tripped' — marketing sends held; transactional bypasses (INVARIANT 6)\n *\n * The aggregate doc is informational only — it never trips. Trips live on\n * buckets so one subdomain tanking doesn't hold mail for the others.\n *\n * Recovery is manual (admin UI: POST /api/health/resume[?domain&kind]).\n */\n\nimport type { TemplateKind } from '../../shared/enums.js'\nimport type { HealthDoc } from '../models/index.js'\nimport { HEALTH_AGG_ID, healthBucketId } from '../models/index.js'\nimport { extractDomain } from '../templates/sender-domain.js'\nimport type { RunnerContext } from './index.js'\n\ntype CounterKey =\n | 'sent'\n | 'delivered'\n | 'bounced'\n | 'hardBounced'\n | 'softBounced'\n | 'complained'\n | 'failedToSend'\n\nexport interface HealthDims {\n /** Caller passes the raw `fromEmail`; we extract the domain here. */\n fromEmail: string | null\n kind: TemplateKind\n}\n\nconst ZERO_COUNTERS = {\n sent: 0,\n delivered: 0,\n bounced: 0,\n hardBounced: 0,\n softBounced: 0,\n complained: 0,\n failedToSend: 0,\n}\n\nconst ZERO_RATES = {\n bounceRate: 0,\n hardBounceRate: 0,\n complaintRate: 0,\n failureRate: 0,\n}\n\n/**\n * Bump a counter on the relevant bucket doc plus the aggregate doc. Called\n * from the send / webhook paths. Idempotent at the document level (upsert).\n *\n * `dims` is null when we can't attribute the event (e.g. webhook event with\n * no matching send) — in that case only the aggregate is updated.\n */\nexport async function recordHealthCounter(\n ctx: RunnerContext,\n counter: CounterKey,\n dims: HealthDims | null,\n by = 1,\n): Promise<void> {\n const windowMs = ctx.config.circuitBreaker.windowMinutes * 60 * 1000\n const writes: Array<Promise<unknown>> = []\n\n writes.push(upsertCounter(ctx, HEALTH_AGG_ID, null, null, counter, by, windowMs))\n\n if (dims) {\n // Skip the bucket write when we can't extract a real domain from\n // fromEmail rather than funneling unrelated invalid-sender sends into a\n // shared `_unknown` bucket — that bucket can collect bounces from many\n // unrelated sources and falsely trip them all at once.\n const domain = dims.fromEmail ? extractDomain(dims.fromEmail) : null\n if (domain) {\n const id = healthBucketId(domain, dims.kind)\n writes.push(upsertCounter(ctx, id, domain, dims.kind, counter, by, windowMs))\n }\n }\n\n await Promise.all(writes)\n}\n\nasync function upsertCounter(\n ctx: RunnerContext,\n _id: string,\n senderDomain: string | null,\n kind: TemplateKind | null,\n counter: CounterKey,\n by: number,\n windowMs: number,\n): Promise<void> {\n await ctx.collections.health.updateOne(\n { _id },\n {\n $inc: { [`counters.${counter}`]: by },\n $setOnInsert: {\n _id,\n senderDomain,\n kind,\n windowStartedAt: new Date(),\n windowDurationMs: windowMs,\n status: 'healthy',\n trippedAt: null,\n trippedReason: null,\n manuallyResumedAt: null,\n rates: { ...ZERO_RATES },\n } as Partial<HealthDoc>,\n $set: { updatedAt: new Date() },\n },\n { upsert: true },\n )\n}\n\n/**\n * Recompute rates from the rolling window for every bucket and trip individual\n * buckets when thresholds are exceeded. The aggregate doc is updated but never\n * tripped. Called from the tick.\n */\nexport async function evaluateHealth(ctx: RunnerContext): Promise<void> {\n const cb = ctx.config.circuitBreaker\n const windowMs = cb.windowMinutes * 60 * 1000\n\n const docs = await ctx.collections.health.find({}).toArray()\n if (docs.length === 0) return\n\n // Ensure the aggregate doc exists so the worker-heartbeat check has\n // something to look at as soon as any bucket exists.\n const hasAgg = docs.some((d) => d._id === HEALTH_AGG_ID)\n if (!hasAgg) {\n await upsertCounter(ctx, HEALTH_AGG_ID, null, null, 'sent', 0, windowMs)\n }\n\n for (const doc of docs) {\n const isAgg = doc._id === HEALTH_AGG_ID\n const windowAge = Date.now() - new Date(doc.windowStartedAt).getTime()\n\n if (windowAge > windowMs && doc.status !== 'tripped') {\n // Window roll: zero out counters AND reset status to healthy. A bucket\n // that was 'degraded' on the prior window but receives no samples in\n // the new window should not stay degraded — degraded is a function of\n // the current window's failureRate, not a sticky state.\n await ctx.collections.health.updateOne(\n { _id: doc._id },\n {\n $set: {\n windowStartedAt: new Date(),\n windowDurationMs: windowMs,\n counters: { ...ZERO_COUNTERS },\n rates: { ...ZERO_RATES },\n status: 'healthy',\n updatedAt: new Date(),\n },\n },\n )\n continue\n }\n\n const c = doc.counters\n const total = c.sent || 1\n const rates = {\n bounceRate: c.bounced / total,\n hardBounceRate: c.hardBounced / total,\n complaintRate: c.complained / total,\n failureRate: c.failedToSend / total,\n }\n\n await ctx.collections.health.updateOne(\n { _id: doc._id },\n { $set: { rates, updatedAt: new Date() } },\n )\n\n // Aggregate never trips, only reports.\n if (isAgg) continue\n\n if (c.sent < cb.minSendsBeforeEval) continue\n if (doc.status === 'tripped') continue\n\n let trippedReason: string | null = null\n if (rates.hardBounceRate * 100 >= cb.hardBounceRatePctTrip) {\n trippedReason = `hard bounce rate ${(rates.hardBounceRate * 100).toFixed(2)}% >= ${cb.hardBounceRatePctTrip}%`\n } else if (rates.complaintRate * 100 >= cb.complaintRatePctTrip) {\n trippedReason = `complaint rate ${(rates.complaintRate * 100).toFixed(2)}% >= ${cb.complaintRatePctTrip}%`\n } else if (rates.bounceRate * 100 >= cb.combinedBounceRatePctTrip) {\n trippedReason = `combined bounce rate ${(rates.bounceRate * 100).toFixed(2)}% >= ${cb.combinedBounceRatePctTrip}%`\n }\n\n if (trippedReason) {\n // Gate the trip write on the current non-tripped status so two\n // concurrent ticks can't both transition the same bucket. The\n // matchedCount check below tells us whether *this* tick was the one\n // that flipped it — only then do we fire the alert + audit log.\n const result = await ctx.collections.health.updateOne(\n { _id: doc._id, status: { $in: ['healthy', 'degraded'] } },\n { $set: { status: 'tripped', trippedAt: new Date(), trippedReason, updatedAt: new Date() } },\n )\n if (result.modifiedCount > 0) {\n // Audit log so the admin UI's \"Recent trips\" panel has rows to render.\n if (ctx.audit) {\n try {\n await ctx.audit({\n actor: 'system:circuit-breaker',\n action: 'health.trip',\n resource: {\n collection: 'mailer_health',\n id: String(doc._id),\n slug: `${doc.senderDomain ?? '_unknown'}|${doc.kind}`,\n },\n diffSummary: trippedReason,\n })\n } catch {\n /* swallow — audit failure must not block runner */\n }\n }\n if (ctx.config.onCircuitBreakerTrip) {\n try {\n await ctx.config.onCircuitBreakerTrip({\n reason: `[${doc.senderDomain ?? '_unknown'} / ${doc.kind}] ${trippedReason}`,\n rates,\n })\n } catch {\n /* swallow — alert hook failures don't propagate */\n }\n }\n }\n continue\n }\n\n if (rates.failureRate * 100 >= cb.failedToSendRatePctDegrade) {\n if (doc.status !== 'degraded') {\n await ctx.collections.health.updateOne(\n { _id: doc._id },\n { $set: { status: 'degraded', updatedAt: new Date() } },\n )\n }\n } else if (doc.status === 'degraded') {\n await ctx.collections.health.updateOne(\n { _id: doc._id },\n { $set: { status: 'healthy', updatedAt: new Date() } },\n )\n }\n }\n}\n\n/**\n * Look up the bucket status that gates a marketing send. Returns the\n * bucket doc when found, otherwise null (which the caller treats as healthy\n * — sends from a never-seen-before bucket flow through).\n */\nexport async function getBucketStatus(\n ctx: RunnerContext,\n fromEmail: string | null,\n kind: TemplateKind,\n): Promise<HealthDoc | null> {\n const domain = fromEmail ? extractDomain(fromEmail) : null\n const id = healthBucketId(domain, kind)\n return ctx.collections.health.findOne({ _id: id })\n}\n\n/**\n * Derive an effective overall status across all buckets. The aggregate doc\n * itself never trips, so callers that want a single \"is anything wrong\"\n * answer use this. Returns null when no buckets exist yet (no tick has run).\n */\nexport function effectiveOverallStatus(docs: HealthDoc[]): HealthDoc['status'] | null {\n // Only canonical bucket docs (id prefix 'd:') participate. The aggregate\n // never trips and a legacy 'singleton' doc, if it survives the migration,\n // is ignored.\n const buckets = docs.filter((d) => typeof d._id === 'string' && d._id.startsWith('d:'))\n if (buckets.length === 0) {\n return docs.length === 0 ? null : 'healthy'\n }\n if (buckets.some((d) => d.status === 'tripped')) return 'tripped'\n if (buckets.some((d) => d.status === 'degraded')) return 'degraded'\n return 'healthy'\n}\n","/**\n * Apply a normalized provider event to the corresponding Send + cascading\n * suppression / subscription updates. Called from the webhook worker.\n */\n\nimport type { NormalizedEvent } from '../../shared/types.js'\nimport type { SendDoc } from '../models/index.js'\nimport type { RunnerContext } from './index.js'\nimport { sha256Hex } from '../tokens.js'\nimport { recordHealthCounter, type HealthDims } from './health.js'\n\nfunction dimsFromSend(send: SendDoc | null | undefined): HealthDims | null {\n if (!send) return null\n return { fromEmail: send.fromEmail, kind: send.kind }\n}\n\n/**\n * Apply unprocessed rows from mailer_webhook_events. Called by the webhook\n * worker (no age filter) and by the tick as a fallback (`olderThanMs` set) for\n * events whose enqueue failed at ingest — those would otherwise sit unprocessed\n * until the next webhook happened to arrive. The tick's age filter keeps it out\n * of the webhook worker's way in the normal path.\n */\nexport async function processWebhookBacklog(\n ctx: RunnerContext,\n opts: { olderThanMs?: number } = {},\n): Promise<void> {\n const filter: Record<string, unknown> = { processed: false }\n if (opts.olderThanMs) {\n filter.receivedAt = { $lt: new Date(Date.now() - opts.olderThanMs) }\n }\n const batch = await ctx.collections.webhookEvents.find(filter).limit(500).toArray()\n\n for (const evt of batch) {\n // At-most-once: claim the event BEFORE applying. Concurrent workers scan\n // the same unprocessed batch; without the claim each would apply the same\n // event, double-counting bounces/complaints into the circuit-breaker\n // health counters. Losing an event to a crash mid-apply is the cheaper\n // failure mode.\n const claimed = await ctx.collections.webhookEvents.findOneAndUpdate(\n { _id: evt._id, processed: false },\n { $set: { processed: true } },\n )\n if (!claimed) continue\n\n try {\n // The stored `raw` wraps the normalized event we captured at ingest;\n // pull details back out so applyWebhookEvent has the bounce reason etc.\n const normalized = (evt.raw as any)?.normalized\n const details = normalized?.details ?? {}\n await applyWebhookEvent(\n {\n type: evt.normalizedType,\n providerEventId: evt.providerEventId,\n providerMessageId: evt.providerMessageId,\n email: evt.email,\n occurredAt: evt.occurredAt,\n details,\n },\n ctx,\n )\n } catch (err) {\n console.error('mailery: webhook apply failed', { id: String(evt._id), err })\n }\n }\n}\n\nexport async function applyWebhookEvent(event: NormalizedEvent, ctx: RunnerContext): Promise<void> {\n const send = await ctx.collections.sends.findOne(\n event.providerMessageId\n ? { $or: [{ providerMessageId: event.providerMessageId }, { emailAtSend: event.email }] }\n : { emailAtSend: event.email },\n { sort: { queuedAt: -1 } },\n )\n\n switch (event.type) {\n case 'delivered':\n if (send) {\n await ctx.collections.sends.updateOne(\n { _id: send._id },\n { $set: { status: 'delivered', deliveredAt: event.occurredAt } },\n )\n }\n await recordHealthCounter(ctx, 'delivered', dimsFromSend(send))\n break\n\n case 'open':\n if (send) {\n await ctx.collections.sends.updateOne(\n { _id: send._id },\n {\n $set: {\n openedAt: send.openedAt ?? event.occurredAt,\n status: send.status === 'sent' ? 'delivered' : send.status,\n },\n $inc: { openCount: 1 },\n },\n )\n }\n break\n\n case 'click':\n if (send) {\n await ctx.collections.sends.updateOne(\n { _id: send._id },\n {\n $set: { firstClickAt: send.firstClickAt ?? event.occurredAt },\n $inc: { clickCount: 1 },\n $push: {\n clickedLinks: {\n url: event.details.clickedUrl ?? '',\n linkId: '',\n clickedAt: event.occurredAt,\n },\n },\n },\n )\n }\n break\n\n case 'bounce': {\n const bounceType = event.details.bounceType ?? 'hard'\n if (send) {\n await ctx.collections.sends.updateOne(\n { _id: send._id },\n {\n $set: {\n status: 'bounced',\n bounceType,\n bounceReason: event.details.bounceReason ?? null,\n },\n },\n )\n }\n if (bounceType === 'hard') {\n await suppressOnce(ctx, event.email, 'hard_bounce', 'all')\n await ctx.collections.subscriptions.updateOne(\n { emailAtSubscribe: event.email },\n { $set: { status: 'bounced', updatedAt: new Date() } },\n )\n }\n {\n const dims = dimsFromSend(send)\n await recordHealthCounter(ctx, 'bounced', dims)\n await recordHealthCounter(ctx, bounceType === 'hard' ? 'hardBounced' : 'softBounced', dims)\n }\n break\n }\n\n case 'complaint':\n case 'spam_report':\n if (send) {\n await ctx.collections.sends.updateOne(\n { _id: send._id },\n { $set: { complainedAt: event.occurredAt, status: 'complained' } },\n )\n }\n await suppressOnce(ctx, event.email, 'complaint', 'all')\n await ctx.collections.subscriptions.updateOne(\n { emailAtSubscribe: event.email },\n { $set: { status: 'complained', updatedAt: new Date() } },\n )\n await recordHealthCounter(ctx, 'complained', dimsFromSend(send))\n break\n\n case 'unsubscribe':\n if (send) {\n await ctx.collections.sends.updateOne({ _id: send._id }, { $set: { unsubscribedAt: event.occurredAt } })\n }\n await suppressOnce(ctx, event.email, 'unsubscribed', 'marketing')\n await ctx.collections.subscriptions.updateOne(\n { emailAtSubscribe: event.email },\n {\n $set: {\n status: 'unsubscribed',\n unsubscribedAt: event.occurredAt,\n unsubscribeReason: 'user_request',\n updatedAt: new Date(),\n },\n },\n )\n break\n }\n}\n\nasync function suppressOnce(\n ctx: RunnerContext,\n email: string,\n reason: 'hard_bounce' | 'complaint' | 'unsubscribed',\n scope: 'all' | 'marketing' | 'transactional',\n): Promise<void> {\n const normalized = email.toLowerCase()\n await ctx.collections.suppressions.updateOne(\n { email: normalized, scope },\n {\n $setOnInsert: {\n email: normalized,\n emailHash: sha256Hex(normalized),\n scope,\n reason,\n source: 'provider_webhook',\n notes: null,\n addedAt: new Date(),\n expiresAt: null,\n },\n },\n { upsert: true },\n )\n}\n","/**\n * Predicate evaluator. Resolves all Predicate variants from `shared/types.ts`\n * against a Contact (host-side fields/tags) + mailer state (events, sends,\n * subscription).\n *\n * Network calls hit Mongo. Cache the Contact at the call site if you evaluate\n * many predicates in a row.\n */\n\nimport type { Contact, Predicate } from '../../shared/types.js'\nimport type { BotFilterConfig } from '../config.js'\nimport type { Collections, FlowRunDoc, SendDoc } from '../models/index.js'\n\nexport interface PredicateContext {\n contact: Contact\n run: FlowRunDoc\n collections: Collections\n now?: Date\n /**\n * Tuning for the `…ExcludingBots` / `…AtLeastN` predicates. Omit for the\n * defaults (`DEFAULT_BOT_UA_RE`, no timing filter).\n */\n botFilter?: BotFilterConfig\n}\n\n/**\n * User agents treated as automated unless the host overrides\n * `botFilter.userAgentPattern`. Deliberately short: these are the scanners that\n * announce themselves. Anything that impersonates a browser is not catchable\n * from the UA string and is out of scope here — see INVARIANT 7.\n */\nexport const DEFAULT_BOT_UA_RE = /Mimecast|SafeLinks|proofpoint|HeadlessChrome|Googlebot|bingbot/i\n\nexport async function evaluatePredicate(\n predicate: Predicate,\n ctx: PredicateContext,\n): Promise<boolean> {\n const p = predicate as any\n\n if ('hasTag' in p) return ctx.contact.tags.includes(p.hasTag)\n if ('notHasTag' in p) return !ctx.contact.tags.includes(p.notHasTag)\n\n if ('fieldEquals' in p) {\n return ctx.contact.fields[p.fieldEquals.field] === p.fieldEquals.value\n }\n if ('fieldExists' in p) {\n return ctx.contact.fields[p.fieldExists] !== undefined\n }\n\n // Read from the run's own trigger event, NOT the contact — two concurrent\n // runs for the same person can legitimately disagree here.\n if ('triggerPropertyEquals' in p) {\n return (\n (ctx.run.triggerEvent?.properties ?? {})[p.triggerPropertyEquals.key] ===\n p.triggerPropertyEquals.value\n )\n }\n if ('triggerPropertyTruthy' in p) {\n return Boolean((ctx.run.triggerEvent?.properties ?? {})[p.triggerPropertyTruthy])\n }\n\n if ('subscriptionStatus' in p) {\n const sub = await ctx.collections.subscriptions.findOne({ externalId: ctx.contact.externalId })\n return sub?.status === p.subscriptionStatus\n }\n\n if ('hasFiredEvent' in p) {\n return hasEvent(ctx, p.hasFiredEvent, { sinceFlowStart: p.sinceFlowStart, withinDays: p.withinDays })\n }\n if ('notHasFiredEvent' in p) {\n return !(await hasEvent(ctx, p.notHasFiredEvent, { withinDays: p.withinDays }))\n }\n\n if ('hasOpened' in p) return await openOrClickCount(ctx, 'opened', p.hasOpened, false) > 0\n if ('hasClicked' in p) return await openOrClickCount(ctx, 'clicked', p.hasClicked, false) > 0\n if ('hasOpenedExcludingBots' in p) return await openOrClickCount(ctx, 'opened', p.hasOpenedExcludingBots, true) > 0\n if ('hasClickedExcludingBots' in p) return await openOrClickCount(ctx, 'clicked', p.hasClickedExcludingBots, true) > 0\n if ('openedAtLeastN' in p) return await openOrClickCount(ctx, 'opened', p.openedAtLeastN, true) >= p.openedAtLeastN.count\n if ('clickedAtLeastN' in p) return await openOrClickCount(ctx, 'clicked', p.clickedAtLeastN, true) >= p.clickedAtLeastN.count\n\n if ('all' in p) {\n for (const sub of p.all) {\n if (!(await evaluatePredicate(sub, ctx))) return false\n }\n return true\n }\n if ('any' in p) {\n for (const sub of p.any) {\n if (await evaluatePredicate(sub, ctx)) return true\n }\n return false\n }\n if ('not' in p) {\n return !(await evaluatePredicate(p.not, ctx))\n }\n\n return false\n}\n\nasync function hasEvent(\n ctx: PredicateContext,\n name: string,\n opts: { sinceFlowStart?: boolean; withinDays?: number },\n): Promise<boolean> {\n const filter: any = { externalId: ctx.contact.externalId, name }\n const lower = effectiveLowerBound(ctx, opts)\n if (lower) filter.occurredAt = { $gt: lower }\n const found = await ctx.collections.events.findOne(filter, { projection: { _id: 1 } })\n return !!found\n}\n\nasync function openOrClickCount(\n ctx: PredicateContext,\n kind: 'opened' | 'clicked',\n opts: { templateSlug?: string; sinceFlowStart?: boolean; withinDays?: number },\n excludeBots: boolean,\n): Promise<number> {\n const filter: any = { externalId: ctx.contact.externalId }\n if (opts.templateSlug) filter.templateSlug = opts.templateSlug\n if (kind === 'opened') filter.openedAt = { $ne: null }\n if (kind === 'clicked') filter.firstClickAt = { $ne: null }\n const lower = effectiveLowerBound(ctx, opts)\n if (lower) filter[kind === 'opened' ? 'openedAt' : 'firstClickAt'] = { $gt: lower }\n\n if (!excludeBots) {\n return await ctx.collections.sends.countDocuments(filter)\n }\n\n // Bot filtering is best-effort by construction — see INVARIANT 7. A send\n // counts when at least one of its recorded opens (or clicks) looks human;\n // one scanner hit does not disqualify a send the recipient also read.\n const docs = await ctx.collections.sends.find(filter).limit(1000).toArray()\n const botRe = ctx.botFilter?.userAgentPattern ?? DEFAULT_BOT_UA_RE\n const minOpenDelayMs = ctx.botFilter?.minOpenDelayMs ?? 0\n let n = 0\n for (const s of docs) {\n const doc = s as SendDoc\n const human =\n kind === 'opened'\n ? hasHumanOpen(doc, botRe, minOpenDelayMs)\n : (doc.clickedLinks ?? []).some((c) => !isBotUserAgent(c.userAgent, botRe))\n if (human) n++\n }\n return n\n}\n\n/**\n * A user agent is \"bot\" only when it is present *and* matches the pattern.\n *\n * Unknown counts as human. That is the deliberate choice, and it is the same\n * one the click path has always made:\n *\n * - Image fetches frequently carry no `User-Agent` at all, and Apple Mail\n * Privacy Protection proxies strip identifying headers. Scoring unknown as\n * bot would drop a large share of genuine opens on the floor, silently.\n * - It preserves today's counts for sends recorded before user agents were\n * stored, so enabling this fix cannot retroactively empty a running flow.\n *\n * The cost is that a scanner which sends no UA still counts. Treating unknown\n * as bot would be the safer posture against forgery, but forgery is what the\n * URL signature is for; this filter's job is only to be honest about scanners\n * that identify themselves.\n */\nfunction isBotUserAgent(ua: string | null | undefined, botRe: RegExp): boolean {\n if (typeof ua !== 'string' || ua.trim() === '') return false\n return botRe.test(ua)\n}\n\n/**\n * Does this send have at least one open that looks like a person?\n *\n * Sends recorded before `opens[]` existed fall back to the single `openedAt`\n * timestamp with an unknown user agent — which, per the rule above, counts as\n * human. Legacy data therefore behaves exactly as it does today.\n */\nfunction hasHumanOpen(send: SendDoc, botRe: RegExp, minOpenDelayMs: number): boolean {\n const opens =\n send.opens && send.opens.length > 0\n ? send.opens\n : send.openedAt\n ? [{ openedAt: send.openedAt, userAgent: null }]\n : []\n return opens.some((o) => {\n if (isBotUserAgent(o.userAgent, botRe)) return false\n if (isPrefetchOpen(o.openedAt, send.queuedAt, minOpenDelayMs)) return false\n return true\n })\n}\n\n/**\n * Optional second signal (`botFilter.minOpenDelayMs`, default 0 = off): an open\n * that lands within a few seconds of the send being queued is a gateway\n * prefetch or a security scanner, not a reader.\n *\n * Off by default — a recipient who happens to be looking at their inbox when\n * the mail arrives is a real false positive, and turning it on silently changes\n * the numbers every existing flow branches on.\n */\nfunction isPrefetchOpen(openedAt: unknown, queuedAt: unknown, minOpenDelayMs: number): boolean {\n if (!minOpenDelayMs || minOpenDelayMs <= 0) return false\n if (!(openedAt instanceof Date) || !(queuedAt instanceof Date)) return false\n const delta = openedAt.getTime() - queuedAt.getTime()\n if (!Number.isFinite(delta) || delta < 0) return false\n return delta < minOpenDelayMs\n}\n\nfunction effectiveLowerBound(ctx: PredicateContext, opts: { sinceFlowStart?: boolean; withinDays?: number }): Date | null {\n const now = ctx.now ?? new Date()\n if (opts.sinceFlowStart) return ctx.run.enteredAt\n if (opts.withinDays && opts.withinDays > 0) {\n return new Date(now.getTime() - opts.withinDays * 24 * 60 * 60 * 1000)\n }\n return null\n}\n","/**\n * Delivery-window math. Pure — no I/O, no Date.now(); callers pass `now`.\n *\n * Given the moment a send step becomes runnable, `computeDeliveryTime`\n * returns the earliest instant the email is allowed to go out. It only ever\n * moves forward: a send already inside its window returns `now` unchanged.\n *\n * Timezone handling uses the Intl API (no dependency). DST transitions are\n * resolved with a two-pass offset fix; the worst case during a transition is\n * being off by the shifted hour, which is fine for email delivery.\n */\n\nimport type { DeliveryWindow } from '../../shared/types.js'\n\n/**\n * Ticks fire with jitter, so a send arriving shortly AFTER its timeOfDay slot\n * still goes out rather than waiting a full day.\n */\nconst TIME_OF_DAY_GRACE_MS = 60 * 60_000\n\nexport function computeDeliveryTime(\n now: Date,\n window: DeliveryWindow,\n contactTimezone?: string,\n): Date {\n const tz = pickTimezone(window, contactTimezone)\n let candidate = now\n\n if (window.timeOfDay) {\n const [hh, mm] = window.timeOfDay.split(':').map(Number) as [number, number]\n const local = localParts(candidate, tz)\n const todaySlot = utcFromLocal(local.y, local.mo, local.d, hh, mm, tz)\n if (candidate.getTime() < todaySlot.getTime()) {\n candidate = todaySlot\n } else if (candidate.getTime() - todaySlot.getTime() > TIME_OF_DAY_GRACE_MS) {\n const next = addLocalDays(local, 1)\n candidate = utcFromLocal(next.y, next.mo, next.d, hh, mm, tz)\n }\n // else: within grace of today's slot — send now.\n }\n\n if (window.weekdaysOnly) {\n for (let guard = 0; guard < 3; guard++) {\n const local = localParts(candidate, tz)\n if (local.weekday !== 'Sat' && local.weekday !== 'Sun') break\n const shift = local.weekday === 'Sat' ? 2 : 1\n const moved = addLocalDays(local, shift)\n // Preserve the local clock time (timeOfDay slot, or the wall-clock\n // moment the step became runnable).\n candidate = utcFromLocal(moved.y, moved.mo, moved.d, local.hh, local.mi, tz)\n }\n }\n\n return candidate\n}\n\nfunction pickTimezone(window: DeliveryWindow, contactTimezone?: string): string {\n const candidates = [\n window.useContactTimezone ? contactTimezone : undefined,\n window.timezone,\n 'UTC',\n ]\n for (const tz of candidates) {\n if (tz && isValidTimezone(tz)) return tz\n }\n return 'UTC'\n}\n\nconst validatedZones = new Map<string, boolean>()\n\nfunction isValidTimezone(tz: string): boolean {\n const cached = validatedZones.get(tz)\n if (cached !== undefined) return cached\n let ok = true\n try {\n new Intl.DateTimeFormat('en-US', { timeZone: tz })\n } catch {\n ok = false\n }\n validatedZones.set(tz, ok)\n return ok\n}\n\ninterface LocalParts {\n y: number\n mo: number\n d: number\n hh: number\n mi: number\n ss: number\n weekday: string // 'Mon'…'Sun'\n}\n\nconst partFormatters = new Map<string, Intl.DateTimeFormat>()\n\nfunction formatterFor(tz: string): Intl.DateTimeFormat {\n let f = partFormatters.get(tz)\n if (!f) {\n f = new Intl.DateTimeFormat('en-US', {\n timeZone: tz,\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n weekday: 'short',\n hour12: false,\n })\n partFormatters.set(tz, f)\n }\n return f\n}\n\nfunction localParts(date: Date, tz: string): LocalParts {\n const parts: Record<string, string> = {}\n for (const p of formatterFor(tz).formatToParts(date)) parts[p.type] = p.value\n return {\n y: Number(parts.year),\n mo: Number(parts.month),\n d: Number(parts.day),\n hh: Number(parts.hour) % 24, // Intl emits '24' for midnight in some locales\n mi: Number(parts.minute),\n ss: Number(parts.second),\n weekday: parts.weekday!,\n }\n}\n\n/** UTC instant for a wall-clock time in `tz`. Two passes to converge across DST. */\nfunction utcFromLocal(y: number, mo: number, d: number, hh: number, mi: number, tz: string): Date {\n let ts = Date.UTC(y, mo - 1, d, hh, mi, 0)\n for (let i = 0; i < 2; i++) {\n const p = localParts(new Date(ts), tz)\n const asUtc = Date.UTC(p.y, p.mo - 1, p.d, p.hh, p.mi, p.ss)\n const offset = asUtc - ts\n ts = Date.UTC(y, mo - 1, d, hh, mi, 0) - offset\n }\n return new Date(ts)\n}\n\n/** Add days to a local calendar date (normalizes month/year rollover). */\nfunction addLocalDays(p: LocalParts, days: number): { y: number; mo: number; d: number } {\n const dt = new Date(Date.UTC(p.y, p.mo - 1, p.d + days))\n return { y: dt.getUTCFullYear(), mo: dt.getUTCMonth() + 1, d: dt.getUTCDate() }\n}\n","/**\n * Template render pipeline.\n *\n * authorMjml + handlebarsContext\n * ↓ Handlebars render → MJML with substituted vars\n * ↓ mjml-core compile → HTML\n * ↓ html-to-text derive → plain text alternative\n * ↓ applyTracking(sendId) → tracked HTML with rewritten links + open pixel\n *\n * Subject and preheader run through Handlebars too. Plain text is auto-derived\n * unless the template explicitly overrides it.\n */\n\nimport crypto from 'node:crypto'\nimport Handlebars from 'handlebars'\nimport { convert as htmlToText } from 'html-to-text'\nimport mjml2html from 'mjml'\n\nimport type { Contact } from '../../shared/types.js'\nimport type { TemplateDoc } from '../models/index.js'\nimport { signTrackingToken } from '../tokens.js'\n\n// ---------------------------------------------------------------------------\n// Compile (publish-time)\n// ---------------------------------------------------------------------------\n\nexport interface CompileResult {\n html: string\n plainText: string\n errors: Array<{ line?: number; message: string; tagName?: string; formattedMessage?: string }>\n}\n\n/** Compile MJML → HTML, then derive plain text. Called at template publish time. */\nexport async function compileTemplate(mjml: string): Promise<CompileResult> {\n const out = await mjml2html(mjml, { validationLevel: 'soft', minify: false })\n const plainText = derivePlaintext(out.html)\n return { html: out.html, plainText, errors: out.errors ?? [] }\n}\n\n/**\n * Compile Maily editor JSON (Tiptap-shape) → HTML via `@maily-to/render`, then\n * derive plain text. Called at template publish time when the template was\n * authored via the WYSIWYG editor.\n */\nexport async function compileMailyTemplate(content: unknown): Promise<CompileResult> {\n const { render } = await import('@maily-to/render')\n const html = await render(content as any)\n const plainText = derivePlaintext(html)\n return { html, plainText, errors: [] }\n}\n\n/** Auto-derive plain text from compiled HTML. */\nexport function derivePlaintext(html: string): string {\n return htmlToText(html, {\n wordwrap: 80,\n selectors: [\n { selector: 'img', format: 'skip' },\n { selector: 'a', options: { hideLinkHrefIfSameAsText: true } },\n ],\n }).trim()\n}\n\n// ---------------------------------------------------------------------------\n// Render (send-time)\n// ---------------------------------------------------------------------------\n\nexport interface RenderContext {\n /**\n * Host-resolved variables (varsAdapter) live at the context root, so a\n * schema key `user` renders as `{{user.name}}`. Reserved keys below always\n * win over resolved keys.\n */\n [resolvedVar: string]: unknown\n contact: Contact\n vars: Record<string, unknown>\n /** Properties of the event that triggered the flow run ({{event.*}}). Empty outside flow sends. */\n event?: Record<string, unknown>\n /** URL the recipient hits to one-click unsubscribe. */\n unsubscribeUrl: string\n /** URL to view this email in a browser (when implemented). */\n viewInBrowserUrl?: string\n /** URL for the preference center (when implemented). */\n preferenceCenterUrl?: string\n /** Configured sender postal address (CAN-SPAM). */\n senderAddress?: string\n}\n\nexport interface RenderedTemplate {\n subject: string\n preheader: string\n html: string\n plainText: string\n fromName: string\n fromEmail: string\n replyTo: string | null\n}\n\nexport interface RenderOptions {\n /** Extra Handlebars helpers contributed by the host. */\n helpers?: Record<string, Handlebars.HelperDelegate>\n}\n\n/**\n * Compile options for the text/plain alternative, which is not HTML and has\n * nothing downstream to decode entities. Handlebars' default escaping is\n * corruption there rather than safety: a substituted URL ships as\n * `https://host/p?u&#x3D;123&amp;token&#x3D;abc`, which mail clients render\n * literally, so the recipient follows a link whose query string has fallen\n * apart — every param after the first silently lost. `{{ }}` still\n * interpolates; it just stops escaping what it substitutes.\n */\nconst PLAIN_TEXT: CompileOptions = { noEscape: true }\n\n/**\n * Render a published template against a contact + vars context. Returns the\n * substituted subject/preheader/html/plainText. Tracking is NOT applied here —\n * that step needs the send id and runs separately via `applyTracking`.\n */\nexport async function renderTemplate(\n template: TemplateDoc,\n ctx: RenderContext,\n opts: RenderOptions = {},\n): Promise<RenderedTemplate> {\n const hb = makeHandlebars(opts.helpers)\n\n // Both stay escaped: the preheader is injected into the HTML body, and the\n // subject reaches HTML surfaces (admin lists, previews) that render it.\n const subject = hb.compile(template.subject)(ctx)\n const preheader = hb.compile(template.preheader)(ctx)\n\n // Prefer the compiled HTML if present; fall back to compiling MJML on the fly.\n let html: string\n if (template.body.html) {\n html = hb.compile(template.body.html)(ctx)\n } else {\n const compiled = await compileTemplate(template.body.mjml)\n html = hb.compile(compiled.html)(ctx)\n }\n\n const plainText = template.body.plainText\n ? hb.compile(template.body.plainText, PLAIN_TEXT)(ctx)\n : derivePlaintext(html)\n\n return {\n subject,\n preheader,\n html,\n plainText,\n fromName: template.fromName,\n fromEmail: template.fromEmail,\n replyTo: template.replyTo,\n }\n}\n\n// ---------------------------------------------------------------------------\n// Tracking application\n// ---------------------------------------------------------------------------\n\nexport interface TrackingOptions {\n sendId: string\n publicUrl: string\n trackOpens: boolean\n trackClicks: boolean\n /** URL that must NOT be rewritten (e.g. the resolved unsubscribe URL). */\n preserveUrls?: string[]\n /**\n * HMAC key for tracking-URL signatures — pass `config.unsubscribeSecret`.\n *\n * When set, every generated `/m/open` and `/m/click` URL carries a truncated\n * HMAC so it cannot be forged or enumerated from a neighbouring ObjectId.\n * When omitted the legacy unsigned shape is emitted; that path exists for\n * preview/test renders that never reach the tracking endpoints, not as a\n * supported production mode.\n */\n signingSecret?: string\n}\n\nexport interface TrackingResult {\n html: string\n /** linkId → original URL map; persist on `mailer_sends.links` for click resolution. */\n links: Array<{ linkId: string; url: string }>\n}\n\n/**\n * Rewrite `<a href>` in `html` to /m/click/<sendId>/<linkId>/<sig> and append\n * an open pixel at /m/open/<sendId>.<sig>.png. Returns the modified HTML plus\n * the link map to persist on the send document.\n *\n * The `<sig>` components are 12-character truncated HMACs (see\n * `signTrackingToken`) and are present whenever `opts.signingSecret` is set.\n * Without them a Mongo ObjectId is the only thing standing between an attacker\n * and a forged open — and ObjectIds are a timestamp plus a per-process counter,\n * so one received email hands out its neighbours.\n */\nexport function applyTracking(html: string, opts: TrackingOptions): TrackingResult {\n const preserve = new Set((opts.preserveUrls ?? []).map((u) => u.trim()))\n const links: Array<{ linkId: string; url: string }> = []\n const seen = new Map<string, string>() // url → linkId\n\n let out = html\n\n if (opts.trackClicks) {\n out = out.replace(/<a\\b([^>]*?)\\bhref=([\"'])([^\"']+)\\2([^>]*)>/gi, (full, pre, _q, rawUrl, post) => {\n // Handlebars `{{ }}` escapes substituted URLs (& → &amp;, = → &#x3D;). That is\n // correct in HTML source, but the stored/redirect URL must be the decoded one.\n const url = decodeHtmlEntities(rawUrl)\n if (shouldSkipClickRewrite(url, preserve, full)) return full\n let linkId = seen.get(url)\n if (!linkId) {\n linkId = shortHash(`${opts.sendId}:${url}:${links.length}`)\n seen.set(url, linkId)\n links.push({ linkId, url })\n }\n const sig = opts.signingSecret\n ? `/${signTrackingToken('click', { sendId: opts.sendId, linkId }, opts.signingSecret)}`\n : ''\n const newHref = `${opts.publicUrl}/m/click/${opts.sendId}/${linkId}${sig}`\n return `<a${pre}href=\"${newHref}\"${post}>`\n })\n }\n\n if (opts.trackOpens) {\n const sig = opts.signingSecret\n ? `.${signTrackingToken('open', { sendId: opts.sendId }, opts.signingSecret)}`\n : ''\n const pixel = `<img src=\"${opts.publicUrl}/m/open/${opts.sendId}${sig}.png\" width=\"1\" height=\"1\" alt=\"\" style=\"display:block;border:0\" />`\n if (/<\\/body>/i.test(out)) {\n out = out.replace(/<\\/body>/i, `${pixel}</body>`)\n } else {\n out = out + pixel\n }\n }\n\n return { html: out, links }\n}\n\nfunction shouldSkipClickRewrite(url: string, preserve: Set<string>, fullTag: string): boolean {\n if (!url) return true\n if (url.startsWith('#')) return true\n if (url.startsWith('{{') || url.startsWith('{')) return true // unrendered handlebars\n if (preserve.has(url.trim())) return true\n if (/data-mailer-notrack=[\"']true[\"']/.test(fullTag)) return true\n // Defence in depth for the click redirect (which validates the scheme again\n // at redirect time): an href whose scheme isn't http(s) is left exactly as\n // authored, gets no linkId, and is therefore never stored on the send and\n // never becomes a `/m/click/…` URL. Covers `mailto:` and `tel:` — which were\n // already skipped by name — and everything else, including a `javascript:`\n // that arrived via a substituted Handlebars variable.\n //\n // A malformed href is skipped, never thrown on: one bad variable in one link\n // must not fail the render and block the whole send.\n if (!isHttpUrl(url)) return true\n return false\n}\n\n/** True only for an absolute `http:`/`https:` URL. Anything unparseable is false. */\nfunction isHttpUrl(url: string): boolean {\n let parsed: URL\n try {\n parsed = new URL(url.trim())\n } catch {\n return false\n }\n return parsed.protocol === 'http:' || parsed.protocol === 'https:'\n}\n\nconst NAMED_ENTITIES: Record<string, string> = {\n amp: '&',\n lt: '<',\n gt: '>',\n quot: '\"',\n apos: \"'\",\n nbsp: ' ',\n}\n\n/**\n * Decode the HTML entities Handlebars' escapeExpression emits (plus numeric\n * forms), so a captured href round-trips to the URL the browser would request.\n * `&amp;` is decoded last-wins via a single pass so `&amp;lt;` stays `&lt;`.\n */\nfunction decodeHtmlEntities(input: string): string {\n return input.replace(/&(#x[0-9a-f]+|#\\d+|[a-z][a-z0-9]*);/gi, (match, body: string) => {\n if (body[0] === '#') {\n const code =\n body[1] === 'x' || body[1] === 'X'\n ? parseInt(body.slice(2), 16)\n : parseInt(body.slice(1), 10)\n if (!Number.isFinite(code) || code < 0 || code > 0x10ffff) return match\n try {\n return String.fromCodePoint(code)\n } catch {\n return match\n }\n }\n const named = NAMED_ENTITIES[body.toLowerCase()]\n return named ?? match\n })\n}\n\nfunction shortHash(input: string): string {\n return crypto.createHash('sha256').update(input).digest('hex').slice(0, 12)\n}\n\n// ---------------------------------------------------------------------------\n// Handlebars instance + helpers\n// ---------------------------------------------------------------------------\n\nfunction makeHandlebars(extra?: Record<string, Handlebars.HelperDelegate>): typeof Handlebars {\n const hb = Handlebars.create()\n\n hb.registerHelper('eq', (a: unknown, b: unknown) => a === b)\n hb.registerHelper('ne', (a: unknown, b: unknown) => a !== b)\n hb.registerHelper('gt', (a: any, b: any) => a > b)\n hb.registerHelper('lt', (a: any, b: any) => a < b)\n hb.registerHelper('gte', (a: any, b: any) => a >= b)\n hb.registerHelper('lte', (a: any, b: any) => a <= b)\n hb.registerHelper('and', (...args: any[]) => args.slice(0, -1).every(Boolean))\n hb.registerHelper('or', (...args: any[]) => args.slice(0, -1).some(Boolean))\n hb.registerHelper('not', (a: unknown) => !a)\n\n hb.registerHelper('formatDate', (value: unknown, fmt?: string) => {\n if (!value) return ''\n const d = value instanceof Date ? value : new Date(String(value))\n if (Number.isNaN(d.getTime())) return ''\n if (fmt === 'long') return d.toLocaleDateString('en-US', { dateStyle: 'long' })\n if (fmt === 'short') return d.toLocaleDateString('en-US', { dateStyle: 'short' })\n return d.toISOString().slice(0, 10)\n })\n\n hb.registerHelper('formatNumber', (n: unknown) => {\n const v = Number(n)\n return Number.isFinite(v) ? v.toLocaleString('en-US') : ''\n })\n\n hb.registerHelper('formatCurrency', (cents: unknown, currency: string = 'usd') => {\n const v = Number(cents)\n if (!Number.isFinite(v)) return ''\n return new Intl.NumberFormat('en-US', { style: 'currency', currency }).format(v / 100)\n })\n\n hb.registerHelper('pluralize', (n: unknown, one: string, many: string) =>\n Number(n) === 1 ? one : many,\n )\n\n if (extra) {\n for (const [name, fn] of Object.entries(extra)) {\n hb.registerHelper(name, fn)\n }\n }\n\n return hb\n}\n\nexport { makeHandlebars }\n","/**\n * Send pipeline. `handleSend` is called by the runner state machine; it creates\n * the Send document and enqueues a mailer:send job. `dispatchSend` is the\n * worker — re-checks suppression + circuit breaker, applies tracking, calls\n * the provider, updates the Send row.\n */\n\nimport crypto from 'node:crypto'\nimport { ObjectId } from 'mongodb'\n\nimport type { Contact, FlowStep } from '../../shared/types.js'\nimport type { FlowRunDoc, FlowDoc, SendDoc, TemplateDoc } from '../models/index.js'\nimport {\n applyTracking,\n renderTemplate,\n type RenderContext,\n} from '../templates/render.js'\nimport { signUnsubscribeToken } from '../tokens.js'\nimport { registeredProviderNames, resolveProvider } from '../provider-lookup.js'\nimport { resolveVars } from '../adapters/vars.js'\nimport { isSuppressed } from './suppression.js'\nimport { advanceStep, failFlowRun } from './step.js'\nimport { getBucketStatus, recordHealthCounter } from './health.js'\nimport type { RunnerContext } from './index.js'\n\nexport async function handleSend(\n run: FlowRunDoc,\n step: Extract<FlowStep, { type: 'send' }>,\n contact: Contact,\n flow: FlowDoc,\n ctx: RunnerContext,\n): Promise<void> {\n const template = await ctx.collections.templates.findOne({ slug: step.templateSlug })\n if (!template) {\n await failFlowRun(run, `template not found: ${step.templateSlug}`, ctx)\n return\n }\n\n const dedupeKey = `flowrun:${run._id}:step${run.currentStepIndex}`\n\n // Idempotency: has this exact step already produced a send?\n const existing = await ctx.collections.sends.findOne({ dedupeKey })\n if (existing) {\n await advanceStep(run, ctx, {\n action: 'sent',\n details: { dedupeKey, alreadySent: true, sendId: String(existing._id) },\n })\n return\n }\n\n const providerName = pickProviderName(step.providerOverride, template, ctx)\n\n // Render now (with fresh contact + vars). Tracking application happens in\n // dispatchSend once we have the persisted sendId.\n const renderCtx = buildRenderContext(contact, run, step.vars ?? {}, ctx)\n let rendered\n try {\n rendered = await renderTemplate(template, renderCtx, { helpers: ctx.handlebarsHelpers })\n } catch (err: any) {\n await ctx.collections.sends.insertOne(\n newSendDoc({\n dedupeKey,\n run,\n contact,\n template,\n flow,\n providerName,\n renderedSubject: template.subject,\n bodyHash: '',\n status: 'failed',\n errorMessage: `render error: ${err?.message ?? err}`,\n }),\n )\n await advanceStep(run, ctx, {\n action: 'send_skipped',\n details: { reason: 'render_error', message: String(err?.message ?? err) },\n })\n return\n }\n\n const sendId = new ObjectId()\n await ctx.collections.sends.insertOne(\n newSendDoc({\n _id: sendId,\n dedupeKey,\n run,\n contact,\n template,\n flow,\n providerName,\n renderedSubject: rendered.subject,\n bodyHash: sha256(rendered.html),\n status: 'queued',\n renderedFrom: rendered.fromName ? { name: rendered.fromName, email: rendered.fromEmail } : undefined,\n vars: step.vars ?? {},\n }),\n )\n\n await ctx.queues.send.add(\n 'send',\n { sendId: String(sendId) },\n { attempts: ctx.config.sendRetryAttempts, backoff: { type: 'exponential', delay: 60_000 } },\n )\n\n await advanceStep(run, ctx, { action: 'sent', details: { dedupeKey, sendId: String(sendId) } })\n}\n\n// ---------------------------------------------------------------------------\n// Send worker entry point\n// ---------------------------------------------------------------------------\n\nexport async function dispatchSend(sendId: ObjectId, ctx: RunnerContext): Promise<void> {\n // Atomic claim: flip queued/failed → sending so exactly one worker proceeds.\n // The stranded-send sweep and the queue's stalled-job retry can both fire a\n // job for the same send; a read-then-act status check lets both through and\n // the recipient gets the email twice. Every downstream path writes a\n // terminal status (or resets to 'queued' for the breaker retry); a crash\n // leaves 'sending', which the stranded-send sweep resets after 5 minutes.\n const send = await ctx.collections.sends.findOneAndUpdate(\n { _id: sendId, status: { $in: ['queued', 'failed'] } },\n { $set: { status: 'sending', updatedAt: new Date() } },\n )\n if (!send) return // already claimed / dispatched / cancelled\n\n const template = await ctx.collections.templates.findOne({ _id: send.templateId })\n if (!template) {\n await markFailed(send._id!, 'template_missing', ctx)\n return\n }\n\n // 1. Suppression check (INVARIANT 3: always re-checked at send time).\n const supp = await isSuppressed(ctx.collections, send.emailAtSend, send.kind)\n if (supp.suppressed) {\n await ctx.collections.sends.updateOne(\n { _id: send._id },\n { $set: { status: 'suppressed', errorMessage: `suppressed: ${supp.reason}` } },\n )\n return\n }\n\n // 2. Circuit-breaker check (only blocks marketing). The breaker is scoped\n // per (senderDomain, kind) bucket — one bad subdomain doesn't hold mail for\n // the others.\n if (send.kind === 'marketing') {\n const bucket = await getBucketStatus(ctx, send.fromEmail, send.kind)\n if (bucket?.status === 'tripped') {\n // Release the claim so the delayed retry can re-claim it.\n await ctx.collections.sends.updateOne(\n { _id: send._id },\n { $set: { status: 'queued', updatedAt: new Date() } },\n )\n await ctx.queues.send.add('send', { sendId: String(send._id) }, { delay: 60_000 })\n return\n }\n }\n\n // 3. Pull the contact + re-render (use the contact that exists now, not at flow entry).\n const contact = await ctx.adapter.getById(send.externalId)\n if (!contact) {\n await markFailed(send._id!, 'contact_missing', ctx)\n return\n }\n\n const run = send.flowRunId ? await ctx.collections.flowRuns.findOne({ _id: send.flowRunId }) : null\n\n // Aborted-run guard: closes the race where a send is enqueued between the\n // abort's send-cancellation sweep and dispatch. Only host aborts block here —\n // completed/naturally-exited runs may still have legitimately queued mail.\n if (run && run.status === 'exited' && run.exitReason?.startsWith('aborted_by_host')) {\n await ctx.collections.sends.updateOne(\n { _id: send._id },\n { $set: { status: 'cancelled', errorMessage: `cancelled: ${run.exitReason}`, updatedAt: new Date() } },\n )\n return\n }\n\n // Resolve host vars + render. A throw here (host DB hiccup, bad template)\n // marks the send failed and rethrows so the queue retries with backoff —\n // never dispatch a half-rendered email.\n let renderCtx: RenderContext\n let rendered: Awaited<ReturnType<typeof renderTemplate>>\n try {\n const resolved = await resolveVars(ctx.varsAdapter, contact, {\n reason: 'send',\n templateSlug: template.slug,\n flowSlug: run?.flowSlug,\n eventName: run?.triggerEvent?.name,\n eventProperties: run?.triggerEvent?.properties,\n })\n renderCtx = buildRenderContext(contact, run, send.vars ?? {}, ctx, resolved)\n rendered = await renderTemplate(template, renderCtx, { helpers: ctx.handlebarsHelpers })\n } catch (err: any) {\n await markFailed(send._id!, `render error: ${String(err?.message ?? err)}`, ctx)\n throw err // let the queue retry per the attempts policy\n }\n\n // 4. Apply tracking using the now-known send id.\n //\n // text_only skips this entirely: the open pixel needs an HTML part to live\n // in, and click rewriting would replace readable URLs with opaque redirects\n // in text a recipient reads literally — the opposite of what the format is\n // for. Such a send reports no opens and no clicks by design.\n const textOnly = template.bodyFormat === 'text_only'\n const tracking = textOnly\n ? { html: '', links: [] as Array<{ linkId: string; url: string }> }\n : applyTracking(rendered.html, {\n sendId: String(send._id),\n publicUrl: ctx.config.publicUrl,\n trackOpens: template.trackOpens ?? ctx.config.trackOpens,\n trackClicks: template.trackClicks ?? ctx.config.trackClicks,\n preserveUrls: [renderCtx.unsubscribeUrl],\n signingSecret: ctx.config.unsubscribeSecret,\n })\n\n await ctx.collections.sends.updateOne(\n { _id: send._id },\n {\n $set: {\n links: tracking.links,\n // Hash what actually goes out, so a text_only send's fingerprint\n // tracks the text body rather than an HTML part it never had.\n bodyHash: sha256(textOnly ? rendered.plainText : tracking.html),\n status: 'sending',\n fromName: rendered.fromName,\n fromEmail: rendered.fromEmail,\n subject: rendered.subject,\n updatedAt: new Date(),\n },\n },\n )\n\n // 5. Provider dispatch.\n //\n // Guarded lookup (see provider-lookup.ts): a bare `ctx.providers[name]` also\n // resolves inherited Object.prototype keys, so a send row whose `provider` is\n // `constructor` or `toString` used to yield a truthy non-provider that blew up\n // on `.send(...)` further down — inside the try/catch below, so it surfaced as\n // a failed send reading \"provider.send is not a function\" and then burned the\n // full retry budget on a config error no retry can fix.\n //\n // No fallback to the default provider. `send.provider` is written by\n // pickProviderName, which has *already* applied the default; if the name on\n // the row still doesn't resolve it is stale, renamed or mistyped, and quietly\n // routing the mail through a different provider than the row records would\n // send it from the wrong reputation and hide the misconfiguration. Fail this\n // one send with a reason an operator can act on, exactly like the\n // template_missing / contact_missing paths above: no throw, so the send's\n // queue job settles instead of retrying, and nothing else in flight is\n // affected.\n const provider = resolveProvider(ctx.providers, send.provider)\n if (!provider) {\n const known = registeredProviderNames(ctx.providers)\n await markFailed(\n send._id!,\n `provider_unknown: no provider is registered as \"${send.provider}\". ` +\n `Registered providers: ${known.length ? known.join(', ') : '(none)'}.`,\n ctx,\n )\n return\n }\n\n // List-Unsubscribe belongs on bulk mail only. The unsubscribe token is\n // scoped 'marketing', so advertising one-click unsub on a password reset\n // both misrepresents the header and offers an opt-out that wouldn't stop\n // the transactional mail the recipient is looking at.\n const headers: Record<string, string> =\n send.kind === 'marketing'\n ? {\n 'List-Unsubscribe': `<${renderCtx.unsubscribeUrl}>`,\n 'List-Unsubscribe-Post': 'List-Unsubscribe=One-Click',\n }\n : {}\n\n try {\n const result = await provider.send({\n to: send.emailAtSend,\n fromName: rendered.fromName,\n fromEmail: rendered.fromEmail,\n replyTo: rendered.replyTo ?? undefined,\n subject: rendered.subject,\n ...(textOnly ? {} : { html: tracking.html }),\n text: rendered.plainText,\n headers,\n messageMeta: { sendId: String(send._id) },\n })\n\n await ctx.collections.sends.updateOne(\n { _id: send._id },\n {\n $set: {\n status: 'sent',\n sentAt: new Date(),\n providerMessageId: result.providerId,\n },\n },\n )\n // Use send.fromEmail (same field getBucketStatus reads) so the breaker\n // gate and the counter record into the same bucket even if a\n // hypothetical render-time fromDefaults swap ever lands.\n await recordHealthCounter(ctx, 'sent', { fromEmail: send.fromEmail, kind: send.kind })\n } catch (err: any) {\n await ctx.collections.sends.updateOne(\n { _id: send._id },\n { $set: { status: 'failed', errorMessage: String(err?.message ?? err) } },\n )\n await recordHealthCounter(ctx, 'failedToSend', { fromEmail: send.fromEmail, kind: send.kind })\n if (ctx.config.onSendFailure) {\n try {\n await ctx.config.onSendFailure({ send, error: err })\n } catch {\n /* swallow */\n }\n }\n throw err // let BullMQ retry per the attempts policy\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction pickProviderName(stepOverride: string | undefined, tpl: TemplateDoc, ctx: RunnerContext): string {\n if (stepOverride) return stepOverride\n if (tpl.providerOverride) return tpl.providerOverride\n if (tpl.kind === 'transactional' && ctx.config.defaultTransactionalProvider) {\n return ctx.config.defaultTransactionalProvider\n }\n return ctx.config.defaultProvider\n}\n\nfunction buildRenderContext(\n contact: Contact,\n run: FlowRunDoc | null,\n vars: Record<string, unknown>,\n ctx: RunnerContext,\n resolved: Record<string, unknown> = {},\n): RenderContext {\n const scope = 'marketing'\n const expiresAt = new Date(Date.now() + ctx.config.unsubscribeTokenLifetimeDays * 24 * 60 * 60 * 1000)\n const token = signUnsubscribeToken(\n { email: contact.email, scope, expiresAt },\n ctx.config.unsubscribeSecret,\n )\n const unsubscribeUrl = `${ctx.config.publicUrl}/m/unsub/${token}`\n\n return {\n ...resolved,\n contact,\n vars,\n event: run?.triggerEvent?.properties ?? {},\n unsubscribeUrl,\n senderAddress: ctx.config.senderAddress,\n }\n}\n\ninterface NewSendInput {\n _id?: ObjectId\n dedupeKey: string\n run: FlowRunDoc\n contact: Contact\n template: TemplateDoc\n flow: FlowDoc\n providerName: string\n renderedSubject: string\n bodyHash: string\n status: SendDoc['status']\n errorMessage?: string\n renderedFrom?: { name: string; email: string }\n vars?: Record<string, unknown>\n}\n\nfunction newSendDoc(input: NewSendInput): SendDoc {\n const now = new Date()\n return {\n _id: input._id,\n dedupeKey: input.dedupeKey,\n externalId: input.run.externalId,\n emailAtSend: input.contact.email,\n templateId: input.template._id!,\n templateSlug: input.template.slug,\n flowRunId: input.run._id!,\n broadcastId: null,\n manualSendBy: null,\n kind: input.template.kind,\n provider: input.providerName,\n providerMessageId: null,\n fromName: input.renderedFrom?.name ?? input.template.fromName,\n fromEmail: input.renderedFrom?.email ?? input.template.fromEmail,\n subject: input.renderedSubject,\n bodyHash: input.bodyHash,\n status: input.status,\n errorMessage: input.errorMessage ?? null,\n bounceType: null,\n bounceReason: null,\n links: [],\n vars: input.vars ?? {},\n openedAt: null,\n openCount: 0,\n firstClickAt: null,\n clickCount: 0,\n clickedLinks: [],\n unsubscribedAt: null,\n complainedAt: null,\n queuedAt: now,\n updatedAt: now,\n sentAt: null,\n deliveredAt: null,\n }\n}\n\nasync function markFailed(sendId: ObjectId, reason: string, ctx: RunnerContext): Promise<void> {\n await ctx.collections.sends.updateOne(\n { _id: sendId },\n { $set: { status: 'failed', errorMessage: reason } },\n )\n}\n\nfunction sha256(s: string): string {\n return crypto.createHash('sha256').update(s).digest('hex')\n}\n","/**\n * Suppression checks. INVARIANT 3: re-checked at send time, never trusted\n * from enqueue time. INVARIANT 9: hashed-suppression records (GDPR forget)\n * block sends without retaining the plaintext email.\n */\n\nimport type { Collections } from '../models/index.js'\nimport type { SuppressionScope, TemplateKind } from '../../shared/enums.js'\nimport { sha256Hex } from '../tokens.js'\n\nexport interface SuppressionResult {\n suppressed: boolean\n scope?: string\n reason?: string\n}\n\nconst SCOPES_BY_KIND: Record<TemplateKind, SuppressionScope[]> = {\n marketing: ['all', 'marketing'],\n transactional: ['all', 'transactional'],\n}\n\nexport async function isSuppressed(\n collections: Collections,\n email: string,\n kind: TemplateKind,\n): Promise<SuppressionResult> {\n const normalized = email.toLowerCase()\n const allowed = SCOPES_BY_KIND[kind]\n\n const byEmail = await collections.suppressions.findOne({\n email: normalized,\n scope: { $in: allowed },\n $or: [{ expiresAt: null }, { expiresAt: { $gt: new Date() } }],\n })\n if (byEmail) return { suppressed: true, scope: byEmail.scope, reason: byEmail.reason }\n\n const hashed = await collections.suppressions.findOne({\n emailHash: sha256Hex(normalized),\n scope: { $in: allowed },\n })\n if (hashed) return { suppressed: true, scope: hashed.scope, reason: hashed.reason }\n\n return { suppressed: false }\n}\n","/**\n * Flow_run state machine. One step transition per `processOneRunStep` call.\n * Idempotent — optimistic concurrency on `currentStepIndex` means two workers\n * racing on the same run advance exactly once.\n */\n\nimport type { ObjectId } from 'mongodb'\n\nimport type { FlowStep } from '../../shared/types.js'\nimport type { FlowRunDoc, FlowDoc } from '../models/index.js'\nimport { evaluatePredicate } from './predicate.js'\nimport type { RunnerContext } from './index.js'\nimport { computeDeliveryTime } from './delivery-window.js'\nimport { handleSend } from './send.js'\n\n/**\n * Tolerance on the not-yet-due check below. A delayed job may fire a few\n * milliseconds early, and clocks between app servers drift; without slack\n * those runs would bounce to the sweep and stall for a whole tick.\n */\nconst DUE_SKEW_MS = 1_000\n\nexport async function processOneRunStep(runId: ObjectId, ctx: RunnerContext): Promise<void> {\n const run = await ctx.collections.flowRuns.findOne({ _id: runId })\n if (!run || run.status !== 'active') return\n\n // Don't touch a run that is parked in the future. The schedule used to be\n // enforced only by the callers — the sweep's `nextActionAt <= now` filter and\n // the advance job's delay — which is a time-of-check/time-of-use race: the\n // sweep selects a run that is due, the run's own advance job parks it on a\n // wait in the meantime, and the sweep then processes the step AFTER the wait,\n // skipping it entirely. That is reachable on every tick, because a freshly\n // triggered run is inserted with `nextActionAt = now` and `runTick` runs the\n // trigger scan and the sweep back to back — so a flow whose first step is a\n // wait could lose it. The invariant belongs with the state, not the caller.\n if (run.nextActionAt && run.nextActionAt.getTime() > Date.now() + DUE_SKEW_MS) return\n\n const flow = await ctx.collections.flows.findOne({ _id: run.flowId })\n if (!flow) {\n await failFlowRun(run, 'flow_missing', ctx)\n return\n }\n\n const steps = await loadStepsForRun(run, flow, ctx)\n const step = locateStep(steps, run.currentStepIndex, run.currentBranchPath)\n if (!step) {\n await completeFlowRun(run, 'completed', ctx)\n return\n }\n\n const contact = await ctx.adapter.getById(run.externalId)\n if (!contact) {\n await exitFlowRun(run, 'contact_missing', ctx)\n return\n }\n\n // Subscription gate: flows are marketing-scope. Any non-subscribed status\n // exits the run before the next step, regardless of template kind — there is\n // deliberately no transactional bypass here. Transactional mail that must\n // reach not-subscribed contacts (receipts, password resets) goes through\n // sendOneOff, not a flow. Entry is gated the same way in triggers.ts.\n const sub = await ctx.collections.subscriptions.findOne({ externalId: run.externalId })\n if (sub && sub.status !== 'subscribed') {\n await exitFlowRun(run, sub.status, ctx)\n return\n }\n\n switch (step.type) {\n case 'wait':\n return handleWait(run, step, ctx)\n case 'condition':\n return handleCondition(run, step, contact, ctx)\n case 'branch':\n return handleBranch(run, step, contact, ctx)\n case 'send': {\n // Delivery window: push the send to the next allowed slot (weekday /\n // time-of-day, optionally in the contact's timezone) before rendering.\n if (step.delivery) {\n const deliverAt = computeDeliveryTime(new Date(), step.delivery, contact.timezone)\n if (deliverAt.getTime() > Date.now() + 30_000) {\n return deferSendForWindow(run, deliverAt, ctx)\n }\n }\n return handleSend(run, step, contact, flow, ctx)\n }\n case 'tag':\n return handleTag(run, step, ctx)\n case 'fire_event':\n return handleFireEvent(run, step, ctx)\n case 'webhook':\n return handleWebhookStep(run, step, ctx)\n case 'exit':\n return exitFlowRun(run, step.reason ?? 'exit_step', ctx)\n }\n}\n\n// ---------------------------------------------------------------------------\n// Step handlers\n// ---------------------------------------------------------------------------\n\nasync function handleWait(\n run: FlowRunDoc,\n step: Extract<FlowStep, { type: 'wait' }>,\n ctx: RunnerContext,\n): Promise<void> {\n const ms = unitToMs(step.value, step.unit)\n const nextAt = new Date(Date.now() + ms)\n\n const updated = await ctx.collections.flowRuns.findOneAndUpdate(\n { _id: run._id, currentStepIndex: run.currentStepIndex },\n {\n $set: { nextActionAt: nextAt, attemptsForCurrentStep: 0, updatedAt: new Date() },\n $inc: { currentStepIndex: 1 },\n $push: {\n history: {\n stepIndex: run.currentStepIndex,\n action: 'wait_started',\n at: new Date(),\n details: { until: nextAt },\n },\n },\n },\n { returnDocument: 'after' },\n )\n\n if (!updated) return // another worker advanced; their job will fire.\n\n await ctx.queues.advance.add(\n 'advance',\n { flowRunId: String(run._id) },\n { delay: ms, jobId: `advance:${run._id}:${branchKey(run)}:${run.currentStepIndex + 1}` },\n )\n}\n\nasync function handleCondition(\n run: FlowRunDoc,\n step: Extract<FlowStep, { type: 'condition' }>,\n contact: Awaited<ReturnType<typeof ctx.adapter.getById>>,\n ctx: RunnerContext,\n): Promise<void> {\n if (!contact) return\n const result = await evaluatePredicate(step.test, { contact, run, collections: ctx.collections, botFilter: ctx.config.botFilter })\n\n if (result) {\n await advanceStep(run, ctx, { action: 'condition_evaluated', details: { result: true } })\n return\n }\n if (step.ifFalse === 'continue') {\n await advanceStep(run, ctx, { action: 'condition_evaluated', details: { result: false, skipped: 1 } }, { stepInc: 2 })\n return\n }\n await exitFlowRun(run, 'condition_false', ctx)\n}\n\nasync function handleBranch(\n run: FlowRunDoc,\n step: Extract<FlowStep, { type: 'branch' }>,\n contact: Awaited<ReturnType<typeof ctx.adapter.getById>>,\n ctx: RunnerContext,\n): Promise<void> {\n if (!contact) return\n const result = await evaluatePredicate(step.test, { contact, run, collections: ctx.collections, botFilter: ctx.config.botFilter })\n const newPath = [...run.currentBranchPath, run.currentStepIndex, result ? 'true' : 'false', 0] as Array<number | 'true' | 'false'>\n\n const updated = await ctx.collections.flowRuns.findOneAndUpdate(\n { _id: run._id, currentStepIndex: run.currentStepIndex },\n {\n $set: {\n currentBranchPath: newPath,\n currentStepIndex: 0,\n nextActionAt: new Date(),\n attemptsForCurrentStep: 0,\n updatedAt: new Date(),\n },\n $push: {\n history: {\n stepIndex: run.currentStepIndex,\n action: 'branch_taken',\n at: new Date(),\n details: { result },\n },\n },\n },\n { returnDocument: 'after' },\n )\n\n if (!updated) return\n await ctx.queues.advance.add('advance', { flowRunId: String(run._id) })\n}\n\nasync function handleTag(\n run: FlowRunDoc,\n step: Extract<FlowStep, { type: 'tag' }>,\n ctx: RunnerContext,\n): Promise<void> {\n const adds = step.addTags ?? []\n const removes = step.removeTags ?? []\n\n if (ctx.adapter.addTags && adds.length > 0) {\n await ctx.adapter.addTags(run.externalId, adds)\n } else if (adds.length > 0) {\n await ctx.collections.contactTags.bulkWrite(\n adds.map((tag) => ({\n updateOne: {\n filter: { externalId: run.externalId, tag },\n update: { $setOnInsert: { externalId: run.externalId, tag, appliedBy: 'flow', appliedAt: new Date() } },\n upsert: true,\n },\n })),\n )\n }\n\n if (ctx.adapter.removeTags && removes.length > 0) {\n await ctx.adapter.removeTags(run.externalId, removes)\n } else if (removes.length > 0) {\n await ctx.collections.contactTags.deleteMany({ externalId: run.externalId, tag: { $in: removes } })\n }\n\n await advanceStep(run, ctx, { action: 'tagged', details: { addTags: adds, removeTags: removes } })\n}\n\nasync function handleFireEvent(\n run: FlowRunDoc,\n step: Extract<FlowStep, { type: 'fire_event' }>,\n ctx: RunnerContext,\n): Promise<void> {\n const dedupeKey = `flowrun:${run._id}:step${run.currentStepIndex}:${step.eventName}`\n try {\n await ctx.collections.events.insertOne({\n externalId: run.externalId,\n name: step.eventName,\n // Inherit the triggering event's properties so a handoff carries the\n // context that identifies what the run is ABOUT (which account, order,\n // subscription, ...). A step's `properties` are static — authored once in\n // the flow definition — so without this a fired event can only ever say\n // \"this contact\", losing the scope the originating event supplied, and\n // the receiving flow has nothing to resolve variables against. Explicit\n // step.properties win on conflict.\n properties: { ...(run.triggerEvent?.properties ?? {}), ...(step.properties ?? {}) },\n dedupeKey,\n occurredAt: new Date(),\n createdAt: new Date(),\n })\n } catch (err: any) {\n if (err?.code !== 11000) throw err\n }\n await advanceStep(run, ctx, { action: 'event_fired', details: { name: step.eventName } })\n}\n\nasync function handleWebhookStep(\n run: FlowRunDoc,\n step: Extract<FlowStep, { type: 'webhook' }>,\n ctx: RunnerContext,\n): Promise<void> {\n try {\n // `step.url` is passed to fetch VERBATIM — deliberately NOT rendered through\n // Handlebars, and it must stay that way.\n //\n // The URL comes only from a flow definition authored through the admin routes,\n // so the set of reachable destinations is fixed by a privileged system admin.\n // Under that constraint, \"this server can POST to an arbitrary URL\" is an\n // intended admin capability, not a vulnerability.\n //\n // Templating it would invert that. A URL like `{{contact.callbackUrl}}` is a\n // natural-sounding request, but it hands the destination of a server-side\n // fetch — one that originates INSIDE the deployment's network, past any\n // perimeter — to whoever controls the template data: contact fields, event\n // properties, adapter vars. That is a textbook SSRF vector (cloud metadata\n // endpoints, internal admin services, localhost) reachable by an unprivileged\n // party. If templated webhook URLs are ever genuinely needed, they require a\n // destination allowlist plus DNS/redirect-aware egress filtering, not a\n // render call added here.\n //\n // Note the zod schema (`url: z.string().url()` in src/shared/schemas.ts)\n // validates SHAPE only — it accepts http://169.254.169.254/ quite happily and\n // provides no protection whatsoever on this point.\n //\n // The `advanceStep` audit entry below records the resolved URL and response\n // status (and the error on the failure path), so every outbound call a flow\n // makes is attributable after the fact.\n const res = await fetch(step.url, {\n method: step.method ?? 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(step.payload ?? { externalId: run.externalId, flowRunId: String(run._id) }),\n signal: AbortSignal.timeout(10_000),\n })\n if (!res.ok) throw new Error(`webhook step returned ${res.status}`)\n await advanceStep(run, ctx, { action: 'webhook_called', details: { url: step.url, status: res.status } })\n } catch (err: any) {\n const attempts = (run.attemptsForCurrentStep ?? 0) + 1\n if (attempts >= ctx.config.webhookRetryAttempts) {\n if (step.failureMode === 'fail_run') {\n await failFlowRun(run, `webhook failed: ${err?.message}`, ctx)\n } else {\n // Soft fail — log and advance.\n await advanceStep(run, ctx, {\n action: 'webhook_called',\n details: { url: step.url, error: err?.message, exhausted: true },\n })\n }\n } else {\n await ctx.collections.flowRuns.updateOne(\n { _id: run._id, currentStepIndex: run.currentStepIndex },\n { $inc: { attemptsForCurrentStep: 1 }, $set: { nextActionAt: new Date(Date.now() + 60_000) } },\n )\n await ctx.queues.advance.add(\n 'advance',\n { flowRunId: String(run._id) },\n { delay: 60_000, jobId: `advance:${run._id}:${branchKey(run)}:${run.currentStepIndex}:retry-${attempts}` },\n )\n }\n }\n}\n\n/**\n * Park the run on the SAME step until the delivery window opens, then let the\n * normal advance job re-enter processOneRunStep — at which point the window\n * check passes and handleSend runs. Idempotent via the jobId (one defer job\n * per step per slot) and the nextActionAt guard.\n */\nasync function deferSendForWindow(run: FlowRunDoc, deliverAt: Date, ctx: RunnerContext): Promise<void> {\n const updated = await ctx.collections.flowRuns.findOneAndUpdate(\n // Only write once per deferral — if nextActionAt already points at (or\n // past) the slot, another worker/tick got here first.\n { _id: run._id, currentStepIndex: run.currentStepIndex, nextActionAt: { $lt: deliverAt } },\n {\n $set: { nextActionAt: deliverAt, updatedAt: new Date() },\n $push: {\n history: {\n stepIndex: run.currentStepIndex,\n action: 'send_deferred' as const,\n at: new Date(),\n details: { until: deliverAt },\n },\n },\n },\n { returnDocument: 'after' },\n )\n if (!updated) return\n\n await ctx.queues.advance.add(\n 'advance',\n { flowRunId: String(run._id) },\n {\n delay: Math.max(0, deliverAt.getTime() - Date.now()),\n jobId: `advance:${run._id}:${branchKey(run)}:${run.currentStepIndex}:window:${deliverAt.getTime()}`,\n },\n )\n}\n\n// ---------------------------------------------------------------------------\n// Common helpers\n// ---------------------------------------------------------------------------\n\nexport interface AdvanceOptions {\n stepInc?: number\n}\n\nexport interface AdvanceLog {\n action: FlowRunDoc['history'][number]['action']\n details?: Record<string, unknown>\n}\n\nexport async function advanceStep(\n run: FlowRunDoc,\n ctx: RunnerContext,\n log: AdvanceLog,\n opts: AdvanceOptions = {},\n): Promise<void> {\n const stepInc = opts.stepInc ?? 1\n const updated = await ctx.collections.flowRuns.findOneAndUpdate(\n { _id: run._id, currentStepIndex: run.currentStepIndex },\n {\n $set: { nextActionAt: new Date(), attemptsForCurrentStep: 0, updatedAt: new Date() },\n $inc: { currentStepIndex: stepInc },\n $push: {\n history: { stepIndex: run.currentStepIndex, action: log.action, at: new Date(), details: log.details },\n },\n },\n { returnDocument: 'after' },\n )\n if (!updated) return\n await ctx.queues.advance.add('advance', { flowRunId: String(run._id) })\n}\n\nexport async function exitFlowRun(run: FlowRunDoc, reason: string, ctx: RunnerContext): Promise<void> {\n await ctx.collections.flowRuns.updateOne(\n { _id: run._id, status: 'active' },\n {\n $set: { status: 'exited', exitedAt: new Date(), exitReason: reason, updatedAt: new Date() },\n $push: { history: { stepIndex: run.currentStepIndex, action: 'exited', at: new Date(), details: { reason } } },\n },\n )\n}\n\nexport async function completeFlowRun(run: FlowRunDoc, reason: string, ctx: RunnerContext): Promise<void> {\n await ctx.collections.flowRuns.updateOne(\n { _id: run._id, status: 'active' },\n {\n $set: { status: 'completed', exitedAt: new Date(), exitReason: reason, updatedAt: new Date() },\n },\n )\n}\n\nexport async function failFlowRun(run: FlowRunDoc, reason: string, ctx: RunnerContext): Promise<void> {\n await ctx.collections.flowRuns.updateOne(\n { _id: run._id, status: 'active' },\n {\n $set: { status: 'failed', exitedAt: new Date(), exitReason: reason, updatedAt: new Date() },\n $push: { history: { stepIndex: run.currentStepIndex, action: 'failed', at: new Date(), details: { reason } } },\n },\n )\n}\n\nexport async function loadStepsForRun(\n run: FlowRunDoc,\n flow: FlowDoc,\n ctx: RunnerContext,\n): Promise<FlowStep[]> {\n if (run.flowVersion === flow.version) return flow.steps\n const snapshot = await ctx.collections.flowVersions.findOne({ flowId: run.flowId, version: run.flowVersion })\n return snapshot?.steps ?? flow.steps\n}\n\n/**\n * Walk a branch path through nested branch steps to find the active step.\n * Branch path layout: [parentStepIndex, 'true'|'false', childStepIndex, ...repeat]\n */\nexport function locateStep(\n steps: FlowStep[],\n currentStepIndex: number,\n branchPath: ReadonlyArray<number | 'true' | 'false'>,\n): FlowStep | null {\n let arr: FlowStep[] = steps\n\n for (let i = 0; i < branchPath.length; i += 3) {\n const parentIndex = branchPath[i] as number\n const branchKey = branchPath[i + 1] as 'true' | 'false'\n const parent = arr[parentIndex]\n if (!parent || parent.type !== 'branch') return null\n arr = branchKey === 'true' ? parent.ifTrueSteps : parent.ifFalseSteps\n }\n\n return arr[currentStepIndex] ?? null\n}\n\n/**\n * Branch-path discriminator for advance jobIds. `currentStepIndex` resets to 0\n * on branch entry, so (runId, stepIndex) alone is not unique across a run's\n * lifetime — the same numeric index recurs inside each branch arm.\n */\nfunction branchKey(run: FlowRunDoc): string {\n return run.currentBranchPath.join('_')\n}\n\nfunction unitToMs(value: number, unit: 'minutes' | 'hours' | 'days' | 'weeks'): number {\n const m = 60_000\n switch (unit) {\n case 'minutes':\n return value * m\n case 'hours':\n return value * 60 * m\n case 'days':\n return value * 24 * 60 * m\n case 'weeks':\n return value * 7 * 24 * 60 * m\n }\n}\n","/**\n * Recovery sweep: finds active flow_runs whose `nextActionAt` has passed but\n * weren't woken by their delayed `mailer:advance` job (worker restart, BullMQ\n * data loss). Processes each one inline.\n */\n\nimport { processOneRunStep } from './step.js'\nimport type { RunnerContext } from './index.js'\n\nconst SWEEP_LIMIT = 500\n\nexport async function sweepStrandedFlowRuns(ctx: RunnerContext): Promise<void> {\n const runs = await ctx.collections.flowRuns\n .find({ status: 'active', nextActionAt: { $lte: new Date() } })\n .sort({ nextActionAt: 1 })\n .limit(SWEEP_LIMIT)\n .toArray()\n\n for (const run of runs) {\n try {\n await processOneRunStep(run._id!, ctx)\n } catch (err) {\n console.error('mailery: sweep advance failed', { runId: String(run._id), err })\n }\n }\n}\n","/**\n * Broadcast dispatch. Picks up scheduled broadcasts whose `scheduledAt` has\n * passed, streams the segment via the adapter cursor + mailer-side post-filter,\n * and bulk-enqueues Send docs + jobs. Per-provider rate limiting + bounded\n * enqueue (pause when waitingCount > broadcastEnqueueMaxWaiting).\n */\n\nimport { ObjectId } from 'mongodb'\n\nimport type { Contact, SegmentDefinition, SegmentFilter, AdapterFilter } from '../../shared/types.js'\nimport type { BroadcastDoc, SendDoc, TemplateDoc } from '../models/index.js'\nimport { isSuppressed } from './suppression.js'\nimport { sha256Hex } from '../tokens.js'\nimport type { RunnerContext } from './index.js'\n\n/**\n * Broadcasts stuck in 'sending' with updatedAt older than this are assumed\n * dead (worker crashed mid-dispatch). dispatchBroadcast heartbeats updatedAt\n * on every page, so a stale timestamp means no live dispatcher.\n */\nconst STALLED_BROADCAST_THRESHOLD_MS = 10 * 60 * 1000\n\n/**\n * Process scheduled broadcasts whose `scheduledAt` has passed. Called from the\n * tick. Marks each broadcast `sending` before dispatch so concurrent ticks\n * don't double-dispatch.\n */\nexport async function processScheduledBroadcasts(ctx: RunnerContext): Promise<void> {\n const now = new Date()\n const due = await ctx.collections.broadcasts\n .find({ status: 'scheduled', scheduledAt: { $lte: now } })\n .toArray()\n\n for (const b of due) {\n // Optimistic claim — only one worker takes this broadcast.\n const claimed = await ctx.collections.broadcasts.findOneAndUpdate(\n { _id: b._id, status: 'scheduled' },\n { $set: { status: 'sending', startedAt: now, updatedAt: now } },\n { returnDocument: 'after' },\n )\n if (!claimed) continue\n await startBroadcastDispatch(claimed, ctx)\n }\n}\n\n/**\n * Hand the (potentially hours-long) recipient enqueue off the tick. With a\n * real queue driver, dispatch runs as an advance job so a large broadcast\n * can't starve trigger scans and sweeps — the tick worker has concurrency 1.\n * The noop driver has no workers (hosts drive the runner synchronously), so\n * dispatch stays inline there.\n */\nasync function startBroadcastDispatch(broadcast: BroadcastDoc, ctx: RunnerContext): Promise<void> {\n if (ctx.config.queue.driver === 'noop') {\n await runBroadcastDispatch(broadcast, ctx)\n return\n }\n await ctx.queues.advance.add(\n 'advance',\n { broadcastId: String(broadcast._id) },\n {\n attempts: 3,\n backoff: { type: 'exponential', delay: 60_000 },\n jobId: `broadcast-dispatch:${broadcast._id}`,\n },\n )\n}\n\n/** Advance-worker entry point for `{ broadcastId }` jobs. */\nexport async function dispatchBroadcastById(broadcastId: ObjectId, ctx: RunnerContext): Promise<void> {\n const broadcast = await ctx.collections.broadcasts.findOne({ _id: broadcastId, status: 'sending' })\n if (!broadcast) return\n await runBroadcastDispatch(broadcast, ctx)\n}\n\n/**\n * Rescue broadcasts whose dispatcher died. Re-dispatch is idempotent: the\n * per-recipient dedupeKey unique index skips send rows already inserted, so\n * a resumed broadcast picks up where the dead worker left off.\n */\nexport async function resumeStalledBroadcasts(ctx: RunnerContext): Promise<void> {\n const cutoff = new Date(Date.now() - STALLED_BROADCAST_THRESHOLD_MS)\n const stalled = await ctx.collections.broadcasts\n .find({ status: 'sending', updatedAt: { $lt: cutoff } })\n .toArray()\n\n for (const b of stalled) {\n // Touch before re-dispatch so subsequent ticks don't stack rescues.\n await ctx.collections.broadcasts.updateOne(\n { _id: b._id },\n { $set: { updatedAt: new Date() } },\n )\n await startBroadcastDispatch(b, ctx)\n }\n}\n\nasync function runBroadcastDispatch(broadcast: BroadcastDoc, ctx: RunnerContext): Promise<void> {\n try {\n await dispatchBroadcast(broadcast, ctx)\n } catch (err) {\n console.error('mailery: broadcast dispatch failed', { id: String(broadcast._id), err })\n await ctx.collections.broadcasts.updateOne(\n { _id: broadcast._id },\n { $set: { status: 'failed', updatedAt: new Date() } },\n )\n }\n}\n\nasync function dispatchBroadcast(broadcast: BroadcastDoc, ctx: RunnerContext): Promise<void> {\n const template = await ctx.collections.templates.findOne({ slug: broadcast.templateSlug })\n if (!template) {\n await ctx.collections.broadcasts.updateOne(\n { _id: broadcast._id },\n { $set: { status: 'failed', updatedAt: new Date() } },\n )\n return\n }\n\n const hostFilter = toAdapterFilter(broadcast.segmentDefinition)\n const postFilters = broadcast.segmentDefinition.filters.filter((f) => isMailerSide(f))\n\n let cursor: string | undefined = undefined\n let total = 0\n const batchSize = ctx.config.broadcastEnqueueBatchSize\n const maxWaiting = ctx.config.broadcastEnqueueMaxWaiting\n const respectTimezone = broadcast.respectRecipientTimezone === true\n const scheduledMs = broadcast.scheduledAt?.getTime() ?? Date.now()\n\n for (;;) {\n // Progress heartbeat — resumeStalledBroadcasts treats a stale updatedAt\n // as a dead dispatcher, so touch it every page (and during backpressure).\n await ctx.collections.broadcasts.updateOne(\n { _id: broadcast._id },\n { $set: { updatedAt: new Date() } },\n )\n\n const page = await ctx.adapter.query(hostFilter, { limit: batchSize, cursor })\n if (page.contacts.length === 0) break\n\n // Stage B: mailer-side post-filter.\n const eligible = await applyPostFilters(page.contacts, postFilters, ctx)\n\n if (eligible.length > 0) {\n // Backpressure: wait until the send queue's waiting set drains below cap.\n while ((await ctx.queues.send.getWaitingCount()) > maxWaiting) {\n await ctx.collections.broadcasts.updateOne(\n { _id: broadcast._id },\n { $set: { updatedAt: new Date() } },\n )\n await sleep(2000)\n }\n\n const sendDocs = await Promise.all(\n eligible.map(async (contact) => buildSendDoc(broadcast, template, contact, ctx, scheduledMs, respectTimezone)),\n )\n\n // Filter out suppressed (mailer-side suppression check is the same one\n // dispatchSend would do; we short-circuit here to avoid enqueuing).\n const inserted: Array<{ sendId: ObjectId; delayMs: number }> = []\n for (const { doc, delayMs } of sendDocs) {\n if (!doc) continue\n try {\n await ctx.collections.sends.insertOne(doc)\n inserted.push({ sendId: doc._id!, delayMs })\n } catch (err: any) {\n if (err?.code !== 11000) throw err\n // dup dedupeKey — already dispatched somewhere\n }\n }\n\n // Bulk enqueue.\n if (inserted.length > 0) {\n await Promise.all(\n inserted.map(({ sendId, delayMs }) =>\n ctx.queues.send.add(\n 'send',\n { sendId: String(sendId) },\n {\n attempts: ctx.config.sendRetryAttempts,\n backoff: { type: 'exponential', delay: 60_000 },\n ...(delayMs > 0 ? { delay: delayMs } : {}),\n },\n ),\n ),\n )\n }\n\n total += inserted.length\n }\n\n if (!page.nextCursor) break\n cursor = page.nextCursor\n }\n\n await ctx.collections.broadcasts.updateOne(\n { _id: broadcast._id },\n {\n $set: {\n status: 'sent',\n completedAt: new Date(),\n recipientCount: total,\n updatedAt: new Date(),\n },\n },\n )\n}\n\n// ---------------------------------------------------------------------------\n// Segment translation\n// ---------------------------------------------------------------------------\n\nfunction toAdapterFilter(seg: SegmentDefinition): AdapterFilter {\n const out: AdapterFilter = {}\n for (const f of seg.filters) {\n switch (f.kind) {\n case 'hasTag':\n out.hasTag = f.tag\n break\n case 'fieldEquals':\n out.fieldEquals = { field: f.field, value: f.value }\n break\n case 'fieldIn':\n out.fieldIn = { field: f.field, values: f.values }\n break\n case 'fieldExists':\n out.fieldExists = f.field\n break\n // notHasTag isn't a single-condition adapter filter, defer to post-filter\n // subscriptionStatus / firedEvent / opened are all mailer-side\n }\n }\n return out\n}\n\nfunction isMailerSide(f: SegmentFilter): boolean {\n return (\n f.kind === 'subscriptionStatus' ||\n f.kind === 'firedEvent' ||\n f.kind === 'notFiredEvent' ||\n f.kind === 'subscribedAfter' ||\n f.kind === 'subscribedBefore' ||\n f.kind === 'opened' ||\n f.kind === 'notOpened' ||\n f.kind === 'notHasTag' ||\n f.kind === 'any' ||\n f.kind === 'not'\n )\n}\n\nasync function applyPostFilters(contacts: Contact[], filters: SegmentFilter[], ctx: RunnerContext): Promise<Contact[]> {\n if (filters.length === 0) return contacts\n const externalIds = contacts.map((c) => c.externalId)\n\n // Cache common lookups in one Mongo round-trip per filter.\n const cache: Record<string, Set<string>> = {}\n for (const f of filters) {\n if (f.kind === 'subscriptionStatus') {\n const docs = await ctx.collections.subscriptions\n .find({ externalId: { $in: externalIds }, status: f.equals })\n .project<{ externalId: string }>({ externalId: 1 })\n .toArray()\n cache[`sub:${f.equals}`] = new Set(docs.map((d) => d.externalId))\n }\n if (f.kind === 'firedEvent' || f.kind === 'notFiredEvent') {\n const query: any = { externalId: { $in: externalIds }, name: f.eventName }\n if (f.withinDays) {\n query.occurredAt = { $gt: new Date(Date.now() - f.withinDays * 86_400_000) }\n }\n const docs = await ctx.collections.events\n .find(query)\n .project<{ externalId: string }>({ externalId: 1 })\n .toArray()\n cache[`evt:${f.eventName}`] = new Set(docs.map((d) => d.externalId))\n }\n }\n\n return contacts.filter((c) => filters.every((f) => filterMatches(c, f, cache)))\n}\n\nfunction filterMatches(c: Contact, f: SegmentFilter, cache: Record<string, Set<string>>): boolean {\n switch (f.kind) {\n case 'subscriptionStatus':\n return cache[`sub:${f.equals}`]?.has(c.externalId) ?? false\n case 'firedEvent':\n return cache[`evt:${f.eventName}`]?.has(c.externalId) ?? false\n case 'notFiredEvent':\n return !cache[`evt:${f.eventName}`]?.has(c.externalId)\n case 'notHasTag':\n return !c.tags.includes(f.tag)\n case 'opened':\n case 'notOpened':\n // V1: not implemented in batch — would need a per-contact send lookup.\n // Treat as pass for now; suppress at dispatch time.\n return true\n case 'subscribedAfter':\n case 'subscribedBefore':\n return true // V2\n case 'any':\n return f.filters.some((sub) => filterMatches(c, sub, cache))\n case 'not':\n return !filterMatches(c, f.filter, cache)\n default:\n return true\n }\n}\n\n// ---------------------------------------------------------------------------\n// Send doc construction\n// ---------------------------------------------------------------------------\n\ninterface BuildResult {\n doc: SendDoc | null\n delayMs: number\n}\n\nasync function buildSendDoc(\n broadcast: BroadcastDoc,\n template: TemplateDoc,\n contact: Contact,\n ctx: RunnerContext,\n scheduledMs: number,\n respectTimezone: boolean,\n): Promise<BuildResult> {\n // Final suppression check before we insert.\n const supp = await isSuppressed(ctx.collections, contact.email, template.kind)\n if (supp.suppressed) return { doc: null, delayMs: 0 }\n\n const sendId = new ObjectId()\n const dedupeKey = `broadcast:${broadcast._id}:${contact.externalId}`\n\n // Per-recipient TZ delay calculation. Anchored to scheduledAt (not enqueue\n // time) so tick lag and backpressure pauses don't drift later batches.\n let delayMs = Math.max(0, scheduledMs - Date.now())\n if (respectTimezone && contact.timezone) {\n const offsetMs = perRecipientOffsetMs(scheduledMs, contact.timezone)\n delayMs = Math.max(0, scheduledMs + offsetMs - Date.now())\n }\n\n const doc: SendDoc = {\n _id: sendId,\n dedupeKey,\n externalId: contact.externalId,\n emailAtSend: contact.email,\n templateId: template._id!,\n templateSlug: template.slug,\n flowRunId: null,\n broadcastId: broadcast._id!,\n manualSendBy: null,\n kind: template.kind,\n provider: template.providerOverride ?? ctx.config.defaultProvider,\n providerMessageId: null,\n fromName: template.fromName,\n fromEmail: template.fromEmail,\n subject: template.subject,\n bodyHash: '',\n status: 'queued',\n errorMessage: null,\n bounceType: null,\n bounceReason: null,\n links: [],\n vars: {},\n openedAt: null,\n openCount: 0,\n firstClickAt: null,\n clickCount: 0,\n clickedLinks: [],\n unsubscribedAt: null,\n complainedAt: null,\n queuedAt: new Date(),\n updatedAt: new Date(),\n sentAt: null,\n deliveredAt: null,\n }\n void sha256Hex\n return { doc, delayMs }\n}\n\n/**\n * Offset to add to `scheduledMs` so the email arrives at the same WALL-CLOCK\n * time in the recipient's timezone.\n *\n * Example: broadcast `scheduledAt` is 10am UTC, contact is in PST (UTC-8).\n * Their 10am is 6pm UTC → offset +8h.\n *\n * Recipients EAST of the schedule's timezone would need a negative offset —\n * their 10am already passed when dispatch starts. Sending \"now\" would land at\n * the wrong local time, so instead the offset is normalized into [0, 24h):\n * they get the NEXT occurrence of the wall-clock slot, i.e. same time\n * tomorrow. (Berlin, UTC+2: raw offset −2h → +22h.)\n */\nfunction perRecipientOffsetMs(scheduledMs: number, timezone: string): number {\n const DAY_MS = 24 * 60 * 60 * 1000\n try {\n // Get the offset between the scheduled UTC instant interpreted as a wall\n // clock and the same wall clock in the recipient's tz.\n const scheduled = new Date(scheduledMs)\n const utc = scheduled.toLocaleString('en-US', { timeZone: 'UTC', hour12: false })\n const local = scheduled.toLocaleString('en-US', { timeZone: timezone, hour12: false })\n\n // Parse both as Date objects in the runner's local tz and take the diff.\n const parse = (s: string) => {\n const m = s.match(/(\\d+)\\/(\\d+)\\/(\\d+),\\s*(\\d+):(\\d+):(\\d+)/)\n if (!m) return 0\n return Date.UTC(+m[3]!, +m[1]! - 1, +m[2]!, +m[4]!, +m[5]!, +m[6]!)\n }\n const utcMs = parse(utc)\n const localMs = parse(local)\n const offsetMs = utcMs - localMs\n\n return ((offsetMs % DAY_MS) + DAY_MS) % DAY_MS\n } catch {\n return 0\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n","/**\n * Soft → hard bounce promotion. Configurable threshold + window:\n *\n * softBouncePromotionThreshold soft bounces for the same email within\n * softBouncePromotionWindowDays → insert a hard suppression + mark\n * the subscription bounced.\n *\n * Runs on each tick. Idempotent: if a hard suppression already exists for\n * that email, we skip.\n */\n\nimport type { TemplateKind } from '../../shared/enums.js'\nimport { sha256Hex } from '../tokens.js'\nimport { recordHealthCounter } from './health.js'\nimport type { RunnerContext } from './index.js'\n\nexport async function promoteSoftBounces(ctx: RunnerContext): Promise<void> {\n const threshold = ctx.config.softBouncePromotionThreshold\n const windowDays = ctx.config.softBouncePromotionWindowDays\n if (threshold <= 0 || windowDays <= 0) return\n\n const cutoff = new Date(Date.now() - windowDays * 86_400_000)\n\n // Aggregate: count soft bounces per emailAtSend since cutoff, hitting the\n // threshold. Bounded limit to keep the tick fast.\n const offenders = await ctx.collections.sends\n .aggregate<{ _id: string; count: number; lastFromEmail: string | null; lastKind: TemplateKind | null }>([\n { $match: { status: 'bounced', bounceType: 'soft', queuedAt: { $gt: cutoff } } },\n { $sort: { queuedAt: 1 } },\n {\n $group: {\n _id: '$emailAtSend',\n count: { $sum: 1 },\n lastFromEmail: { $last: '$fromEmail' },\n lastKind: { $last: '$kind' },\n },\n },\n { $match: { count: { $gte: threshold } } },\n { $limit: 200 },\n ])\n .toArray()\n\n for (const o of offenders) {\n const email = String(o._id ?? '').toLowerCase()\n if (!email) continue\n\n // Skip if already hard-suppressed.\n const existing = await ctx.collections.suppressions.findOne({\n email,\n scope: 'all',\n })\n if (existing) continue\n\n await ctx.collections.suppressions.updateOne(\n { email, scope: 'all' },\n {\n $setOnInsert: {\n email,\n emailHash: sha256Hex(email),\n scope: 'all',\n reason: 'hard_bounce',\n source: 'soft_promotion',\n notes: `${o.count} soft bounces in last ${windowDays} days`,\n addedAt: new Date(),\n expiresAt: null,\n },\n },\n { upsert: true },\n )\n\n await ctx.collections.subscriptions.updateOne(\n { emailAtSubscribe: email },\n { $set: { status: 'bounced', updatedAt: new Date() } },\n )\n\n await recordHealthCounter(\n ctx,\n 'hardBounced',\n o.lastKind ? { fromEmail: o.lastFromEmail, kind: o.lastKind } : null,\n )\n }\n}\n","/**\n * DNSBL monitor. Once a day (or on demand) we DNS-query each configured\n * sender domain against domain block lists (DBLs) and each configured\n * dedicated IP against IP block lists. Results are stored as one doc per\n * (target, list) — the latest result replaces the prior one.\n *\n * No external API. Pure DNS, so it works in any environment that can\n * resolve public hostnames.\n */\n\nimport dns from 'node:dns/promises'\nimport net from 'node:net'\nimport psl from 'psl'\n\nimport type {\n DnsblConfig,\n DnsblListSpec,\n} from '../config.js'\nimport {\n DEFAULT_DOMAIN_DNSBL_LISTS,\n DEFAULT_IP_DNSBL_LISTS,\n} from '../config.js'\nimport type { DnsblCheckDoc, DnsblResult, DnsblTargetKind } from '../models/index.js'\nimport { extractDomain } from '../templates/sender-domain.js'\nimport type { RunnerContext } from './index.js'\n\n/**\n * Lists that expect a registrable domain (eTLD+1) rather than the full\n * FQDN. Querying `mail.foo.example.com.multi.surbl.org` returns NXDOMAIN\n * even when `example.com` is listed.\n */\nconst REGISTRABLE_ONLY_LISTS = new Set(['multi.surbl.org', 'multi.uribl.com'])\n\n/** DNS-query concurrency for parallel lookups. Keep modest to avoid resolver throttling. */\nconst DNS_CONCURRENCY = 8\n\nexport interface Resolver {\n resolve4(hostname: string): Promise<string[]>\n}\n\nconst defaultResolver: Resolver = {\n resolve4: (hostname) => dns.resolve4(hostname),\n}\n\nexport interface RunDnsblOptions {\n /** Override the DNS resolver (used in tests). */\n resolver?: Resolver\n /** When true, ignore the throttle and run all checks immediately. */\n force?: boolean\n}\n\nexport interface RunDnsblResult {\n ran: boolean\n reason?: string\n totalChecks?: number\n listedCount?: number\n}\n\n/**\n * Run DNSBL checks for every (target × list) pair. Idempotent — the latest\n * result for each pair is upserted.\n */\nexport async function runDnsblChecks(\n ctx: RunnerContext,\n opts: RunDnsblOptions = {},\n): Promise<RunDnsblResult> {\n const cfg = ctx.config.dnsbl ?? {}\n const intervalHours = cfg.intervalHours ?? 24\n\n if (!opts.force && intervalHours <= 0) {\n return { ran: false, reason: 'disabled' }\n }\n\n const targets = collectTargets(ctx, cfg)\n if (targets.domains.length === 0 && targets.ips.length === 0) {\n return { ran: false, reason: 'no_targets' }\n }\n\n const resolver = opts.resolver ?? defaultResolver\n const domainLists = cfg.domainLists ?? DEFAULT_DOMAIN_DNSBL_LISTS\n const ipLists = cfg.ipLists ?? DEFAULT_IP_DNSBL_LISTS\n\n const pairs: Array<{\n target: string\n targetKind: DnsblTargetKind\n list: DnsblListSpec\n }> = []\n for (const d of targets.domains) {\n for (const l of domainLists) pairs.push({ target: d, targetKind: 'domain', list: l })\n }\n for (const ip of targets.ips) {\n for (const l of ipLists) pairs.push({ target: ip, targetKind: 'ip', list: l })\n }\n\n // Per-pair throttle: skip pairs whose existing row is fresher than the\n // interval. Force ignores the throttle. This replaces the previous\n // single-most-recent-check gate that blocked the whole suite based on\n // one stale row.\n const throttleCutoff = opts.force ? null : Date.now() - intervalHours * 60 * 60 * 1000\n let duePairs = pairs\n if (throttleCutoff != null) {\n const existing = await ctx.collections.dnsblChecks\n .find(\n {\n $or: pairs.map((p) => ({ target: p.target, list: p.list.host })),\n },\n { projection: { target: 1, list: 1, runAt: 1 } },\n )\n .toArray()\n const fresh = new Set<string>()\n for (const e of existing) {\n if (new Date(e.runAt).getTime() > throttleCutoff) {\n fresh.add(`${e.target}|${e.list}`)\n }\n }\n duePairs = pairs.filter((p) => !fresh.has(`${p.target}|${p.list.host}`))\n if (duePairs.length === 0) {\n return { ran: false, reason: 'not_due', totalChecks: 0, listedCount: 0 }\n }\n }\n\n let listedCount = 0\n\n // Bounded parallelism — DNS lookups are I/O-bound, but blasting all 25+\n // queries at once invites resolver throttling.\n async function processPair(p: typeof pairs[number]) {\n const queryName = buildQueryName(p.target, p.targetKind, p.list.host)\n const lookup = queryName\n ? await queryDnsbl(resolver, queryName)\n : { result: 'error' as DnsblResult, returnCodes: [], errorMessage: 'unsupported target format' }\n // Transient DNS failure: preserve the prior verdict so a momentary\n // resolver hiccup doesn't flip a clean target to 'error' in setup-status.\n if (lookup.transient) return\n if (lookup.result === 'listed') listedCount++\n await ctx.collections.dnsblChecks.updateOne(\n { target: p.target, list: p.list.host },\n {\n $set: {\n target: p.target,\n targetKind: p.targetKind,\n list: p.list.host,\n listLabel: p.list.label,\n result: lookup.result,\n returnCodes: lookup.returnCodes,\n errorMessage: lookup.errorMessage,\n runAt: new Date(),\n },\n },\n { upsert: true },\n )\n }\n\n let idx = 0\n await Promise.all(\n Array.from({ length: Math.min(DNS_CONCURRENCY, duePairs.length) }, async () => {\n while (idx < duePairs.length) {\n const my = idx++\n await processPair(duePairs[my]!)\n }\n }),\n )\n\n return { ran: true, totalChecks: duePairs.length, listedCount }\n}\n\n/**\n * Targets we'll check: every sender domain we know about + any explicitly\n * configured dedicated IPs. Domains come from `senderDomains` registry plus\n * the From defaults so an operator who only set fromDefaults still gets\n * coverage.\n */\nfunction collectTargets(ctx: RunnerContext, cfg: DnsblConfig): { domains: string[]; ips: string[] } {\n const domains = new Set<string>()\n const registry = ctx.config.senderDomains\n if (registry) {\n for (const d of Object.keys(registry)) domains.add(d.toLowerCase())\n }\n const fromDomain = ctx.config.fromDefaults?.email\n ? extractDomain(ctx.config.fromDefaults.email)\n : null\n if (fromDomain) domains.add(fromDomain)\n const txnDomain = ctx.config.transactionalFromDefaults?.email\n ? extractDomain(ctx.config.transactionalFromDefaults.email)\n : null\n if (txnDomain) domains.add(txnDomain)\n\n // Both IPv4 and IPv6 are valid query targets — let the lookup layer handle\n // formatting per RFC 5782. Invalid strings are dropped here so they don't\n // produce a row with errorMessage='unsupported target format' on every run.\n return {\n domains: Array.from(domains),\n ips: (cfg.dedicatedIps ?? []).filter((ip) => net.isIP(ip) !== 0),\n }\n}\n\n/**\n * Compute the DNS name to query for a (target, list) pair, honoring the\n * per-list peculiarities:\n * - IPv4: reverse octets and prepend.\n * - IPv6: reverse nibble-by-nibble per RFC 5782.\n * - Domain on a registrable-only list (SURBL/URIBL): collapse to eTLD+1.\n *\n * Returns null when the target shape isn't supported by the list (e.g.,\n * IPv4-only list given an IPv6 target).\n */\nfunction buildQueryName(target: string, kind: DnsblTargetKind, listHost: string): string | null {\n if (kind === 'ip') {\n const v = net.isIP(target)\n if (v === 4) return `${reverseIPv4(target)}.${listHost}`\n if (v === 6) return `${reverseIPv6Nibbles(target)}.${listHost}`\n return null\n }\n // Domain — collapse to registrable label for lists that demand it.\n const domain = REGISTRABLE_ONLY_LISTS.has(listHost) ? registrableDomain(target) : target\n return `${domain}.${listHost}`\n}\n\ninterface QueryResult {\n /** When true, the underlying DNS query failed transiently (SERVFAIL etc).\n * Caller should leave the existing row in place rather than overwrite it. */\n transient?: boolean\n result: DnsblResult\n returnCodes: string[]\n errorMessage: string | null\n}\n\n// Transient DNS errors we don't want to treat as a \"list error\" — these\n// indicate a resolver problem or rate-limit at the block-list side and\n// should be retried next tick rather than producing a setup-status warn.\nconst TRANSIENT_DNS_CODES = new Set(['ESERVFAIL', 'EREFUSED', 'ETIMEOUT', 'ETIMEDOUT', 'ECONNRESET', 'ECONNREFUSED'])\n\nasync function queryDnsbl(resolver: Resolver, query: string): Promise<QueryResult> {\n try {\n const records = await resolver.resolve4(query)\n return interpretRecords(records)\n } catch (err: any) {\n const code = err?.code\n // NXDOMAIN / no records → not listed.\n if (code === 'ENOTFOUND' || code === 'ENODATA') {\n return { result: 'clean', returnCodes: [], errorMessage: null }\n }\n // Transient: signal the runner to skip the upsert. Spamhaus and friends\n // SERVFAIL when rate-limiting public resolvers; storing those as 'error'\n // produces setup-status warn churn without operator-actionable signal.\n if (code && TRANSIENT_DNS_CODES.has(code)) {\n return {\n transient: true,\n result: 'error',\n returnCodes: [],\n errorMessage: String(err?.message ?? err),\n }\n }\n return {\n result: 'error',\n returnCodes: [],\n errorMessage: String(err?.message ?? err),\n }\n }\n}\n\nexport function interpretRecords(records: string[]): QueryResult {\n if (!records || records.length === 0) {\n return { result: 'clean', returnCodes: [], errorMessage: null }\n }\n // Per Spamhaus convention, 127.255.255.x is reserved for query-error /\n // public-resolver / blocked-by-list signals. Treat those as errors so they\n // don't false-positive a \"listed\" verdict.\n const errorish = records.filter((r) => r.startsWith('127.255.255.'))\n if (errorish.length === records.length) {\n return {\n result: 'error',\n returnCodes: records,\n errorMessage: `list returned reserved code(s): ${records.join(', ')}`,\n }\n }\n const listed = records.filter((r) => r.startsWith('127.') && !r.startsWith('127.255.255.'))\n if (listed.length > 0) {\n return { result: 'listed', returnCodes: records, errorMessage: null }\n }\n return { result: 'clean', returnCodes: records, errorMessage: null }\n}\n\nexport function reverseIPv4(ip: string): string {\n return ip.split('.').reverse().join('.')\n}\n\n/**\n * RFC 5782 §2.4 nibble-reversed form for IPv6. Each hex digit becomes its\n * own label in reverse order. Example:\n * 2001:db8::1\n * → 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2\n *\n * Handles IPv4-mapped form (`::ffff:1.2.3.4`) by converting the embedded\n * dot-octet portion into two hex groups before nibble-expanding.\n */\nexport function reverseIPv6Nibbles(ip: string): string {\n // First convert any embedded IPv4 (\"::ffff:1.2.3.4\" → \"::ffff:0102:0304\").\n const v4Match = /:(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})$/.exec(ip)\n let normalized = ip\n if (v4Match) {\n const octets = v4Match[1]!.split('.').map((o) => Number(o))\n if (octets.length === 4 && octets.every((o) => o >= 0 && o <= 255)) {\n const hi = ((octets[0]! << 8) | octets[1]!).toString(16).padStart(4, '0')\n const lo = ((octets[2]! << 8) | octets[3]!).toString(16).padStart(4, '0')\n normalized = ip.slice(0, v4Match.index) + ':' + hi + ':' + lo\n }\n }\n\n // Expand `::` shorthand and zero-pad each group to 4 chars.\n const sides = normalized.split('::')\n let groups: string[]\n if (sides.length === 1) {\n groups = sides[0]!.split(':')\n } else {\n const left = sides[0]!.split(':').filter(Boolean)\n const right = sides[1]!.split(':').filter(Boolean)\n const missing = 8 - left.length - right.length\n groups = [...left, ...Array(missing).fill('0'), ...right]\n }\n if (groups.length !== 8) {\n throw new Error(`unexpected IPv6 group count for ${ip}: ${groups.length}`)\n }\n const padded = groups.map((g) => g.toLowerCase().padStart(4, '0')).join('')\n return padded.split('').reverse().join('.')\n}\n\n/**\n * Public Suffix List-aware eTLD+1 extraction. Required for SURBL / URIBL\n * which need the registrable domain — `mail.example.co.uk` must collapse to\n * `example.co.uk`, not `co.uk`. Falls back to the original input when PSL\n * can't classify the domain (e.g., a private TLD).\n */\nfunction registrableDomain(domain: string): string {\n const parsed = psl.parse(domain)\n if ('domain' in parsed && parsed.domain) return parsed.domain\n return domain\n}\n","/**\n * Google Postmaster Tools API client + daily puller.\n *\n * - Exchanges the operator-provided OAuth refresh token for short-lived\n * access tokens (cached until ~5 minutes before expiry).\n * - Pulls per-domain TrafficStats for each registered sender domain.\n * - Persists one PostmasterSnapshot per (domain, day).\n * - When a snapshot reports `domainReputation: 'BAD'`, trips the\n * (domain × marketing) health bucket so the runner stops dispatching\n * marketing mail from that domain.\n *\n * Setup is one-time and external — operator creates an OAuth client in their\n * own Google Cloud project, performs the consent flow, and configures the\n * refresh token in MailerConfig.postmaster.\n */\n\nimport type { PostmasterConfig } from '../config.js'\nimport type {\n PostmasterReputation,\n PostmasterSnapshotDoc,\n} from '../models/index.js'\nimport { extractDomain } from '../templates/sender-domain.js'\nimport type { RunnerContext } from './index.js'\nimport { healthBucketId } from '../models/index.js'\n\nconst OAUTH_TOKEN_URL = 'https://oauth2.googleapis.com/token'\nconst POSTMASTER_BASE = 'https://gmailpostmastertools.googleapis.com/v1'\nconst FETCH_TIMEOUT_MS = 15_000\n\nexport type Fetcher = (url: string, init?: RequestInit) => Promise<Response>\n\nasync function fetchWithTimeout(fetcher: Fetcher, url: string, init: RequestInit = {}, timeoutMs = FETCH_TIMEOUT_MS): Promise<Response> {\n const ctl = new AbortController()\n const t = setTimeout(() => ctl.abort(), timeoutMs)\n try {\n return await fetcher(url, { ...init, signal: ctl.signal })\n } finally {\n clearTimeout(t)\n }\n}\n\nexport interface PostmasterClient {\n listDomains(): Promise<Array<{ name: string; createTime?: string }>>\n getLatestTrafficStats(domain: string): Promise<TrafficStat | null>\n}\n\ninterface OAuthResponse {\n access_token: string\n expires_in: number\n scope?: string\n token_type?: string\n}\n\nexport interface TrafficStat {\n /** Resource name, e.g. `domains/example.com/trafficStats/20240101`. */\n name: string\n domainReputation?: PostmasterReputation\n ipReputations?: Array<{ reputation: PostmasterReputation; ipCount: string | number }>\n userReportedSpamRatio?: number\n spfSuccessRatio?: number\n dkimSuccessRatio?: number\n dmarcSuccessRatio?: number\n inboundEncryptionRatio?: number\n outboundEncryptionRatio?: number\n deliveryErrors?: Array<{ errorType: string; errorClass: string; errorRatio: number }>\n spammyFeedbackLoops?: Array<{ id: string; spamRatio: number }>\n}\n\nexport function createPostmasterClient(\n cfg: Pick<PostmasterConfig, 'clientId' | 'clientSecret' | 'refreshToken'>,\n fetcher: Fetcher = globalThis.fetch,\n): PostmasterClient {\n let cached: { accessToken: string; expiresAt: number } | null = null\n\n async function getAccessToken(): Promise<string> {\n if (cached && cached.expiresAt > Date.now() + 5 * 60 * 1000) {\n return cached.accessToken\n }\n const body = new URLSearchParams({\n client_id: cfg.clientId,\n client_secret: cfg.clientSecret,\n refresh_token: cfg.refreshToken,\n grant_type: 'refresh_token',\n })\n const res = await fetchWithTimeout(fetcher, OAUTH_TOKEN_URL, {\n method: 'POST',\n headers: { 'content-type': 'application/x-www-form-urlencoded' },\n body: body.toString(),\n })\n if (!res.ok) {\n throw new Error(`Postmaster OAuth token refresh failed: ${res.status} ${await safeText(res)}`)\n }\n const data = (await res.json()) as OAuthResponse\n cached = {\n accessToken: data.access_token,\n expiresAt: Date.now() + data.expires_in * 1000,\n }\n return cached.accessToken\n }\n\n async function authedGet<T>(path: string): Promise<T> {\n const token = await getAccessToken()\n const res = await fetchWithTimeout(fetcher, `${POSTMASTER_BASE}${path}`, {\n method: 'GET',\n headers: { authorization: `Bearer ${token}` },\n })\n if (!res.ok) {\n throw new Error(`Postmaster GET ${path} failed: ${res.status} ${await safeText(res)}`)\n }\n return (await res.json()) as T\n }\n\n return {\n async listDomains() {\n const data = await authedGet<{ domains?: Array<{ name: string; createTime?: string }> }>('/domains')\n return data.domains ?? []\n },\n\n async getLatestTrafficStats(domain: string) {\n // Postmaster traffic stats are reported with a ~2-day delay. Pull the\n // most recent available; the API returns them in reverse-chronological\n // order when no date range is specified.\n const data = await authedGet<{ trafficStats?: TrafficStat[] }>(\n `/domains/${encodeURIComponent(domain)}/trafficStats?pageSize=1`,\n )\n return data.trafficStats?.[0] ?? null\n },\n }\n}\n\nasync function safeText(res: Response): Promise<string> {\n try {\n return await res.text()\n } catch {\n return '<no body>'\n }\n}\n\n// ---------------------------------------------------------------------------\n// Puller\n// ---------------------------------------------------------------------------\n\nexport interface RunPostmasterOptions {\n client?: PostmasterClient\n fetcher?: Fetcher\n force?: boolean\n}\n\nexport interface RunPostmasterResult {\n ran: boolean\n reason?: string\n fetched?: number\n trippedDomains?: string[]\n}\n\nexport async function runPostmasterPull(\n ctx: RunnerContext,\n opts: RunPostmasterOptions = {},\n): Promise<RunPostmasterResult> {\n const cfg = ctx.config.postmaster\n if (!cfg) return { ran: false, reason: 'not_configured' }\n\n const intervalHours = cfg.intervalHours ?? 24\n if (!opts.force && intervalHours <= 0) {\n return { ran: false, reason: 'disabled' }\n }\n\n const client =\n opts.client ?? createPostmasterClient(cfg, opts.fetcher)\n const allDomains = resolveDomains(ctx, cfg)\n if (allDomains.length === 0) {\n return { ran: false, reason: 'no_domains' }\n }\n\n // Per-domain throttle — fetch only domains whose latest snapshot is\n // older than intervalHours. Previously a single global timestamp across\n // all domains locked unfetched / partially-failed domains out of the\n // next run for a full window.\n let domains = allDomains\n if (!opts.force) {\n const cutoff = Date.now() - intervalHours * 60 * 60 * 1000\n const latest = await ctx.collections.postmasterSnapshots\n .find({ domain: { $in: allDomains } }, { projection: { domain: 1, fetchedAt: 1 } })\n .sort({ fetchedAt: -1 })\n .limit(allDomains.length * 8)\n .toArray()\n const lastByDomain = new Map<string, number>()\n for (const s of latest) {\n const ts = new Date(s.fetchedAt).getTime()\n const cur = lastByDomain.get(s.domain) ?? 0\n if (ts > cur) lastByDomain.set(s.domain, ts)\n }\n domains = allDomains.filter((d) => (lastByDomain.get(d) ?? 0) < cutoff)\n if (domains.length === 0) {\n return { ran: false, reason: 'not_due' }\n }\n }\n\n // Fetch all domains in parallel — they're independent HTTP calls and\n // serial ordering only multiplies tick latency.\n const fetches = await Promise.all(\n domains.map(async (domain) => {\n try {\n const stat = await client.getLatestTrafficStats(domain)\n return { domain, stat, error: null as Error | null }\n } catch (err: any) {\n console.error(`mailery: postmaster fetch failed for ${domain}`, err)\n return { domain, stat: null, error: err as Error }\n }\n }),\n )\n\n let fetched = 0\n const trippedDomains: string[] = []\n for (const { domain, stat } of fetches) {\n if (!stat) continue\n const snapshot = toSnapshot(domain, stat)\n if (!snapshot) continue\n fetched++\n\n await ctx.collections.postmasterSnapshots.updateOne(\n { domain: snapshot.domain, date: snapshot.date },\n { $set: snapshot },\n { upsert: true },\n )\n\n if (snapshot.domainReputation === 'BAD') {\n // Trip every kind the registry says this domain is allowed to send\n // as. If the registry doesn't know this domain at all, skip the\n // auto-trip — we have no signal that the operator wants this domain\n // gated by mailery.\n const kindsToTrip = kindsForDomain(ctx, domain)\n for (const kind of kindsToTrip) {\n const tripped = await tripBucket(ctx, domain, kind, snapshot)\n if (tripped) trippedDomains.push(`${domain}|${kind}`)\n }\n }\n }\n\n return { ran: true, fetched, trippedDomains }\n}\n\nfunction kindsForDomain(ctx: RunnerContext, domain: string): Array<'marketing' | 'transactional'> {\n const registry = ctx.config.senderDomains ?? {}\n const entry = registry[domain.toLowerCase()]\n if (!entry) return []\n if (entry.kind === 'both') return ['marketing', 'transactional']\n return [entry.kind]\n}\n\nfunction resolveDomains(ctx: RunnerContext, cfg: PostmasterConfig): string[] {\n if (cfg.domains && cfg.domains.length > 0) {\n return cfg.domains.map((d) => d.toLowerCase())\n }\n const out = new Set<string>()\n const registry = ctx.config.senderDomains\n if (registry) {\n for (const d of Object.keys(registry)) out.add(d.toLowerCase())\n }\n const f = ctx.config.fromDefaults?.email ? extractDomain(ctx.config.fromDefaults.email) : null\n if (f) out.add(f)\n const t = ctx.config.transactionalFromDefaults?.email\n ? extractDomain(ctx.config.transactionalFromDefaults.email)\n : null\n if (t) out.add(t)\n return Array.from(out)\n}\n\nfunction toSnapshot(domain: string, stat: TrafficStat): PostmasterSnapshotDoc | null {\n // `name` looks like `domains/example.com/trafficStats/20240115`. Bail out\n // when the format isn't recognized rather than overwriting today's snapshot\n // every run — the previous fallback to today's UTC date silently rewrote\n // legitimate data when the API format ever drifted.\n const m = /\\/trafficStats\\/(\\d{8})$/.exec(stat.name ?? '')\n if (!m) {\n console.error(`mailery: postmaster snapshot for ${domain} has unrecognized name \"${stat.name}\" — skipping`)\n return null\n }\n const yyyymmdd = m[1]!\n const date = `${yyyymmdd.slice(0, 4)}-${yyyymmdd.slice(4, 6)}-${yyyymmdd.slice(6, 8)}`\n\n return {\n domain,\n date,\n domainReputation: stat.domainReputation ?? null,\n ipReputations: stat.ipReputations\n ? stat.ipReputations.map((r) => ({\n reputation: r.reputation,\n ipCount: typeof r.ipCount === 'string' ? Number(r.ipCount) : r.ipCount,\n }))\n : null,\n userReportedSpamRatio: stat.userReportedSpamRatio ?? null,\n spfSuccessRatio: stat.spfSuccessRatio ?? null,\n dkimSuccessRatio: stat.dkimSuccessRatio ?? null,\n dmarcSuccessRatio: stat.dmarcSuccessRatio ?? null,\n outboundEncryptionRatio: stat.outboundEncryptionRatio ?? null,\n inboundEncryptionRatio: stat.inboundEncryptionRatio ?? null,\n deliveryErrors: stat.deliveryErrors ?? null,\n spammyFeedbackLoops: stat.spammyFeedbackLoops ?? null,\n fetchedAt: new Date(),\n }\n}\n\n/**\n * Set a (domain × kind) bucket to `tripped` so the dispatcher holds matching\n * sends. The bucket is created on demand if it doesn't exist yet — Postmaster\n * can flag a domain before mailery has ever sent from it.\n */\nasync function tripBucket(\n ctx: RunnerContext,\n domain: string,\n kind: 'marketing' | 'transactional',\n snapshot: PostmasterSnapshotDoc,\n): Promise<boolean> {\n const id = healthBucketId(domain, kind)\n const reason = `Postmaster Tools reports ${domain} reputation = BAD on ${snapshot.date}`\n\n // Only update + alert when the bucket transitions to tripped — otherwise a\n // sustained BAD reputation would fire onCircuitBreakerTrip on every pull.\n const prior = await ctx.collections.health.findOne({ _id: id })\n if (prior?.status === 'tripped') {\n return false\n }\n\n await ctx.collections.health.updateOne(\n { _id: id },\n {\n $set: {\n status: 'tripped',\n trippedAt: new Date(),\n trippedReason: reason,\n updatedAt: new Date(),\n },\n $setOnInsert: {\n _id: id,\n senderDomain: domain,\n kind,\n windowStartedAt: new Date(),\n windowDurationMs: ctx.config.circuitBreaker.windowMinutes * 60 * 1000,\n manuallyResumedAt: null,\n counters: { sent: 0, delivered: 0, bounced: 0, hardBounced: 0, softBounced: 0, complained: 0, failedToSend: 0 },\n rates: { bounceRate: 0, hardBounceRate: 0, complaintRate: 0, failureRate: 0 },\n },\n },\n { upsert: true },\n )\n if (ctx.config.onCircuitBreakerTrip) {\n try {\n await ctx.config.onCircuitBreakerTrip({ reason, rates: { userReportedSpamRatio: snapshot.userReportedSpamRatio ?? 0 } })\n } catch {\n /* swallow */\n }\n }\n return true\n}\n","/**\n * Microsoft SNDS (Smart Network Data Services) puller.\n *\n * https://sendersupport.olc.protection.outlook.com/snds/\n *\n * SNDS reports IP-level Outlook/Hotmail/Live reputation: filter verdict\n * (GREEN/YELLOW/RED), complaint rate, spam-trap hits, and sample HELO /\n * MAIL FROM strings for each activity window. Only meaningful when the\n * operator sends from a dedicated IP — shared-IP senders see nothing\n * meaningful here.\n *\n * Auth is a per-account access key (no OAuth). The data endpoint returns\n * CSV. Snapshots are stored per (ip, activityStart) so historical windows\n * accumulate.\n */\n\nimport type { SndsConfig } from '../config.js'\nimport type { SndsFilterResult, SndsSnapshotDoc } from '../models/index.js'\nimport type { RunnerContext } from './index.js'\n\nconst SNDS_DATA_URL = 'https://postmaster.live.com/snds/data.aspx'\nconst FETCH_TIMEOUT_MS = 30_000\n\nexport type Fetcher = (url: string, init?: RequestInit) => Promise<Response>\n\nexport interface RunSndsOptions {\n fetcher?: Fetcher\n force?: boolean\n}\n\nexport interface RunSndsResult {\n ran: boolean\n reason?: string\n rowsParsed?: number\n rowsPersisted?: number\n}\n\nexport async function runSndsPull(\n ctx: RunnerContext,\n opts: RunSndsOptions = {},\n): Promise<RunSndsResult> {\n const cfg = ctx.config.snds\n if (!cfg?.accessKey) return { ran: false, reason: 'not_configured' }\n\n const intervalHours = cfg.intervalHours ?? 24\n if (!opts.force && intervalHours <= 0) return { ran: false, reason: 'disabled' }\n\n if (!opts.force) {\n const latest = await ctx.collections.sndsSnapshots\n .find({})\n .sort({ fetchedAt: -1 })\n .limit(1)\n .toArray()\n if (latest[0]) {\n const ageMs = Date.now() - new Date(latest[0].fetchedAt).getTime()\n if (ageMs < intervalHours * 60 * 60 * 1000) {\n return { ran: false, reason: 'not_due' }\n }\n }\n }\n\n const fetcher = opts.fetcher ?? globalThis.fetch\n const url = `${SNDS_DATA_URL}?key=${encodeURIComponent(cfg.accessKey)}`\n const ctl = new AbortController()\n const t = setTimeout(() => ctl.abort(), FETCH_TIMEOUT_MS)\n let res: Response\n try {\n res = await fetcher(url, { method: 'GET', signal: ctl.signal })\n } catch (err: any) {\n // Scrub the access key from any error message before it reaches a log.\n throw new Error(`SNDS data fetch failed: ${redactKey(String(err?.message ?? err), cfg.accessKey)}`)\n } finally {\n clearTimeout(t)\n }\n if (!res.ok) {\n throw new Error(`SNDS data fetch failed: ${res.status} ${redactKey(await safeText(res), cfg.accessKey)}`)\n }\n const csv = await res.text()\n const rows = parseSndsCsv(csv)\n\n const ipFilter = cfg.ips?.length ? new Set(cfg.ips) : null\n const now = new Date()\n const ops = rows\n .filter((row) => !ipFilter || ipFilter.has(row.ip))\n .map((row) => ({\n updateOne: {\n filter: { ip: row.ip, activityStart: row.activityStart },\n update: { $set: { ...row, fetchedAt: now } },\n upsert: true,\n },\n }))\n let persisted = 0\n if (ops.length > 0) {\n const r = await ctx.collections.sndsSnapshots.bulkWrite(ops, { ordered: false })\n persisted = (r.modifiedCount ?? 0) + (r.upsertedCount ?? 0)\n }\n\n return { ran: true, rowsParsed: rows.length, rowsPersisted: persisted }\n}\n\nfunction redactKey(s: string, key: string): string {\n if (!key) return s\n return s.split(key).join('<redacted>').split(encodeURIComponent(key)).join('<redacted>')\n}\n\nasync function safeText(res: Response): Promise<string> {\n try { return await res.text() } catch { return '<no body>' }\n}\n\n// ---------------------------------------------------------------------------\n// CSV parsing\n// ---------------------------------------------------------------------------\n\nexport interface ParsedSndsRow {\n ip: string\n activityStart: Date\n activityEnd: Date\n rcptCommands: number\n dataCommands: number\n messageRecipients: number\n filterResult: SndsFilterResult\n complaintRate: number | null\n trapMessageCount: number\n sampleHelo: string | null\n sampleMailFrom: string | null\n}\n\n/**\n * SNDS returns CSV with columns:\n * IP, ActivityStart, ActivityEnd, RCPTCommands, DATACommands,\n * MessageRecipients, FilterResult, ComplaintRate, TrapMessageCount,\n * SampleHELO, SampleMailFrom\n *\n * No header row. Fields may contain commas inside quoted strings (sample\n * HELO / MAIL FROM) — we handle simple double-quote escaping.\n */\nexport function parseSndsCsv(csv: string): ParsedSndsRow[] {\n const out: ParsedSndsRow[] = []\n for (const raw of csv.split(/\\r?\\n/)) {\n if (!raw.trim()) continue\n const fields = splitCsvRow(raw)\n if (fields.length < 7) continue // malformed row\n const parsed = parseRow(fields)\n if (parsed) out.push(parsed)\n }\n return out\n}\n\nfunction splitCsvRow(row: string): string[] {\n const out: string[] = []\n let cur = ''\n let inQuotes = false\n for (let i = 0; i < row.length; i++) {\n const ch = row[i]!\n if (inQuotes) {\n if (ch === '\"') {\n if (row[i + 1] === '\"') {\n cur += '\"'\n i++\n } else {\n inQuotes = false\n }\n } else {\n cur += ch\n }\n } else if (ch === '\"') {\n inQuotes = true\n } else if (ch === ',') {\n out.push(cur)\n cur = ''\n } else {\n cur += ch\n }\n }\n out.push(cur)\n return out.map((f) => f.trim())\n}\n\nfunction parseRow(fields: string[]): ParsedSndsRow | null {\n const [\n ip,\n activityStart,\n activityEnd,\n rcptCommands,\n dataCommands,\n messageRecipients,\n filterResult,\n complaintRate,\n trapMessageCount,\n sampleHelo,\n sampleMailFrom,\n ] = fields\n\n const start = parseSndsDate(activityStart ?? '')\n const end = parseSndsDate(activityEnd ?? '')\n if (!ip || !start || !end) return null\n\n return {\n ip,\n activityStart: start,\n activityEnd: end,\n rcptCommands: toInt(rcptCommands),\n dataCommands: toInt(dataCommands),\n messageRecipients: toInt(messageRecipients),\n filterResult: normalizeFilter(filterResult ?? ''),\n complaintRate: parseComplaintRate(complaintRate ?? ''),\n trapMessageCount: toInt(trapMessageCount),\n sampleHelo: sampleHelo ? sampleHelo : null,\n sampleMailFrom: sampleMailFrom ? sampleMailFrom : null,\n }\n}\n\nfunction toInt(s: string | undefined): number {\n if (!s) return 0\n const n = Number(s.replace(/[^\\d-]/g, ''))\n return Number.isFinite(n) ? n : 0\n}\n\nfunction normalizeFilter(s: string): SndsFilterResult {\n const u = s.toUpperCase().trim()\n if (u === 'GREEN' || u === 'YELLOW' || u === 'RED') return u\n return 'UNKNOWN'\n}\n\n/**\n * SNDS reports complaint rate in the formats: `<0.1%`, `0.1-0.3%`, `0.3-0.5%`,\n * `0.5-1%`, `1-2%`, `2-4%`, `>4%`. We persist the upper bound as a 0-1 fraction.\n */\nexport function parseComplaintRate(s: string): number | null {\n const trimmed = s.trim()\n if (!trimmed || trimmed === '-' || /n\\/?a/i.test(trimmed)) return null\n\n const cleaned = trimmed.replace(/%/g, '')\n // `<X` → X\n let m = /^<\\s*(\\d+(?:\\.\\d+)?)$/.exec(cleaned)\n if (m) return Number(m[1]) / 100\n // `>X` → X (lower bound; treat as the floor of what they're reporting)\n m = /^>\\s*(\\d+(?:\\.\\d+)?)$/.exec(cleaned)\n if (m) return Number(m[1]) / 100\n // `A-B` → B\n m = /^(\\d+(?:\\.\\d+)?)\\s*-\\s*(\\d+(?:\\.\\d+)?)$/.exec(cleaned)\n if (m) return Number(m[2]) / 100\n // Plain number\n m = /^(\\d+(?:\\.\\d+)?)$/.exec(cleaned)\n if (m) return Number(m[1]) / 100\n return null\n}\n\n/**\n * SNDS reports dates as `M/D/YYYY h:mm AM/PM` in Microsoft's Pacific time\n * (PST/PDT) — Microsoft's own docs are silent but community testing\n * consistently shows Pacific. Convert to UTC by applying the offset that\n * was in effect at that local timestamp.\n *\n * Daylight saving in the US runs second-Sunday-of-March → first-Sunday-of-\n * November. We compute the offset based on the parsed local-Pacific\n * timestamp; a fixed -8/-7 offset would be wrong around the boundaries.\n */\nexport function parseSndsDate(s: string): Date | null {\n const trimmed = s.trim()\n if (!trimmed) return null\n const m = /^(\\d{1,2})\\/(\\d{1,2})\\/(\\d{4})\\s+(\\d{1,2}):(\\d{2})(?::(\\d{2}))?\\s*(AM|PM)?$/i.exec(trimmed)\n if (m) {\n const month = Number(m[1]) - 1\n const day = Number(m[2])\n const year = Number(m[3])\n let hour = Number(m[4])\n const minute = Number(m[5])\n const second = Number(m[6] ?? 0)\n const meridiem = m[7]?.toUpperCase()\n if (meridiem === 'PM' && hour < 12) hour += 12\n if (meridiem === 'AM' && hour === 12) hour = 0\n // First place the wall-clock instant in UTC, then add the Pacific\n // offset to convert back to a real UTC moment.\n const wallMs = Date.UTC(year, month, day, hour, minute, second)\n if (!Number.isFinite(wallMs)) return null\n const offsetHours = isUsPacificDst(year, month, day) ? 7 : 8\n return new Date(wallMs + offsetHours * 60 * 60 * 1000)\n }\n // Fallback: ISO-ish strings get parsed as expected by Date.\n const d = new Date(trimmed)\n if (!isNaN(d.getTime())) return d\n return null\n}\n\n/**\n * US daylight saving runs from the second Sunday of March through the\n * first Sunday of November. Pure date math against the wall-clock day —\n * close enough for SNDS export granularity (full-day activity windows).\n */\nfunction isUsPacificDst(year: number, month0: number, day: number): boolean {\n if (month0 > 2 && month0 < 10) return true\n if (month0 < 2 || month0 > 10) return false\n // March: starts on second Sunday.\n if (month0 === 2) {\n const dst = nthSundayOfMonth(year, 2, 2)\n return day >= dst\n }\n // November: ends on first Sunday.\n const dst = nthSundayOfMonth(year, 10, 1)\n return day < dst\n}\n\nfunction nthSundayOfMonth(year: number, month0: number, n: number): number {\n const first = new Date(Date.UTC(year, month0, 1))\n const dayOfWeek = first.getUTCDay()\n const firstSunday = 1 + ((7 - dayOfWeek) % 7)\n return firstSunday + (n - 1) * 7\n}\n","/**\n * DMARC RUA aggregate report ingestion.\n *\n * - extractDmarcXml(buffer, filename) — decompresses .zip / .gz / .xml\n * - parseDmarcReport(xml) — pure RFC 7489 XML → normalized doc + failures\n * - ingestDmarcAttachment(ctx, buffer, filename) — full ingest path:\n * extract → parse → upsert into mailer_dmarc_reports + _dmarc_failures\n *\n * Designed so the same `ingestDmarcAttachment` is used by:\n * - the admin file-upload endpoint\n * - the (future) SendGrid Inbound Parse webhook\n * - the (future) IMAP poller\n * - the `mailery ingest-dmarc` CLI\n */\n\n// `adm-zip` is still loaded lazily — `extractDmarcXmls` is already async, so\n// `await import()` costs nothing and compiles correctly under both output\n// formats.\n//\n// `fast-xml-parser` is NOT lazy. `parseDmarcReport` is synchronous, so the\n// only lazy form available to it was `require()`, and tsup compiles that to\n// esbuild's `__require` shim, which throws unconditionally in the ESM output\n// of a `\"type\": \"module\"` package. That shipped broken in v0.14.0 (see #12).\n// A static import is the one form that is correct in both the esm and cjs\n// bundles. The cost is ~25ms of module init at import time (against ~360ms\n// for the bundle as a whole) for a package that is a hard, non-optional\n// dependency and is therefore always installed anyway.\nimport type AdmZipType from 'adm-zip'\nimport { XMLParser } from 'fast-xml-parser'\n\nimport type {\n DmarcAuthResult,\n DmarcFailureDoc,\n DmarcPolicy,\n DmarcReportDoc,\n} from '../models/index.js'\nimport type { RunnerContext } from './index.js'\n\n/**\n * Hard cap on decompressed bytes. A real RUA aggregate report is well under\n * 1 MB; anything above this is either malformed or an attempted zip bomb.\n */\nconst MAX_DECOMPRESSED_BYTES = 50 * 1024 * 1024\n\n/**\n * Reject zip entry names that would escape the extraction directory if we\n * were writing them to disk, plus null-byte injection. We only ever read\n * the buffer in memory, but defense-in-depth keeps us safe if the storage\n * model changes.\n */\nexport function assertSafeZipEntryName(rawName: string): void {\n if (typeof rawName !== 'string' || rawName.length === 0) {\n throw new Error(`zip entry has unsafe path: <empty>`)\n }\n if (rawName.includes('\\0')) {\n throw new Error(`zip entry has unsafe path: contains null byte`)\n }\n // POSIX absolute (`/etc/passwd`) or Windows-drive (`C:\\…`) paths.\n if (rawName.startsWith('/') || rawName.startsWith('\\\\') || /^[a-zA-Z]:[\\\\/]/.test(rawName)) {\n throw new Error(`zip entry has unsafe path: ${rawName}`)\n }\n const parts = rawName.split(/[/\\\\]/)\n if (parts.some((p) => p === '..')) {\n throw new Error(`zip entry has unsafe path: ${rawName}`)\n }\n}\n\n// ---------------------------------------------------------------------------\n// Extraction\n// ---------------------------------------------------------------------------\n\n/**\n * Pull DMARC XML payload(s) out of an attachment. Receivers send `.zip` or\n * `.gz` (or rarely a bare `.xml`). A multi-file zip returns each entry as a\n * separate string — concatenating them with `\\n` produces invalid XML with\n * two `<feedback>` roots.\n *\n * Defends against:\n * - decompression bombs — caps inflated bytes at MAX_DECOMPRESSED_BYTES\n * - zip-slip path traversal — rejects entries with absolute or `..` paths\n * - empty / malformed archives — throws with a useful message\n */\nexport async function extractDmarcXmls(buffer: Buffer, filename: string): Promise<string[]> {\n const lower = (filename ?? '').toLowerCase()\n const zlib = await import('node:zlib')\n\n if (lower.endsWith('.gz')) {\n const xml = await new Promise<string>((resolve, reject) => {\n const chunks: Buffer[] = []\n let bytes = 0\n const stream = zlib.createGunzip()\n stream.on('data', (chunk: Buffer) => {\n bytes += chunk.length\n if (bytes > MAX_DECOMPRESSED_BYTES) {\n stream.destroy()\n reject(new Error(`DMARC gzip exceeds ${MAX_DECOMPRESSED_BYTES} bytes (decompression bomb?)`))\n return\n }\n chunks.push(chunk)\n })\n stream.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')))\n stream.on('error', reject)\n stream.end(buffer)\n })\n return [xml]\n }\n\n if (lower.endsWith('.zip')) {\n const { default: AdmZip } = await import('adm-zip')\n const zip = new (AdmZip as unknown as typeof AdmZipType)(buffer)\n const entries = zip.getEntries().filter((e) => !e.isDirectory)\n if (entries.length === 0) throw new Error('zip contains no files')\n\n let total = 0\n const pieces: string[] = []\n for (const entry of entries) {\n // Zip-slip defense — adm-zip has had CVE history (CVE-2018-1002204).\n assertSafeZipEntryName(entry.entryName)\n\n // Declared size is the fast-path bail — reject before decompressing\n // when a (truthful) header already exceeds the cap. Reject entries\n // with no declared size at all (DMARC receivers always populate it).\n const declaredSize = (entry.header as any)?.size\n if (typeof declaredSize !== 'number' || declaredSize <= 0) {\n throw new Error(`zip entry ${entry.entryName} has no declared size (refusing to decompress)`)\n }\n if (declaredSize > MAX_DECOMPRESSED_BYTES || total + declaredSize > MAX_DECOMPRESSED_BYTES) {\n throw new Error(`DMARC zip exceeds ${MAX_DECOMPRESSED_BYTES} bytes (decompression bomb?)`)\n }\n\n // Actual decompressed payload — defends against a forged header that\n // claims a tiny size but inflates huge. We pay the inflation cost for\n // this entry, but cap on cumulative real bytes before the next entry.\n const data = entry.getData()\n total += data.length\n if (total > MAX_DECOMPRESSED_BYTES) {\n throw new Error(`DMARC zip decompressed payload exceeds ${MAX_DECOMPRESSED_BYTES} bytes (forged header?)`)\n }\n // Compression-ratio sanity check only kicks in on larger entries —\n // legitimate tiny XML inflates ~64x routinely. The cumulative cap\n // above already covers the real bomb scenarios for small entries.\n if (declaredSize > 10 * 1024 && data.length > declaredSize * 64 + 1024) {\n throw new Error(`DMARC zip entry ${entry.entryName} decompressed size (${data.length}) far exceeds declared (${declaredSize})`)\n }\n pieces.push(data.toString('utf8'))\n }\n return pieces\n }\n\n // Treat as raw XML — still cap by raw buffer size.\n if (buffer.length > MAX_DECOMPRESSED_BYTES) {\n throw new Error(`DMARC payload exceeds ${MAX_DECOMPRESSED_BYTES} bytes`)\n }\n return [buffer.toString('utf8')]\n}\n\n/**\n * Convenience wrapper for callers that handle a single report.\n * @deprecated prefer `extractDmarcXmls` so multi-file zips can be parsed\n * independently. Kept temporarily; remove once all callers migrate.\n */\nexport async function extractDmarcXml(buffer: Buffer, filename: string): Promise<string> {\n const xmls = await extractDmarcXmls(buffer, filename)\n return xmls.join('\\n')\n}\n\n// ---------------------------------------------------------------------------\n// XML parsing\n// ---------------------------------------------------------------------------\n\nexport interface ParsedDmarcReport {\n report: Omit<DmarcReportDoc, 'receivedAt'>\n failures: Array<Omit<DmarcFailureDoc, 'receivedAt'>>\n}\n\n/**\n * Parse RFC 7489 aggregate report XML. Tolerant — receivers vary slightly in\n * casing and field order. Throws if the XML can't be parsed at all or if\n * required identifiers (report_id, domain, date_range) are missing.\n */\nexport function parseDmarcReport(xml: string): ParsedDmarcReport {\n const parser = new XMLParser({\n ignoreAttributes: false,\n parseAttributeValue: false,\n parseTagValue: false,\n trimValues: true,\n // RFC 7489 specifies lowercase snake_case tag names, but some\n // less-careful receivers emit CamelCase. Normalize before lookup.\n transformTagName: (t: string) => t.toLowerCase(),\n })\n const root: any = parser.parse(xml)\n const fb = root?.feedback\n if (!fb) throw new Error('DMARC XML missing <feedback> root')\n\n const meta = fb.report_metadata ?? {}\n const policy = fb.policy_published ?? {}\n\n const reportId = String(meta.report_id ?? '').trim()\n const orgName = String(meta.org_name ?? '').trim()\n const email = String(meta.email ?? '').trim()\n const domain = String(policy.domain ?? '').trim().toLowerCase()\n const policyP = (policy.p ?? 'none') as DmarcPolicy\n const rawPct = Number(policy.pct ?? 100)\n // Use isFinite so pct=0 (legit \"monitor only\" config) survives.\n const policyPct = Number.isFinite(rawPct) ? Math.max(0, Math.min(100, rawPct)) : 100\n\n if (!reportId) throw new Error('DMARC XML missing report_id')\n if (!domain) throw new Error('DMARC XML missing policy_published.domain')\n\n const range = meta.date_range ?? {}\n const begin = secondsToDate(range.begin)\n const end = secondsToDate(range.end)\n if (!begin || !end) throw new Error('DMARC XML missing date_range')\n\n const records = toArray<any>(fb.record)\n const failures: ParsedDmarcReport['failures'] = []\n let totalMessages = 0\n let passCount = 0\n let failCount = 0\n\n // Day bucket = mid-point of the report window.\n const midMs = Math.floor((begin.getTime() + end.getTime()) / 2)\n const day = new Date(midMs).toISOString().slice(0, 10)\n\n for (const rec of records) {\n const row = rec?.row ?? {}\n const count = Number(row.count ?? 0) || 0\n totalMessages += count\n\n const evald = row.policy_evaluated ?? {}\n const dkim = (evald.dkim ?? 'none') as DmarcAuthResult\n const spf = (evald.spf ?? 'none') as DmarcAuthResult\n const aligned = dkim === 'pass' || spf === 'pass'\n\n if (aligned) {\n passCount += count\n continue\n }\n failCount += count\n\n const sourceIp = String(row.source_ip ?? '').trim()\n if (!sourceIp) continue\n const headerFrom = String(rec?.identifiers?.header_from ?? '').toLowerCase()\n const dispositionApplied = String(evald.disposition ?? 'none')\n\n failures.push({\n reportId,\n domain,\n sourceIp,\n count,\n headerFrom,\n dkimResult: dkim,\n spfResult: spf,\n dispositionApplied,\n day,\n })\n }\n\n return {\n report: {\n reportId,\n orgName,\n email,\n domain,\n policyP,\n policyPct,\n rangeStart: begin,\n rangeEnd: end,\n totalMessages,\n passCount,\n failCount,\n },\n failures,\n }\n}\n\nfunction secondsToDate(v: unknown): Date | null {\n if (v === undefined || v === null) return null\n const n = typeof v === 'number' ? v : Number(String(v))\n if (!Number.isFinite(n) || n <= 0) return null\n return new Date(n * 1000)\n}\n\nfunction toArray<T>(v: T | T[] | undefined | null): T[] {\n if (v === undefined || v === null) return []\n return Array.isArray(v) ? v : [v]\n}\n\n// ---------------------------------------------------------------------------\n// Persistence\n// ---------------------------------------------------------------------------\n\nexport interface IngestResult {\n ok: true\n reportId: string\n domain: string\n rangeStart: Date\n rangeEnd: Date\n totalMessages: number\n passCount: number\n failCount: number\n duplicate: boolean\n}\n\nexport interface IngestOptions {\n /**\n * Gate on the report's `<policy_published><domain>`, checked after parsing\n * and before any write.\n *\n * The admin upload leaves this unset: the caller is already a privileged\n * operator who chose the file. The public inbound route\n * (`api/dmarc-inbound.ts`) sets it, because that endpoint authenticates with\n * a shared secret and nothing else — if the secret leaks, this is what keeps\n * the blast radius at \"reports about domains you actually send from\" rather\n * than \"arbitrary rows in your DMARC dashboard\".\n */\n allowDomain?: (domain: string) => boolean\n}\n\n/**\n * Full ingest path: extract attachment → parse each XML payload → upsert\n * into mailer_dmarc_reports + mailer_dmarc_failures. Idempotent on\n * (reportId, orgName) — re-uploading the same report is a no-op. When the\n * attachment is a multi-file zip, each entry is parsed independently and\n * the first ingest result is returned (with `additionalReports` count).\n */\nexport async function ingestDmarcAttachment(\n ctx: RunnerContext,\n buffer: Buffer,\n filename: string,\n opts: IngestOptions = {},\n): Promise<IngestResult & { additionalReports?: number }> {\n const xmls = await extractDmarcXmls(buffer, filename)\n if (xmls.length === 0) throw new Error('attachment contained no XML payload')\n const results: IngestResult[] = []\n let firstError: unknown = null\n for (const xml of xmls) {\n try {\n const parsed = parseDmarcReport(xml)\n if (opts.allowDomain && !opts.allowDomain(parsed.report.domain)) {\n throw new Error(`DMARC report is for domain \"${parsed.report.domain}\", which this deployment does not send from`)\n }\n results.push(await ingestParsedDmarcReport(ctx, parsed))\n } catch (err) {\n if (!firstError) firstError = err\n // Continue ingesting siblings — one malformed report in a multi-file\n // archive shouldn't reject all valid siblings.\n }\n }\n if (results.length === 0) {\n throw firstError ?? new Error('no parseable DMARC reports in attachment')\n }\n return { ...results[0]!, additionalReports: results.length - 1 }\n}\n\nexport async function ingestParsedDmarcReport(\n ctx: RunnerContext,\n parsed: ParsedDmarcReport,\n): Promise<IngestResult> {\n const now = new Date()\n const { report, failures } = parsed\n\n // Race-safe duplicate detection — let the unique index on\n // (reportId, orgName) decide. The prior findOne→insertOne split admitted\n // a window where two concurrent uploads of the same report could both\n // succeed.\n let duplicate = false\n try {\n await ctx.collections.dmarcReports.insertOne({ ...report, receivedAt: now })\n } catch (err: any) {\n if (err?.code === 11000) {\n duplicate = true\n } else {\n throw err\n }\n }\n\n if (!duplicate && failures.length > 0) {\n // Idempotent: unique index on (reportId, sourceIp) — duplicates skipped.\n // BulkWriteError mixes real + duplicate-key errors; inspect each write\n // error and rethrow if any aren't 11000.\n try {\n await ctx.collections.dmarcFailures.insertMany(\n failures.map((f) => ({ ...f, receivedAt: now })),\n { ordered: false },\n )\n } catch (err: any) {\n const writeErrors: Array<{ code?: number }> | undefined = err?.writeErrors\n if (Array.isArray(writeErrors)) {\n const nonDup = writeErrors.find((w) => w?.code !== 11000)\n if (nonDup) throw err\n } else if (err?.code !== 11000) {\n throw err\n }\n }\n }\n\n return {\n ok: true,\n reportId: report.reportId,\n domain: report.domain,\n rangeStart: report.rangeStart,\n rangeEnd: report.rangeEnd,\n totalMessages: report.totalMessages,\n passCount: report.passCount,\n failCount: report.failCount,\n duplicate,\n }\n}\n\n// ---------------------------------------------------------------------------\n// Retention\n// ---------------------------------------------------------------------------\n\n// Throttle DMARC prune so it doesn't fire on every tick (60s default). Once\n// per hour is plenty — failure rows live for retentionDays (default 90).\nlet _lastPruneAt = 0\nconst PRUNE_INTERVAL_MS = 60 * 60 * 1000\n\nexport async function pruneDmarcFailures(ctx: RunnerContext, opts: { force?: boolean } = {}): Promise<number> {\n const cfg = ctx.config.dmarc\n const days = cfg?.retentionDays ?? 90\n if (days <= 0) return 0\n if (!opts.force && Date.now() - _lastPruneAt < PRUNE_INTERVAL_MS) return 0\n _lastPruneAt = Date.now()\n const cutoff = new Date(Date.now() - days * 86_400_000)\n const r = await ctx.collections.dmarcFailures.deleteMany({ receivedAt: { $lt: cutoff } })\n return r.deletedCount ?? 0\n}\n\n// ---------------------------------------------------------------------------\n// Source tags — merge config-defined + db-defined\n// ---------------------------------------------------------------------------\n\nexport interface ResolvedSourceTag {\n ip: string\n label: string\n ignored: boolean\n /** 'config' = read-only (set in MailerConfig), 'db' = mutable from UI. */\n source: 'config' | 'db'\n}\n\nexport async function resolveSourceTags(ctx: RunnerContext): Promise<Map<string, ResolvedSourceTag>> {\n const out = new Map<string, ResolvedSourceTag>()\n for (const t of ctx.config.dmarc?.knownSources ?? []) {\n out.set(t.ip, { ip: t.ip, label: t.label, ignored: !!t.ignored, source: 'config' })\n }\n // DB tags override config tags so the operator can re-label without redeploy.\n const dbTags = await ctx.collections.dmarcSourceTags.find({}).toArray()\n for (const t of dbTags) {\n out.set(t.ip, { ip: t.ip, label: t.label, ignored: t.ignored, source: 'db' })\n }\n return out\n}\n\n// ---------------------------------------------------------------------------\n// Policy progression suggestion\n// ---------------------------------------------------------------------------\n\nexport interface DomainProgression {\n domain: string\n currentPolicy: 'none' | 'quarantine' | 'reject' | null\n currentPct: number | null\n /** null when no suggestion (already at strictest, or insufficient data). */\n suggested: { policy: 'none' | 'quarantine' | 'reject'; pct: number; reason: string } | null\n}\n\n/**\n * Heuristic: walk through the DMARC ramp progression.\n * p=none → suggest p=quarantine pct=10 when last 30d alignment ≥99%\n * from non-ignored sources AND ≥30 reports AND ≥1k messages\n * p=quarantine pct<100 → ramp pct (10→25→50→100) when alignment stays high\n * p=quarantine pct=100 → suggest p=reject when alignment ≥99.9% for 14+ days\n * p=reject → no suggestion (already at strictest)\n *\n * Pure function so it's easy to unit-test.\n */\nexport interface ProgressionInput {\n reports: Array<{ rangeEnd: Date; passCount: number; failCount: number }>\n failures: Array<{ sourceIp: string; count: number; receivedAt: Date }>\n knownSourceIps: Set<string>\n ignoredSourceIps: Set<string>\n currentPolicy: 'none' | 'quarantine' | 'reject' | null\n currentPct: number | null\n}\n\nexport function suggestPolicyProgression(input: ProgressionInput): DomainProgression['suggested'] {\n const { reports, failures, knownSourceIps, ignoredSourceIps, currentPolicy, currentPct } = input\n\n if (currentPolicy === 'reject') return null\n\n const since30 = Date.now() - 30 * 86_400_000\n const recentReports = reports.filter((r) => r.rangeEnd.getTime() >= since30)\n const totalMsgs = recentReports.reduce((acc, r) => acc + r.passCount + r.failCount, 0)\n const totalPass = recentReports.reduce((acc, r) => acc + r.passCount, 0)\n\n if (recentReports.length < 30) return null\n if (totalMsgs < 1000) return null\n\n // Failures from untagged (and non-ignored) sources mean we don't yet know\n // who they are — never tighten policy until they're identified.\n const untaggedFailures = failures.filter(\n (f) => f.receivedAt.getTime() >= since30 && !knownSourceIps.has(f.sourceIp) && !ignoredSourceIps.has(f.sourceIp),\n )\n if (untaggedFailures.length > 0) return null\n\n const alignmentRate = totalMsgs === 0 ? 0 : totalPass / totalMsgs\n\n if (currentPolicy === null || currentPolicy === 'none') {\n if (alignmentRate >= 0.99) {\n return {\n policy: 'quarantine',\n pct: 10,\n reason: `${(alignmentRate * 100).toFixed(2)}% alignment over ${recentReports.length} reports / ${totalMsgs.toLocaleString()} messages, all known sources tagged.`,\n }\n }\n return null\n }\n\n if (currentPolicy === 'quarantine') {\n const pct = currentPct ?? 100\n if (alignmentRate < 0.995) return null\n if (pct < 25) return { policy: 'quarantine', pct: 25, reason: `Alignment held at ${(alignmentRate * 100).toFixed(2)}% — safe to ramp pct from ${pct} to 25.` }\n if (pct < 50) return { policy: 'quarantine', pct: 50, reason: `Alignment held at ${(alignmentRate * 100).toFixed(2)}% — safe to ramp pct from ${pct} to 50.` }\n if (pct < 100) return { policy: 'quarantine', pct: 100, reason: `Alignment held at ${(alignmentRate * 100).toFixed(2)}% — safe to ramp pct from ${pct} to 100.` }\n\n // pct=100 + alignment ≥99.9% for 14+ days → suggest reject\n if (alignmentRate >= 0.999) {\n return { policy: 'reject', pct: 100, reason: `Alignment at ${(alignmentRate * 100).toFixed(3)}% with policy=quarantine pct=100 — safe to move to p=reject.` }\n }\n }\n\n return null\n}\n","/**\n * The pending-unsubscribe journal — the on-disk half of INVARIANT 8.\n *\n * When `POST /m/unsub/:token` cannot reach Mongo, the opt-out is appended here\n * as one JSON object per line, and `runner/pending-unsubs.ts` replays it on a\n * later tick. Until v0.15 the write existed and the replay did not, so a\n * recipient who unsubscribed during a Mongo outage was told \"you are\n * unsubscribed\" and then kept receiving mail. That is a legal failure, not a\n * dropped metric.\n *\n * This module owns only the file: append, rotate, read, delete. It never\n * touches Mongo, so it can be unit tested against a tmpdir with no database.\n *\n * ## Why there is no default path\n *\n * The old default was `/tmp/mailery-pending-unsubs.jsonl`: world-writable\n * directory, cleared on reboot, and — since nothing drained it — write-only.\n * There is no replacement default, because a library mounted into an unknown\n * host cannot pick a directory that is simultaneously writable, durable and\n * private: `/var/lib/...` needs root to create, `$HOME` may not exist in a\n * container, and the working directory may be read-only or ephemeral. On top of\n * that the journal holds recipient email addresses in plaintext outside the\n * database, so choosing a location on the operator's behalf is a data-residency\n * decision the operator has to make.\n *\n * So the journal is opt-in: set `pendingUnsubsPath` in `MailerConfig`. With it\n * unset, a failed Mongo write makes the endpoint answer 503 instead of\n * silently dropping the opt-out (see INVARIANT 8).\n *\n * ## Layout\n *\n * <path> the live journal — appended to by the route\n * <path>.draining.<token> a batch claimed by one drain pass\n *\n * Claiming is done with `rename`, which is atomic on POSIX within a directory:\n * exactly one process can move the live journal to its own `.draining.<token>`\n * name, and a second process racing it gets ENOENT and moves on. That is the\n * whole concurrency story — no lock files, no leases.\n *\n * A drain that crashes leaves its `.draining.<token>` file behind. A later pass\n * adopts any such file older than `ADOPT_AFTER_MS` (again by rename, so only\n * one adopter wins) and replays it. Replaying is idempotent, so adopting a file\n * another process is in fact still working on costs duplicate writes and\n * nothing else.\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { randomBytes } from 'node:crypto'\n\nimport { unsubscribeInputSchema, type UnsubscribeInput } from '../shared/schemas.js'\n\n/** One line of the journal. */\nexport interface PendingUnsubEntry {\n email: string\n scope: 'all' | 'marketing' | 'transactional'\n /** Epoch ms the unsubscribe was received. */\n at: number\n /**\n * How many drain passes have already failed to apply this entry. Absent on\n * entries written by the route; incremented each time the drain writes one\n * back. Purely diagnostic — an entry is never dropped for being old.\n */\n attempts?: number\n}\n\n/** Marker inserted between the journal path and a claim token. */\nconst DRAINING_INFIX = '.draining.'\n\n/**\n * How long a `.draining.<token>` file must sit untouched before another pass\n * treats its owner as dead and adopts it. Matches the stranded-send and\n * stranded-webhook thresholds in `runner/tick.ts`.\n */\nexport const ADOPT_AFTER_MS = 5 * 60 * 1000\n\n/** Beyond this the operator has a real outage and should be told. */\nexport const JOURNAL_WARN_BYTES = 8 * 1024 * 1024\n\n/**\n * `O_NOFOLLOW` where the platform has it (POSIX), 0 elsewhere (Windows).\n * Stops the final path component being swapped for a symlink pointing at\n * something we should not be appending recipient addresses to.\n */\nconst O_NOFOLLOW = (fs.constants as { O_NOFOLLOW?: number }).O_NOFOLLOW ?? 0\n\nconst APPEND_FLAGS =\n fs.constants.O_WRONLY | fs.constants.O_CREAT | fs.constants.O_APPEND | O_NOFOLLOW\n\n// ---------------------------------------------------------------------------\n// Append\n// ---------------------------------------------------------------------------\n\n/**\n * Append one entry to the live journal. Synchronous on purpose: this runs on\n * the failure path of an HTTP request that is holding a compliance obligation,\n * and an `await` there is one more place to lose it.\n *\n * Throws on any failure, including a path that is not a plain private file.\n * The caller (the unsubscribe route) turns a throw into a 503.\n *\n * Concurrency: the parent directory is created 0700 and the file 0600, and the\n * write is a single `O_APPEND` write of a short line, so concurrent appenders\n * from multiple processes interleave at line granularity rather than within a\n * line. A line that does get torn is dropped by the drain as malformed and\n * logged; it is not able to corrupt its neighbours.\n */\nexport function appendPendingUnsub(journalPath: string, entry: PendingUnsubEntry): void {\n fs.mkdirSync(path.dirname(journalPath), { recursive: true, mode: 0o700 })\n\n const fd = fs.openSync(journalPath, APPEND_FLAGS, 0o600)\n try {\n assertPrivateRegularFile(fd, journalPath)\n fs.writeSync(fd, serializeEntry(entry))\n } finally {\n fs.closeSync(fd)\n }\n}\n\n/**\n * Reject anything that is not a regular file we exclusively own.\n *\n * `O_NOFOLLOW` covers a symlink swapped in at the last component; it does not\n * cover a regular file pre-created by someone else in a shared directory, nor\n * a hard link pointing our appends at a file that matters. `nlink > 1` catches\n * the hard link; the `chmod` narrows a file that was created with looser\n * permissions before this version shipped.\n */\nfunction assertPrivateRegularFile(fd: number, journalPath: string): void {\n const st = fs.fstatSync(fd)\n if (!st.isFile()) {\n throw new Error(`pending-unsubscribe journal is not a regular file: ${journalPath}`)\n }\n if (st.nlink > 1) {\n throw new Error(`pending-unsubscribe journal has ${st.nlink} hard links: ${journalPath}`)\n }\n if ((st.mode & 0o077) !== 0) fs.fchmodSync(fd, 0o600)\n}\n\nexport function serializeEntry(entry: PendingUnsubEntry): string {\n return JSON.stringify(entry) + '\\n'\n}\n\n// ---------------------------------------------------------------------------\n// Claiming\n// ---------------------------------------------------------------------------\n\nfunction claimToken(): string {\n return `${Date.now().toString(36)}-${randomBytes(6).toString('hex')}`\n}\n\n/**\n * Move the live journal aside so this pass owns its contents and the route can\n * keep appending to a fresh file. Returns the claimed path, or null when there\n * was nothing to claim (no journal, or another process won the race).\n */\nexport function claimJournal(journalPath: string): string | null {\n const claimed = `${journalPath}${DRAINING_INFIX}${claimToken()}`\n try {\n fs.renameSync(journalPath, claimed)\n } catch (err) {\n if (isMissing(err)) return null\n throw err\n }\n markClaimActive(claimed)\n return claimed\n}\n\n/**\n * Stamp a claim as owned *now*.\n *\n * `rename` preserves mtime, so a journal whose last append was during an\n * outage an hour ago would arrive already looking abandoned, and a second\n * process would adopt it out from under the pass that just claimed it. The\n * touch is what makes `mtime` mean \"this batch has an owner that was alive\n * recently\" rather than \"this is when the last unsubscribe came in\".\n */\nfunction markClaimActive(claimPath: string): void {\n const now = new Date()\n try {\n fs.utimesSync(claimPath, now, now)\n } catch (err) {\n // Not fatal — worst case another pass adopts the batch and applies it\n // twice, which is a no-op.\n if (!isMissing(err)) throw err\n }\n}\n\n/**\n * Find `.draining.*` files left behind by a pass that died, and take ownership\n * of the ones that have been idle longer than `olderThanMs`.\n *\n * Adoption is a rename to a fresh token, so two processes scanning at the same\n * instant cannot both end up owning the same batch.\n */\nexport function adoptAbandonedClaims(\n journalPath: string,\n opts: { olderThanMs?: number; now?: number } = {},\n): string[] {\n const olderThanMs = opts.olderThanMs ?? ADOPT_AFTER_MS\n const now = opts.now ?? Date.now()\n const dir = path.dirname(journalPath)\n const prefix = path.basename(journalPath) + DRAINING_INFIX\n\n let names: string[]\n try {\n names = fs.readdirSync(dir)\n } catch (err) {\n if (isMissing(err)) return []\n throw err\n }\n\n const adopted: string[] = []\n for (const name of names) {\n if (!name.startsWith(prefix)) continue\n const full = path.join(dir, name)\n let st: fs.Stats\n try {\n st = fs.statSync(full)\n } catch (err) {\n if (isMissing(err)) continue\n throw err\n }\n if (!st.isFile()) continue\n if (now - st.mtimeMs < olderThanMs) continue\n\n const mine = `${journalPath}${DRAINING_INFIX}${claimToken()}`\n try {\n fs.renameSync(full, mine)\n markClaimActive(mine)\n adopted.push(mine)\n } catch (err) {\n // Lost the race to another adopter — that is the mechanism working.\n if (!isMissing(err)) throw err\n }\n }\n return adopted\n}\n\n// ---------------------------------------------------------------------------\n// Reading\n// ---------------------------------------------------------------------------\n\nexport interface ReadResult {\n entries: PendingUnsubEntry[]\n /** Lines that were not usable — torn by a crash mid-append, or hand-edited. */\n malformed: Array<{ lineNumber: number; preview: string }>\n bytes: number\n}\n\n/**\n * Read a claimed batch.\n *\n * Every failure mode of a file that is appended to by a process which may be\n * killed at any moment is tolerated here, because the alternative is a drain\n * that aborts and leaves valid opt-outs unapplied:\n *\n * - absent file → empty result\n * - empty file → empty result\n * - truncated final line → that line is malformed, every earlier line is\n * still returned\n * - a malformed line → skipped, reported, neighbours unaffected\n * - a JSON line that is not a valid unsubscribe (bad email, bad scope)\n * → malformed; it can never be applied, so retrying\n * it forever would only pin the journal open\n */\nexport function readClaim(claimPath: string): ReadResult {\n let raw: string\n try {\n raw = fs.readFileSync(claimPath, 'utf8')\n } catch (err) {\n if (isMissing(err)) return { entries: [], malformed: [], bytes: 0 }\n throw err\n }\n\n const entries: PendingUnsubEntry[] = []\n const malformed: ReadResult['malformed'] = []\n\n const lines = raw.split('\\n')\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!\n if (line.trim() === '') continue\n const parsed = parseEntry(line)\n if (parsed) entries.push(parsed)\n else malformed.push({ lineNumber: i + 1, preview: line.slice(0, 120) })\n }\n\n return { entries, malformed, bytes: Buffer.byteLength(raw) }\n}\n\n/**\n * Parse one journal line. Returns null for anything that could not be turned\n * into an applicable unsubscribe.\n */\nexport function parseEntry(line: string): PendingUnsubEntry | null {\n let obj: unknown\n try {\n obj = JSON.parse(line)\n } catch {\n return null\n }\n if (!obj || typeof obj !== 'object' || Array.isArray(obj)) return null\n const o = obj as Record<string, unknown>\n\n // Validated with the same schema the live route uses, so an entry that\n // survives here is one `applyUnsubscribe` can definitely accept.\n const check = unsubscribeInputSchema.safeParse({\n email: o.email,\n scope: o.scope,\n reason: 'user_request',\n source: 'one-click',\n })\n if (!check.success) return null\n\n const at = typeof o.at === 'number' && Number.isFinite(o.at) ? o.at : Date.now()\n const attempts =\n typeof o.attempts === 'number' && Number.isFinite(o.attempts) && o.attempts > 0\n ? Math.floor(o.attempts)\n : undefined\n\n return {\n email: check.data.email,\n scope: check.data.scope,\n at,\n ...(attempts === undefined ? {} : { attempts }),\n }\n}\n\n/** The `UnsubscribeInput` a journal entry replays as. */\nexport function entryToInput(entry: PendingUnsubEntry): UnsubscribeInput {\n return unsubscribeInputSchema.parse({\n email: entry.email,\n scope: entry.scope,\n reason: 'user_request',\n // Distinguishable in `mailer_suppressions.source` from a live one-click,\n // but only on rows the drain actually created (the upsert is\n // `$setOnInsert`, so a row the live path already wrote keeps its own).\n source: 'one-click-drain',\n })\n}\n\n// ---------------------------------------------------------------------------\n// Finishing a batch\n// ---------------------------------------------------------------------------\n\n/**\n * Hand entries this pass could not apply back to the live journal, then drop\n * the claim.\n *\n * Returning them to the live journal rather than leaving them in the claim\n * file is what makes the next tick pick them up immediately instead of waiting\n * out `ADOPT_AFTER_MS`. The order — append first, unlink second — is chosen so\n * a crash in between duplicates entries rather than losing them, and duplicates\n * are free because applying twice is a no-op.\n */\nexport function releaseClaim(\n journalPath: string,\n claimPath: string,\n remaining: PendingUnsubEntry[],\n): void {\n if (remaining.length > 0) {\n fs.mkdirSync(path.dirname(journalPath), { recursive: true, mode: 0o700 })\n const fd = fs.openSync(journalPath, APPEND_FLAGS, 0o600)\n try {\n assertPrivateRegularFile(fd, journalPath)\n fs.writeSync(\n fd,\n remaining.map((e) => serializeEntry({ ...e, attempts: (e.attempts ?? 0) + 1 })).join(''),\n )\n } finally {\n fs.closeSync(fd)\n }\n }\n try {\n fs.unlinkSync(claimPath)\n } catch (err) {\n if (!isMissing(err)) throw err\n }\n}\n\n/** True when the journal (or any claim of it) has anything worth draining. */\nexport function journalExists(journalPath: string): boolean {\n try {\n return fs.statSync(journalPath).isFile()\n } catch (err) {\n if (isMissing(err)) return false\n throw err\n }\n}\n\nfunction isMissing(err: unknown): boolean {\n const code = (err as NodeJS.ErrnoException | undefined)?.code\n return code === 'ENOENT' || code === 'ENOTDIR'\n}\n","/**\n * The pending-unsubscribe drain — the second half of INVARIANT 8.\n *\n * `POST /m/unsub/:token` journals an opt-out to disk when Mongo is unreachable\n * (`src/server/unsub-journal.ts`). This replays those entries. It runs from\n * `runTick`, so it needs no scheduling of its own and inherits the tick's\n * cadence (`tickIntervalSeconds`, default 60) and its per-runner error\n * isolation. It is also exported so a host can run it from a script or a\n * one-shot process.\n *\n * ## Where the drain runs, and why only here\n *\n * The tick, not a CLI command. `src/cli/` is a DNS/provider setup tool: it has\n * no Mongo connection, no contact adapter and no config loader, so a\n * `mailery drain-unsubs` command would have to invent a whole configuration\n * story to reach the database. Every deployment that can journal an opt-out is\n * by definition already running the library, and most run the tick;\n * `drainPendingUnsubscribes` is exported for the ones that don't.\n *\n * ## Guarantees\n *\n * - **Idempotent.** Replay goes through `applyUnsubscribe`, whose suppression\n * write is a `$setOnInsert` upsert and whose subscription write is a `$set`\n * to a terminal state. Draining the same entry twice is indistinguishable\n * from draining it once.\n * - **Nothing is lost to a crash.** A pass claims a batch by renaming the\n * journal aside; if it dies, the claim file stays on disk and a later pass\n * adopts it. Entries it could not apply are appended back to the live\n * journal *before* the claim is unlinked, so the failure window duplicates\n * rather than drops.\n * - **Concurrency-safe.** Claiming and adopting are `rename`, which is atomic\n * within a directory. Two processes draining the same journal cannot both\n * own the same batch.\n * - **Fails soft.** A Mongo write failure aborts the pass immediately — the\n * database being down is exactly why these entries exist, and hammering it\n * with the rest of the batch achieves nothing.\n */\n\nimport {\n adoptAbandonedClaims,\n claimJournal,\n entryToInput,\n journalExists,\n readClaim,\n releaseClaim,\n JOURNAL_WARN_BYTES,\n type PendingUnsubEntry,\n} from '../unsub-journal.js'\nimport { applyUnsubscribe } from '../unsubscribe.js'\nimport type { RunnerContext } from './index.js'\n\n/**\n * Entries applied per pass. A long outage can leave a journal with far more\n * than this; the remainder is written back and picked up by the next tick,\n * which keeps a single tick's latency bounded.\n */\nconst MAX_ENTRIES_PER_PASS = 1000\n\n/**\n * Attempts after which an entry is loud rather than routine. It is never\n * dropped — a stuck opt-out is a compliance problem an operator has to see,\n * not one the library gets to discard.\n */\nconst NOISY_AFTER_ATTEMPTS = 10\n\nexport interface DrainPendingUnsubsResult {\n /** False when no `pendingUnsubsPath` is configured — the journal is opt-in. */\n enabled: boolean\n applied: number\n /** Entries handed back to the journal for a later pass. */\n deferred: number\n /** Lines that could never be applied (torn by a crash, or hand-edited). */\n malformed: number\n /** Claim files processed, including ones adopted from a dead pass. */\n batches: number\n}\n\nexport interface DrainPendingUnsubsOptions {\n /** Overrides `config.pendingUnsubsPath`. Mostly for tests. */\n path?: string\n maxEntries?: number\n /** Structured sink for diagnostics. Defaults to `console`. */\n log?: {\n warn?: (fields: Record<string, unknown>, msg?: string) => void\n error?: (fields: Record<string, unknown>, msg?: string) => void\n }\n}\n\nconst consoleLog = {\n warn: (fields: Record<string, unknown>, msg?: string) => console.warn(msg ?? 'mailery', fields),\n error: (fields: Record<string, unknown>, msg?: string) => console.error(msg ?? 'mailery', fields),\n}\n\nexport async function drainPendingUnsubscribes(\n ctx: RunnerContext,\n opts: DrainPendingUnsubsOptions = {},\n): Promise<DrainPendingUnsubsResult> {\n const journalPath = opts.path ?? ctx.config.pendingUnsubsPath\n const result: DrainPendingUnsubsResult = {\n enabled: Boolean(journalPath),\n applied: 0,\n deferred: 0,\n malformed: 0,\n batches: 0,\n }\n if (!journalPath) return result\n\n const log = opts.log ?? consoleLog\n const budget = opts.maxEntries ?? MAX_ENTRIES_PER_PASS\n\n // Claims left behind by a pass that died mid-drain come first: they are\n // strictly older than anything in the live journal.\n const claims: string[] = []\n try {\n claims.push(...adoptAbandonedClaims(journalPath))\n } catch (err) {\n log.error?.({ err, path: journalPath }, 'mailery: pending-unsub claim adoption failed')\n }\n\n if (journalExists(journalPath)) {\n const claimed = claimJournal(journalPath)\n if (claimed) claims.push(claimed)\n }\n if (claims.length === 0) return result\n\n let remainingBudget = budget\n\n for (const claimPath of claims) {\n result.batches++\n const batch = readClaim(claimPath)\n\n if (batch.bytes > JOURNAL_WARN_BYTES) {\n log.warn?.(\n { path: claimPath, bytes: batch.bytes, entries: batch.entries.length },\n 'mailery: pending-unsubscribe journal is large — Mongo has been unreachable for a while',\n )\n }\n for (const bad of batch.malformed) {\n result.malformed++\n log.warn?.(\n { path: claimPath, lineNumber: bad.lineNumber, preview: bad.preview },\n 'mailery: pending-unsubscribe journal line unusable — skipped',\n )\n }\n\n const deferred: PendingUnsubEntry[] = []\n let stop = false\n\n for (let i = 0; i < batch.entries.length; i++) {\n const entry = batch.entries[i]!\n if (stop || remainingBudget <= 0) {\n deferred.push(entry)\n continue\n }\n try {\n await applyUnsubscribe(ctx.collections, entryToInput(entry))\n result.applied++\n remainingBudget--\n } catch (err) {\n // The database is the reason this file exists. Stop the pass rather\n // than replay the rest of the batch into the same failure.\n stop = true\n deferred.push(entry)\n const attempts = (entry.attempts ?? 0) + 1\n const fields = { err, path: claimPath, attempts, pending: batch.entries.length - i }\n if (attempts >= NOISY_AFTER_ATTEMPTS) {\n log.error?.(\n fields,\n 'mailery: pending unsubscribe still not applied after repeated attempts — investigate',\n )\n } else {\n log.warn?.(fields, 'mailery: pending-unsubscribe replay failed — deferred to next tick')\n }\n }\n }\n\n result.deferred += deferred.length\n // Always release, even after an abort: the entries are back in the live\n // journal, and holding the claim would only make the next pass wait out\n // the adoption threshold before retrying them.\n releaseClaim(journalPath, claimPath, deferred)\n }\n\n return result\n}\n","/**\n * The mailer:tick handler. Orchestrates all the periodic work that doesn't\n * fit a delayed-job model: event-trigger scanning, recovery sweep,\n * scheduled-broadcast dispatch, outbox draining, rollups.\n */\n\nimport { processNewlyFiredEventTriggers } from './triggers.js'\nimport { processWebhookBacklog } from './webhook.js'\nimport { sweepStrandedFlowRuns } from './sweep.js'\nimport { processScheduledBroadcasts as dispatchScheduled, resumeStalledBroadcasts } from './broadcasts.js'\nimport { evaluateHealth } from './health.js'\nimport { promoteSoftBounces } from './bounce-promotion.js'\nimport { runDnsblChecks } from './dnsbl.js'\nimport { runPostmasterPull } from './postmaster.js'\nimport { runSndsPull } from './snds.js'\nimport { pruneDmarcFailures } from './dmarc.js'\nimport { drainPendingUnsubscribes } from './pending-unsubs.js'\nimport { HEALTH_AGG_ID } from '../models/index.js'\nimport type { RunnerContext } from './index.js'\n\n/**\n * Sends that entered the 'sending' state more than this long ago are assumed\n * to have been abandoned mid-dispatch (worker crash, OOM kill, ...). The tick\n * resets them to 'queued' and re-enqueues. Providers should treat the sendId\n * (passed in messageMeta) as an idempotency key to avoid duplicate delivery on\n * the rare case where the original call did reach the provider.\n */\nconst STRANDED_SEND_THRESHOLD_MS = 5 * 60 * 1000\n\n/**\n * Webhook events older than this and still unprocessed are assumed stranded\n * (the ingest-time queue add failed). The tick drains them; fresher rows are\n * left to the webhook worker to avoid racing it in the normal path.\n */\nconst STRANDED_WEBHOOK_THRESHOLD_MS = 5 * 60 * 1000\n\nexport async function runTick(ctx: RunnerContext): Promise<void> {\n // Heartbeat: ensure the aggregate health doc exists with an up-to-date\n // `updatedAt` so the setup-status check can detect \"workers are running.\"\n // Wrapped in try/catch — a Mongo blip should never abort the whole tick.\n try {\n await ctx.collections.health.updateOne(\n { _id: HEALTH_AGG_ID },\n {\n $set: { updatedAt: new Date() },\n $setOnInsert: {\n _id: HEALTH_AGG_ID,\n senderDomain: null,\n kind: null,\n windowStartedAt: new Date(),\n windowDurationMs: ctx.config.circuitBreaker.windowMinutes * 60 * 1000,\n status: 'healthy',\n trippedAt: null,\n trippedReason: null,\n manuallyResumedAt: null,\n counters: { sent: 0, delivered: 0, bounced: 0, hardBounced: 0, softBounced: 0, complained: 0, failedToSend: 0 },\n rates: { bounceRate: 0, hardBounceRate: 0, complaintRate: 0, failureRate: 0 },\n },\n },\n { upsert: true },\n )\n } catch (err) {\n console.error('mailery: heartbeat write failed', err)\n }\n\n // Core runners: order matters (sweep before send dispatch, drain outbox\n // before triggers re-scan, etc). Keep these serial.\n await processNewlyFiredEventTriggers(ctx).catch((err) => {\n console.error('mailery: triggers scan failed', err)\n })\n await sweepStrandedFlowRuns(ctx).catch((err) => {\n console.error('mailery: sweep failed', err)\n })\n await sweepStrandedSends(ctx).catch((err) => {\n console.error('mailery: stranded-send sweep failed', err)\n })\n await drainOutbox(ctx).catch((err) => {\n console.error('mailery: outbox drain failed', err)\n })\n // INVARIANT 8: opt-outs journaled to disk while Mongo was unreachable. Runs\n // early and unconditionally — a pending unsubscribe is a legal obligation,\n // and every send dispatched below re-checks suppression at send time\n // (INVARIANT 3), so applying these first is what stops the next broadcast\n // mailing someone who already opted out.\n await drainPendingUnsubscribes(ctx).catch((err) => {\n console.error('mailery: pending-unsubscribe drain failed', err)\n })\n await processScheduledBroadcasts(ctx).catch((err) => {\n console.error('mailery: broadcast dispatch failed', err)\n })\n await resumeStalledBroadcasts(ctx).catch((err) => {\n console.error('mailery: stalled-broadcast resume failed', err)\n })\n await evaluateHealth(ctx).catch((err) => {\n console.error('mailery: health evaluation failed', err)\n })\n await promoteSoftBounces(ctx).catch((err) => {\n console.error('mailery: soft-bounce promotion failed', err)\n })\n await processWebhookBacklog(ctx, { olderThanMs: STRANDED_WEBHOOK_THRESHOLD_MS }).catch((err) => {\n console.error('mailery: stranded-webhook drain failed', err)\n })\n\n // Independent reputation pollers + housekeeping — run in parallel so tick\n // latency is max() not sum(). Each is already throttled internally and\n // catches its own errors.\n await Promise.all([\n runDnsblChecks(ctx).catch((err) => {\n console.error('mailery: dnsbl checks failed', err)\n }),\n runPostmasterPull(ctx).catch((err) => {\n console.error('mailery: postmaster pull failed', err)\n }),\n runSndsPull(ctx).catch((err) => {\n console.error('mailery: snds pull failed', err)\n }),\n pruneDmarcFailures(ctx).catch((err) => {\n console.error('mailery: dmarc prune failed', err)\n }),\n ])\n}\n\n/**\n * Find sends stuck in 'sending' past the threshold (crashed mid-dispatch) and\n * re-enqueue them. Returning to 'queued' lets `dispatchSend` pick them back up.\n */\nasync function sweepStrandedSends(ctx: RunnerContext): Promise<void> {\n const cutoff = new Date(Date.now() - STRANDED_SEND_THRESHOLD_MS)\n const cursor = ctx.collections.sends.find(\n { status: 'sending', updatedAt: { $lt: cutoff } },\n { projection: { _id: 1 } },\n ).limit(500)\n for await (const row of cursor) {\n const reset = await ctx.collections.sends.updateOne(\n { _id: row._id, status: 'sending', updatedAt: { $lt: cutoff } },\n { $set: { status: 'queued', updatedAt: new Date() } },\n )\n if (reset.modifiedCount === 0) continue\n await ctx.queues.send.add('send', { sendId: String(row._id) }, {\n attempts: ctx.config.sendRetryAttempts,\n backoff: { type: 'exponential', delay: 60_000 },\n })\n }\n}\n\n/**\n * Pull pending outbox rows committed by host transactions and promote them\n * into the real collections (events / subscriptions / suppressions).\n */\nasync function drainOutbox(ctx: RunnerContext): Promise<void> {\n const batch = await ctx.collections.outbox\n .find({ status: 'pending' })\n .sort({ enqueuedAt: 1 })\n .limit(200)\n .toArray()\n\n for (const row of batch) {\n try {\n if (row.payload.type === 'event') {\n try {\n await ctx.collections.events.insertOne({\n externalId: row.payload.data.externalId as string,\n name: row.payload.data.name as string,\n properties: (row.payload.data.properties as Record<string, unknown>) ?? {},\n dedupeKey: row.payload.dedupeKey,\n occurredAt: (row.payload.data.occurredAt as Date | undefined) ?? new Date(),\n createdAt: new Date(),\n })\n } catch (err: any) {\n if (err?.code !== 11000) throw err\n }\n }\n await ctx.collections.outbox.updateOne(\n { _id: row._id },\n { $set: { status: 'processed', processedAt: new Date() } },\n )\n } catch (err: any) {\n await ctx.collections.outbox.updateOne(\n { _id: row._id },\n {\n $set: { lastAttemptAt: new Date(), lastError: String(err?.message ?? err) },\n $inc: { attempts: 1 },\n },\n )\n }\n }\n}\n\n/**\n * Claim broadcasts whose `scheduledAt` has passed and hand their recipient\n * enqueue to an advance job (inline for the noop driver), so a large\n * broadcast never blocks the tick. The dispatch itself streams the segment\n * cursor and bulk-enqueues sends, pausing when the send queue's waiting\n * count exceeds the configured cap (broadcastEnqueueMaxWaiting).\n */\nasync function processScheduledBroadcasts(ctx: RunnerContext): Promise<void> {\n await dispatchScheduled(ctx)\n}\n","/**\n * Mailer — public facade. Hosts call `Mailer.init(config)` and get an object\n * exposing the public API (fire, upsertSubscription, unsubscribe, ...) plus\n * mountable Express routers.\n *\n * See plans/10-public-api.md for the surface.\n */\n\nimport type { Db, ClientSession, ObjectId } from 'mongodb'\nimport { ObjectId as ObjectIdCtor } from 'mongodb'\n\nimport type {\n ContactAdapter,\n MailProvider,\n} from '../shared/types.js'\nimport {\n abortAllFlowsInputSchema,\n abortFlowInputSchema,\n fireInputSchema,\n registerEventSchema,\n sendOneOffInputSchema,\n suppressInputSchema,\n tagInputSchema,\n unsubscribeInputSchema,\n upsertSubscriptionSchema,\n type FireInput,\n type RegisterEventInput,\n type SendOneOffInput,\n type SuppressInput,\n type TagInput,\n type UnsubscribeInput,\n type UpsertSubscriptionInput,\n} from '../shared/schemas.js'\nimport { resolveConfig, type MailerConfig, type ResolvedConfig } from './config.js'\nimport {\n ensureIndexes,\n getCollections,\n} from './models/index.js'\nimport type { Collections } from './models/index.js'\nimport { EventRegistry } from './events.js'\nimport { resolveProvider, registeredProviderNames } from './provider-lookup.js'\nimport { sha256Hex, signDoiToken } from './tokens.js'\nimport { applyUnsubscribe } from './unsubscribe.js'\nimport {\n createQueueDriver,\n type QueueDriver,\n type Queues,\n} from './queues/index.js'\nimport {\n dispatchBroadcastById,\n dispatchSend,\n exitFlowRun,\n processOneRunStep,\n runTick,\n type RunnerContext,\n} from './runner/index.js'\nimport { processWebhookBacklog } from './runner/webhook.js'\n\nexport class Mailer {\n readonly db: Db\n readonly collections: Collections\n readonly adapter: ContactAdapter\n readonly providers: Record<string, MailProvider>\n readonly queues: Queues\n readonly config: ResolvedConfig\n readonly events: EventRegistry\n\n private queueDriver: QueueDriver\n private workersStarted = false\n private runnerContext: RunnerContext\n\n private constructor(args: {\n config: ResolvedConfig\n db: Db\n collections: Collections\n adapter: ContactAdapter\n providers: Record<string, MailProvider>\n queueDriver: QueueDriver\n events: EventRegistry\n }) {\n this.config = args.config\n this.db = args.db\n this.collections = args.collections\n this.adapter = args.adapter\n this.providers = args.providers\n this.queueDriver = args.queueDriver\n this.queues = args.queueDriver.queues\n this.events = args.events\n\n this.runnerContext = {\n db: this.db,\n collections: this.collections,\n adapter: this.adapter,\n varsAdapter: this.config.varsAdapter,\n providers: this.providers,\n queues: this.queues,\n config: this.config,\n handlebarsHelpers: this.config.handlebarsHelpers,\n audit: (entry) => this.audit(entry),\n }\n }\n\n /**\n * Construct a Mailer from environment variables. Reads:\n *\n * MAILER_MONGODB_URI — Mongo connection string (required)\n * MAILER_MONGODB_DB — database name (optional; defaults to the URI default)\n * MAILER_REDIS_URL — Redis connection URL (required)\n * MAILER_QUEUE_PREFIX — namespaces this instance (optional). Bull: Redis key\n * prefix. Agenda: jobs collection suffix.\n * MAILER_PUBLIC_URL — base for tracking/unsub URLs (required)\n * MAILER_UNSUBSCRIBE_SECRET — HMAC key (required)\n * MAILER_SENDER_ADDRESS — postal address for CAN-SPAM (optional)\n * MAILER_FROM_NAME / MAILER_FROM_EMAIL\n * MAILER_DEFAULT_PROVIDER — defaults to 'sendgrid' if SENDGRID_API_KEY is set\n * MAILER_SENDGRID_API_KEY / MAILER_SENDGRID_WEBHOOK_KEY\n * MAILER_SENDGRID_WEBHOOK_TOLERANCE — signed-webhook replay window, seconds\n * (default 300; '0' disables the check).\n * Unparseable values fall back to the\n * default rather than disabling it.\n * MAILER_HOST_USERS_COLLECTION (default 'users')\n * MAILER_HOST_USERS_EMAIL_FIELD (default 'email')\n * MAILER_HOST_USERS_ID_FIELD (default '_id')\n * MAILER_HOST_USERS_TAGS_FIELD\n * MAILER_HOST_USERS_TAGS_WRITABLE — '1' or 'true' to enable\n *\n * For anything beyond this (custom toContact, custom providers, hooks),\n * use the programmatic init.\n */\n static async fromEnv(): Promise<Mailer> {\n const env = process.env\n const required = (k: string) => {\n const v = env[k]\n if (!v) throw new Error(`Mailer.fromEnv: missing env var ${k}`)\n return v\n }\n\n const { MongoClient } = await import('mongodb')\n const mongoClient = await MongoClient.connect(required('MAILER_MONGODB_URI'))\n const db = env.MAILER_MONGODB_DB ? mongoClient.db(env.MAILER_MONGODB_DB) : mongoClient.db()\n\n const { MongoContactAdapter } = await import('./adapters/mongo.js')\n const adapter = new MongoContactAdapter({\n db,\n collection: env.MAILER_HOST_USERS_COLLECTION ?? 'users',\n emailField: env.MAILER_HOST_USERS_EMAIL_FIELD ?? 'email',\n idField: env.MAILER_HOST_USERS_ID_FIELD ?? '_id',\n tagsField: env.MAILER_HOST_USERS_TAGS_FIELD,\n tagsWritable:\n env.MAILER_HOST_USERS_TAGS_WRITABLE === '1' || env.MAILER_HOST_USERS_TAGS_WRITABLE === 'true',\n })\n\n const providers: Record<string, MailProvider> = {}\n if (env.MAILER_SENDGRID_API_KEY) {\n const { SendGridProvider } = await import('./providers/sendgrid.js')\n providers.sendgrid = new SendGridProvider({\n apiKey: env.MAILER_SENDGRID_API_KEY,\n webhookVerificationKey: env.MAILER_SENDGRID_WEBHOOK_KEY,\n // Left undefined when unset/blank so the provider default (300s) applies.\n // resolveWebhookToleranceSeconds() rejects NaN back to the default, so a\n // typo here can never silently switch the replay check off.\n webhookToleranceSeconds: env.MAILER_SENDGRID_WEBHOOK_TOLERANCE\n ? Number(env.MAILER_SENDGRID_WEBHOOK_TOLERANCE)\n : undefined,\n sandbox: env.NODE_ENV !== 'production',\n })\n }\n if (Object.keys(providers).length === 0) {\n throw new Error('Mailer.fromEnv: no provider configured (set MAILER_SENDGRID_API_KEY, ...)')\n }\n\n const defaultProvider = env.MAILER_DEFAULT_PROVIDER ?? Object.keys(providers)[0]!\n\n const driverEnv = env.MAILER_QUEUE_DRIVER ?? 'bull'\n const queue =\n driverEnv === 'agenda'\n ? ({ driver: 'agenda' as const, prefix: env.MAILER_QUEUE_PREFIX })\n : driverEnv === 'noop'\n ? ({ driver: 'noop' as const })\n : ({\n driver: 'bull' as const,\n redis: { url: required('MAILER_REDIS_URL') },\n prefix: env.MAILER_QUEUE_PREFIX,\n })\n\n return Mailer.init({\n db,\n adapter,\n queue,\n providers,\n defaultProvider,\n publicUrl: required('MAILER_PUBLIC_URL'),\n unsubscribeSecret: required('MAILER_UNSUBSCRIBE_SECRET'),\n senderAddress: env.MAILER_SENDER_ADDRESS,\n fromDefaults:\n env.MAILER_FROM_NAME && env.MAILER_FROM_EMAIL\n ? { name: env.MAILER_FROM_NAME, email: env.MAILER_FROM_EMAIL }\n : undefined,\n })\n }\n\n static async init(input: MailerConfig): Promise<Mailer> {\n const config = resolveConfig(input)\n // Both defaults are validated here, through the same guarded lookup the\n // routes and the runner use — a name that resolves to an inherited\n // `Object.prototype` member is not a provider. `defaultTransactionalProvider`\n // was previously unchecked, so a typo in it stayed silent until a\n // transactional send failed at dispatch time, long after startup.\n if (!resolveProvider(config.providers, config.defaultProvider)) {\n throw new Error(\n `defaultProvider \"${config.defaultProvider}\" is not a registered provider. `\n + `Registered: ${registeredProviderNames(config.providers).join(', ') || '(none)'}`,\n )\n }\n if (\n config.defaultTransactionalProvider != null\n && !resolveProvider(config.providers, config.defaultTransactionalProvider)\n ) {\n throw new Error(\n `defaultTransactionalProvider \"${config.defaultTransactionalProvider}\" is not a `\n + `registered provider. `\n + `Registered: ${registeredProviderNames(config.providers).join(', ') || '(none)'}`,\n )\n }\n if (config.varsAdapter) {\n const { assertNoReservedVarKeys } = await import('./adapters/vars.js')\n assertNoReservedVarKeys(config.varsAdapter)\n }\n\n const collections = getCollections(config.db, config.collectionPrefix)\n await ensureIndexes(config.db, config.collectionPrefix)\n\n const queueDriver = await createQueueDriver(config.queue, config.db)\n if (!config.workerless && config.queue.driver !== 'noop') {\n await queueDriver.scheduleRepeatingTick(config.tickIntervalSeconds)\n }\n\n return new Mailer({\n config,\n db: config.db,\n collections,\n adapter: config.adapter,\n providers: config.providers,\n queueDriver,\n events: new EventRegistry(),\n })\n }\n\n // -------------------------------------------------------------------------\n // Event registration + firing\n // -------------------------------------------------------------------------\n\n registerEvent(reg: RegisterEventInput): void {\n const parsed = registerEventSchema.parse(reg)\n this.events.register(parsed)\n }\n\n async fire(\n eventName: string,\n externalId: string,\n properties: Record<string, unknown> = {},\n dedupeKey?: string,\n ): Promise<void> {\n const input = fireInputSchema.parse({ eventName, externalId, properties, dedupeKey })\n const key = this.events.deriveKey(input.eventName, input.externalId, input.dedupeKey, new Date())\n if (!key) {\n throw new Error(\n `fire(\"${input.eventName}\") missing dedupeKey and no policy registered. ` +\n `Call mailer.registerEvent(\"${input.eventName}\", { dedupePolicy }) or pass a key explicitly.`,\n )\n }\n try {\n await this.collections.events.insertOne({\n externalId: input.externalId,\n name: input.eventName,\n properties: input.properties ?? {},\n dedupeKey: key,\n occurredAt: new Date(),\n createdAt: new Date(),\n })\n } catch (err: any) {\n if (err?.code !== 11000) throw err\n // Duplicate dedupeKey — no-op by design.\n }\n }\n\n async fireFromSession(\n session: ClientSession,\n eventName: string,\n externalId: string,\n properties: Record<string, unknown> = {},\n dedupeKey?: string,\n ): Promise<void> {\n const input = fireInputSchema.parse({ eventName, externalId, properties, dedupeKey })\n const key = this.events.deriveKey(input.eventName, input.externalId, input.dedupeKey, new Date())\n if (!key) {\n throw new Error(`fireFromSession(\"${input.eventName}\") missing dedupeKey and no policy registered.`)\n }\n try {\n await this.collections.outbox.insertOne(\n {\n payload: {\n type: 'event',\n data: {\n externalId: input.externalId,\n name: input.eventName,\n properties: input.properties ?? {},\n occurredAt: new Date(),\n },\n dedupeKey: key,\n },\n status: 'pending',\n attempts: 0,\n lastAttemptAt: null,\n lastError: null,\n enqueuedAt: new Date(),\n processedAt: null,\n },\n { session },\n )\n } catch (err: any) {\n if (err?.code !== 11000) throw err\n }\n }\n\n // -------------------------------------------------------------------------\n // Subscription / unsubscribe / tags / suppression\n // -------------------------------------------------------------------------\n\n async upsertSubscription(input: UpsertSubscriptionInput): Promise<void> {\n const parsed = upsertSubscriptionSchema.parse(input)\n const contact = await this.adapter.getById(parsed.externalId)\n if (!contact) throw new Error(`adapter has no contact for externalId ${parsed.externalId}`)\n\n const status = this.config.requireDoubleOptIn ? 'pending_doi' : 'subscribed'\n const now = new Date()\n\n // Generate a DOI token up front when DOI is required. We store its hash\n // (not the raw token) on the subscription doc for audit.\n let doiToken: string | null = null\n let doiTokenHash: string | null = null\n if (status === 'pending_doi') {\n const expiresAt = new Date(now.getTime() + this.config.doiTokenLifetimeDays * 86_400_000)\n doiToken = signDoiToken({ externalId: parsed.externalId, expiresAt }, this.config.unsubscribeSecret)\n doiTokenHash = sha256Hex(doiToken)\n }\n\n await this.collections.subscriptions.updateOne(\n { externalId: parsed.externalId },\n {\n $set: {\n status,\n source: parsed.source,\n emailAtSubscribe: contact.email,\n subscribedAt: status === 'subscribed' ? (parsed.consentTimestamp ?? now) : null,\n updatedAt: now,\n ...(doiTokenHash ? { doiTokenHash, doiRequestedAt: now } : {}),\n },\n $setOnInsert: {\n externalId: parsed.externalId,\n createdAt: now,\n unsubscribedAt: null,\n unsubscribeReason: null,\n doiTokenHash: null,\n doiRequestedAt: null,\n doiConfirmedAt: null,\n doiIp: parsed.consentIp ?? null,\n doiUserAgent: parsed.consentUserAgent ?? null,\n },\n },\n { upsert: true },\n )\n\n // Send the DOI confirmation email (best-effort — failures here don't\n // unwind the subscription; the host can poll pending DOI rows + re-fire).\n if (status === 'pending_doi' && doiToken) {\n const tpl = await this.collections.templates.findOne({ slug: this.config.doiTemplateSlug })\n if (!tpl) {\n console.warn(`mailery: DOI required but template \"${this.config.doiTemplateSlug}\" not found — skipping confirmation email`)\n return\n }\n const dedupeKey = `doi:${parsed.externalId}:${now.toISOString().slice(0, 10)}`\n try {\n await this.sendOneOff({\n templateSlug: tpl.slug,\n externalId: parsed.externalId,\n vars: { confirmDoiUrl: `${this.config.publicUrl}/m/confirm-doi/${doiToken}` },\n dedupeKey,\n })\n } catch (err) {\n console.error('mailery: DOI confirmation send failed', err)\n }\n }\n }\n\n /**\n * The writes live in `server/unsubscribe.ts` so the pending-unsubscribe\n * drain (INVARIANT 8) replays a journaled opt-out through exactly this path\n * without holding a `Mailer` instance.\n */\n async unsubscribe(email: string, opts: Omit<UnsubscribeInput, 'email'>): Promise<void> {\n const parsed = unsubscribeInputSchema.parse({ email, ...opts })\n await applyUnsubscribe(this.collections, parsed)\n }\n\n async suppress(email: string, opts: Omit<SuppressInput, 'email'>): Promise<void> {\n const parsed = suppressInputSchema.parse({ email, ...opts })\n await this.collections.suppressions.updateOne(\n { email: parsed.email, scope: parsed.scope },\n {\n $setOnInsert: {\n email: parsed.email,\n emailHash: sha256Hex(parsed.email),\n scope: parsed.scope,\n reason: parsed.reason,\n source: parsed.source,\n notes: parsed.notes ?? null,\n addedAt: new Date(),\n expiresAt: parsed.expiresAt ?? null,\n },\n },\n { upsert: true },\n )\n }\n\n async tag(externalId: string, tag: string): Promise<void> {\n const parsed = tagInputSchema.parse({ externalId, tag })\n if (this.adapter.addTags) {\n await this.adapter.addTags(parsed.externalId, [parsed.tag])\n } else {\n await this.collections.contactTags.updateOne(\n { externalId: parsed.externalId, tag: parsed.tag },\n {\n $setOnInsert: {\n externalId: parsed.externalId,\n tag: parsed.tag,\n appliedBy: 'admin',\n appliedAt: new Date(),\n },\n },\n { upsert: true },\n )\n }\n }\n\n async untag(externalId: string, tag: string): Promise<void> {\n const parsed = tagInputSchema.parse({ externalId, tag })\n if (this.adapter.removeTags) {\n await this.adapter.removeTags(parsed.externalId, [parsed.tag])\n } else {\n await this.collections.contactTags.deleteOne({ externalId: parsed.externalId, tag: parsed.tag })\n }\n }\n\n // -------------------------------------------------------------------------\n // Flow abort\n // -------------------------------------------------------------------------\n\n /**\n * Abort every active run of one flow for a contact, immediately. Runs parked\n * in a `wait` exit too — their delayed wake-up jobs find the run exited and\n * no-op. Also cancels any of the flow's emails still sitting in the send\n * queue for this contact (queued or awaiting retry), so an abort means no\n * further mail, not just no further steps.\n *\n * No-op (returns zero counts) when nothing is active. Safe to call from the\n * same handler that processes the business event (\"user upgraded\").\n */\n async abortFlow(\n flowSlug: string,\n externalId: string,\n opts: { reason?: string; matchTriggerProperties?: Record<string, unknown> } = {},\n ): Promise<{ abortedRuns: number; cancelledSends: number }> {\n const parsed = abortFlowInputSchema.parse({\n flowSlug,\n externalId,\n reason: opts.reason,\n matchTriggerProperties: opts.matchTriggerProperties,\n })\n const flow = await this.collections.flows.findOne(\n { slug: parsed.flowSlug },\n { projection: { _id: 1 } },\n )\n if (!flow) throw new Error(`abortFlow: unknown flow slug \"${parsed.flowSlug}\"`)\n\n // Dotted paths so the match is against individual trigger properties; a\n // nested-object equality would demand the whole properties bag match.\n const triggerMatch = Object.fromEntries(\n Object.entries(parsed.matchTriggerProperties ?? {}).map(([k, v]) => [\n `triggerEvent.properties.${k}`,\n v,\n ]),\n )\n\n const result = await this.abortActiveRuns(\n { externalId: parsed.externalId, flowId: flow._id!, ...triggerMatch },\n parsed.reason ? `aborted_by_host:${parsed.reason}` : 'aborted_by_host',\n )\n if (result.abortedRuns > 0 || result.cancelledSends > 0) {\n await this.audit({\n actor: 'host',\n action: 'flow.abort',\n resource: { collection: 'mailer_flow_runs', slug: parsed.flowSlug },\n // Record the scope: without it a one-account abort and an abort-every-\n // run-for-this-contact are indistinguishable in the audit trail.\n diffSummary: `abortFlow slug=${parsed.flowSlug} externalId=${parsed.externalId} scope=${\n parsed.matchTriggerProperties ? JSON.stringify(parsed.matchTriggerProperties) : 'all'\n } runs=${result.abortedRuns} sends=${result.cancelledSends}${parsed.reason ? ` reason=${parsed.reason}` : ''}`,\n })\n }\n return result\n }\n\n /**\n * Abort every active flow run for a contact across all flows. Same semantics\n * as `abortFlow` — for \"stop everything\" events (account deleted, churned).\n */\n async abortAllFlows(\n externalId: string,\n opts: { reason?: string } = {},\n ): Promise<{ abortedRuns: number; cancelledSends: number }> {\n const parsed = abortAllFlowsInputSchema.parse({ externalId, reason: opts.reason })\n\n const result = await this.abortActiveRuns(\n { externalId: parsed.externalId },\n parsed.reason ? `aborted_by_host:${parsed.reason}` : 'aborted_by_host',\n )\n if (result.abortedRuns > 0 || result.cancelledSends > 0) {\n await this.audit({\n actor: 'host',\n action: 'flow.abort_all',\n resource: { collection: 'mailer_flow_runs' },\n diffSummary: `abortAllFlows externalId=${parsed.externalId} runs=${result.abortedRuns} sends=${result.cancelledSends}${parsed.reason ? ` reason=${parsed.reason}` : ''}`,\n })\n }\n return result\n }\n\n private async abortActiveRuns(\n // Open-ended extra keys carry caller-supplied dotted paths (e.g.\n // 'triggerEvent.properties.accountId') straight into the run query.\n filter: { externalId: string; flowId?: ObjectId } & Record<string, unknown>,\n exitReason: string,\n ): Promise<{ abortedRuns: number; cancelledSends: number }> {\n const runs = await this.collections.flowRuns\n .find({ ...filter, status: 'active' })\n .toArray()\n if (runs.length === 0) return { abortedRuns: 0, cancelledSends: 0 }\n\n for (const run of runs) {\n await exitFlowRun(run, exitReason, this.runnerContext)\n }\n\n // Exiting the runs stops future steps; this stops mail already produced by\n // past send steps but not yet dispatched (provider retry backoff, tripped\n // circuit breaker, stranded-send sweep). 'failed' is included because the\n // send queue re-dispatches failed sends on retry.\n const cancelled = await this.collections.sends.updateMany(\n { flowRunId: { $in: runs.map((r) => r._id!) }, status: { $in: ['queued', 'failed'] } },\n { $set: { status: 'cancelled', errorMessage: `cancelled: ${exitReason}`, updatedAt: new Date() } },\n )\n\n return { abortedRuns: runs.length, cancelledSends: cancelled.modifiedCount }\n }\n\n /**\n * GDPR right-to-erasure. Hard-deletes the contact's PII and leaves a hashed\n * suppression row to block re-import. INVARIANT 9.\n */\n async forget(externalId: string): Promise<void> {\n const sub = await this.collections.subscriptions.findOne({ externalId })\n const email = sub?.emailAtSubscribe?.toLowerCase()\n\n const collected = await Promise.all([\n this.collections.sends.find({ externalId }).map((s) => s.emailAtSend).toArray(),\n ])\n const emails = new Set<string>()\n if (email) emails.add(email)\n for (const e of collected[0]) if (e) emails.add(e.toLowerCase())\n\n await Promise.all([\n this.collections.events.deleteMany({ externalId }),\n this.collections.flowRuns.deleteMany({ externalId }),\n this.collections.sends.deleteMany({ externalId }),\n this.collections.subscriptions.deleteMany({ externalId }),\n this.collections.contactTags.deleteMany({ externalId }),\n ])\n if (email) {\n await this.collections.leads.deleteMany({ email })\n }\n\n for (const e of emails) {\n await this.collections.suppressions.updateOne(\n { emailHash: sha256Hex(e), scope: 'all' },\n {\n $setOnInsert: {\n email: null,\n emailHash: sha256Hex(e),\n scope: 'all',\n reason: 'gdpr_forget',\n source: 'gdpr_request',\n notes: null,\n addedAt: new Date(),\n expiresAt: null,\n },\n },\n { upsert: true },\n )\n }\n\n await this.audit({\n actor: 'system:gdpr',\n action: 'gdpr.forget',\n resource: { collection: 'mailer_subscriptions', id: sub?._id },\n diffSummary: `forget externalId=${externalId}`,\n })\n }\n\n /** GDPR data export. JSON-serializable. */\n async exportContactData(externalId: string): Promise<Record<string, unknown>> {\n const subscription = await this.collections.subscriptions.findOne({ externalId })\n const [events, flowRuns, sends, suppressions, tags] = await Promise.all([\n this.collections.events.find({ externalId }).toArray(),\n this.collections.flowRuns.find({ externalId }).toArray(),\n this.collections.sends.find({ externalId }).toArray(),\n subscription?.emailAtSubscribe\n ? this.collections.suppressions.find({ email: subscription.emailAtSubscribe }).toArray()\n : Promise.resolve([]),\n this.collections.contactTags.find({ externalId }).toArray(),\n ])\n return { subscription, events, flowRuns, sends, suppressions, tags }\n }\n\n // -------------------------------------------------------------------------\n // One-off transactional send (password reset etc.)\n // -------------------------------------------------------------------------\n\n async sendOneOff(input: SendOneOffInput): Promise<{ sendId: string }> {\n const parsed = sendOneOffInputSchema.parse(input)\n const template = await this.collections.templates.findOne({ slug: parsed.templateSlug })\n if (!template) throw new Error(`template not found: ${parsed.templateSlug}`)\n\n const contact = await this.adapter.getById(parsed.externalId)\n if (!contact) throw new Error(`contact not found: ${parsed.externalId}`)\n\n const dedupeKey = `oneoff:${parsed.dedupeKey}`\n const existing = await this.collections.sends.findOne({ dedupeKey })\n if (existing) return { sendId: String(existing._id) }\n\n const providerName =\n parsed.providerOverride\n ?? template.providerOverride\n ?? (template.kind === 'transactional' ? this.config.defaultTransactionalProvider : null)\n ?? this.config.defaultProvider\n\n const sendId = new ObjectIdCtor()\n try {\n await this.collections.sends.insertOne({\n _id: sendId,\n dedupeKey,\n externalId: parsed.externalId,\n emailAtSend: contact.email,\n templateId: template._id!,\n templateSlug: template.slug,\n flowRunId: null,\n broadcastId: null,\n manualSendBy: 'sendOneOff',\n kind: template.kind,\n provider: providerName,\n providerMessageId: null,\n fromName: template.fromName,\n fromEmail: template.fromEmail,\n subject: template.subject,\n bodyHash: '',\n status: 'queued',\n errorMessage: null,\n bounceType: null,\n bounceReason: null,\n links: [],\n vars: parsed.vars ?? {},\n openedAt: null,\n openCount: 0,\n firstClickAt: null,\n clickCount: 0,\n clickedLinks: [],\n unsubscribedAt: null,\n complainedAt: null,\n queuedAt: new Date(),\n updatedAt: new Date(),\n sentAt: null,\n deliveredAt: null,\n })\n } catch (err: any) {\n // Concurrent call with the same dedupeKey won the insert — return its id.\n if (err?.code !== 11000) throw err\n const winner = await this.collections.sends.findOne({ dedupeKey })\n if (winner) return { sendId: String(winner._id) }\n throw err\n }\n\n await this.queues.send.add(\n 'send',\n { sendId: String(sendId) },\n { attempts: this.config.sendRetryAttempts, backoff: { type: 'exponential', delay: 60_000 } },\n )\n\n return { sendId: String(sendId) }\n }\n\n // -------------------------------------------------------------------------\n // Audit log helper\n // -------------------------------------------------------------------------\n\n async audit(entry: {\n actor: string\n action: string\n resource: { collection: string; id?: string | ObjectId; slug?: string }\n before?: Record<string, unknown> | null\n after?: Record<string, unknown> | null\n diffSummary?: string\n ip?: string\n userAgent?: string\n requestId?: string\n }): Promise<void> {\n await this.collections.auditLog.insertOne({\n actor: entry.actor,\n action: entry.action,\n resource: entry.resource,\n before: entry.before ?? null,\n after: entry.after ?? null,\n diffSummary: entry.diffSummary ?? null,\n ip: entry.ip ?? null,\n userAgent: entry.userAgent ?? null,\n requestId: entry.requestId ?? null,\n occurredAt: new Date(),\n })\n }\n\n // -------------------------------------------------------------------------\n // Workers\n // -------------------------------------------------------------------------\n\n async startWorkers(): Promise<void> {\n if (this.workersStarted) return\n if (this.config.queue.driver === 'noop') {\n throw new Error('startWorkers requires a non-noop queue driver')\n }\n const provider = this.providers[this.config.defaultProvider]\n const sendRate = provider?.sendRatePerSecond ?? this.config.sendRatePerSecond\n\n await this.queueDriver.startWorkers({\n concurrency: { send: this.config.sendConcurrency },\n sendRateLimit: { max: sendRate, durationMs: 1_000 },\n retryAttempts: this.config.sendRetryAttempts,\n handlers: {\n tick: async () => {\n await runTick(this.runnerContext)\n },\n advance: async (data) => {\n if (data.broadcastId) {\n if (!ObjectIdCtor.isValid(data.broadcastId)) return\n await dispatchBroadcastById(new ObjectIdCtor(data.broadcastId), this.runnerContext)\n return\n }\n if (!data.flowRunId || !ObjectIdCtor.isValid(data.flowRunId)) return\n await processOneRunStep(new ObjectIdCtor(data.flowRunId), this.runnerContext)\n },\n send: async (data) => {\n if (!ObjectIdCtor.isValid(data.sendId)) return\n await dispatchSend(new ObjectIdCtor(data.sendId), this.runnerContext)\n },\n webhook: async () => {\n await this.processWebhookBacklog()\n },\n },\n })\n this.workersStarted = true\n }\n\n /** Process unprocessed webhook events in mailer_webhook_events. */\n private async processWebhookBacklog(): Promise<void> {\n await processWebhookBacklog(this.runnerContext)\n }\n\n async stop(): Promise<void> {\n await this.queueDriver.close()\n this.workersStarted = false\n }\n\n /** Used internally by the admin router and tests; not part of the public API. */\n getRunnerContext(): RunnerContext {\n return this.runnerContext\n }\n}\n","/**\n * Public exports for the `mailery` package.\n */\n\ndeclare const __PKG_VERSION__: string | undefined\n\n/**\n * Library version, stamped from package.json at build time (tsup/vitest\n * `define`). 'dev' when the source runs without a bundler define (plain tsx).\n */\nexport const VERSION = typeof __PKG_VERSION__ === 'string' ? __PKG_VERSION__ : 'dev'\n\n// Core\nexport { Mailer } from './mailer.js'\nexport type { MailerConfig, RedisOptions, CircuitBreakerThresholds, BotFilterConfig, SenderDomainConfig, SenderDomainRegistry } from './config.js'\nexport { validateSenderDomain } from './templates/sender-domain.js'\nexport type { SenderDomainValidation } from './templates/sender-domain.js'\n\n// Adapters\nexport { MongoContactAdapter } from './adapters/mongo.js'\nexport type { MongoContactAdapterOptions } from './adapters/mongo.js'\nexport { defineVars, varsJsonSchema, RESERVED_VAR_KEYS } from './adapters/vars.js'\nexport type { VarsAdapter, VarsResolveInfo } from './adapters/vars.js'\n\n// Providers\nexport { NullProvider } from './providers/null.js'\nexport { SendGridProvider } from './providers/sendgrid.js'\nexport type { SendGridProviderOptions } from './providers/sendgrid.js'\n\n// HTTP routers\nexport { createAdminRouter, createAdminApiRouter } from './api/admin.js'\nexport type { AdminRouterOptions } from './api/admin.js'\nexport { createAgentRouter, verifyTemplate, renderForContact, referencedPaths, MIN_AGENT_TOKEN_LENGTH } from './api/agent.js'\nexport type { AgentRouterOptions, AgentToken, VerifyReport, VerifyOptions } from './api/agent.js'\nexport {\n armFlow,\n disarmFlow,\n gateFlow,\n ungateFlow,\n isCanaryGate,\n stampWatermarkIfNull,\n FlowOperationError,\n} from './runner/arm.js'\nexport type { ArmFlowOptions, ArmFlowResult, GateFlowResult, UngateFlowResult } from './runner/arm.js'\nexport { simulateFlow } from './runner/simulate.js'\nexport type { SimulateOptions, SimulationResult, SimulatedStep } from './runner/simulate.js'\nexport { createPublicRouter } from './api/public.js'\nexport type { PublicRouterOptions } from './api/public.js'\nexport { sendgridInboundParser } from './api/dmarc-inbound.js'\nexport type {\n DmarcInboundOptions,\n InboundAttachment,\n InboundParser,\n} from './api/dmarc-inbound.js'\nexport type { RouteLogger } from './api/wrap.js'\n\n// Templates (host apps may want compile + render directly for previews)\nexport {\n compileTemplate,\n compileMailyTemplate,\n derivePlaintext,\n renderTemplate,\n applyTracking,\n} from './templates/render.js'\n\n// Runner internals — exported so test harnesses and advanced hosts can drive\n// the runner inline. In production let `startWorkers()` invoke these.\nexport {\n runTick,\n processOneRunStep,\n dispatchSend,\n applyWebhookEvent,\n processNewlyFiredEventTriggers,\n sweepStrandedFlowRuns,\n drainPendingUnsubscribes,\n} from './runner/index.js'\nexport type {\n DrainPendingUnsubsOptions,\n DrainPendingUnsubsResult,\n} from './runner/index.js'\n\n// Models (collection helpers, in case hosts need to query directly)\nexport { getCollections, ensureIndexes } from './models/index.js'\nexport type {\n Collections,\n SubscriptionDoc,\n EventDoc,\n FlowDoc,\n FlowRunDoc,\n TemplateDoc,\n SendDoc,\n SuppressionDoc,\n BroadcastDoc,\n AuditLogDoc,\n WebhookEventDoc,\n HealthDoc,\n ContactTagDoc,\n LeadDoc,\n OutboxDoc,\n FlowVersionDoc,\n TemplateVersionDoc,\n} from './models/index.js'\n\n// Token helpers (rarely needed by hosts, useful for tests)\nexport { signUnsubscribeToken, verifyUnsubscribeToken, sha256Hex } from './tokens.js'\nexport {\n signTrackingToken,\n verifyTrackingToken,\n TRACKING_SIG_LENGTH,\n type TrackingScope,\n type TrackingTokenParams,\n} from './tokens.js'\nexport { DEFAULT_BOT_UA_RE } from './runner/predicate.js'\n\n// Shared types\nexport { computeDeliveryTime } from './runner/delivery-window.js'\n\nexport type {\n Contact,\n ContactAdapter,\n AdapterFilter,\n DeliveryWindow,\n MailProvider,\n SendArgs,\n SendResult,\n NormalizedEvent,\n FlowStep,\n Predicate,\n SegmentDefinition,\n SegmentFilter,\n} from '../shared/types.js'\n\nexport type {\n SubscriptionStatus,\n SendStatus,\n TemplateKind,\n SuppressionScope,\n SuppressionReason,\n FlowRunStatus,\n BroadcastStatus,\n HealthStatus,\n FlowGoal,\n} from '../shared/enums.js'\n\n// Option lists for tooling / admin UIs — flow step kinds, predicate kinds,\n// segment filter kinds, dedupe policies.\nexport {\n FLOW_STEP_KINDS,\n defaultFlowStep,\n PREDICATE_KINDS,\n defaultPredicate,\n predicateKind,\n SEGMENT_FILTER_KINDS,\n defaultSegmentFilter,\n DEDUPE_POLICIES,\n} from '../shared/options.js'\nexport type {\n FlowStepKindOption,\n PredicateKindOption,\n PredicateKind,\n SegmentFilterKindOption,\n SegmentFilterKind,\n DedupePolicyOption,\n} from '../shared/options.js'\n","/**\n * NullProvider — in-memory provider for tests and dev. Records every send\n * without dispatching anything. Inspect `.sent` to assert what would have\n * been delivered.\n */\n\nimport type { MailProvider, NormalizedEvent, SendArgs, SendResult } from '../../shared/types.js'\n\nlet counter = 0\n\nexport class NullProvider implements MailProvider {\n readonly name = 'null'\n readonly sendRatePerSecond = 1000\n public readonly sent: SendArgs[] = []\n\n async send(args: SendArgs): Promise<SendResult> {\n this.sent.push(args)\n return {\n providerId: `null-${Date.now()}-${++counter}`,\n status: 'accepted',\n }\n }\n\n /**\n * Fails closed. This provider has no signing key, so it can never establish\n * that an inbound payload is authentic — and a method whose entire job is to\n * reject unauthenticated input must not answer \"yes\" by default. Returning\n * `true` here would mean any unsigned body posted to the webhook route is\n * accepted as genuine whenever the null provider is registered, which is\n * exactly the dev/staging configuration where that is easiest to miss.\n *\n * Nothing is lost: `parseWebhookEvents()` returns `[]`, so there was never\n * any inbound behaviour to preserve. To exercise the inbound half locally,\n * use a provider that actually signs (see `test/README.md`).\n */\n async verifyWebhook(): Promise<boolean> {\n return false\n }\n\n parseWebhookEvents(): NormalizedEvent[] {\n return []\n }\n\n reset(): void {\n this.sent.length = 0\n }\n}\n","/**\n * Content linter for email templates. Pure function — no I/O.\n *\n * const result = lintTemplate(input, { senderDomains })\n * if (result.errors.length) refuse to publish\n *\n * The publish endpoint runs this as a gate. The editor will eventually run it\n * live for inline squiggles (PR10) — same engine, same rules.\n */\n\nimport type { TemplateKind } from '../../shared/enums.js'\nimport type { SenderDomainRegistry } from './sender-domain.js'\nimport { validateSenderDomain } from './sender-domain.js'\n\nexport type LintSeverity = 'error' | 'warning' | 'info'\n\nexport interface LintIssue {\n /** Stable rule identifier, e.g. 'missing_plain_text'. */\n rule: string\n severity: LintSeverity\n message: string\n /** Optional remediation hint shown in tooltips/expanders. */\n hint?: string\n}\n\nexport interface LintResult {\n errors: LintIssue[]\n warnings: LintIssue[]\n infos: LintIssue[]\n}\n\nexport interface LintInput {\n subject: string\n preheader: string\n /** MJML source, when authored that way. Empty string when authored via Maily. */\n mjml: string\n /**\n * Maily editor JSON source, when authored that way. Optional — passing it\n * helps rules that scan for merge tags survive HTML-encoding of braces\n * in body text.\n */\n editorJson?: unknown\n /** Rendered HTML. */\n html: string\n /** Rendered plain-text alternative. */\n plainText: string\n kind: TemplateKind\n fromEmail: string\n}\n\nexport interface LintConfig {\n senderDomains?: SenderDomainRegistry\n /**\n * JSON Schema of the host's varsAdapter (see `varsJsonSchema`). When set,\n * `{{paths}}` in subject/preheader/MJML/editorJson that don't exist in the\n * schema (or the built-in keys) are flagged as `unknown_variable` warnings.\n */\n varsJsonSchema?: Record<string, unknown> | null\n}\n\nconst URL_SHORTENERS = ['bit.ly', 't.co', 'tinyurl.com', 'goo.gl', 'ow.ly']\n\nconst SPAM_PHRASES: Array<{ pattern: RegExp; phrase: string }> = [\n { pattern: /\\bFREE\\b/, phrase: 'FREE' },\n { pattern: /\\bACT NOW\\b/i, phrase: 'ACT NOW' },\n { pattern: /\\b100%\\s+guaranteed\\b/i, phrase: '100% guaranteed' },\n]\n\nconst MARKETING_UNSUBSCRIBE_TAG = /\\{\\{\\s*unsubscribeUrl\\s*\\}\\}/\n\nexport function lintTemplate(rawInput: LintInput, config: LintConfig = {}): LintResult {\n // Coerce missing/undefined fields so downstream `.length` / `.test()`\n // calls don't throw. The publish path can hand us a draft with an\n // undefined subject, and we'd rather lint it (and emit a length warning)\n // than 500.\n const input: LintInput = {\n subject: typeof rawInput.subject === 'string' ? rawInput.subject : '',\n preheader: typeof rawInput.preheader === 'string' ? rawInput.preheader : '',\n mjml: typeof rawInput.mjml === 'string' ? rawInput.mjml : '',\n editorJson: rawInput.editorJson,\n html: typeof rawInput.html === 'string' ? rawInput.html : '',\n plainText: typeof rawInput.plainText === 'string' ? rawInput.plainText : '',\n kind: rawInput.kind === 'marketing' || rawInput.kind === 'transactional' ? rawInput.kind : 'transactional',\n fromEmail: typeof rawInput.fromEmail === 'string' ? rawInput.fromEmail : '',\n }\n const issues: LintIssue[] = []\n\n // 1. Missing plain-text alternative — error\n if (!input.plainText || input.plainText.trim().length === 0) {\n issues.push({\n rule: 'missing_plain_text',\n severity: 'error',\n message: 'Plain-text alternative is empty.',\n hint: 'Email clients and spam filters use the plain-text part. Add visible text content (MJML mj-text blocks, or text content in the Maily editor) — do not strip plain-text to empty.',\n })\n }\n\n // 2. Image-only body — error\n const imageCount = countMatches(input.html, /<img\\b/gi)\n const textLen = input.plainText.trim().length\n if (imageCount >= 1 && textLen < 20) {\n issues.push({\n rule: 'image_only_body',\n severity: 'error',\n message: 'Body is mostly images with little or no text.',\n hint: 'Image-only emails are heavily filtered as spam. Add at least one paragraph of meaningful text.',\n })\n }\n\n // 3. URL shortener — error\n const shortenerLinks = findShortenerLinks(input.html)\n if (shortenerLinks.length > 0) {\n issues.push({\n rule: 'url_shortener',\n severity: 'error',\n message: `Link uses a URL shortener: ${shortenerLinks.join(', ')}.`,\n hint: 'URL shorteners are strongly correlated with spam and are routinely blocked. Use a direct link to your domain.',\n })\n }\n\n // 4. Bare URL in body — warning\n if (hasBareUrlInVisibleText(input.html)) {\n issues.push({\n rule: 'bare_url',\n severity: 'warning',\n message: 'A URL appears in the body text without being wrapped in a link.',\n hint: 'Wrap visible URLs in an anchor tag — bare URLs look like spam template residue and reduce engagement.',\n })\n }\n\n // 5. Spammy phrases — warning (check both subject and plainText)\n const spam = findSpamSignals(`${input.subject}\\n${input.plainText}`)\n if (spam.length > 0) {\n issues.push({\n rule: 'spam_phrases',\n severity: 'warning',\n message: `Content contains spam-flagged phrases: ${spam.join(', ')}.`,\n hint: 'These phrases trigger content filters. Rephrase if possible.',\n })\n }\n\n // 6. All-caps subject — warning\n if (isAllCaps(input.subject)) {\n issues.push({\n rule: 'all_caps_subject',\n severity: 'warning',\n message: 'Subject line is mostly uppercase.',\n hint: 'All-caps subjects are flagged by spam filters and reduce click-through. Use sentence case.',\n })\n }\n\n // 7. Missing unsubscribe merge tag (marketing only) — error.\n // Check the raw mjml + editorJson + compiled HTML. @maily-to/render\n // HTML-encodes the `{{ }}` braces when they're placed in body text\n // (not in href), so checking only the rendered html misses legitimate\n // unsubscribe-tag placements.\n if (input.kind === 'marketing') {\n const sources = [input.mjml ?? '', input.html ?? '', JSON.stringify(input.editorJson ?? null)]\n const hasTag = sources.some((s) => MARKETING_UNSUBSCRIBE_TAG.test(s))\n if (!hasTag) {\n issues.push({\n rule: 'missing_unsubscribe_tag',\n severity: 'error',\n message: 'Marketing template is missing the {{unsubscribeUrl}} merge tag.',\n hint: 'CAN-SPAM, GDPR, and Gmail/Yahoo bulk-sender rules all require a working unsubscribe link. Add {{unsubscribeUrl}} somewhere in the body.',\n })\n }\n }\n\n // 8. From-domain mismatch — error (mirrors the publish-time check)\n const senderCheck = validateSenderDomain(input.fromEmail, input.kind, config.senderDomains)\n if (!senderCheck.ok) {\n issues.push({\n rule: 'sender_domain_invalid',\n severity: 'error',\n message: senderCheck.reason,\n hint: 'Edit the template fromEmail to use a domain declared for this kind in senderDomains, or update the registry.',\n })\n }\n\n // 9. Empty preheader — info\n if (!input.preheader || input.preheader.trim().length === 0) {\n issues.push({\n rule: 'empty_preheader',\n severity: 'info',\n message: 'No preheader set.',\n hint: 'The preheader shows next to the subject in most inbox previews. A good preheader lifts open rate 5-10%.',\n })\n }\n\n // 10. Subject too long — warning\n if (input.subject.length > 60) {\n issues.push({\n rule: 'subject_too_long',\n severity: 'warning',\n message: `Subject is ${input.subject.length} characters; mobile clients truncate around 60.`,\n hint: 'Front-load the important words so the truncated preview still makes sense.',\n })\n }\n\n // 11a. Unknown template variables — warning (only when a vars schema is provided)\n if (config.varsJsonSchema) {\n const sources = [input.subject, input.preheader, input.mjml, JSON.stringify(input.editorJson ?? null)]\n const unknown = findUnknownVariables(sources.join('\\n'), config.varsJsonSchema)\n if (unknown.length > 0) {\n issues.push({\n rule: 'unknown_variable',\n severity: 'warning',\n message: `Template references variable(s) not in the vars schema: ${unknown.join(', ')}.`,\n hint: 'These render as empty strings. Check for typos, or add the key to your varsAdapter schema. Paths inside {{#each}}/{{#with}} blocks are relative and not checked.',\n })\n }\n }\n\n // 12. Off-domain links — warning.\n // Mailbox providers weigh whether link domains line up with the From\n // domain. A stray off-domain link is normal (docs, social); a body whose\n // links mostly point elsewhere reads like a forwarded/spoofed template.\n const offDomain = findOffDomainLinkHosts(input.html, input.fromEmail)\n if (offDomain.majority && offDomain.hosts.length > 0) {\n issues.push({\n rule: 'offdomain_links',\n severity: 'warning',\n message: `Most links point away from the From domain: ${offDomain.hosts.join(', ')}.`,\n hint: 'Link domains that match the sending domain build reputation. Route links through your own domain (or a tracking subdomain of it) where you can.',\n })\n }\n\n // 13. Insecure links — warning.\n // Note: this is a scheme check only. Liveness (200 vs 404) needs network\n // I/O and does not belong in a pure lint pass.\n const insecure = findInsecureLinkHosts(input.html)\n if (insecure.length > 0) {\n issues.push({\n rule: 'insecure_link',\n severity: 'warning',\n message: `Link uses plain http://: ${insecure.join(', ')}.`,\n hint: 'Mixed-content links get rewritten or warned about by some clients, and http:// correlates with stale spam templates. Use https://.',\n })\n }\n\n // 14. Images missing alt text — warning.\n if (countImagesMissingAlt(input.html) > 0) {\n issues.push({\n rule: 'image_missing_alt',\n severity: 'warning',\n message: 'One or more images have no alt text.',\n hint: 'Most clients block images by default on first open. Alt text is what the recipient actually sees, and screen readers need it.',\n })\n }\n\n // 15. Image-only link — warning.\n if (hasImageOnlyLink(input.html)) {\n issues.push({\n rule: 'image_only_link',\n severity: 'warning',\n message: 'A link wraps an image with no accompanying text.',\n hint: 'With images blocked, an image-only call-to-action is invisible and unclickable. Add a text label inside the link.',\n })\n }\n\n // 11. Too many links — warning\n // Match href= with or without surrounding quotes — same shape as\n // extractHrefs above.\n const linkCount = countMatches(input.html, /<a\\s[^>]*\\bhref\\s*=/gi)\n if (linkCount > 10) {\n issues.push({\n rule: 'too_many_links',\n severity: 'warning',\n message: `${linkCount} links in body; promotional content with many links is flagged by content filters.`,\n hint: 'Consolidate calls-to-action. Aim for one primary action plus a footer link or two.',\n })\n }\n\n return splitBySeverity(issues)\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction splitBySeverity(issues: LintIssue[]): LintResult {\n const out: LintResult = { errors: [], warnings: [], infos: [] }\n for (const i of issues) {\n if (i.severity === 'error') out.errors.push(i)\n else if (i.severity === 'warning') out.warnings.push(i)\n else out.infos.push(i)\n }\n return out\n}\n\nfunction countMatches(s: string, re: RegExp): number {\n return (s.match(re) ?? []).length\n}\n\nfunction findShortenerLinks(html: string): string[] {\n const hrefs = extractHrefs(html)\n const hits = new Set<string>()\n for (const href of hrefs) {\n const domain = hostnameOf(href)\n if (!domain) continue\n if (URL_SHORTENERS.includes(domain)) hits.add(domain)\n }\n return Array.from(hits)\n}\n\nfunction extractHrefs(html: string): string[] {\n const out: string[] = []\n // Match href values in any of: double-quoted, single-quoted, or\n // unquoted (terminated by space, `>`, or end of tag). Maily-generated\n // HTML mostly quotes but operator-edited MJML may not.\n const re = /<a\\s[^>]*\\bhref\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)'|([^\\s>]+))/gi\n let m: RegExpExecArray | null\n while ((m = re.exec(html))) {\n const href = m[1] ?? m[2] ?? m[3]\n if (href) out.push(href)\n }\n return out\n}\n\nfunction hostnameOf(url: string): string | null {\n try {\n return new URL(url).hostname.toLowerCase()\n } catch {\n return null\n }\n}\n\n/**\n * Heuristic: strip anchor tags (and their contents), plus `<style>`,\n * `<script>`, and `<head>` blocks before looking for a bare URL. Otherwise\n * URLs in CSS (`@import url(...)`) or scripts trigger a false positive.\n */\nfunction hasBareUrlInVisibleText(html: string): boolean {\n const stripped = html\n .replace(/<a\\b[^>]*>.*?<\\/a>/gis, ' ')\n .replace(/<style\\b[^>]*>.*?<\\/style>/gis, ' ')\n .replace(/<script\\b[^>]*>.*?<\\/script>/gis, ' ')\n .replace(/<head\\b[^>]*>.*?<\\/head>/gis, ' ')\n return /https?:\\/\\/[^\\s<>\"']+/i.test(stripped)\n}\n\n/**\n * Hosts linked in the body that don't belong to the From domain, plus whether\n * they're the majority of resolvable links. Unresolved merge-tag hrefs\n * (`{{unsubscribeUrl}}`), mailto:/tel:, anchors, and relative URLs are\n * ignored — none of them carry a domain to compare.\n */\nfunction findOffDomainLinkHosts(html: string, fromEmail: string): { hosts: string[]; majority: boolean } {\n const fromDomain = fromEmail.split('@')[1]?.toLowerCase()\n if (!fromDomain) return { hosts: [], majority: false }\n\n const hosts = new Set<string>()\n let total = 0\n let off = 0\n for (const href of extractHrefs(html)) {\n if (href.includes('{{')) continue\n const host = hostnameOf(href)\n if (!host) continue\n total++\n if (sameSite(host, fromDomain)) continue\n off++\n hosts.add(host)\n }\n return { hosts: Array.from(hosts), majority: total > 0 && off * 2 > total }\n}\n\n/**\n * Approximate same-site test: exact match, either side a subdomain of the\n * other, or a shared last-two-label suffix (so `mail.example.com` and\n * `www.example.com` match). Deliberately loose — a false \"off-domain\"\n * warning is worse than a missed one, and we don't ship a PSL.\n */\nfunction sameSite(a: string, b: string): boolean {\n if (a === b) return true\n if (a.endsWith(`.${b}`) || b.endsWith(`.${a}`)) return true\n return lastLabels(a) === lastLabels(b)\n}\n\nfunction lastLabels(host: string): string {\n return host.split('.').slice(-2).join('.')\n}\n\nfunction findInsecureLinkHosts(html: string): string[] {\n const hits = new Set<string>()\n for (const href of extractHrefs(html)) {\n if (!/^http:\\/\\//i.test(href)) continue\n const host = hostnameOf(href)\n if (host) hits.add(host)\n }\n return Array.from(hits)\n}\n\nfunction countImagesMissingAlt(html: string): number {\n let missing = 0\n const re = /<img\\b[^>]*>/gi\n let m: RegExpExecArray | null\n while ((m = re.exec(html))) {\n const tag = m[0]\n const alt = /\\balt\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)'|([^\\s>]+))/i.exec(tag)\n const value = alt ? (alt[1] ?? alt[2] ?? alt[3] ?? '') : ''\n if (value.trim().length === 0) missing++\n }\n return missing\n}\n\n/** An anchor whose entire content is one or more images and no visible text. */\nfunction hasImageOnlyLink(html: string): boolean {\n const re = /<a\\b[^>]*>(.*?)<\\/a>/gis\n let m: RegExpExecArray | null\n while ((m = re.exec(html))) {\n const inner = m[1]!\n if (!/<img\\b/i.test(inner)) continue\n const text = inner\n .replace(/<[^>]*>/g, '')\n .replace(/&nbsp;/gi, ' ')\n .trim()\n if (text.length === 0) return true\n }\n return false\n}\n\nfunction findSpamSignals(text: string): string[] {\n const out = new Set<string>()\n for (const { pattern, phrase } of SPAM_PHRASES) {\n if (pattern.test(text)) out.add(phrase)\n }\n if (/!{3,}/.test(text)) out.add('excessive \"!!!\"')\n return Array.from(out)\n}\n\n// --- unknown_variable helpers ----------------------------------------------\n\n/** Render-context keys mailery provides regardless of the host schema. */\nconst BUILTIN_VAR_ROOTS = new Set([\n 'contact',\n 'vars',\n 'event',\n 'unsubscribeUrl',\n 'viewInBrowserUrl',\n 'preferenceCenterUrl',\n 'senderAddress',\n 'this',\n])\n\nconst PATH_TOKEN = /^@?[A-Za-z_][\\w$]*(\\.[A-Za-z_][\\w$]*)*$/\n\n/**\n * Extract `{{ ... }}` expressions and return the dotted paths that cannot be\n * found in the vars JSON Schema. Conservative by design: helper arguments,\n * block-relative paths, and any schema shape we can't confidently walk are\n * treated as valid — a warning here should never be a false alarm the\n * operator has to fight.\n */\nexport function findUnknownVariables(source: string, schema: Record<string, unknown>): string[] {\n // Block helpers introduce relative scopes ({{#each topics}} → {{title}}),\n // so bare single-segment identifiers can't be validated when any exist.\n const hasBlockScopes = /\\{\\{[#^]\\s*(each|with)\\b/.test(source)\n\n const unknown = new Set<string>()\n const re = /\\{\\{\\{?\\s*([^{}]+?)\\s*\\}?\\}\\}/g\n let m: RegExpExecArray | null\n while ((m = re.exec(source))) {\n const expr = m[1]!.trim()\n if (!expr || /^[#^/>!]/.test(expr) || expr === 'else') continue // blocks, partials, comments\n if (expr.includes('(')) continue // subexpressions — too dynamic to check\n\n // Helper call: skip the helper name, validate path-shaped args.\n // Single token: validate it directly.\n const parts = expr.split(/\\s+/)\n const candidates = parts.length > 1 ? parts.slice(1) : parts\n for (const raw of candidates) {\n if (!PATH_TOKEN.test(raw)) continue // quoted strings, numbers, key=val hash args\n if (raw.startsWith('@')) continue // @index, @key, @root\n const segments = raw.split('.')\n if (BUILTIN_VAR_ROOTS.has(segments[0]!)) continue\n if (hasBlockScopes && segments.length === 1) continue // possibly block-relative\n if (!schemaHasPath(schema, segments)) unknown.add(raw)\n }\n }\n return Array.from(unknown)\n}\n\n/**\n * Walk a JSON Schema along `segments`. Returns false only when we positively\n * know the path is absent (an object node with declared properties that lacks\n * the segment and forbids extras). Unions, arrays, open objects → true.\n */\nfunction schemaHasPath(node: unknown, segments: string[]): boolean {\n if (segments.length === 0) return true\n if (!node || typeof node !== 'object') return true // can't tell — accept\n const n = node as Record<string, any>\n\n // Union shapes (zod nullable/optional/union): valid if any branch accepts.\n for (const key of ['anyOf', 'oneOf', 'allOf']) {\n if (Array.isArray(n[key])) {\n return (n[key] as unknown[]).some((branch) => schemaHasPath(branch, segments))\n }\n }\n\n if (Array.isArray(n.type) && n.type.includes('object') && !n.properties) return true\n if (n.type === 'array') {\n if (segments[0] === 'length') return true // {{topics.length}}\n return schemaHasPath(n.items, segments)\n }\n\n const props = n.properties\n if (!props || typeof props !== 'object') return true // not a closed object — accept\n\n const [head, ...rest] = segments\n if (head! in props) return schemaHasPath(props[head!], rest)\n // Segment missing — only reject when the object doesn't allow extras.\n if (n.additionalProperties === undefined || n.additionalProperties === false) return false\n return true\n}\n\nfunction isAllCaps(subject: string): boolean {\n const letters = subject.replace(/[^a-zA-Z]/g, '')\n if (letters.length < 5) return false\n const upper = subject.replace(/[^A-Z]/g, '').length\n return upper / letters.length > 0.5\n}\n","/**\n * Admin router — serves the prebuilt React SPA + REST endpoints the SPA\n * consumes. Mount inside a host Express app, gated by host auth.\n *\n * app.use('/admin/mailer', requireAdmin, createAdminRouter(mailer))\n *\n * REST routes under /api/* are documented in plans/14-admin-api.md.\n */\n\nimport express, { Router, type Request, type Response, type NextFunction } from 'express'\nimport multer from 'multer'\nimport net from 'node:net'\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { ObjectId } from 'mongodb'\n\nimport type { Mailer } from '../mailer.js'\nimport {\n applyTracking,\n compileMailyTemplate,\n compileTemplate,\n renderTemplate,\n} from '../templates/render.js'\nimport { validateSenderDomain } from '../templates/sender-domain.js'\nimport { lintTemplate } from '../templates/linter.js'\nimport { resolveVars, varsJsonSchema, RESERVED_VAR_KEYS } from '../adapters/vars.js'\nimport type { Contact } from '../../shared/types.js'\nimport { TEMPLATE_BODY_FORMATS } from '../../shared/enums.js'\nimport { runSetupChecks } from './setup-status.js'\nimport { sha256Hex, signUnsubscribeToken } from '../tokens.js'\nimport { registeredProviderNames, resolveProvider } from '../provider-lookup.js'\nimport { effectiveOverallStatus } from '../runner/health.js'\nimport { runDnsblChecks } from '../runner/dnsbl.js'\nimport { runPostmasterPull } from '../runner/postmaster.js'\nimport { runSndsPull } from '../runner/snds.js'\nimport { ingestDmarcAttachment, resolveSourceTags, suggestPolicyProgression } from '../runner/dmarc.js'\nimport { computeListHygiene } from '../runner/hygiene.js'\nimport {\n createMailTesterClient,\n evaluateMailTesterGate,\n findCachedScore,\n mailTesterContentKey,\n persistScore,\n type MailTesterClient,\n} from '../runner/mail-tester.js'\nimport { HEALTH_AGG_ID, healthBucketId } from '../models/index.js'\n\nconst __filename = fileURLToPath(import.meta.url)\nconst __dirname = path.dirname(__filename)\n\nfunction defaultSpaDir(): string {\n // After tsup build: dist/index.{js,cjs} + dist/admin/spa/. __dirname = dist/.\n return path.resolve(__dirname, 'admin/spa')\n}\n\nexport interface AdminRouterOptions {\n /** Override path to the built SPA. Defaults to `dist/admin/spa` shipped with the package. */\n spaDir?: string\n /** Resolve actor metadata from a Request. Defaults to `human:${req.user?.email || 'anonymous'}`. */\n getActor?: (req: Request) => string\n /**\n * Inject a Mail-Tester client (tests use a stub). When omitted, a real\n * client is created from `mailer.config.mailTester`.\n */\n mailTesterClient?: MailTesterClient\n}\n\nexport function createAdminRouter(mailer: Mailer, opts: AdminRouterOptions = {}): Router {\n const router = Router()\n const spaDir = opts.spaDir ?? defaultSpaDir()\n const getActor =\n opts.getActor ?? ((req: Request) => `human:${(req as any).user?.email ?? 'anonymous'}`)\n\n // Static assets — long cache, hashed filenames.\n router.use(\n '/_assets',\n express.static(spaDir, {\n maxAge: '1y',\n immutable: true,\n index: false,\n }),\n )\n\n // JSON body parsing for mutating endpoints.\n router.use('/api', express.json({ limit: '1mb' }))\n\n // Inject actor on every API request (read after the host's auth middleware).\n router.use('/api', (req: Request, _res, next: NextFunction) => {\n ;(req as any).actor = getActor(req)\n next()\n })\n\n router.use('/api', createAdminApiRouter(mailer, opts))\n\n // SPA shell — any other route returns index.html so client-side routing\n // doesn't 404 on refresh.\n router.get(/.*/, (_req: Request, res: Response) => {\n res.sendFile(path.join(spaDir, 'index.html'))\n })\n\n return router\n}\n\n// ---------------------------------------------------------------------------\n// JSON API\n// ---------------------------------------------------------------------------\n\n/**\n * The JSON API alone, without the SPA shell or the static assets. Exported\n * so `createAgentRouter` can offer the same endpoints under bearer-token\n * auth; hosts mounting the SPA should keep using `createAdminRouter`.\n *\n * Expects `(req as any).actor` to be set by whatever sits in front of it.\n */\nexport function createAdminApiRouter(mailer: Mailer, opts: AdminRouterOptions = {}): Router {\n const r = Router()\n const c = mailer.collections\n\n // Computed once — the vars schema is fixed for the process lifetime.\n const varsSchema = mailer.config.varsAdapter ? varsJsonSchema(mailer.config.varsAdapter) : null\n\n function getMailTesterClient(): MailTesterClient | null {\n if (opts.mailTesterClient) return opts.mailTesterClient\n const cfg = mailer.config.mailTester\n if (!cfg?.apiKey) return null\n return createMailTesterClient(cfg)\n }\n\n // Vars contract for the template editor — JSON Schema of the host's\n // varsAdapter (null when none configured) plus the mailery-provided\n // built-in keys, so autocomplete/linting have one source of truth.\n r.get(\n '/vars-schema',\n asyncHandler(async (_req, res) => {\n res.json({ schema: varsSchema, builtins: RESERVED_VAR_KEYS })\n }),\n )\n\n r.get(\n '/me',\n asyncHandler(async (req, res) => {\n const [flows, templates, broadcasts, contacts, suppressions, healthDocs] = await Promise.all([\n c.flows.estimatedDocumentCount(),\n c.templates.estimatedDocumentCount(),\n c.broadcasts.estimatedDocumentCount(),\n c.subscriptions.countDocuments({ status: 'subscribed' }),\n c.suppressions.estimatedDocumentCount(),\n c.health.find({}).limit(500).toArray(),\n ])\n res.json({\n actor: (req as any).actor,\n counts: { flows, templates, broadcasts, contacts, suppressions },\n health: { status: effectiveOverallStatus(healthDocs) },\n providers: {\n names: Object.keys(mailer.config.providers),\n default: mailer.config.defaultProvider,\n },\n broadcastConfirmationThreshold: mailer.config.broadcastConfirmationThreshold,\n })\n }),\n )\n\n // ----- Dashboard ----------------------------------------------------------\n r.get(\n '/dashboard',\n asyncHandler(async (_req, res) => {\n const now = Date.now()\n const HOUR = 60 * 60 * 1000\n const since24h = new Date(now - 24 * HOUR)\n const since48h = new Date(now - 48 * HOUR)\n\n const [\n sentTotal, deliveredCount, bouncedCount, openedCount, clickedCount,\n sentPrev, deliveredPrev, openedPrev, clickedPrev,\n hourly,\n ] = await Promise.all([\n c.sends.countDocuments({ queuedAt: { $gt: since24h } }),\n c.sends.countDocuments({ queuedAt: { $gt: since24h }, status: 'delivered' }),\n c.sends.countDocuments({ queuedAt: { $gt: since24h }, status: 'bounced' }),\n c.sends.countDocuments({ queuedAt: { $gt: since24h }, openedAt: { $ne: null } }),\n c.sends.countDocuments({ queuedAt: { $gt: since24h }, firstClickAt: { $ne: null } }),\n c.sends.countDocuments({ queuedAt: { $gt: since48h, $lte: since24h } }),\n c.sends.countDocuments({ queuedAt: { $gt: since48h, $lte: since24h }, status: 'delivered' }),\n c.sends.countDocuments({ queuedAt: { $gt: since48h, $lte: since24h }, openedAt: { $ne: null } }),\n c.sends.countDocuments({ queuedAt: { $gt: since48h, $lte: since24h }, firstClickAt: { $ne: null } }),\n c.sends\n .aggregate<{ _id: number; sends: number; opens: number }>([\n { $match: { queuedAt: { $gt: since24h } } },\n {\n $project: {\n hour: {\n $toInt: {\n $divide: [{ $subtract: [now, { $toLong: '$queuedAt' }] }, HOUR],\n },\n },\n opened: { $cond: [{ $ifNull: ['$openedAt', false] }, 1, 0] },\n },\n },\n { $group: { _id: '$hour', sends: { $sum: 1 }, opens: { $sum: '$opened' } } },\n ])\n .toArray(),\n ])\n\n const sendSeries = new Array(24).fill(0)\n const openSeries = new Array(24).fill(0)\n for (const row of hourly) {\n const idx = 23 - Math.max(0, Math.min(23, row._id))\n sendSeries[idx] = row.sends\n openSeries[idx] = row.opens\n }\n\n const delta = (cur: number, prev: number): number | null => {\n if (prev === 0) return null\n return (cur - prev) / prev\n }\n const rateDelta = (curN: number, curD: number, prevN: number, prevD: number): number | null => {\n if (prevD === 0 || curD === 0) return null\n return curN / curD - prevN / prevD\n }\n\n const healthDocs = await c.health.find({}).limit(500).toArray()\n const healthAgg = healthDocs.find((d) => d._id === HEALTH_AGG_ID) ?? null\n const recentFlowsRaw = await c.flows.find({ enabled: true }).limit(5).toArray()\n const flowStatsMap = await computeFlowStats(mailer)\n const recentFlows = recentFlowsRaw.map((f) => ({ ...f, stats: flowStatsMap.get(f.slug) ?? emptyFlowStats() }))\n const recentSends = await c.sends.find().sort({ queuedAt: -1 }).limit(6).toArray()\n const recentAudit = await c.auditLog.find().sort({ occurredAt: -1 }).limit(5).toArray()\n\n const queueCounts = await collectQueueCounts(mailer)\n const lastSendError = await c.sends\n .findOne({ status: { $in: ['bounced', 'failed'] } }, { sort: { queuedAt: -1 } })\n const lastSendOk = await c.sends\n .findOne({ status: 'delivered' }, { sort: { queuedAt: -1 } })\n const providerOk =\n lastSendOk && lastSendError\n ? new Date(lastSendOk.queuedAt as Date).getTime() >= new Date(lastSendError.queuedAt as Date).getTime()\n : lastSendOk\n ? true\n : lastSendError\n ? false\n : null\n\n res.json({\n kpis: {\n sends: { value: sentTotal, delta: delta(sentTotal, sentPrev) },\n deliveredRate: {\n value: sentTotal === 0 ? null : deliveredCount / sentTotal,\n delta: rateDelta(deliveredCount, sentTotal, deliveredPrev, sentPrev),\n bounced: bouncedCount,\n },\n openRate: {\n value: sentTotal === 0 ? null : openedCount / sentTotal,\n delta: rateDelta(openedCount, sentTotal, openedPrev, sentPrev),\n },\n clickRate: {\n value: sentTotal === 0 ? null : clickedCount / sentTotal,\n delta: rateDelta(clickedCount, sentTotal, clickedPrev, sentPrev),\n },\n },\n series: { hourly: { sends: sendSeries, opens: openSeries } },\n health: {\n status: effectiveOverallStatus(healthDocs),\n rates: healthAgg?.rates ?? null,\n thresholds: {\n hardBounceRatePctTrip: mailer.config.circuitBreaker.hardBounceRatePctTrip,\n complaintRatePctTrip: mailer.config.circuitBreaker.complaintRatePctTrip,\n combinedBounceRatePctTrip: mailer.config.circuitBreaker.combinedBounceRatePctTrip,\n failedToSendRatePctDegrade: mailer.config.circuitBreaker.failedToSendRatePctDegrade,\n },\n },\n queue: {\n inFlight: queueCounts?.inFlight ?? null,\n delayed: queueCounts?.delayed ?? null,\n providerOk,\n providerName: mailer.config.defaultProvider,\n },\n recentFlows,\n recentSends,\n recentAudit,\n })\n }),\n )\n\n // ----- Events registry ----------------------------------------------------\n r.get(\n '/events',\n asyncHandler(async (_req, res) => {\n const registered = mailer.events.list()\n const seenNames = await c.events.distinct('name')\n const known = new Set(registered.map((r) => r.name))\n const unregistered = (seenNames as string[]).filter((n) => n && !known.has(n))\n res.json({\n registered: registered.sort((a, b) => a.name.localeCompare(b.name)),\n seen: unregistered.sort(),\n })\n }),\n )\n\n // ----- Flows --------------------------------------------------------------\n r.get(\n '/flows',\n asyncHandler(async (_req, res) => {\n const flows = await c.flows.find().sort({ updatedAt: -1 }).toArray()\n const stats = await computeFlowStats(mailer)\n res.json(flows.map((f) => ({ ...f, stats: stats.get(f.slug) ?? emptyFlowStats() })))\n }),\n )\n\n r.get(\n '/flows/:slug',\n asyncHandler(async (req, res) => {\n const flow = await c.flows.findOne({ slug: req.params.slug })\n if (!flow) return res.status(404).json({ error: 'not_found' })\n const stats = (await computeFlowStats(mailer, flow.slug)).get(flow.slug) ?? emptyFlowStats()\n return res.json({ ...flow, stats })\n }),\n )\n\n r.post(\n '/flows/:slug/pause',\n asyncHandler(async (req, res) => {\n const before = await c.flows.findOne({ slug: req.params.slug })\n if (!before) return res.status(404).json({ error: 'not_found' })\n await c.flows.updateOne({ _id: before._id }, { $set: { enabled: false, updatedAt: new Date() } })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'flow.pause',\n resource: { collection: 'mailer_flows', id: before._id, slug: before.slug },\n })\n return res.json({ ok: true })\n }),\n )\n\n r.post(\n '/flows/:slug/resume',\n asyncHandler(async (req, res) => {\n const before = await c.flows.findOne({ slug: req.params.slug })\n if (!before) return res.status(404).json({ error: 'not_found' })\n // A flow that has never scanned has a null watermark, and the trigger\n // scan falls back to `createdAt` — so a first \"resume\" replayed every\n // matching event since the document was created. Stamp now; a flow that\n // HAS scanned keeps its watermark, so events fired during a pause enter.\n const now = new Date()\n await c.flows.updateOne(\n { _id: before._id },\n { $set: { enabled: true, updatedAt: now, ...(before.lastTriggerScanAt ? {} : { lastTriggerScanAt: now }) } },\n )\n await mailer.audit({\n actor: (req as any).actor,\n action: 'flow.resume',\n resource: { collection: 'mailer_flows', id: before._id, slug: before.slug },\n })\n return res.json({ ok: true })\n }),\n )\n\n // ----- Templates ----------------------------------------------------------\n r.get(\n '/templates',\n asyncHandler(async (_req, res) => {\n const templates = await c.templates.find().sort({ updatedAt: -1 }).toArray()\n const stats = await computeTemplateStats(mailer)\n res.json(templates.map((t) => ({ ...t, stats: stats.get(t.slug) ?? emptyTemplateStats() })))\n }),\n )\n\n r.get(\n '/templates/:slug',\n asyncHandler(async (req, res) => {\n const template = await c.templates.findOne({ slug: req.params.slug })\n if (!template) return res.status(404).json({ error: 'not_found' })\n const stats = (await computeTemplateStats(mailer, template.slug)).get(template.slug) ?? emptyTemplateStats()\n return res.json({ ...template, stats })\n }),\n )\n\n // ----- Broadcasts ---------------------------------------------------------\n r.get(\n '/broadcasts',\n asyncHandler(async (_req, res) => {\n const broadcasts = await c.broadcasts.find().sort({ createdAt: -1 }).toArray()\n const stats = await computeBroadcastStats(mailer)\n res.json(broadcasts.map((b) => ({ ...b, stats: stats.get(String(b._id)) ?? emptyBroadcastStats() })))\n }),\n )\n\n r.get(\n '/broadcasts/:slug',\n asyncHandler(async (req, res) => {\n const broadcast = await c.broadcasts.findOne({ slug: req.params.slug })\n if (!broadcast) return res.status(404).json({ error: 'not_found' })\n const stats = (await computeBroadcastStats(mailer, broadcast._id)).get(String(broadcast._id)) ?? emptyBroadcastStats()\n return res.json({ ...broadcast, stats })\n }),\n )\n\n // ----- Contacts -----------------------------------------------------------\n r.get(\n '/contacts',\n asyncHandler(async (req, res) => {\n const cursor = typeof req.query.cursor === 'string' ? req.query.cursor : undefined\n const limit = Math.min(Number(req.query.limit ?? 50), 200)\n const [{ contacts, nextCursor }, counts] = await Promise.all([\n mailer.adapter.query({}, { limit, cursor }),\n (async () => {\n const rows = await c.subscriptions\n .aggregate<{ _id: string; n: number }>([{ $group: { _id: '$status', n: { $sum: 1 } } }])\n .toArray()\n const out: Record<string, number> = { subscribed: 0, pending_doi: 0, unsubscribed: 0, bounced: 0, complained: 0 }\n let total = 0\n for (const r of rows) {\n if (r._id) out[r._id] = r.n\n total += r.n\n }\n return { ...out, total }\n })(),\n ])\n res.json({ contacts, nextCursor, counts })\n }),\n )\n\n r.get(\n '/contacts/:externalId',\n asyncHandler(async (req, res) => {\n const externalId = String(req.params.externalId)\n const [contact, subscription, recentEvents, recentSends, activeRuns] = await Promise.all([\n mailer.adapter.getById(externalId),\n c.subscriptions.findOne({ externalId }),\n c.events.find({ externalId }).sort({ occurredAt: -1 }).limit(50).toArray(),\n c.sends.find({ externalId }).sort({ queuedAt: -1 }).limit(50).toArray(),\n c.flowRuns.find({ externalId, status: 'active' }).sort({ nextActionAt: 1 }).limit(50).toArray(),\n ])\n if (!contact) return res.status(404).json({ error: 'not_found' })\n return res.json({ contact, subscription, recentEvents, recentSends, activeRuns })\n }),\n )\n\n // ----- Sends --------------------------------------------------------------\n r.get(\n '/sends',\n asyncHandler(async (req, res) => {\n const limit = Math.min(Number(req.query.limit ?? 100), 500)\n const status = typeof req.query.status === 'string' ? req.query.status : undefined\n const filter: any = {}\n if (status) filter.status = status\n const sends = await c.sends.find(filter).sort({ queuedAt: -1 }).limit(limit).toArray()\n res.json(sends)\n }),\n )\n\n r.get(\n '/sends/:id',\n asyncHandler(async (req, res) => {\n const id = String(req.params.id)\n if (!ObjectId.isValid(id)) return res.status(400).json({ error: 'bad_id' })\n const send = await c.sends.findOne({ _id: new ObjectId(id) })\n if (!send) return res.status(404).json({ error: 'not_found' })\n const events = send.providerMessageId\n ? await c.webhookEvents\n .find({ providerMessageId: send.providerMessageId })\n .sort({ receivedAt: -1 })\n .limit(100)\n .toArray()\n : []\n return res.json({ send, webhookEvents: events })\n }),\n )\n\n // ----- Suppressions -------------------------------------------------------\n r.get(\n '/suppressions',\n asyncHandler(async (_req, res) => {\n const rows = await c.suppressions.find().sort({ addedAt: -1 }).limit(500).toArray()\n res.json(rows)\n }),\n )\n\n r.post(\n '/suppressions',\n asyncHandler(async (req, res) => {\n const { email, scope, reason, source, notes } = req.body ?? {}\n await mailer.suppress(email, { scope, reason, source, notes })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'suppression.add',\n resource: { collection: 'mailer_suppressions' },\n diffSummary: `${email} → ${scope}/${reason}`,\n })\n res.json({ ok: true })\n }),\n )\n\n // ----- Audit log ----------------------------------------------------------\n r.get(\n '/audit',\n asyncHandler(async (_req, res) => {\n const rows = await c.auditLog.find().sort({ occurredAt: -1 }).limit(200).toArray()\n res.json(rows)\n }),\n )\n\n // ----- Setup status -------------------------------------------------------\n r.get(\n '/setup-status',\n asyncHandler(async (_req, res) => {\n const status = await runSetupChecks(mailer)\n res.json(status)\n }),\n )\n\n // ----- Health -------------------------------------------------------------\n r.get(\n '/health',\n asyncHandler(async (_req, res) => {\n const cb = mailer.config.circuitBreaker\n const thresholds = {\n hardBounceRatePctTrip: cb.hardBounceRatePctTrip,\n complaintRatePctTrip: cb.complaintRatePctTrip,\n combinedBounceRatePctTrip: cb.combinedBounceRatePctTrip,\n failedToSendRatePctDegrade: cb.failedToSendRatePctDegrade,\n }\n const docs = await c.health.find({}).limit(500).toArray()\n const aggregate = docs.find((d) => d._id === HEALTH_AGG_ID) ?? null\n const buckets = docs.filter((d) => d._id !== HEALTH_AGG_ID)\n const overall = effectiveOverallStatus(docs)\n if (docs.length === 0) {\n // No tick has run yet. UI renders \"—\" / muted dots when status is null.\n res.json({ status: null, rates: null, counters: null, aggregate: null, buckets: [], thresholds })\n return\n }\n // Keep top-level `status` / `rates` for back-compat with consumers that\n // expect a single status (broadcast-new pre-flight, shell pill).\n res.json({\n status: overall,\n rates: aggregate?.rates ?? null,\n counters: aggregate?.counters ?? null,\n aggregate,\n buckets,\n thresholds,\n })\n }),\n )\n\n r.get(\n '/health/trips',\n asyncHandler(async (_req, res) => {\n const rows = await c.auditLog\n .find({ action: { $in: ['health.trip', 'health.resume'] } })\n .sort({ occurredAt: -1 })\n .limit(50)\n .toArray()\n res.json(rows)\n }),\n )\n\n r.post(\n '/health/resume',\n asyncHandler(async (req, res) => {\n const body = (req.body ?? {}) as { senderDomain?: string; kind?: 'marketing' | 'transactional' }\n // Half-specified body (only senderDomain or only kind) is almost\n // certainly an operator error — fail closed rather than silently\n // resume every tripped bucket.\n if ((body.senderDomain != null) !== (body.kind != null)) {\n return res.status(400).json({\n error: 'validation_failed',\n message: 'senderDomain and kind must both be provided to target a single bucket, or both omitted to resume all tripped buckets.',\n })\n }\n if (body.kind && !['marketing', 'transactional'].includes(body.kind)) {\n return res.status(400).json({ error: 'validation_failed', message: 'kind must be \"marketing\" or \"transactional\"' })\n }\n const target = body.senderDomain && body.kind\n ? { _id: healthBucketId(body.senderDomain.toLowerCase(), body.kind) }\n // Explicitly exclude the aggregate doc — it never trips, but guard\n // anyway so a future schema change can't accidentally flip its status.\n : { status: 'tripped' as const, _id: { $ne: HEALTH_AGG_ID } }\n\n const result = await c.health.updateMany(\n target,\n { $set: { status: 'healthy', manuallyResumedAt: new Date(), updatedAt: new Date() } },\n )\n await mailer.audit({\n actor: (req as any).actor,\n action: 'health.resume',\n resource: {\n collection: 'mailer_health',\n id: body.senderDomain && body.kind ? `${body.senderDomain}|${body.kind}` : 'all-tripped',\n },\n })\n res.json({ ok: true, resumed: result.modifiedCount })\n }),\n )\n\n // ----- DNSBL --------------------------------------------------------------\n r.get(\n '/dnsbl',\n asyncHandler(async (_req, res) => {\n const checks = await c.dnsblChecks.find({}).sort({ result: 1, target: 1, list: 1 }).limit(500).toArray()\n const latestRunAt = checks.reduce<Date | null>((acc, d) => {\n const t = new Date(d.runAt)\n return acc && acc.getTime() >= t.getTime() ? acc : t\n }, null)\n res.json({\n checks,\n latestRunAt: latestRunAt ? latestRunAt.toISOString() : null,\n intervalHours: mailer.config.dnsbl?.intervalHours ?? 24,\n })\n }),\n )\n\n r.post(\n '/dnsbl/recheck',\n asyncHandler(async (req, res) => {\n const result = await runDnsblChecks(mailer.getRunnerContext(), { force: true })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'dnsbl.recheck',\n resource: { collection: 'mailer_dnsbl_checks' },\n diffSummary: result.ran\n ? `${result.totalChecks} checks, ${result.listedCount} listed`\n : `not run: ${result.reason}`,\n })\n res.json(result)\n }),\n )\n\n // ----- Postmaster Tools ---------------------------------------------------\n r.get(\n '/postmaster',\n asyncHandler(async (_req, res) => {\n const cfg = mailer.config.postmaster\n const configured = !!cfg?.clientId && !!cfg?.clientSecret && !!cfg?.refreshToken\n const all = await c.postmasterSnapshots.find({}).sort({ domain: 1, date: -1 }).limit(2000).toArray()\n // Group by domain, keep last 30 entries per domain.\n const byDomain = new Map<string, typeof all>()\n for (const s of all) {\n const arr = byDomain.get(s.domain) ?? []\n if (arr.length < 30) arr.push(s)\n byDomain.set(s.domain, arr)\n }\n const domains = Array.from(byDomain.entries()).map(([domain, snapshots]) => ({\n domain,\n latest: snapshots[0] ?? null,\n history: snapshots,\n }))\n res.json({\n configured,\n intervalHours: cfg?.intervalHours ?? 24,\n domains,\n })\n }),\n )\n\n r.post(\n '/postmaster/refresh',\n asyncHandler(async (req, res) => {\n const result = await runPostmasterPull(mailer.getRunnerContext(), { force: true })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'postmaster.refresh',\n resource: { collection: 'mailer_postmaster_snapshots' },\n diffSummary: result.ran\n ? `fetched ${result.fetched ?? 0}, tripped ${(result.trippedDomains ?? []).length}`\n : `not run: ${result.reason}`,\n })\n res.json(result)\n }),\n )\n\n // ----- List Hygiene -------------------------------------------------------\n // The hygiene aggregation iterates every send doc — at scale that's\n // expensive. Cache the result for 60s and serialize concurrent requests\n // so a few rapid-fire dashboard loads can't pile up multiple full scans.\n let hygieneCache: { computedAt: number; report: Awaited<ReturnType<typeof computeListHygiene>> } | null = null\n let hygieneInFlight: Promise<Awaited<ReturnType<typeof computeListHygiene>>> | null = null\n const HYGIENE_CACHE_MS = 60_000\n\n r.get(\n '/hygiene',\n asyncHandler(async (req, res) => {\n const force = req.query.refresh === '1' || req.query.refresh === 'true'\n const now = Date.now()\n if (!force && hygieneCache && now - hygieneCache.computedAt < HYGIENE_CACHE_MS) {\n return res.json(hygieneCache.report)\n }\n if (!hygieneInFlight) {\n hygieneInFlight = (async () => {\n try {\n const report = await computeListHygiene(mailer.getRunnerContext())\n hygieneCache = { computedAt: Date.now(), report }\n return report\n } finally {\n hygieneInFlight = null\n }\n })()\n }\n const report = await hygieneInFlight\n res.json(report)\n }),\n )\n\n // ----- DMARC RUA ingestion ------------------------------------------------\n const dmarcUpload = multer({\n storage: multer.memoryStorage(),\n limits: { fileSize: 10 * 1024 * 1024 }, // 10 MB; reports are typically <100KB\n })\n\n r.post(\n '/dmarc/upload',\n dmarcUpload.single('file'),\n asyncHandler(async (req, res) => {\n const file = (req as any).file as Express.Multer.File | undefined\n if (!file) return res.status(400).json({ error: 'no_file', message: 'expected a \"file\" field' })\n\n try {\n const result = await ingestDmarcAttachment(mailer.getRunnerContext(), file.buffer, file.originalname)\n await mailer.audit({\n actor: (req as any).actor,\n action: 'dmarc.ingest',\n resource: { collection: 'mailer_dmarc_reports', id: result.reportId },\n diffSummary: result.duplicate\n ? `duplicate report ${result.reportId}`\n : `ingested ${result.totalMessages} msgs (${result.passCount} pass / ${result.failCount} fail) for ${result.domain}`,\n })\n return res.json(result)\n } catch (err: any) {\n return res.status(400).json({ error: 'ingest_failed', message: String(err?.message ?? err) })\n }\n }),\n )\n\n r.get(\n '/dmarc',\n asyncHandler(async (_req, res) => {\n const ctx = mailer.getRunnerContext()\n const tagged = await resolveSourceTags(ctx)\n const reports = await c.dmarcReports.find({}).sort({ rangeEnd: -1 }).limit(200).toArray()\n const since30 = new Date(Date.now() - 30 * 86_400_000)\n // Cap at 5k rows — busy domains can easily generate that many failure\n // rows over 30 days. We only consume these for per-domain progression\n // suggestions (untagged-source check); a partial page is fine.\n const recentFailures = await c.dmarcFailures\n .find({ receivedAt: { $gte: since30 } })\n .sort({ receivedAt: -1 })\n .limit(5000)\n .toArray()\n\n const byDomain = new Map<string, { passCount: number; failCount: number; totalMessages: number; reportCount: number; latestRangeEnd: Date | null; latestPolicy: 'none' | 'quarantine' | 'reject' | null; latestPct: number | null; reports: typeof reports }>()\n for (const r of reports) {\n const cur = byDomain.get(r.domain) ?? { passCount: 0, failCount: 0, totalMessages: 0, reportCount: 0, latestRangeEnd: null, latestPolicy: null, latestPct: null, reports: [] }\n cur.passCount += r.passCount\n cur.failCount += r.failCount\n cur.totalMessages += r.totalMessages\n cur.reportCount += 1\n const re = new Date(r.rangeEnd)\n if (!cur.latestRangeEnd || re > cur.latestRangeEnd) {\n cur.latestRangeEnd = re\n cur.latestPolicy = r.policyP\n cur.latestPct = r.policyPct\n }\n cur.reports.push(r)\n byDomain.set(r.domain, cur)\n }\n\n // Build per-day alignment series (last 14 days) per domain for sparklines.\n const since14 = Date.now() - 14 * 86_400_000\n\n const domains = Array.from(byDomain.entries()).map(([domain, s]) => {\n // Sparkline series — pass rate per day from recent reports.\n const dayTotals = new Map<string, { pass: number; total: number }>()\n for (const r of s.reports) {\n if (new Date(r.rangeEnd).getTime() < since14) continue\n const day = new Date(r.rangeEnd).toISOString().slice(0, 10)\n const d = dayTotals.get(day) ?? { pass: 0, total: 0 }\n d.pass += r.passCount\n d.total += r.passCount + r.failCount\n dayTotals.set(day, d)\n }\n const series = Array.from(dayTotals.entries())\n .sort((a, b) => a[0].localeCompare(b[0]))\n .map(([day, d]) => ({ day, alignmentRate: d.total === 0 ? null : d.pass / d.total }))\n\n // Policy progression suggestion.\n const knownIps = new Set(Array.from(tagged.values()).filter((t) => !t.ignored).map((t) => t.ip))\n const ignoredIps = new Set(Array.from(tagged.values()).filter((t) => t.ignored).map((t) => t.ip))\n const suggested = suggestPolicyProgression({\n reports: s.reports.map((r) => ({ rangeEnd: new Date(r.rangeEnd), passCount: r.passCount, failCount: r.failCount })),\n failures: recentFailures.filter((f) => f.domain === domain).map((f) => ({ sourceIp: f.sourceIp, count: f.count, receivedAt: new Date(f.receivedAt) })),\n knownSourceIps: knownIps,\n ignoredSourceIps: ignoredIps,\n currentPolicy: s.latestPolicy,\n currentPct: s.latestPct,\n })\n\n return {\n domain,\n passCount: s.passCount,\n failCount: s.failCount,\n totalMessages: s.totalMessages,\n reportCount: s.reportCount,\n latestRangeEnd: s.latestRangeEnd,\n alignmentRate: s.totalMessages === 0 ? null : s.passCount / s.totalMessages,\n currentPolicy: s.latestPolicy,\n currentPct: s.latestPct,\n progression: suggested\n ? { ...suggested, current: { policy: s.latestPolicy, pct: s.latestPct } }\n : null,\n series,\n }\n })\n\n const topFailures = await c.dmarcFailures\n .aggregate<{ _id: { sourceIp: string; domain: string }; total: number; days: number; lastSeen: Date; sample: any }>([\n { $match: { receivedAt: { $gte: since30 } } },\n {\n $group: {\n _id: { sourceIp: '$sourceIp', domain: '$domain' },\n total: { $sum: '$count' },\n days: { $addToSet: '$day' },\n lastSeen: { $max: '$receivedAt' },\n sample: { $first: '$$ROOT' },\n },\n },\n { $project: { sourceIp: '$_id.sourceIp', domain: '$_id.domain', total: 1, days: { $size: '$days' }, lastSeen: 1, sample: 1 } },\n { $sort: { total: -1 } },\n { $limit: 50 },\n ])\n .toArray()\n\n const sources = topFailures.map((f) => {\n const tag = tagged.get(f._id.sourceIp)\n return {\n sourceIp: f._id.sourceIp,\n domain: f._id.domain,\n totalMessages: f.total,\n daysSeen: f.days,\n lastSeen: f.lastSeen,\n dkimResult: f.sample.dkimResult,\n spfResult: f.sample.spfResult,\n dispositionApplied: f.sample.dispositionApplied,\n label: tag?.label ?? null,\n ignored: !!tag?.ignored,\n tagSource: tag?.source ?? null,\n }\n })\n\n res.json({\n domains,\n sources,\n recentReports: reports.slice(0, 30),\n retentionDays: mailer.config.dmarc?.retentionDays ?? 90,\n })\n }),\n )\n\n // ----- DMARC source tags (mutable from UI) --------------------------------\n r.put(\n '/dmarc/sources/:ip',\n asyncHandler(async (req, res) => {\n const ip = String(req.params.ip ?? '')\n if (!net.isIP(ip)) {\n return res.status(400).json({ error: 'validation_failed', message: 'invalid IP' })\n }\n const body = (req.body ?? {}) as { label?: string; ignored?: boolean }\n if (!body.label || typeof body.label !== 'string') {\n return res.status(400).json({ error: 'validation_failed', message: 'label is required' })\n }\n const label = body.label.trim().slice(0, 200)\n if (!label) {\n return res.status(400).json({ error: 'validation_failed', message: 'label is required' })\n }\n const ignored = !!body.ignored\n await c.dmarcSourceTags.updateOne(\n { ip },\n { $set: { ip, label, ignored, setBy: (req as any).actor ?? 'unknown', setAt: new Date() } },\n { upsert: true },\n )\n await mailer.audit({\n actor: (req as any).actor,\n action: 'dmarc.source_tag.upsert',\n resource: { collection: 'mailer_dmarc_source_tags', id: ip },\n diffSummary: `${ip} → \"${label}\"${ignored ? ' (ignored)' : ''}`,\n })\n res.json({ ok: true })\n }),\n )\n\n r.delete(\n '/dmarc/sources/:ip',\n asyncHandler(async (req, res) => {\n const ip = String(req.params.ip ?? '')\n if (!net.isIP(ip)) {\n return res.status(400).json({ error: 'validation_failed', message: 'invalid IP' })\n }\n const result = await c.dmarcSourceTags.deleteOne({ ip })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'dmarc.source_tag.delete',\n resource: { collection: 'mailer_dmarc_source_tags', id: ip },\n })\n res.json({ ok: true, deleted: result.deletedCount })\n }),\n )\n\n // ----- Microsoft SNDS -----------------------------------------------------\n r.get(\n '/snds',\n asyncHandler(async (_req, res) => {\n const cfg = mailer.config.snds\n const configured = !!cfg?.accessKey\n const all = await c.sndsSnapshots.find({}).sort({ ip: 1, activityStart: -1 }).limit(2000).toArray()\n const byIp = new Map<string, typeof all>()\n for (const s of all) {\n const arr = byIp.get(s.ip) ?? []\n if (arr.length < 30) arr.push(s)\n byIp.set(s.ip, arr)\n }\n const ips = Array.from(byIp.entries()).map(([ip, snapshots]) => ({\n ip,\n latest: snapshots[0] ?? null,\n history: snapshots,\n }))\n res.json({\n configured,\n intervalHours: cfg?.intervalHours ?? 24,\n ips,\n })\n }),\n )\n\n r.post(\n '/snds/refresh',\n asyncHandler(async (req, res) => {\n const result = await runSndsPull(mailer.getRunnerContext(), { force: true })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'snds.refresh',\n resource: { collection: 'mailer_snds_snapshots' },\n diffSummary: result.ran\n ? `parsed ${result.rowsParsed ?? 0}, persisted ${result.rowsPersisted ?? 0}`\n : `not run: ${result.reason}`,\n })\n res.json(result)\n }),\n )\n\n // ----- Flows: create / edit / publish ------------------------------------\n r.post(\n '/flows',\n asyncHandler(async (req, res) => {\n const { slug, name, description, trigger, goal, audience } = req.body ?? {}\n if (!slug || !name || !trigger?.eventName) {\n return res.status(400).json({ error: 'validation_failed', message: 'slug, name, and trigger.eventName required' })\n }\n const now = new Date()\n const doc = {\n slug,\n name,\n description: description ?? '',\n trigger: { type: 'event' as const, eventName: trigger.eventName, once: trigger.once !== false },\n enabled: false,\n steps: [],\n version: 0,\n draft: {\n steps: [],\n notes: 'Initial draft',\n lastModifiedBy: (req as any).actor ?? 'unknown',\n lastModifiedAt: now,\n },\n goal: goal ?? 'activation',\n audience: audience ?? '',\n expectedVolumePerWeek: null,\n stats: { activeRuns: 0, completedRuns: 0, sendsTotal: 0, sendsLast7Days: 0 },\n lastTriggerScanAt: null,\n publishedAt: null,\n publishedBy: null,\n createdAt: now,\n updatedAt: now,\n }\n try {\n await c.flows.insertOne(doc as any)\n } catch (err: any) {\n if (err?.code === 11000) return res.status(409).json({ error: 'slug_taken' })\n throw err\n }\n await mailer.audit({\n actor: (req as any).actor,\n action: 'flow.create',\n resource: { collection: 'mailer_flows', slug },\n })\n return res.json({ ok: true, slug })\n }),\n )\n\n r.patch(\n '/flows/:slug/draft',\n asyncHandler(async (req, res) => {\n const flow = await c.flows.findOne({ slug: req.params.slug })\n if (!flow) return res.status(404).json({ error: 'not_found' })\n const { steps, notes, trigger, name, description, goal, audience } = req.body ?? {}\n\n const set: Record<string, unknown> = {\n 'draft.lastModifiedBy': (req as any).actor,\n 'draft.lastModifiedAt': new Date(),\n updatedAt: new Date(),\n }\n if (Array.isArray(steps)) set['draft.steps'] = steps\n if (typeof notes === 'string') set['draft.notes'] = notes\n if (trigger?.eventName) set.trigger = { type: 'event' as const, eventName: trigger.eventName, once: trigger.once !== false }\n if (typeof name === 'string') set.name = name\n if (typeof description === 'string') set.description = description\n if (typeof goal === 'string') set.goal = goal\n if (typeof audience === 'string') set.audience = audience\n\n await c.flows.updateOne({ _id: flow._id }, { $set: set })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'flow.draft.update',\n resource: { collection: 'mailer_flows', id: flow._id, slug: flow.slug },\n diffSummary: `Updated draft (${steps ? `${steps.length} steps` : 'metadata only'})`,\n })\n return res.json({ ok: true })\n }),\n )\n\n r.post(\n '/flows/:slug/publish',\n asyncHandler(async (req, res) => {\n const flow = await c.flows.findOne({ slug: req.params.slug })\n if (!flow) return res.status(404).json({ error: 'not_found' })\n const draftSteps = flow.draft?.steps ?? flow.steps\n if (!Array.isArray(draftSteps) || draftSteps.length === 0) {\n return res.status(400).json({ error: 'empty_flow', message: 'flow has no steps to publish' })\n }\n // `enable: false` publishes without turning the flow on — the human\n // decision to enable stays separate from the mechanical one to promote\n // a draft. Default true for compatibility with the SPA's Publish button.\n const enable = req.body?.enable !== false\n const nextVersion = (flow.version ?? 0) + 1\n const now = new Date()\n await c.flowVersions.insertOne({\n flowId: flow._id!,\n version: nextVersion,\n steps: draftSteps,\n trigger: flow.trigger,\n publishedAt: now,\n publishedBy: (req as any).actor,\n })\n await c.flows.updateOne(\n { _id: flow._id },\n {\n $set: {\n steps: draftSteps,\n version: nextVersion,\n enabled: enable ? true : flow.enabled,\n draft: null,\n publishedAt: now,\n publishedBy: (req as any).actor,\n updatedAt: now,\n // First enable: stamp the trigger watermark so the scan does not\n // replay every event since the flow document was created.\n ...(enable && !flow.lastTriggerScanAt ? { lastTriggerScanAt: now } : {}),\n },\n },\n )\n await mailer.audit({\n actor: (req as any).actor,\n action: 'flow.publish',\n resource: { collection: 'mailer_flows', id: flow._id, slug: flow.slug },\n diffSummary: `Published v${nextVersion}${enable ? '' : ' (left disabled)'}`,\n })\n return res.json({ ok: true, version: nextVersion, enabled: enable ? true : flow.enabled })\n }),\n )\n\n r.delete(\n '/flows/:slug',\n asyncHandler(async (req, res) => {\n const flow = await c.flows.findOne({ slug: req.params.slug })\n if (!flow) return res.status(404).json({ error: 'not_found' })\n const everRan = await c.flowRuns.countDocuments({ flowId: flow._id }, { limit: 1 })\n if (everRan > 0) return res.status(409).json({ error: 'has_runs', message: 'flow has runs — pause it instead' })\n await c.flows.deleteOne({ _id: flow._id })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'flow.delete',\n resource: { collection: 'mailer_flows', id: flow._id, slug: flow.slug },\n })\n return res.json({ ok: true })\n }),\n )\n\n // ----- Templates: create / edit / publish --------------------------------\n r.post(\n '/templates',\n asyncHandler(async (req, res) => {\n const { slug, name, kind, subject, preheader, fromName, fromEmail } = req.body ?? {}\n if (!slug || !name || !kind) {\n return res.status(400).json({ error: 'validation_failed', message: 'slug, name, kind required' })\n }\n if (kind !== 'marketing' && kind !== 'transactional') {\n return res.status(400).json({ error: 'validation_failed', message: 'kind must be marketing or transactional' })\n }\n const resolvedFromEmail =\n fromEmail ??\n (kind === 'transactional' ? mailer.config.transactionalFromDefaults?.email : undefined) ??\n mailer.config.fromDefaults?.email ??\n 'noreply@example.com'\n const senderCheck = validateSenderDomain(resolvedFromEmail, kind, mailer.config.senderDomains)\n if (!senderCheck.ok) {\n return res.status(400).json({\n error: 'sender_domain_invalid',\n code: senderCheck.code,\n message: senderCheck.reason,\n })\n }\n const now = new Date()\n try {\n await c.templates.insertOne({\n slug,\n name,\n description: '',\n kind,\n fromName:\n fromName ??\n (kind === 'transactional' ? mailer.config.transactionalFromDefaults?.name : undefined) ??\n mailer.config.fromDefaults?.name ??\n 'Mailery',\n fromEmail: resolvedFromEmail,\n replyTo: null,\n providerOverride: null,\n subject: subject ?? `Untitled — ${name}`,\n preheader: preheader ?? '',\n body: { mjml: '', editorJson: null, html: '', plainText: '', compiledAt: null },\n variablesSchema: {},\n draft: {\n subject: subject ?? `Untitled — ${name}`,\n preheader: preheader ?? '',\n mjml: '',\n editorJson: null,\n notes: 'Initial draft',\n lastModifiedBy: (req as any).actor,\n lastModifiedAt: now,\n },\n tags: [],\n bodyFormat: 'multipart',\n trackOpens: kind === 'marketing',\n trackClicks: kind === 'marketing',\n stats: { sent: 0, delivered: 0, opened: 0, clicked: 0, bounced: 0, complained: 0, unsubscribed: 0, lastSentAt: null },\n publishedAt: null,\n publishedBy: null,\n createdAt: now,\n updatedAt: now,\n } as any)\n } catch (err: any) {\n if (err?.code === 11000) return res.status(409).json({ error: 'slug_taken' })\n throw err\n }\n await mailer.audit({\n actor: (req as any).actor,\n action: 'template.create',\n resource: { collection: 'mailer_templates', slug },\n })\n return res.json({ ok: true, slug })\n }),\n )\n\n r.patch(\n '/templates/:slug/draft',\n asyncHandler(async (req, res) => {\n const tpl = await c.templates.findOne({ slug: req.params.slug })\n if (!tpl) return res.status(404).json({ error: 'not_found' })\n\n const { subject, preheader, mjml, editorJson, notes, name, fromName, fromEmail, replyTo, kind, bodyFormat, trackOpens, trackClicks } = req.body ?? {}\n\n const set: Record<string, unknown> = {\n 'draft.lastModifiedBy': (req as any).actor,\n 'draft.lastModifiedAt': new Date(),\n updatedAt: new Date(),\n }\n if (typeof subject === 'string') set['draft.subject'] = subject\n if (typeof preheader === 'string') set['draft.preheader'] = preheader\n if (typeof mjml === 'string') set['draft.mjml'] = mjml\n if (editorJson !== undefined) set['draft.editorJson'] = editorJson\n if (typeof notes === 'string') set['draft.notes'] = notes\n if (typeof name === 'string') set.name = name\n if (typeof fromName === 'string') set.fromName = fromName\n if (typeof fromEmail === 'string') set.fromEmail = fromEmail\n if (typeof replyTo === 'string' || replyTo === null) set.replyTo = replyTo\n if (kind === 'marketing' || kind === 'transactional') set.kind = kind\n\n // Validate resulting (kind, fromEmail) against the senderDomains registry\n // whenever either field is being touched.\n if (typeof fromEmail === 'string' || kind === 'marketing' || kind === 'transactional') {\n const resultingKind = (set.kind as typeof tpl.kind) ?? tpl.kind\n const resultingFromEmail = (set.fromEmail as string) ?? tpl.fromEmail\n const senderCheck = validateSenderDomain(resultingFromEmail, resultingKind, mailer.config.senderDomains)\n if (!senderCheck.ok) {\n return res.status(400).json({\n error: 'sender_domain_invalid',\n code: senderCheck.code,\n message: senderCheck.reason,\n })\n }\n }\n if (TEMPLATE_BODY_FORMATS.includes(bodyFormat)) set.bodyFormat = bodyFormat\n if (typeof trackOpens === 'boolean') set.trackOpens = trackOpens\n if (typeof trackClicks === 'boolean') set.trackClicks = trackClicks\n\n await c.templates.updateOne({ _id: tpl._id }, { $set: set })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'template.draft.update',\n resource: { collection: 'mailer_templates', id: tpl._id, slug: tpl.slug },\n })\n return res.json({ ok: true })\n }),\n )\n\n // ----- Mail-Tester deliverability check ----------------------------------\n r.get(\n '/templates/:slug/mail-tester',\n asyncHandler(async (req, res) => {\n const cfg = mailer.config.mailTester\n const configured = !!cfg?.apiKey\n const tpl = await c.templates.findOne({ slug: req.params.slug })\n if (!tpl) return res.status(404).json({ error: 'not_found' })\n\n // Cache key must reflect the same fingerprint the check + publish gate\n // use — render the *current* draft if there is one, otherwise the\n // most recent published body. Previously this mixed draft.subject\n // with published body.html, which always missed pre-first-publish\n // and drifted whenever a subject edit followed a publish.\n let bodyHash = ''\n let subject = tpl.subject ?? ''\n if (tpl.draft) {\n try {\n const compiled = tpl.draft.editorJson\n ? await compileMailyTemplate(tpl.draft.editorJson)\n : tpl.draft.mjml\n ? await compileTemplate(tpl.draft.mjml)\n : null\n if (compiled) {\n bodyHash = sha256Hex(compiled.html)\n subject = tpl.draft.subject || subject\n }\n } catch {\n // If the draft no longer compiles, fall back to the published body.\n }\n }\n if (!bodyHash && tpl.body?.html) {\n bodyHash = sha256Hex(tpl.body.html)\n }\n const key = bodyHash ? mailTesterContentKey({ bodyHash, subject, fromEmail: tpl.fromEmail }) : null\n const cached = key ? await findCachedScore(mailer.getRunnerContext(), key) : null\n\n res.json({\n configured,\n minScore: cfg?.minScore ?? 8.0,\n requireScore: !!cfg?.requireScore,\n cacheHours: cfg?.cacheHours ?? 24,\n score: cached,\n })\n }),\n )\n\n r.post(\n '/templates/:slug/mail-tester-check',\n asyncHandler(async (req, res) => {\n const client = getMailTesterClient()\n if (!client) {\n return res.status(400).json({\n error: 'not_configured',\n message: 'Mail-Tester is not configured. Set mailer.config.mailTester.apiKey to enable.',\n })\n }\n\n const tpl = await c.templates.findOne({ slug: req.params.slug })\n if (!tpl) return res.status(404).json({ error: 'not_found' })\n const draft = tpl.draft\n if (!draft) return res.status(400).json({ error: 'no_draft', message: 'Save a draft before running a deliverability check.' })\n\n let compiled: { html: string; plainText: string }\n try {\n if (draft.editorJson) compiled = await compileMailyTemplate(draft.editorJson)\n else if (draft.mjml) compiled = await compileTemplate(draft.mjml)\n else return res.status(400).json({ error: 'empty_draft' })\n } catch (err: any) {\n return res.status(400).json({ error: 'compile_failed', message: String(err?.message ?? err) })\n }\n\n const bodyHash = sha256Hex(compiled.html)\n const contentKey = mailTesterContentKey({ bodyHash, subject: draft.subject, fromEmail: tpl.fromEmail })\n const ctx = mailer.getRunnerContext()\n\n // Cache hit — return without burning a credit.\n const cached = await findCachedScore(ctx, contentKey)\n if (cached) {\n return res.json({ cached: true, status: 'ready', score: cached })\n }\n\n // Resolve the provider *before* provisioning: provisionCheck burns a\n // Mail-Tester credit, and a template pointing at a provider that isn't\n // registered can never get past the send below.\n const provider = resolveProvider(mailer.providers, tpl.providerOverride ?? mailer.config.defaultProvider)\n if (!provider) {\n return res.status(400).json(unknownProviderError(mailer, tpl))\n }\n\n // Provision a new test address and send the rendered draft to it.\n const { checkId, emailAddress } = await client.provisionCheck()\n\n try {\n await provider.send({\n to: emailAddress,\n fromName: tpl.fromName,\n fromEmail: tpl.fromEmail,\n replyTo: tpl.replyTo ?? undefined,\n subject: draft.subject,\n // Match the real send shape — a text_only template's deliverability\n // should be scored on the single-part message it actually sends.\n ...(tpl.bodyFormat === 'text_only' ? {} : { html: compiled.html }),\n text: compiled.plainText,\n headers: {},\n messageMeta: { mailTesterCheckId: checkId },\n })\n } catch (err: any) {\n return res.status(502).json({ error: 'send_failed', message: String(err?.message ?? err) })\n }\n\n await mailer.audit({\n actor: (req as any).actor,\n action: 'mail_tester.check.start',\n resource: { collection: 'mailer_mail_tester_scores', id: contentKey, slug: tpl.slug },\n diffSummary: `Sent draft to ${emailAddress} for Mail-Tester check ${checkId}`,\n })\n\n res.json({\n cached: false,\n status: 'pending',\n checkId,\n contentKey,\n message: 'Test email sent. Poll /mail-tester-result?checkId=...&contentKey=... for the score.',\n })\n }),\n )\n\n r.get(\n '/templates/:slug/mail-tester-result',\n asyncHandler(async (req, res) => {\n const client = getMailTesterClient()\n if (!client) return res.status(400).json({ error: 'not_configured' })\n\n const checkId = String(req.query.checkId ?? '')\n if (!checkId) return res.status(400).json({ error: 'validation_failed', message: 'checkId is required' })\n\n const tpl = await c.templates.findOne({ slug: req.params.slug })\n if (!tpl) return res.status(404).json({ error: 'not_found' })\n const draft = tpl.draft\n if (!draft) return res.status(400).json({ error: 'no_draft', message: 'Draft no longer exists.' })\n\n // Re-derive the content key server-side from the current draft so an\n // attacker can't land a score under an arbitrary fingerprint and game\n // the publish gate. We must recompile to recompute bodyHash.\n let compiled: { html: string; plainText: string }\n try {\n if (draft.editorJson) compiled = await compileMailyTemplate(draft.editorJson)\n else if (draft.mjml) compiled = await compileTemplate(draft.mjml)\n else return res.status(400).json({ error: 'empty_draft' })\n } catch (err: any) {\n return res.status(400).json({ error: 'compile_failed', message: String(err?.message ?? err) })\n }\n const contentKey = mailTesterContentKey({\n bodyHash: sha256Hex(compiled.html),\n subject: draft.subject,\n fromEmail: tpl.fromEmail,\n })\n\n const result = await client.fetchResult(checkId)\n if (!result.ready) {\n return res.json({ status: 'pending', score: null })\n }\n\n const ctx = mailer.getRunnerContext()\n const persisted = await persistScore(ctx, { templateSlug: tpl.slug, contentKey, checkId, result })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'mail_tester.check.complete',\n resource: { collection: 'mailer_mail_tester_scores', id: contentKey, slug: tpl.slug },\n diffSummary: `Score ${result.score.toFixed(1)}`,\n })\n res.json({ status: 'ready', score: persisted })\n }),\n )\n\n r.post(\n '/templates/:slug/lint',\n asyncHandler(async (req, res) => {\n const tpl = await c.templates.findOne({ slug: req.params.slug })\n if (!tpl) return res.status(404).json({ error: 'not_found' })\n\n // Lint against the supplied draft if present, otherwise the saved draft,\n // otherwise the last-published body. Keep this tolerant so the editor\n // can call it without juggling round-trips.\n const body = (req.body ?? {}) as {\n subject?: string\n preheader?: string\n mjml?: string\n editorJson?: Record<string, unknown> | null\n fromEmail?: string\n kind?: 'marketing' | 'transactional'\n }\n\n const subject = body.subject ?? tpl.draft?.subject ?? tpl.subject ?? ''\n const preheader = body.preheader ?? tpl.draft?.preheader ?? tpl.preheader ?? ''\n const mjml = body.mjml ?? tpl.draft?.mjml ?? tpl.body?.mjml ?? ''\n const editorJson = body.editorJson !== undefined ? body.editorJson : (tpl.draft?.editorJson ?? tpl.body?.editorJson ?? null)\n const fromEmail = body.fromEmail ?? tpl.fromEmail\n // Whitelist kind — otherwise body.kind:'foo' bypasses the marketing-\n // only missing_unsubscribe_tag check by hitting neither branch.\n const kind = body.kind === 'marketing' || body.kind === 'transactional' ? body.kind : tpl.kind\n\n let html = ''\n let plainText = ''\n try {\n if (editorJson) {\n const compiled = await compileMailyTemplate(editorJson)\n html = compiled.html\n plainText = compiled.plainText\n } else if (mjml) {\n const compiled = await compileTemplate(mjml)\n html = compiled.html\n plainText = compiled.plainText\n }\n } catch (err: any) {\n return res.status(200).json({\n errors: [{ rule: 'compile_failed', severity: 'error', message: `Compile error: ${String(err?.message ?? err)}` }],\n warnings: [],\n infos: [],\n compileFailed: true,\n })\n }\n\n // Script-seeded templates can have no draft source at all (body.html +\n // body.plainText inserted directly, editorJson/mjml empty). Fall back to\n // the stored body so lint judges what actually sends instead of\n // reporting an empty template.\n if (!html && typeof tpl.body?.html === 'string') html = tpl.body.html\n if (!plainText && typeof tpl.body?.plainText === 'string') plainText = tpl.body.plainText\n\n const lint = lintTemplate(\n { subject, preheader, mjml, editorJson, html, plainText, kind, fromEmail },\n { senderDomains: mailer.config.senderDomains, varsJsonSchema: varsSchema },\n )\n res.json({ ...lint, compileFailed: false })\n }),\n )\n\n r.post(\n '/templates/:slug/publish',\n asyncHandler(async (req, res) => {\n const tpl = await c.templates.findOne({ slug: req.params.slug })\n if (!tpl) return res.status(404).json({ error: 'not_found' })\n const draft = tpl.draft\n if (!draft) return res.status(400).json({ error: 'no_draft' })\n\n // Short-circuit sender-domain check — preserves the pre-linter 400\n // sender_domain_invalid contract so external callers (and the SPA's\n // own publish modal) can key on it without conflating with lint errors.\n const senderCheck = validateSenderDomain(tpl.fromEmail, tpl.kind, mailer.config.senderDomains)\n if (!senderCheck.ok) {\n return res.status(400).json({\n error: 'sender_domain_invalid',\n code: senderCheck.code,\n message: senderCheck.reason,\n })\n }\n\n let compiled: { html: string; plainText: string; errors: any[] }\n try {\n if (draft.editorJson) {\n compiled = await compileMailyTemplate(draft.editorJson)\n } else if (draft.mjml) {\n compiled = await compileTemplate(draft.mjml)\n } else {\n return res.status(400).json({ error: 'empty_draft', message: 'draft has no MJML or editorJson content' })\n }\n } catch (err: any) {\n // Same shape as the lint endpoint's compileFailed branch so the UI\n // can surface compile errors uniformly with lint errors.\n return res.status(422).json({\n error: 'compile_failed',\n message: String(err?.message ?? err),\n lint: {\n errors: [{ rule: 'compile_failed', severity: 'error', message: `Compile error: ${String(err?.message ?? err)}` }],\n warnings: [],\n infos: [],\n },\n })\n }\n\n const lint = lintTemplate(\n {\n subject: draft.subject,\n preheader: draft.preheader,\n mjml: draft.mjml ?? '',\n editorJson: draft.editorJson,\n html: compiled.html,\n plainText: compiled.plainText,\n kind: tpl.kind,\n fromEmail: tpl.fromEmail,\n },\n { senderDomains: mailer.config.senderDomains, varsJsonSchema: varsSchema },\n )\n\n if (lint.errors.length > 0) {\n return res.status(422).json({\n error: 'lint_failed',\n message: `Template publish blocked by ${lint.errors.length} content issue(s).`,\n lint,\n })\n }\n\n // Mail-Tester gate. Blocks when a cached score for this exact content is\n // below minScore, and — when `requireScore` is configured — when no score\n // for this content exists at all. Operator can override either with\n // `bypassMailTester: true` in the request body.\n const bypass = Boolean(req.body?.bypassMailTester)\n if (!bypass) {\n const gate = await evaluateMailTesterGate(mailer.getRunnerContext(), {\n bodyHash: sha256Hex(compiled.html),\n subject: draft.subject,\n fromEmail: tpl.fromEmail,\n })\n if (!gate.allowed) {\n return res.status(422).json({\n error: 'mail_tester_blocked',\n code: gate.code,\n message: gate.reason,\n score: gate.score,\n hint:\n gate.code === 'no_score'\n ? 'POST to `/templates/:slug/mail-tester-check`, poll `/mail-tester-result`, then publish — or POST `bypassMailTester: true` to publish anyway.'\n : 'Re-run the deliverability check after fixing the feedback, or POST `bypassMailTester: true` to publish anyway.',\n })\n }\n }\n\n const now = new Date()\n const nextVersion = await c.templateVersions.countDocuments({ templateId: tpl._id }) + 1\n await c.templateVersions.insertOne({\n templateId: tpl._id!,\n version: nextVersion,\n mjml: draft.mjml,\n html: compiled.html,\n plainText: compiled.plainText,\n subject: draft.subject,\n preheader: draft.preheader,\n publishedAt: now,\n publishedBy: (req as any).actor,\n })\n\n await c.templates.updateOne(\n { _id: tpl._id },\n {\n $set: {\n subject: draft.subject,\n preheader: draft.preheader,\n body: {\n mjml: draft.mjml,\n editorJson: draft.editorJson,\n html: compiled.html,\n plainText: compiled.plainText,\n compiledAt: now,\n },\n draft: null,\n publishedAt: now,\n publishedBy: (req as any).actor,\n updatedAt: now,\n },\n },\n )\n await mailer.audit({\n actor: (req as any).actor,\n action: 'template.publish',\n resource: { collection: 'mailer_templates', id: tpl._id, slug: tpl.slug },\n diffSummary: `Published v${nextVersion}`,\n })\n return res.json({\n ok: true,\n version: nextVersion,\n warnings: compiled.errors,\n lint, // warnings + infos for UI\n })\n }),\n )\n\n r.post(\n '/templates/:slug/preview',\n asyncHandler(async (req, res) => {\n const tpl = await c.templates.findOne({ slug: req.params.slug })\n if (!tpl) return res.status(404).json({ error: 'not_found' })\n\n const useDraft = req.body?.useDraft !== false\n let html = ''\n let plainText = ''\n if (useDraft && tpl.draft) {\n const compiled = tpl.draft.editorJson\n ? await compileMailyTemplate(tpl.draft.editorJson)\n : await compileTemplate(tpl.draft.mjml || '<mjml><mj-body></mj-body></mjml>')\n html = compiled.html\n plainText = compiled.plainText\n } else {\n if (!tpl.body?.html) {\n return res.status(409).json({ error: 'not_published', message: 'Template has not been published yet.' })\n }\n html = tpl.body.html\n plainText = tpl.body.plainText\n }\n\n // Preview as a real contact when contactId is given — pulls the actual\n // contact through the adapter and runs the host's varsAdapter, so the\n // preview shows exactly what that person would receive.\n let contact: Contact\n const contactId = typeof req.body?.contactId === 'string' ? req.body.contactId : null\n if (contactId) {\n const found = await mailer.adapter.getById(contactId)\n if (!found) return res.status(404).json({ error: 'contact_not_found', contactId })\n contact = found\n } else {\n contact = req.body?.sampleContact ?? {\n externalId: 'preview-contact',\n email: 'preview@example.com',\n tags: [],\n fields: { firstName: 'Alex' },\n }\n }\n\n // Optional simulated trigger-event properties, so account/topic-scoped\n // templates ({{event.*}} or resolver branching) preview realistically.\n const eventProperties =\n req.body?.eventProperties && typeof req.body.eventProperties === 'object'\n ? (req.body.eventProperties as Record<string, unknown>)\n : undefined\n\n let resolved: Record<string, unknown> = {}\n try {\n resolved = await resolveVars(mailer.config.varsAdapter, contact, {\n reason: 'preview',\n templateSlug: tpl.slug,\n eventProperties,\n })\n } catch (err: any) {\n return res.status(502).json({\n error: 'vars_resolve_failed',\n message: `varsAdapter.resolve threw: ${String(err?.message ?? err)}`,\n })\n }\n\n const renderCtx = {\n ...resolved,\n contact,\n vars: req.body?.vars ?? {},\n event: eventProperties ?? {},\n unsubscribeUrl: `${mailer.config.publicUrl}/m/unsub/preview`,\n senderAddress: mailer.config.senderAddress,\n }\n\n const previewTpl = { ...tpl, body: { ...tpl.body, html, plainText } }\n const rendered = await renderTemplate(previewTpl as any, renderCtx, { helpers: mailer.config.handlebarsHelpers })\n return res.json({\n subject: rendered.subject,\n preheader: rendered.preheader,\n html: rendered.html,\n plainText: rendered.plainText,\n contact: { externalId: contact.externalId, email: contact.email },\n })\n }),\n )\n\n r.post(\n '/templates/:slug/send-test',\n asyncHandler(async (req, res) => {\n const { to, sampleData, contactId, eventProperties } = req.body ?? {}\n if (!to) return res.status(400).json({ error: 'to_required' })\n const tpl = await c.templates.findOne({ slug: req.params.slug })\n if (!tpl) return res.status(404).json({ error: 'not_found' })\n\n // Render as a real contact when contactId is given (vars included),\n // but always deliver to the operator-typed address.\n let contact: Contact\n if (typeof contactId === 'string' && contactId) {\n const found = await mailer.adapter.getById(contactId)\n if (!found) return res.status(404).json({ error: 'contact_not_found', contactId })\n contact = { ...found, email: to }\n } else {\n contact = sampleData?.contact ?? {\n externalId: 'test-recipient',\n email: to,\n tags: [],\n fields: { firstName: 'Test' },\n }\n contact.email = to\n }\n\n const evProps =\n eventProperties && typeof eventProperties === 'object'\n ? (eventProperties as Record<string, unknown>)\n : undefined\n\n let resolved: Record<string, unknown> = {}\n try {\n resolved = await resolveVars(mailer.config.varsAdapter, contact, {\n reason: 'test',\n templateSlug: tpl.slug,\n eventProperties: evProps,\n })\n } catch (err: any) {\n return res.status(502).json({\n error: 'vars_resolve_failed',\n message: `varsAdapter.resolve threw: ${String(err?.message ?? err)}`,\n })\n }\n\n const renderCtx = {\n ...resolved,\n contact,\n vars: sampleData?.vars ?? {},\n event: evProps ?? {},\n unsubscribeUrl: `${mailer.config.publicUrl}/m/unsub/test`,\n senderAddress: mailer.config.senderAddress,\n }\n const rendered = await renderTemplate(tpl as any, renderCtx, { helpers: mailer.config.handlebarsHelpers })\n const tracking = applyTracking(rendered.html, {\n sendId: `test-${Date.now()}`,\n publicUrl: mailer.config.publicUrl,\n trackOpens: false,\n trackClicks: false,\n })\n\n const provider = resolveProvider(mailer.providers, tpl.providerOverride ?? mailer.config.defaultProvider)\n if (!provider) {\n return res.status(400).json(unknownProviderError(mailer, tpl))\n }\n const result = await provider.send({\n to,\n fromName: rendered.fromName,\n fromEmail: rendered.fromEmail,\n subject: `[TEST] ${rendered.subject}`,\n // Match the real send shape, or a test of a text_only template would\n // arrive as HTML and hide exactly what the author is checking.\n ...(tpl.bodyFormat === 'text_only' ? {} : { html: tracking.html }),\n text: rendered.plainText,\n })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'template.send-test',\n resource: { collection: 'mailer_templates', slug: tpl.slug },\n diffSummary: `to=${to}`,\n })\n // Avoid unused — sign helper is exposed for future preview routes.\n void signUnsubscribeToken\n return res.json({ ok: true, providerId: result.providerId })\n }),\n )\n\n // ----- Broadcasts: create / patch / schedule / cancel --------------------\n r.post(\n '/broadcasts',\n asyncHandler(async (req, res) => {\n const { slug, name, templateSlug, segmentDefinition } = req.body ?? {}\n if (!slug || !name || !templateSlug) {\n return res.status(400).json({ error: 'validation_failed', message: 'slug, name, templateSlug required' })\n }\n const now = new Date()\n try {\n await c.broadcasts.insertOne({\n slug,\n name,\n templateSlug,\n segmentDefinition: segmentDefinition ?? { filters: [{ kind: 'subscriptionStatus', equals: 'subscribed' }] },\n status: 'draft',\n scheduledAt: null,\n startedAt: null,\n completedAt: null,\n confirmationRequired: true,\n confirmedCount: null,\n confirmedAt: null,\n confirmedBy: null,\n recipientCount: null,\n stats: { sent: 0, delivered: 0, opened: 0, clicked: 0, bounced: 0, complained: 0, unsubscribed: 0 },\n createdAt: now,\n createdBy: (req as any).actor,\n updatedAt: now,\n } as any)\n } catch (err: any) {\n if (err?.code === 11000) return res.status(409).json({ error: 'slug_taken' })\n throw err\n }\n await mailer.audit({\n actor: (req as any).actor,\n action: 'broadcast.create',\n resource: { collection: 'mailer_broadcasts', slug },\n })\n return res.json({ ok: true, slug })\n }),\n )\n\n r.patch(\n '/broadcasts/:slug',\n asyncHandler(async (req, res) => {\n const b = await c.broadcasts.findOne({ slug: req.params.slug })\n if (!b) return res.status(404).json({ error: 'not_found' })\n if (b.status !== 'draft') return res.status(409).json({ error: 'not_draft' })\n const { name, templateSlug, segmentDefinition } = req.body ?? {}\n const set: Record<string, unknown> = { updatedAt: new Date() }\n if (typeof name === 'string') set.name = name\n if (typeof templateSlug === 'string') set.templateSlug = templateSlug\n if (segmentDefinition) set.segmentDefinition = segmentDefinition\n await c.broadcasts.updateOne({ _id: b._id }, { $set: set })\n return res.json({ ok: true })\n }),\n )\n\n r.post(\n '/broadcasts/:slug/segment/count',\n asyncHandler(async (req, res) => {\n const segmentDefinition = req.body?.segmentDefinition\n if (!segmentDefinition?.filters) return res.status(400).json({ error: 'segment_required' })\n const t0 = Date.now()\n // V1: only host-side filter translation. Mailer-side filters\n // (subscription status, fired events, etc.) and the suppression check\n // are applied at dispatch time over the streamed cursor, so the live\n // counter would have to scan-and-filter the full audience to be\n // precise. We return the upper-bound count and tell the UI it's an\n // estimate. When richer estimation lands, swap this for a sampled\n // pass that includes mailer-side filters + suppression.\n const hostFilter: any = {}\n for (const f of segmentDefinition.filters) {\n if (f.kind === 'hasTag') hostFilter.hasTag = f.tag\n if (f.kind === 'fieldEquals') hostFilter.fieldEquals = { field: f.field, value: f.value }\n }\n const hasMailerFilters = segmentDefinition.filters.some((f: any) =>\n ['subscriptionStatus', 'firedEvent', 'notFiredEvent', 'notHasTag', 'opened', 'notOpened', 'subscribedAfter', 'subscribedBefore'].includes(f.kind),\n )\n const upperBound = await mailer.adapter.count(hostFilter)\n return res.json({\n upperBound,\n approximate: hasMailerFilters,\n computedMs: Date.now() - t0,\n })\n }),\n )\n\n r.post(\n '/broadcasts/:slug/schedule',\n asyncHandler(async (req, res) => {\n const b = await c.broadcasts.findOne({ slug: req.params.slug })\n if (!b) return res.status(404).json({ error: 'not_found' })\n if (b.status !== 'draft') return res.status(409).json({ error: 'not_draft' })\n const { scheduledAt, confirmedCount, respectRecipientTimezone } = req.body ?? {}\n if (!scheduledAt) return res.status(400).json({ error: 'scheduledAt_required' })\n const scheduled = new Date(scheduledAt)\n if (Number.isNaN(scheduled.getTime())) return res.status(400).json({ error: 'bad_scheduledAt' })\n\n const threshold = mailer.config.broadcastConfirmationThreshold\n if (typeof confirmedCount !== 'number') {\n return res.status(400).json({ error: 'confirmedCount_required' })\n }\n\n const set: Record<string, unknown> = {\n status: 'scheduled',\n scheduledAt: scheduled,\n confirmedCount,\n confirmedAt: new Date(),\n confirmedBy: (req as any).actor,\n updatedAt: new Date(),\n }\n if (respectRecipientTimezone) set.respectRecipientTimezone = true\n\n await c.broadcasts.updateOne({ _id: b._id }, { $set: set })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'broadcast.schedule',\n resource: { collection: 'mailer_broadcasts', id: b._id, slug: b.slug },\n diffSummary: `scheduled at ${scheduled.toISOString()} · confirmedCount=${confirmedCount} · threshold=${threshold}`,\n })\n return res.json({ ok: true })\n }),\n )\n\n r.post(\n '/broadcasts/:slug/cancel',\n asyncHandler(async (req, res) => {\n const b = await c.broadcasts.findOne({ slug: req.params.slug })\n if (!b) return res.status(404).json({ error: 'not_found' })\n await c.broadcasts.updateOne({ _id: b._id }, { $set: { status: 'cancelled', updatedAt: new Date() } })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'broadcast.cancel',\n resource: { collection: 'mailer_broadcasts', id: b._id, slug: b.slug },\n })\n return res.json({ ok: true })\n }),\n )\n\n // Catch-all 404 for /api.\n r.use((_req, res) => res.status(404).json({ error: 'not_found' }))\n\n return r\n}\n\ntype AsyncHandler = (req: Request, res: Response, next: NextFunction) => Promise<unknown>\nfunction asyncHandler(fn: AsyncHandler) {\n return (req: Request, res: Response, next: NextFunction) => {\n fn(req, res, next).catch(next)\n }\n}\n\n/**\n * Body for the 4xx a route returns when a template's effective provider name\n * doesn't resolve (see `resolveProvider`).\n *\n * These routes are behind the host's admin gate, and the name comes from\n * `providerOverride` on a stored template or from `defaultProvider` in config —\n * never from the request. So this is a misconfiguration report, not a security\n * boundary: 400 rather than 500 because the server is fine and the *stored*\n * input is what's wrong, and it names both the unresolved provider and the\n * registered alternatives, which is the whole difference between an operator\n * fixing the template and an operator reading a stack trace.\n */\nfunction unknownProviderError(\n mailer: Mailer,\n tpl: { slug?: string; providerOverride?: string | null },\n): { error: string; message: string; provider: string; registeredProviders: string[] } {\n const override = tpl.providerOverride ?? null\n const name = override ?? mailer.config.defaultProvider\n const known = registeredProviderNames(mailer.providers)\n const source = override\n ? `template \"${tpl.slug ?? '?'}\" overrides the provider to \"${name}\"`\n : `the configured defaultProvider is \"${name}\"`\n return {\n error: 'provider_unknown',\n message:\n `${source}, but no such provider is registered. ` +\n `Registered providers: ${known.length ? known.join(', ') : '(none)'}.`,\n provider: name,\n registeredProviders: known,\n }\n}\n\n/**\n * Sum inFlight and delayed across every queue the driver exposes. Returns\n * `null` for either count when the driver doesn't implement that accessor\n * (e.g. Agenda/Noop), so the UI can render \"—\" instead of a misleading 0.\n */\nasync function collectQueueCounts(\n mailer: Mailer,\n): Promise<{ inFlight: number | null; delayed: number | null }> {\n const qs = Object.values(mailer.queues) as Array<{\n getInFlightCount?: () => Promise<number | null>\n getDelayedCount?: () => Promise<number | null>\n }>\n const sum = async (key: 'getInFlightCount' | 'getDelayedCount'): Promise<number | null> => {\n let total = 0\n let supported = false\n for (const q of qs) {\n const fn = q[key]\n if (!fn) continue\n try {\n const v = await fn.call(q)\n if (v == null) continue\n total += v\n supported = true\n } catch {\n // Treat one queue's failure as \"unknown\" — surface as null upstream.\n return null\n }\n }\n return supported ? total : null\n }\n const [inFlight, delayed] = await Promise.all([sum('getInFlightCount'), sum('getDelayedCount')])\n return { inFlight, delayed }\n}\n\n// ---------------------------------------------------------------------------\n// Live stats aggregation\n//\n// The flow / template / broadcast list endpoints used to return zeros for\n// every metric because no rollup ever wrote to `stats.*` on those docs. We\n// now compute them on-the-fly from the canonical `sends` and `flowRuns`\n// collections. Optional slug/id filters keep single-resource reads cheap.\n// ---------------------------------------------------------------------------\n\ninterface FlowStats {\n activeRuns: number\n completedRuns: number\n sendsLast7Days: number\n sendsTotal: number\n}\nfunction emptyFlowStats(): FlowStats {\n return { activeRuns: 0, completedRuns: 0, sendsLast7Days: 0, sendsTotal: 0 }\n}\n\nasync function computeFlowStats(mailer: Mailer, slugFilter?: string): Promise<Map<string, FlowStats>> {\n const out = new Map<string, FlowStats>()\n const match = slugFilter ? { flowSlug: slugFilter } : {}\n\n const runRows = await mailer.collections.flowRuns\n .aggregate<{ _id: { flowSlug: string; status: string }; count: number }>([\n { $match: match },\n { $group: { _id: { flowSlug: '$flowSlug', status: '$status' }, count: { $sum: 1 } } },\n ])\n .toArray()\n for (const row of runRows) {\n const slug = row._id.flowSlug\n if (!slug) continue\n const cur = out.get(slug) ?? emptyFlowStats()\n if (row._id.status === 'active') cur.activeRuns += row.count\n else if (row._id.status === 'completed') cur.completedRuns += row.count\n out.set(slug, cur)\n }\n\n const sevenDaysAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000)\n const sendRows = await mailer.collections.sends\n .aggregate<{ _id: string; total: number; last7: number }>([\n { $match: { flowRunId: { $ne: null } } },\n {\n $lookup: {\n from: mailer.collections.flowRuns.collectionName,\n localField: 'flowRunId',\n foreignField: '_id',\n as: 'run',\n pipeline: slugFilter\n ? [{ $match: { flowSlug: slugFilter } }, { $project: { flowSlug: 1 } }]\n : [{ $project: { flowSlug: 1 } }],\n },\n },\n { $unwind: '$run' },\n {\n $group: {\n _id: '$run.flowSlug',\n total: { $sum: 1 },\n last7: { $sum: { $cond: [{ $gte: ['$queuedAt', sevenDaysAgo] }, 1, 0] } },\n },\n },\n ])\n .toArray()\n for (const row of sendRows) {\n if (!row._id) continue\n const cur = out.get(row._id) ?? emptyFlowStats()\n cur.sendsTotal = row.total\n cur.sendsLast7Days = row.last7\n out.set(row._id, cur)\n }\n\n return out\n}\n\ninterface TemplateStats {\n sent: number\n opened: number\n clicked: number\n bounced: number\n sentLast7Days: number\n lastSentAt: Date | null\n}\nfunction emptyTemplateStats(): TemplateStats {\n return { sent: 0, opened: 0, clicked: 0, bounced: 0, sentLast7Days: 0, lastSentAt: null }\n}\n\nasync function computeTemplateStats(mailer: Mailer, slugFilter?: string): Promise<Map<string, TemplateStats>> {\n const out = new Map<string, TemplateStats>()\n const match: Record<string, unknown> = {}\n if (slugFilter) match.templateSlug = slugFilter\n const sevenDaysAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000)\n\n const rows = await mailer.collections.sends\n .aggregate<{\n _id: string\n sent: number\n opened: number\n clicked: number\n bounced: number\n sentLast7Days: number\n lastSentAt: Date | null\n }>([\n { $match: match },\n {\n $group: {\n _id: '$templateSlug',\n sent: { $sum: 1 },\n opened: { $sum: { $cond: [{ $ifNull: ['$openedAt', false] }, 1, 0] } },\n clicked: { $sum: { $cond: [{ $ifNull: ['$firstClickAt', false] }, 1, 0] } },\n bounced: { $sum: { $cond: [{ $eq: ['$status', 'bounced'] }, 1, 0] } },\n sentLast7Days: { $sum: { $cond: [{ $gte: ['$queuedAt', sevenDaysAgo] }, 1, 0] } },\n lastSentAt: { $max: '$queuedAt' },\n },\n },\n ])\n .toArray()\n for (const row of rows) {\n if (!row._id) continue\n out.set(row._id, {\n sent: row.sent,\n opened: row.opened,\n clicked: row.clicked,\n bounced: row.bounced,\n sentLast7Days: row.sentLast7Days,\n lastSentAt: row.lastSentAt ?? null,\n })\n }\n return out\n}\n\ninterface BroadcastStats {\n delivered: number\n opened: number\n clicked: number\n bounced: number\n}\nfunction emptyBroadcastStats(): BroadcastStats {\n return { delivered: 0, opened: 0, clicked: 0, bounced: 0 }\n}\n\nasync function computeBroadcastStats(\n mailer: Mailer,\n idFilter?: ObjectId,\n): Promise<Map<string, BroadcastStats>> {\n const out = new Map<string, BroadcastStats>()\n const match: Record<string, unknown> = { broadcastId: { $ne: null } }\n if (idFilter) match.broadcastId = idFilter\n\n const rows = await mailer.collections.sends\n .aggregate<{\n _id: ObjectId\n delivered: number\n opened: number\n clicked: number\n bounced: number\n }>([\n { $match: match },\n {\n $group: {\n _id: '$broadcastId',\n delivered: { $sum: { $cond: [{ $eq: ['$status', 'delivered'] }, 1, 0] } },\n opened: { $sum: { $cond: [{ $ifNull: ['$openedAt', false] }, 1, 0] } },\n clicked: { $sum: { $cond: [{ $ifNull: ['$firstClickAt', false] }, 1, 0] } },\n bounced: { $sum: { $cond: [{ $eq: ['$status', 'bounced'] }, 1, 0] } },\n },\n },\n ])\n .toArray()\n for (const row of rows) {\n if (!row._id) continue\n out.set(String(row._id), {\n delivered: row.delivered,\n opened: row.opened,\n clicked: row.clicked,\n bounced: row.bounced,\n })\n }\n return out\n}\n","/**\n * Shared enums — string-literal unions for status fields and other discriminators.\n * Kept separate from types.ts so the client can import these without pulling in\n * server-shaped interfaces.\n */\n\nexport type SubscriptionStatus = 'subscribed' | 'pending_doi' | 'unsubscribed' | 'bounced' | 'complained'\n\nexport type SendStatus =\n | 'queued'\n | 'sending'\n | 'sent'\n | 'delivered'\n | 'bounced'\n | 'complained'\n | 'failed'\n | 'suppressed'\n | 'cancelled'\n\nexport type TemplateKind = 'transactional' | 'marketing'\n\n/**\n * How a template's body goes on the wire.\n *\n * multipart — HTML + plain-text alternative (the default, and what almost\n * every template wants).\n * text_only — plain text alone, no HTML part at all. For mail that should\n * read as if it were typed by a person. Open tracking is\n * impossible without an HTML part to carry the pixel, and click\n * tracking is skipped too (rewriting bare URLs in text produces\n * the opaque redirect links this format exists to avoid), so a\n * text_only send reports no opens and no clicks — by design.\n */\nexport type TemplateBodyFormat = 'multipart' | 'text_only'\nexport const TEMPLATE_BODY_FORMATS: readonly TemplateBodyFormat[] = ['multipart', 'text_only'] as const\n\nexport type SuppressionScope = 'all' | 'marketing' | 'transactional'\n\nexport type SuppressionReason =\n | 'unsubscribed'\n | 'hard_bounce'\n | 'complaint'\n | 'manual'\n | 'list_cleaning'\n | 'gdpr_forget'\n\nexport type FlowRunStatus = 'active' | 'completed' | 'exited' | 'failed'\n\nexport type BroadcastStatus = 'draft' | 'scheduled' | 'sending' | 'sent' | 'cancelled' | 'failed'\n\nexport type HealthStatus = 'healthy' | 'degraded' | 'tripped'\n\nexport type FlowGoal = 'activation' | 'conversion' | 'retention' | 'reactivation' | 'transactional' | 'broadcast'\n","/**\n * Setup-status: a small suite of synchronous checks the admin dashboard\n * surfaces as a banner. Each check returns an `ok | warn | error` verdict\n * with a short message and optional hint. The endpoint exists to catch the\n * \"silent misconfiguration that breaks sends\" class of bug — missing DOI\n * template, workers not running, fromDefaults on a domain that doesn't pass\n * the senderDomains registry, etc.\n */\n\nimport type { Mailer } from '../mailer.js'\nimport { validateSenderDomain } from '../templates/sender-domain.js'\nimport { resolveSourceTags } from '../runner/dmarc.js'\nimport { HEALTH_AGG_ID } from '../models/index.js'\n\nexport type CheckSeverity = 'ok' | 'warn' | 'error'\n\nexport interface SetupCheck {\n /** Stable identifier, e.g. 'mongo', 'workers_heartbeat'. */\n name: string\n /** Human-readable label, e.g. \"MongoDB connection\". */\n label: string\n severity: CheckSeverity\n message: string\n /** Optional remediation hint shown when the user expands the row. */\n hint?: string\n}\n\nexport interface SetupStatus {\n overall: CheckSeverity\n generatedAt: string\n checks: SetupCheck[]\n}\n\nexport async function runSetupChecks(mailer: Mailer): Promise<SetupStatus> {\n const checks: SetupCheck[] = []\n\n checks.push(await checkMongo(mailer))\n checks.push(await checkQueue(mailer))\n // Run the heartbeat check even in a workerless process: in a web/worker\n // split the workerless web process is the one WITH the admin UI, so it is\n // exactly where an operator will look for \"are the workers alive\". The\n // heartbeat lives in Mongo, which both processes share, so the check works\n // from either side — only the remediation wording differs.\n if (mailer.config.queue.driver !== 'noop') {\n checks.push(await checkWorkersHeartbeat(mailer))\n }\n checks.push(await checkCircuitBreaker(mailer))\n checks.push(await checkDnsbl(mailer))\n checks.push(await checkPostmaster(mailer))\n checks.push(await checkSnds(mailer))\n const jmrp = checkJmrp(mailer)\n if (jmrp) checks.push(jmrp)\n checks.push(await checkDmarc(mailer))\n checks.push(...checkFromDefaultsAgainstRegistry(mailer))\n checks.push(...(await checkPublishedTemplates(mailer)))\n checks.push(await checkPostalAddress(mailer))\n checks.push(await checkDoiTemplate(mailer))\n\n const overall: CheckSeverity = checks.some((c) => c.severity === 'error')\n ? 'error'\n : checks.some((c) => c.severity === 'warn')\n ? 'warn'\n : 'ok'\n\n return {\n overall,\n generatedAt: new Date().toISOString(),\n checks,\n }\n}\n\nasync function checkMongo(mailer: Mailer): Promise<SetupCheck> {\n try {\n await mailer.db.admin().ping()\n return { name: 'mongo', label: 'MongoDB connection', severity: 'ok', message: 'reachable' }\n } catch (err) {\n return {\n name: 'mongo',\n label: 'MongoDB connection',\n severity: 'error',\n message: `MongoDB ping failed: ${(err as Error)?.message ?? err}`,\n hint: 'Mailery is configured against an unreachable Mongo. Sends, flow advancement, and admin reads will all fail.',\n }\n }\n}\n\nasync function checkQueue(mailer: Mailer): Promise<SetupCheck> {\n const driver = mailer.config.queue.driver\n if (driver === 'noop') {\n return {\n name: 'queue',\n label: 'Queue driver',\n severity: 'ok',\n message: 'driver: noop (synchronous-only mode)',\n }\n }\n try {\n await mailer.queues.send.getWaitingCount()\n return { name: 'queue', label: 'Queue driver', severity: 'ok', message: `driver: ${driver}` }\n } catch (err) {\n return {\n name: 'queue',\n label: 'Queue driver',\n severity: 'error',\n message: `${driver} queue is not responding: ${(err as Error)?.message ?? err}`,\n hint:\n driver === 'bull'\n ? 'Check Redis connectivity (queue.redis.url).'\n : 'Check the @hokify/agenda + Mongo connection.',\n }\n }\n}\n\nasync function checkWorkersHeartbeat(mailer: Mailer): Promise<SetupCheck> {\n // The aggregate doc's updatedAt is touched on every counter increment and\n // on every evaluate tick, so it's the canonical worker-heartbeat marker.\n const h = await mailer.collections.health.findOne(\n {},\n { sort: { updatedAt: -1 } },\n )\n const tickIntervalMs = mailer.config.tickIntervalSeconds * 1000\n const staleAfterMs = Math.max(tickIntervalMs * 3, 30_000) // tolerate a couple missed ticks\n\n // This process may not run the workers itself (web/worker split) — keep the\n // verdicts identical either way, but point the operator at the right place.\n const workerless = mailer.config.workerless\n\n if (!h) {\n return {\n name: 'workers_heartbeat',\n label: 'Background workers',\n severity: 'warn',\n message: workerless ? 'no tick has run yet (workers run in another process)' : 'no tick has run yet',\n hint: workerless\n ? 'This process is workerless; the heartbeat comes from your separate worker process. If that process is started, the heartbeat will appear within one tick interval — a fresh install legitimately has none yet.'\n : 'If your separate worker process is started, the heartbeat will appear within one tick interval. If you forgot to run `mailer.startWorkers()`, sends will sit queued indefinitely.',\n }\n }\n\n const ageMs = Date.now() - new Date(h.updatedAt).getTime()\n if (ageMs > staleAfterMs) {\n return {\n name: 'workers_heartbeat',\n label: 'Background workers',\n severity: 'error',\n message: `last tick ${humanDuration(ageMs)} ago (expected within ${humanDuration(tickIntervalMs)})`,\n hint: workerless\n ? 'Workers run in another process, and that process appears to be down. Sends and flow advancement are halted. Restart the process that calls `mailer.startWorkers()`.'\n : 'Workers appear to be down. Sends and flow advancement are halted. Restart your worker process (`mailer.startWorkers()`).',\n }\n }\n return {\n name: 'workers_heartbeat',\n label: 'Background workers',\n severity: 'ok',\n message: `last tick ${humanDuration(ageMs)} ago${workerless ? ' (worker process)' : ''}`,\n }\n}\n\nasync function checkCircuitBreaker(mailer: Mailer): Promise<SetupCheck> {\n const docs = await mailer.collections.health.find({}).toArray()\n const buckets = docs.filter((d) => d._id !== HEALTH_AGG_ID)\n\n if (buckets.length === 0) {\n // No telemetry yet (heartbeat-only state, no sends recorded). Claiming\n // \"healthy\" misleads — there's nothing to base it on.\n return {\n name: 'circuit_breaker',\n label: 'Circuit breaker',\n severity: 'ok',\n message: 'no telemetry yet',\n hint: 'The breaker tracks bounce / complaint rates per (sender domain × kind) and starts evaluating once enough sends have been recorded. Send some mail to populate.',\n }\n }\n\n const tripped = buckets.filter((d) => d.status === 'tripped')\n if (tripped.length > 0) {\n const summary = tripped\n .map((d) => `${d.senderDomain ?? '_unknown'}/${d.kind}`)\n .join(', ')\n return {\n name: 'circuit_breaker',\n label: 'Circuit breaker',\n severity: 'error',\n message: `tripped: ${summary}`,\n hint: 'Marketing sends are held for the listed bucket(s). Investigate the underlying bounce / complaint cause, then POST /api/health/resume (with optional senderDomain + kind to resume one bucket).',\n }\n }\n\n const degraded = buckets.filter((d) => d.status === 'degraded')\n if (degraded.length > 0) {\n const summary = degraded\n .map((d) => `${d.senderDomain ?? '_unknown'}/${d.kind}`)\n .join(', ')\n return {\n name: 'circuit_breaker',\n label: 'Circuit breaker',\n severity: 'warn',\n message: `degraded: ${summary}`,\n hint: 'Marketing sends still flow but failure rate is above the degraded threshold for the listed bucket(s). Investigate provider errors before they escalate to tripped.',\n }\n }\n\n return { name: 'circuit_breaker', label: 'Circuit breaker', severity: 'ok', message: 'healthy' }\n}\n\nasync function checkDnsbl(mailer: Mailer): Promise<SetupCheck> {\n const docs = await mailer.collections.dnsblChecks.find({}).toArray()\n if (docs.length === 0) {\n return {\n name: 'dnsbl',\n label: 'DNS block-list checks',\n severity: 'ok',\n message: 'no checks run yet',\n hint: 'Checks run automatically once per dnsbl.intervalHours (default 24h). To run now, POST /api/dnsbl/recheck.',\n }\n }\n const listed = docs.filter((d) => d.result === 'listed')\n if (listed.length > 0) {\n const summary = listed\n .map((d) => `${d.target} on ${d.listLabel}`)\n .slice(0, 3)\n .join('; ')\n const more = listed.length > 3 ? ` (+${listed.length - 3} more)` : ''\n return {\n name: 'dnsbl',\n label: 'DNS block-list checks',\n severity: 'error',\n message: `${listed.length} listing(s): ${summary}${more}`,\n hint: 'A sender domain or IP is listed on a public DNSBL. Investigate the listing source — most lists publish a removal procedure on their website. Mail to the affected (domain, kind) bucket will likely land in spam until delisted.',\n }\n }\n const errored = docs.filter((d) => d.result === 'error')\n if (errored.length === docs.length) {\n return {\n name: 'dnsbl',\n label: 'DNS block-list checks',\n severity: 'warn',\n message: `all ${docs.length} checks errored`,\n hint: 'Lookups against block lists are failing — usually a DNS-resolution problem on the host running mailery, or a list rate-limiting your public resolver. Verify outbound DNS works.',\n }\n }\n return {\n name: 'dnsbl',\n label: 'DNS block-list checks',\n severity: 'ok',\n message: `clean (${docs.length} checks)`,\n }\n}\n\nasync function checkPostmaster(mailer: Mailer): Promise<SetupCheck> {\n const cfg = mailer.config.postmaster\n if (!cfg?.clientId || !cfg?.clientSecret || !cfg?.refreshToken) {\n // Postmaster is opt-in (needs OAuth setup) and only meaningful at >100/day\n // to Gmail. Treat \"not configured\" as ok so it doesn't spam every operator\n // with a permanent warning banner.\n return {\n name: 'postmaster',\n label: 'Google Postmaster Tools',\n severity: 'ok',\n message: 'not configured (optional)',\n hint: 'Set mailer.config.postmaster with an OAuth client + refresh token to pull authoritative Gmail reputation data. Only meaningful at >100 sends/day to Gmail.',\n }\n }\n\n const snapshots = await mailer.collections.postmasterSnapshots.find({}).sort({ fetchedAt: -1 }).toArray()\n if (snapshots.length === 0) {\n return {\n name: 'postmaster',\n label: 'Google Postmaster Tools',\n severity: 'warn',\n message: 'configured but no data yet',\n hint: 'A pull runs once per postmaster.intervalHours (default 24h). To run now, POST /api/postmaster/refresh. Postmaster only reports for domains with >100 messages/day to Gmail; smaller senders see empty responses.',\n }\n }\n\n // Find the latest snapshot per domain (snapshots are already sorted by fetchedAt desc).\n const latestByDomain = new Map<string, typeof snapshots[number]>()\n for (const s of snapshots) {\n if (!latestByDomain.has(s.domain)) latestByDomain.set(s.domain, s)\n }\n const bad: string[] = []\n const low: string[] = []\n for (const s of latestByDomain.values()) {\n if (s.domainReputation === 'BAD') bad.push(s.domain)\n else if (s.domainReputation === 'LOW') low.push(s.domain)\n }\n\n if (bad.length > 0) {\n return {\n name: 'postmaster',\n label: 'Google Postmaster Tools',\n severity: 'error',\n message: `BAD reputation on ${bad.join(', ')}`,\n hint: 'Gmail considers these domains spammy. Most mail to Gmail addresses will land in spam folder. Marketing breaker has been tripped for affected domains. See docs/guide/warming.md §6 for recovery.',\n }\n }\n if (low.length > 0) {\n return {\n name: 'postmaster',\n label: 'Google Postmaster Tools',\n severity: 'warn',\n message: `LOW reputation on ${low.join(', ')}`,\n hint: 'Reputation has slipped below Medium. Review recent complaint + bounce activity, slow down marketing volume, and re-engage your most active segment only.',\n }\n }\n return {\n name: 'postmaster',\n label: 'Google Postmaster Tools',\n severity: 'ok',\n // Includes REPUTATION_CATEGORY_UNSPECIFIED (\"no data yet\") domains —\n // surface that explicitly so the operator isn't misled.\n message: (() => {\n const tiers = new Set(Array.from(latestByDomain.values()).map((d) => d.domainReputation))\n const hasUnspec = tiers.has('REPUTATION_CATEGORY_UNSPECIFIED' as any)\n return `${latestByDomain.size} domain(s) tracked${hasUnspec ? ' (some have no reputation data yet)' : ', all High/Medium'}`\n })(),\n }\n}\n\n/**\n * JMRP enrolment is a manual one-time setup on the Microsoft sender-support\n * portal — there's no API to confirm completion. We surface a persistent\n * info-level reminder whenever the operator has configured a dedicated IP,\n * regardless of whether SNDS itself is set up. Operators can suppress this\n * by setting `dnsbl.dedicatedIps = []` once they've confirmed enrolment in\n * their runbook.\n */\nfunction checkJmrp(mailer: Mailer): SetupCheck | null {\n const hasDedicatedIp = (mailer.config.dnsbl?.dedicatedIps?.length ?? 0) > 0\n if (!hasDedicatedIp) return null\n return {\n name: 'snds_jmrp',\n label: 'Microsoft JMRP enrolment',\n severity: 'ok',\n message: 'manual setup — confirm in your runbook',\n hint: 'Outlook spam complaints only land in mailery if you enrol each sending IP in JMRP. Visit https://sendersupport.olc.protection.outlook.com/snds/JMRP.aspx and complete the form for each IP. There is no API to verify completion; mailery shows this reminder whenever dedicatedIps is non-empty.',\n }\n}\n\nasync function checkSnds(mailer: Mailer): Promise<SetupCheck> {\n const cfg = mailer.config.snds\n const hasDedicatedIp = (mailer.config.dnsbl?.dedicatedIps?.length ?? 0) > 0\n\n if (!cfg?.accessKey) {\n if (!hasDedicatedIp) {\n return {\n name: 'snds',\n label: 'Microsoft SNDS',\n severity: 'ok',\n message: 'not applicable (no dedicated IP)',\n hint: 'SNDS reports IP-level Outlook/Hotmail reputation. Only meaningful when you send from a dedicated IP. Skip unless you do.',\n }\n }\n return {\n name: 'snds',\n label: 'Microsoft SNDS',\n severity: 'warn',\n message: 'dedicated IP configured but SNDS access key not set',\n hint: 'Sign in at https://sendersupport.olc.protection.outlook.com/snds/ , request access for your IP(s), then set mailer.config.snds.accessKey to enable daily pulls. Also enrol in JMRP at https://sendersupport.olc.protection.outlook.com/snds/JMRP.aspx so Outlook complaints flow back to your suppression list.',\n }\n }\n\n const snapshots = await mailer.collections.sndsSnapshots.find({}).sort({ fetchedAt: -1 }).toArray()\n if (snapshots.length === 0) {\n return {\n name: 'snds',\n label: 'Microsoft SNDS',\n severity: 'warn',\n message: 'configured but no data yet',\n hint: 'A pull runs every snds.intervalHours (default 24h). To run now, POST /api/snds/refresh. If you just enrolled, SNDS data can take 1-2 days to populate.',\n }\n }\n\n const latestByIp = new Map<string, typeof snapshots[number]>()\n for (const s of snapshots) {\n if (!latestByIp.has(s.ip)) latestByIp.set(s.ip, s)\n }\n const red: string[] = []\n const yellow: string[] = []\n for (const s of latestByIp.values()) {\n if (s.filterResult === 'RED') red.push(s.ip)\n else if (s.filterResult === 'YELLOW') yellow.push(s.ip)\n }\n\n if (red.length > 0) {\n return {\n name: 'snds',\n label: 'Microsoft SNDS',\n severity: 'error',\n message: `RED filter on ${red.join(', ')}`,\n hint: 'Outlook/Hotmail is filtering mail from these IPs as spam. Reduce volume, audit recent complaints / trap hits, fix any auth alignment problems, and wait for reputation to recover (typically 1-2 weeks).',\n }\n }\n if (yellow.length > 0) {\n return {\n name: 'snds',\n label: 'Microsoft SNDS',\n severity: 'warn',\n message: `YELLOW filter on ${yellow.join(', ')}`,\n hint: 'Outlook is putting some mail from these IPs in the junk folder. Investigate recent complaint rate and trap hits before reputation slips to RED.',\n }\n }\n return {\n name: 'snds',\n label: 'Microsoft SNDS',\n severity: 'ok',\n message: `${latestByIp.size} IP(s) tracked, all GREEN`,\n }\n}\n\nasync function checkDmarc(mailer: Mailer): Promise<SetupCheck> {\n const reportCount = await mailer.collections.dmarcReports.estimatedDocumentCount()\n if (reportCount === 0) {\n return {\n name: 'dmarc',\n label: 'DMARC RUA reports',\n severity: 'ok',\n message: 'no reports ingested yet',\n hint: 'Publish DMARC `rua=mailto:<your-mailbox>` in DNS, then upload received reports via /admin/mailer/api/dmarc/upload (or drag-drop in the Health screen). RUA tells you who is sending mail as your domain — both legitimate sources and spoofers.',\n }\n }\n\n const since = new Date(Date.now() - 7 * 86_400_000)\n const recent = await mailer.collections.dmarcReports.find({ rangeEnd: { $gte: since } }).toArray()\n if (recent.length === 0) {\n return {\n name: 'dmarc',\n label: 'DMARC RUA reports',\n severity: 'warn',\n message: `no reports in the last 7 days (${reportCount} total)`,\n hint: 'Receivers email RUA reports daily. A gap suggests inbound delivery is broken or the rua= mailbox is no longer monitored. Check inbound mail flow.',\n }\n }\n\n // Merge config-defined tags with DB-defined tags so operator tags set via\n // the admin UI count. Both labeled (non-ignored) and ignored sources are\n // treated as \"known\" — operator already triaged them.\n const tagged = await resolveSourceTags(mailer.getRunnerContext())\n const known = new Set(Array.from(tagged.keys()))\n const since30 = new Date(Date.now() - 30 * 86_400_000)\n const failures = await mailer.collections.dmarcFailures.find({ receivedAt: { $gte: since30 } }).toArray()\n const unknownFailing = failures.filter((f) => !known.has(f.sourceIp))\n\n if (unknownFailing.length === 0) {\n return {\n name: 'dmarc',\n label: 'DMARC RUA reports',\n severity: 'ok',\n message: `${recent.length} report(s) this week, no failing unknown sources`,\n }\n }\n\n const totalFailing = unknownFailing.reduce((acc, f) => acc + f.count, 0)\n const ips = Array.from(new Set(unknownFailing.map((f) => f.sourceIp))).slice(0, 3)\n const more = unknownFailing.length > 3 ? ` (+${unknownFailing.length - 3} more)` : ''\n return {\n name: 'dmarc',\n label: 'DMARC RUA reports',\n severity: 'warn',\n message: `${totalFailing} failing message(s) from ${ips.join(', ')}${more}`,\n hint: 'These IPs sent mail claiming to be from your domain that failed DMARC alignment. Tag known-legit sources in mailer.config.dmarc.knownSources to silence them. Untagged sources are likely either forgotten SaaS tools or active spoofing.',\n }\n}\n\nfunction checkFromDefaultsAgainstRegistry(mailer: Mailer): SetupCheck[] {\n const registry = mailer.config.senderDomains\n if (!registry || Object.keys(registry).length === 0) return []\n\n const out: SetupCheck[] = []\n const from = mailer.config.fromDefaults?.email\n const tx = mailer.config.transactionalFromDefaults?.email\n\n if (from) {\n const r = validateSenderDomain(from, 'marketing', registry)\n if (!r.ok) {\n out.push({\n name: 'from_defaults_marketing',\n label: 'fromDefaults vs senderDomains',\n severity: 'error',\n message: r.reason,\n hint: 'New marketing templates that fall back to fromDefaults will fail to publish.',\n })\n }\n }\n\n if (tx) {\n const r = validateSenderDomain(tx, 'transactional', registry)\n if (!r.ok) {\n out.push({\n name: 'transactional_from_defaults',\n label: 'transactionalFromDefaults vs senderDomains',\n severity: 'error',\n message: r.reason,\n hint: 'New transactional templates that fall back to transactionalFromDefaults will fail to publish.',\n })\n }\n } else if (from) {\n // No transactional defaults set; transactional creates will fall back to\n // fromDefaults. Check whether that fallback is valid for transactional.\n const r = validateSenderDomain(from, 'transactional', registry)\n if (!r.ok) {\n out.push({\n name: 'transactional_fallback',\n label: 'Transactional fallback',\n severity: 'warn',\n message: `transactionalFromDefaults is unset and fromDefaults (${from}) is invalid for transactional templates`,\n hint: 'Set transactionalFromDefaults to a transactional-kind domain, or set senderDomains entry for the existing one to \"both\".',\n })\n }\n }\n\n return out\n}\n\nasync function checkPublishedTemplates(mailer: Mailer): Promise<SetupCheck[]> {\n const registry = mailer.config.senderDomains\n if (!registry || Object.keys(registry).length === 0) return []\n\n const published = await mailer.collections.templates\n .find({ publishedAt: { $ne: null } }, { projection: { slug: 1, kind: 1, fromEmail: 1 } })\n .toArray()\n\n const broken: Array<{ slug: string; reason: string }> = []\n for (const tpl of published) {\n const r = validateSenderDomain(tpl.fromEmail, tpl.kind, registry)\n if (!r.ok) broken.push({ slug: tpl.slug, reason: r.reason })\n }\n\n if (broken.length === 0) return []\n const list = broken.slice(0, 5).map((b) => `${b.slug} (${b.reason})`).join('; ')\n const more = broken.length > 5 ? ` …and ${broken.length - 5} more` : ''\n return [\n {\n name: 'published_template_domains',\n label: 'Published templates',\n severity: 'error',\n message: `${broken.length} published template${broken.length === 1 ? '' : 's'} use a fromEmail that no longer matches senderDomains: ${list}${more}`,\n hint: 'These templates will still send with their stored fromEmail until re-published. Edit each template and republish to surface the validation, or update senderDomains.',\n },\n ]\n}\n\nasync function checkPostalAddress(mailer: Mailer): Promise<SetupCheck> {\n if (mailer.config.senderAddress) {\n return { name: 'postal_address', label: 'CAN-SPAM postal address', severity: 'ok', message: 'set' }\n }\n const marketingCount = await mailer.collections.templates.countDocuments({\n kind: 'marketing',\n publishedAt: { $ne: null },\n })\n if (marketingCount === 0) {\n return { name: 'postal_address', label: 'CAN-SPAM postal address', severity: 'ok', message: 'no published marketing templates yet' }\n }\n return {\n name: 'postal_address',\n label: 'CAN-SPAM postal address',\n severity: 'warn',\n message: `${marketingCount} published marketing template${marketingCount === 1 ? '' : 's'} but senderAddress is unset`,\n hint: 'CAN-SPAM requires a postal address in marketing emails. Set `senderAddress` in your Mailer config and reference the `{{senderAddress}}` render variable in your templates.',\n }\n}\n\nasync function checkDoiTemplate(mailer: Mailer): Promise<SetupCheck> {\n if (!mailer.config.requireDoubleOptIn) {\n return { name: 'doi_template', label: 'DOI template', severity: 'ok', message: 'DOI not required' }\n }\n const tpl = await mailer.collections.templates.findOne({\n slug: mailer.config.doiTemplateSlug,\n publishedAt: { $ne: null },\n })\n if (tpl) {\n return { name: 'doi_template', label: 'DOI template', severity: 'ok', message: `template \"${tpl.slug}\" published` }\n }\n return {\n name: 'doi_template',\n label: 'DOI template',\n severity: 'error',\n message: `requireDoubleOptIn is true but no published template with slug \"${mailer.config.doiTemplateSlug}\"`,\n hint: 'New subscriptions will silently fail to send confirmation emails. Create and publish a template with this slug, or unset requireDoubleOptIn.',\n }\n}\n\nfunction humanDuration(ms: number): string {\n if (ms < 1000) return `${ms}ms`\n if (ms < 60_000) return `${Math.round(ms / 1000)}s`\n if (ms < 3_600_000) return `${Math.round(ms / 60_000)}m`\n return `${Math.round(ms / 3_600_000)}h`\n}\n","/**\n * List hygiene aggregations. Reports the engagement health of the\n * subscriber list: how many contacts engaged recently, how many are\n * stale, and what the bounce/complaint impact of sunsetting the stale\n * cohort would be.\n *\n * Pure read — no writes. Caller decides when to run.\n */\n\nimport type { RunnerContext } from './index.js'\n\nconst DAY_MS = 86_400_000\n\nexport const HYGIENE_BUCKETS = [\n { label: 'Engaged (last 30 days)', maxDays: 30 },\n { label: 'Engaged (31-60 days)', minDays: 30, maxDays: 60 },\n { label: 'Engaged (61-90 days)', minDays: 60, maxDays: 90 },\n { label: 'Engaged (91-180 days)', minDays: 90, maxDays: 180 },\n { label: 'Inactive (>180 days)', minDays: 180 },\n { label: 'Never engaged', neverEngaged: true },\n] as const\n\nexport interface HygieneBucket {\n label: string\n /** Lower bound of \"days since last engagement\" inclusive. Null for never-engaged. */\n minDays?: number | null\n /** Upper bound of \"days since last engagement\" exclusive. Null = unbounded. */\n maxDays?: number | null\n /** True for the \"never engaged\" bucket (sent but no open/click ever). */\n neverEngaged?: boolean\n count: number\n pctOfTotal: number\n}\n\nexport interface HygieneReport {\n totalSubscribers: number\n totalWithSends: number\n buckets: HygieneBucket[]\n sunsetCandidate: {\n /** Cohort: subscribed contacts whose lastEngagedAt is >180 days ago, or who have never engaged after >180 days of being subscribed. */\n count: number\n pctOfTotal: number\n /** Lifetime metrics for the cohort, when data exists. */\n cohortLifetime: {\n totalSends: number\n bouncedRate: number\n hardBouncedRate: number\n complaintRate: number\n } | null\n /** Projected impact: how recent (90d) rates would change if this cohort were sunset. */\n projectedImpact: {\n recentTotalSends: number\n recentBounced: number\n recentComplained: number\n cohortRecentSends: number\n cohortRecentBounced: number\n cohortRecentComplained: number\n currentOverallBounceRate: number\n projectedBounceRate: number\n currentOverallComplaintRate: number\n projectedComplaintRate: number\n } | null\n }\n computedAt: string\n}\n\nexport interface ComputeHygieneOptions {\n /** Override now() for tests. */\n now?: number\n /** Days of inactivity considered \"stale\" enough to sunset. Default 180. */\n sunsetThresholdDays?: number\n /** Window for projected-impact calculations. Default 90. */\n recentWindowDays?: number\n}\n\nexport async function computeListHygiene(\n ctx: RunnerContext,\n opts: ComputeHygieneOptions = {},\n): Promise<HygieneReport> {\n const now = opts.now ?? Date.now()\n const sunsetDays = opts.sunsetThresholdDays ?? 180\n const recentDays = opts.recentWindowDays ?? 90\n const recentCutoff = new Date(now - recentDays * DAY_MS)\n\n const totalSubscribers = await ctx.collections.subscriptions.countDocuments({ status: 'subscribed' })\n\n // Restrict the engagement aggregation to currently-subscribed contacts.\n // We materialize the subscriber externalId set in memory (one short\n // string per row). At ~10M subscribers this would be ~hundreds of MB —\n // a real concern at that scale. Below ~1M it's negligible. If list\n // sizes ever push past that, move to a server-side $lookup join inside\n // the sends aggregation.\n const subscribedIds = new Set<string>()\n {\n const cursor = ctx.collections.subscriptions\n .find({ status: 'subscribed' }, { projection: { externalId: 1 } })\n for await (const s of cursor) subscribedIds.add(s.externalId)\n }\n\n type EngagementRow = {\n _id: string\n lastOpened: Date | null\n lastClicked: Date | null\n firstSent: Date | null\n totalSends: number\n bounced: number\n hardBounced: number\n complained: number\n recentSends: number\n recentBounced: number\n recentComplained: number\n }\n\n // Single aggregation: group by externalId, computing engagement + lifetime\n // counts + recent-window counts in one pass. Cursor iteration avoids\n // loading the full per-contact map at once; allowDiskUse keeps Mongo from\n // OOMing on the $group stage at scale.\n const cursor = ctx.collections.sends.aggregate<EngagementRow>(\n [\n {\n $group: {\n _id: '$externalId',\n lastOpened: { $max: '$openedAt' },\n lastClicked: { $max: '$firstClickAt' },\n firstSent: { $min: '$queuedAt' },\n totalSends: { $sum: 1 },\n bounced: { $sum: { $cond: [{ $eq: ['$status', 'bounced'] }, 1, 0] } },\n hardBounced: {\n $sum: {\n $cond: [\n { $and: [{ $eq: ['$status', 'bounced'] }, { $eq: ['$bounceType', 'hard'] }] },\n 1,\n 0,\n ],\n },\n },\n complained: { $sum: { $cond: [{ $ne: ['$complainedAt', null] }, 1, 0] } },\n recentSends: { $sum: { $cond: [{ $gte: ['$queuedAt', recentCutoff] }, 1, 0] } },\n recentBounced: {\n $sum: {\n $cond: [\n { $and: [{ $eq: ['$status', 'bounced'] }, { $gte: ['$queuedAt', recentCutoff] }] },\n 1,\n 0,\n ],\n },\n },\n recentComplained: {\n $sum: {\n $cond: [\n { $and: [{ $ne: ['$complainedAt', null] }, { $gte: ['$queuedAt', recentCutoff] }] },\n 1,\n 0,\n ],\n },\n },\n },\n },\n ],\n { allowDiskUse: true },\n )\n\n const buckets: HygieneBucket[] = HYGIENE_BUCKETS.map((b) => ({\n label: b.label,\n minDays: 'minDays' in b ? b.minDays : null,\n maxDays: 'maxDays' in b ? b.maxDays : null,\n neverEngaged: 'neverEngaged' in b && b.neverEngaged,\n count: 0,\n pctOfTotal: 0,\n }))\n\n let totalWithSends = 0\n let sunsetCount = 0\n\n const cohortLifetimeAcc = { totalSends: 0, bounced: 0, hardBounced: 0, complained: 0 }\n const cohortRecentAcc = { totalSends: 0, bounced: 0, complained: 0 }\n\n for await (const row of cursor) {\n if (!subscribedIds.has(row._id)) continue\n totalWithSends++\n\n const lastOpened = row.lastOpened ? new Date(row.lastOpened).getTime() : null\n const lastClicked = row.lastClicked ? new Date(row.lastClicked).getTime() : null\n const lastEngaged = lastOpened == null && lastClicked == null\n ? null\n : Math.max(lastOpened ?? 0, lastClicked ?? 0)\n\n let isSunset = false\n if (lastEngaged == null) {\n const firstSent = row.firstSent ? new Date(row.firstSent).getTime() : null\n buckets[5]!.count++\n if (firstSent != null && now - firstSent > sunsetDays * DAY_MS) {\n isSunset = true\n }\n } else {\n const daysSince = (now - lastEngaged) / DAY_MS\n if (daysSince <= 30) buckets[0]!.count++\n else if (daysSince <= 60) buckets[1]!.count++\n else if (daysSince <= 90) buckets[2]!.count++\n else if (daysSince <= 180) buckets[3]!.count++\n else {\n buckets[4]!.count++\n isSunset = true\n }\n }\n\n if (isSunset) {\n sunsetCount++\n cohortLifetimeAcc.totalSends += row.totalSends\n cohortLifetimeAcc.bounced += row.bounced\n cohortLifetimeAcc.hardBounced += row.hardBounced\n cohortLifetimeAcc.complained += row.complained\n cohortRecentAcc.totalSends += row.recentSends\n cohortRecentAcc.bounced += row.recentBounced\n cohortRecentAcc.complained += row.recentComplained\n }\n }\n\n for (const b of buckets) {\n b.pctOfTotal = totalSubscribers === 0 ? 0 : b.count / totalSubscribers\n }\n\n const cohortLifetime: HygieneReport['sunsetCandidate']['cohortLifetime'] =\n cohortLifetimeAcc.totalSends > 0\n ? {\n totalSends: cohortLifetimeAcc.totalSends,\n bouncedRate: cohortLifetimeAcc.bounced / cohortLifetimeAcc.totalSends,\n hardBouncedRate: cohortLifetimeAcc.hardBounced / cohortLifetimeAcc.totalSends,\n complaintRate: cohortLifetimeAcc.complained / cohortLifetimeAcc.totalSends,\n }\n : null\n\n // Recent-window overall stats are bounded by the date window and small at\n // any realistic volume.\n let projectedImpact: HygieneReport['sunsetCandidate']['projectedImpact'] = null\n const recentAll = await ctx.collections.sends\n .aggregate<{ totalSends: number; bounced: number; complained: number }>([\n { $match: { queuedAt: { $gte: recentCutoff } } },\n {\n $group: {\n _id: null,\n totalSends: { $sum: 1 },\n bounced: { $sum: { $cond: [{ $eq: ['$status', 'bounced'] }, 1, 0] } },\n complained: { $sum: { $cond: [{ $ne: ['$complainedAt', null] }, 1, 0] } },\n },\n },\n ])\n .toArray()\n\n if (recentAll[0] && recentAll[0].totalSends > 0) {\n const all = recentAll[0]\n const cohort = cohortRecentAcc\n const currentBounceRate = all.bounced / all.totalSends\n const currentComplaintRate = all.complained / all.totalSends\n const remainingSends = all.totalSends - cohort.totalSends\n const remainingBounces = all.bounced - cohort.bounced\n const remainingComplaints = all.complained - cohort.complained\n const projectedBounceRate = remainingSends > 0 ? remainingBounces / remainingSends : 0\n const projectedComplaintRate = remainingSends > 0 ? remainingComplaints / remainingSends : 0\n\n projectedImpact = {\n recentTotalSends: all.totalSends,\n recentBounced: all.bounced,\n recentComplained: all.complained,\n cohortRecentSends: cohort.totalSends,\n cohortRecentBounced: cohort.bounced,\n cohortRecentComplained: cohort.complained,\n currentOverallBounceRate: currentBounceRate,\n projectedBounceRate,\n currentOverallComplaintRate: currentComplaintRate,\n projectedComplaintRate,\n }\n }\n\n return {\n totalSubscribers,\n totalWithSends,\n buckets,\n sunsetCandidate: {\n count: sunsetCount,\n pctOfTotal: totalSubscribers === 0 ? 0 : sunsetCount / totalSubscribers,\n cohortLifetime,\n projectedImpact,\n },\n computedAt: new Date(now).toISOString(),\n }\n}\n","/**\n * Mail-Tester deliverability check.\n *\n * 1. Operator clicks \"Run deliverability check\" in the template editor.\n * 2. Mailery provisions a check (gets a unique test address from Mail-Tester).\n * 3. Mailery sends the rendered draft to that address via the operator's\n * default provider.\n * 4. Mailery polls Mail-Tester for the score (typically arrives 10-30s after\n * receipt) and caches it keyed on a content fingerprint.\n * 5. If the score is below `minScore` the publish endpoint refuses unless\n * the operator passes `bypassMailTester: true` in the publish request.\n *\n * The client interface is pluggable so tests inject a stub. Real\n * implementation hits https://mail-tester.com/api/.\n */\n\nimport crypto from 'node:crypto'\n\nimport type { MailTesterConfig } from '../config.js'\nimport type { MailTesterFeedback, MailTesterScoreDoc } from '../models/index.js'\nimport type { RunnerContext } from './index.js'\n\nexport type Fetcher = (url: string, init?: RequestInit) => Promise<Response>\n\nexport interface ProvisionedCheck {\n checkId: string\n emailAddress: string\n}\n\nexport interface MailTesterResult {\n ready: boolean\n score: number\n feedback: MailTesterFeedback[]\n rawSummary: string | null\n}\n\nexport interface MailTesterClient {\n provisionCheck(): Promise<ProvisionedCheck>\n fetchResult(checkId: string): Promise<MailTesterResult>\n}\n\nconst FETCH_TIMEOUT_MS = 15_000\n\nexport function createMailTesterClient(\n cfg: MailTesterConfig,\n fetcher: Fetcher = globalThis.fetch,\n): MailTesterClient {\n const base = cfg.baseUrl ?? 'https://mail-tester.com/api'\n\n function sanitize(s: string): string {\n if (!cfg.apiKey) return s\n return s.split(cfg.apiKey).join('<redacted>').split(encodeURIComponent(cfg.apiKey)).join('<redacted>')\n }\n\n async function call(method: string, path: string, body?: unknown): Promise<any> {\n const ctl = new AbortController()\n const t = setTimeout(() => ctl.abort(), FETCH_TIMEOUT_MS)\n let res: Response\n try {\n res = await fetcher(`${base}/${encodeURIComponent(cfg.apiKey)}${path}`, {\n method,\n headers: { 'content-type': 'application/json' },\n body: body ? JSON.stringify(body) : undefined,\n signal: ctl.signal,\n })\n } catch (err: any) {\n throw new Error(`Mail-Tester ${method} ${sanitize(path)} failed: ${sanitize(String(err?.message ?? err))}`)\n } finally {\n clearTimeout(t)\n }\n if (!res.ok) {\n const text = await safeText(res)\n throw new Error(`Mail-Tester ${method} ${sanitize(path)} → ${res.status}: ${sanitize(text)}`)\n }\n return res.json()\n }\n\n return {\n async provisionCheck() {\n const data = await call('POST', '/new')\n const checkId = String(data.check_id ?? data.checkId ?? '')\n const emailAddress = String(data.email_address ?? data.email ?? '')\n if (!checkId || !emailAddress) throw new Error('Mail-Tester /new returned an unexpected shape')\n return { checkId, emailAddress }\n },\n async fetchResult(checkId) {\n const data = await call('GET', `/${encodeURIComponent(checkId)}`)\n // Ready is decided independently from score finiteness so a malformed\n // score number can't accidentally surface as `score: 0` and trip the\n // publish gate.\n const ready = Boolean(data.ready ?? data.complete ?? data.score != null)\n const scoreRaw = Number(data.score)\n const score = Number.isFinite(scoreRaw) ? scoreRaw : 0\n const feedback: MailTesterFeedback[] = Array.isArray(data.feedback)\n ? data.feedback.map(normalizeFeedback)\n : []\n const rawSummary = typeof data.summary === 'string' ? data.summary : null\n return { ready: ready && Number.isFinite(scoreRaw), score, feedback, rawSummary }\n },\n }\n}\n\nfunction normalizeFeedback(raw: any): MailTesterFeedback {\n const severity = String(raw.severity ?? 'info').toLowerCase()\n return {\n category: String(raw.category ?? 'other'),\n severity: severity === 'error' || severity === 'warning' || severity === 'info' ? severity : 'info',\n message: String(raw.message ?? ''),\n }\n}\n\nasync function safeText(res: Response): Promise<string> {\n try { return await res.text() } catch { return '<no body>' }\n}\n\n// ---------------------------------------------------------------------------\n// Content fingerprint + cache lookups\n// ---------------------------------------------------------------------------\n\nexport function mailTesterContentKey(input: { bodyHash: string; subject: string; fromEmail: string }): string {\n return crypto\n .createHash('sha256')\n .update(`${input.bodyHash}|${input.subject}|${input.fromEmail}`)\n .digest('hex')\n}\n\nexport async function findCachedScore(\n ctx: RunnerContext,\n contentKey: string,\n): Promise<MailTesterScoreDoc | null> {\n const doc = await ctx.collections.mailTesterScores.findOne({ contentKey })\n if (!doc) return null\n if (new Date(doc.expiresAt).getTime() < Date.now()) return null\n return doc\n}\n\nexport async function persistScore(\n ctx: RunnerContext,\n input: {\n templateSlug: string\n contentKey: string\n checkId: string\n result: MailTesterResult\n },\n): Promise<MailTesterScoreDoc> {\n const cfg = ctx.config.mailTester\n const hours = cfg?.cacheHours ?? 24\n const now = new Date()\n const expiresAt = new Date(now.getTime() + hours * 60 * 60 * 1000)\n const doc: MailTesterScoreDoc = {\n templateSlug: input.templateSlug,\n contentKey: input.contentKey,\n checkId: input.checkId,\n score: input.result.score,\n feedback: input.result.feedback,\n rawSummary: input.result.rawSummary,\n fetchedAt: now,\n expiresAt,\n }\n await ctx.collections.mailTesterScores.updateOne(\n { contentKey: input.contentKey },\n { $set: doc },\n { upsert: true },\n )\n return doc\n}\n\n// ---------------------------------------------------------------------------\n// Publish gate\n// ---------------------------------------------------------------------------\n\nexport interface MailTesterGateResult {\n allowed: boolean\n /** Reason for blocking. Null when allowed. */\n reason: string | null\n /** The cached score (if one exists for the content being published). */\n score: MailTesterScoreDoc | null\n /**\n * Why the gate blocked, for callers that render different guidance:\n * - 'low_score' — a score exists and is below minScore\n * - 'no_score' — requireScore is on and this content was never checked\n * Null when allowed.\n */\n code: 'low_score' | 'no_score' | null\n}\n\n/**\n * Check whether a publish is allowed under the Mail-Tester gate.\n *\n * Default mode (`requireScore` unset/false) blocks only content already known\n * to score below `minScore`. That is a ratchet on known-bad content, not a\n * gate: the content key covers body + subject + fromEmail, so any edit misses\n * the cache and publishes freely — a failing score is one whitespace change\n * away from irrelevant.\n *\n * With `requireScore: true`, a cache miss blocks too, so every publish is\n * backed by a score for that exact content. Costs one Mail-Tester credit per\n * content revision. Either mode is overridable per-request with\n * `bypassMailTester: true`.\n *\n * We never auto-trigger a check at publish time — that would send mail as a\n * side effect of a publish request.\n */\nexport async function evaluateMailTesterGate(\n ctx: RunnerContext,\n input: { bodyHash: string; subject: string; fromEmail: string },\n): Promise<MailTesterGateResult> {\n const cfg = ctx.config.mailTester\n if (!cfg?.apiKey) return { allowed: true, reason: null, score: null, code: null }\n\n const minScore = cfg.minScore ?? 8.0\n const key = mailTesterContentKey(input)\n const cached = await findCachedScore(ctx, key)\n\n if (!cached) {\n if (cfg.requireScore) {\n return {\n allowed: false,\n reason:\n 'No Mail-Tester score for this exact content. Run a deliverability check before publishing.',\n score: null,\n code: 'no_score',\n }\n }\n return { allowed: true, reason: null, score: null, code: null }\n }\n\n if (cached.score < minScore) {\n return {\n allowed: false,\n reason: `Mail-Tester score ${cached.score.toFixed(1)} is below minimum ${minScore.toFixed(1)}`,\n score: cached,\n code: 'low_score',\n }\n }\n return { allowed: true, reason: null, score: cached, code: null }\n}\n","/**\n * Async handler wrapper for the *public* router.\n *\n * The admin router's `asyncHandler` (`api/admin.ts`) is a plain `.catch(next)`,\n * which is right there: every admin handler computes first and responds last, so\n * a rejection always arrives before any header is written and Express can turn\n * it into a clean JSON 500.\n *\n * The public router cannot use that. `/open`, `/click` and `/webhooks` respond\n * *first* and do their work after — never make a mail client or a provider\n * wait on our database. By the time those handlers can reject,\n * `res.headersSent` is already true, and forwarding post-headers makes Express\n * destroy the socket underneath a response the client has already been\n * promised.\n *\n * (`POST /unsub` used to be in that list. It now awaits its write before\n * answering, because a response sent first can only ever report success —\n * see INVARIANT 8 and the route's own comment. It still needs this wrapper for\n * the pre-headers branch.)\n *\n * So this is a log-and-swallow wrapper, ported from featureboard's\n * `src/server/routes/wrap.js`, with one deliberate difference: featureboard\n * forwards with `next(err)` on the `headersSent` branch, and here that branch\n * only logs. See issue #5 — every public route is unauthenticated, and the\n * failure mode being fixed is precisely \"a rejected promise in a public route\n * takes down the host process\".\n */\n\nimport type { NextFunction, Request, RequestHandler, Response } from 'express'\n\n/**\n * Minimal structured-logger shape, compatible with pino/bunyan-style loggers\n * (`logger.error(fields, message)`). Every method is optional, so `{}` is a\n * valid silent logger and a bare `console` is not accidentally accepted with\n * mismatched argument order.\n */\nexport interface RouteLogger {\n error?: (fields: Record<string, unknown>, msg?: string) => void\n warn?: (fields: Record<string, unknown>, msg?: string) => void\n /**\n * Routine, high-volume telemetry — currently only \"an unsigned (pre-signing)\n * tracking URL was accepted in grace mode\", which is one line per legacy open\n * and is not a fault. Kept off `warn` deliberately so it can be routed or\n * dropped separately from things that are.\n */\n info?: (fields: Record<string, unknown>, msg?: string) => void\n}\n\n/**\n * Default logger — preserves the `console.error('mailery: …', details)` output\n * this package emitted before the `logger` option existed, so hosts that don't\n * pass one see no change.\n */\nexport const consoleRouteLogger: RouteLogger = {\n error(fields, msg) {\n console.error(msg ?? 'mailery: request failed', fields)\n },\n warn(fields, msg) {\n console.warn(msg ?? 'mailery: request warning', fields)\n },\n info(fields, msg) {\n console.info(msg ?? 'mailery: request', fields)\n },\n}\n\nexport type AsyncRouteHandler = (\n req: Request,\n res: Response,\n next: NextFunction,\n) => unknown | Promise<unknown>\n\n/**\n * Wrap a public route handler so a rejection can never become an unhandled\n * promise rejection (which, under Node's default `--unhandled-rejections=throw`,\n * takes the whole host application down — an unauthenticated DoS).\n *\n * Rejection handling:\n * - always log, with the request path\n * - headers already sent → swallow; the client has its response already\n * - otherwise → a plain 500\n */\nexport function wrap(logger: RouteLogger, handler: AsyncRouteHandler): RequestHandler {\n return async (req: Request, res: Response, next: NextFunction) => {\n try {\n await handler(req, res, next)\n } catch (err) {\n logger.error?.({ err, path: req.originalUrl }, 'mailery: request failed')\n if (res.headersSent) return\n res.status(500).json({ error: 'internal_error' })\n }\n }\n}\n","/**\n * Agent router — the mailery surface for automation.\n *\n * Everything an operator does by hand in the admin SPA to take an email\n * program from \"deployed\" to \"safely on\" — render a template as a real\n * contact and check it, send it through the real pipeline and watch delivery,\n * ask what a flow would do to a contact, walk a canary run step by step,\n * gate and arm a flow — is reachable here as JSON, behind a bearer token,\n * with no browser session. It is built for an AI agent or a CI job to drive,\n * which shapes three things:\n *\n * - Every answer is structured. A verification is a list of named checks\n * with pass/warn/fail, not a rendered page to squint at.\n * - Every operation that could touch a real person is guarded by the\n * `testContacts` pattern: test sends, event firing, run stepping and\n * resets only apply to contacts whose email matches it. A router with no\n * pattern configured refuses those routes outright rather than assuming.\n * - Nothing here can enable a flow without stamping its trigger watermark\n * (see runner/arm.ts), so an agent cannot replay a month of signups.\n *\n * Mount it beside the admin router, on a path the host's session middleware\n * does not cover, and give it the same JSON body the SPA would:\n *\n * app.use('/admin/mailer/agent', createAgentRouter(mailer, {\n * tokens: [{ token: process.env.MAILERY_AGENT_TOKEN!, actor: 'agent:claude' }],\n * testContacts: /^qa\\+.*@example\\.com$/i,\n * }))\n *\n * `GET /` describes every route so a client can discover the surface. The\n * full admin JSON API (docs/reference/admin-api.md) is mounted under `/api`\n * with the token's actor, so reads and existing operations need no second\n * auth path.\n */\n\nimport crypto from 'node:crypto'\nimport express, { Router, type NextFunction, type Request, type Response } from 'express'\nimport { ObjectId } from 'mongodb'\n\nimport type { Mailer } from '../mailer.js'\nimport type { Contact } from '../../shared/types.js'\nimport type { FlowRunDoc, SendDoc, TemplateDoc } from '../models/index.js'\nimport { HEALTH_AGG_ID } from '../models/index.js'\nimport { createAdminApiRouter, type AdminRouterOptions } from './admin.js'\nimport { runSetupChecks } from './setup-status.js'\nimport { consoleRouteLogger, type RouteLogger } from './wrap.js'\nimport { renderTemplate, type RenderedTemplate } from '../templates/render.js'\nimport { lintTemplate } from '../templates/linter.js'\nimport { validateSenderDomain } from '../templates/sender-domain.js'\nimport { resolveVars, varsJsonSchema, RESERVED_VAR_KEYS } from '../adapters/vars.js'\nimport { signUnsubscribeToken } from '../tokens.js'\nimport { effectiveOverallStatus } from '../runner/health.js'\nimport { runTick } from '../runner/tick.js'\nimport { dispatchSend } from '../runner/send.js'\nimport { processOneRunStep, exitFlowRun } from '../runner/step.js'\nimport {\n armFlow,\n disarmFlow,\n gateFlow,\n ungateFlow,\n isCanaryGate,\n FlowOperationError,\n} from '../runner/arm.js'\nimport { simulateFlow } from '../runner/simulate.js'\n\ndeclare const __PKG_VERSION__: string | undefined\nconst VERSION = typeof __PKG_VERSION__ === 'string' ? __PKG_VERSION__ : 'dev'\n\nexport interface AgentToken {\n /** The bearer token. At least 24 characters; generate it, never type it. */\n token: string\n /** Audit actor recorded for everything done with this token, e.g. `agent:claude`. */\n actor: string\n}\n\nexport interface AgentRouterOptions {\n /** Required. The router refuses to construct without at least one token. */\n tokens: AgentToken[]\n /**\n * Which contacts may be test-sent to, stepped through flows, fired events\n * for, or reset. A regular expression over the email address, or a\n * predicate. Routes that need it answer 403 when it is not configured —\n * the safe default for a surface an automated caller drives.\n */\n testContacts?: RegExp | ((email: string) => boolean)\n /** Structured logger for failures. Defaults to console. */\n logger?: RouteLogger\n /** Passed through to the admin JSON API (tests inject a stub). */\n mailTesterClient?: AdminRouterOptions['mailTesterClient']\n}\n\nexport const MIN_AGENT_TOKEN_LENGTH = 24\n\ntype Check = { id: string; status: 'pass' | 'warn' | 'fail'; detail?: unknown }\n\n// ---------------------------------------------------------------------------\n// Router\n// ---------------------------------------------------------------------------\n\nexport function createAgentRouter(mailer: Mailer, opts: AgentRouterOptions): Router {\n if (!opts || !Array.isArray(opts.tokens) || opts.tokens.length === 0) {\n throw new Error('createAgentRouter: at least one bearer token is required — the agent API is never open')\n }\n for (const t of opts.tokens) {\n if (typeof t?.token !== 'string' || t.token.length < MIN_AGENT_TOKEN_LENGTH) {\n throw new Error(\n `createAgentRouter: every token must be at least ${MIN_AGENT_TOKEN_LENGTH} characters (got ${t?.token?.length ?? 0})`,\n )\n }\n if (typeof t.actor !== 'string' || !t.actor.trim()) {\n throw new Error('createAgentRouter: every token needs an actor label, e.g. \"agent:claude\"')\n }\n }\n const logger = opts.logger ?? consoleRouteLogger\n const isTestContact = testContactMatcher(opts.testContacts)\n const c = mailer.collections\n const varsSchema = mailer.config.varsAdapter ? varsJsonSchema(mailer.config.varsAdapter) : null\n\n const router = Router()\n router.use(express.json({ limit: '1mb' }))\n router.use(bearerAuth(opts.tokens))\n\n // The admin JSON API, verbatim, with this token's actor.\n router.use('/api', createAdminApiRouter(mailer, { mailTesterClient: opts.mailTesterClient }))\n\n const actorOf = (req: Request): string => String((req as any).actor)\n\n /** 403 unless the contact matches `testContacts`. Responds itself. */\n function guardTestContact(res: Response, contact: Contact): boolean {\n if (!isTestContact) {\n res.status(403).json({\n error: 'test_contacts_not_configured',\n message:\n 'this route only acts on test contacts, and the router was constructed without a testContacts pattern',\n })\n return false\n }\n if (!isTestContact(contact.email)) {\n res.status(403).json({\n error: 'not_a_test_contact',\n message: `${contact.email} does not match the testContacts pattern`,\n externalId: contact.externalId,\n })\n return false\n }\n return true\n }\n\n async function loadContact(res: Response, externalId: string): Promise<Contact | null> {\n const contact = await mailer.adapter.getById(externalId)\n if (!contact) res.status(404).json({ error: 'contact_not_found', externalId })\n return contact\n }\n\n async function loadTemplate(res: Response, slug: string): Promise<TemplateDoc | null> {\n const tpl = await c.templates.findOne({ slug })\n if (!tpl) res.status(404).json({ error: 'template_not_found', slug })\n return tpl\n }\n\n // ----- Discovery -----------------------------------------------------------\n router.get('/', (req, res) => {\n res.json({\n service: 'mailery-agent',\n version: VERSION,\n actor: actorOf(req),\n testContactsConfigured: !!isTestContact,\n docs: 'https://jeffjassky.github.io/mailery/reference/agent-api',\n endpoints: ENDPOINTS,\n })\n })\n\n // ----- Templates: verify / render / real sends -----------------------------\n router.post(\n '/templates/:slug/verify',\n wrap(async (req, res) => {\n const tpl = await loadTemplate(res, String(req.params.slug))\n if (!tpl) return\n const contact = await contactForRender(req, res)\n if (!contact) return\n const report = await verifyTemplate(mailer, tpl, contact, {\n eventProperties: objectOrUndefined(req.body?.eventProperties),\n vars: objectOrUndefined(req.body?.vars),\n includeRendered: req.body?.includeRendered === true,\n varsSchema,\n })\n res.status(200).json(report)\n }),\n )\n\n router.post(\n '/templates/verify-all',\n wrap(async (req, res) => {\n const slugs: string[] | null = Array.isArray(req.body?.slugs) ? req.body.slugs.map(String) : null\n const contactIds: string[] = Array.isArray(req.body?.contactIds) ? req.body.contactIds.map(String) : []\n if (contactIds.length === 0) {\n return res.status(400).json({ error: 'validation_failed', message: 'contactIds (non-empty array) is required' })\n }\n const templates = await c.templates\n .find(slugs ? { slug: { $in: slugs } } : {})\n .sort({ slug: 1 })\n .toArray()\n const contacts: Contact[] = []\n for (const id of contactIds) {\n const found = await mailer.adapter.getById(id)\n if (!found) return res.status(404).json({ error: 'contact_not_found', externalId: id })\n contacts.push(found)\n }\n const results: Array<{\n slug: string\n contactId: string\n ok: boolean\n failed: string[]\n warned: string[]\n }> = []\n for (const tpl of templates) {\n for (const contact of contacts) {\n const report = await verifyTemplate(mailer, tpl, contact, {\n eventProperties: objectOrUndefined(req.body?.eventProperties),\n includeRendered: false,\n varsSchema,\n })\n results.push({\n slug: tpl.slug,\n contactId: contact.externalId,\n ok: report.ok,\n failed: report.checks.filter((k) => k.status === 'fail').map((k) => k.id),\n warned: report.checks.filter((k) => k.status === 'warn').map((k) => k.id),\n })\n }\n }\n const failing = results.filter((r) => !r.ok)\n res.json({\n ok: failing.length === 0,\n templates: templates.length,\n contacts: contacts.length,\n verified: results.length,\n failing: failing.length,\n results,\n })\n }),\n )\n\n router.post(\n '/templates/:slug/render',\n wrap(async (req, res) => {\n const tpl = await loadTemplate(res, String(req.params.slug))\n if (!tpl) return\n const contact = await contactForRender(req, res)\n if (!contact) return\n const out = await renderForContact(mailer, tpl, contact, {\n reason: 'preview',\n eventProperties: objectOrUndefined(req.body?.eventProperties),\n vars: objectOrUndefined(req.body?.vars),\n })\n res.json({\n template: { slug: tpl.slug, kind: tpl.kind },\n contact: { externalId: contact.externalId, email: contact.email },\n subject: out.rendered.subject,\n preheader: out.rendered.preheader,\n fromName: out.rendered.fromName,\n fromEmail: out.rendered.fromEmail,\n replyTo: out.rendered.replyTo,\n html: out.rendered.html,\n plainText: out.rendered.plainText,\n resolvedVars: out.resolved,\n unsubscribeUrl: out.unsubscribeUrl,\n })\n }),\n )\n\n /**\n * A REAL send: a `mailer_sends` row, the queue, the provider, tracking and\n * webhook attribution — everything a flow send gets — to a test contact.\n * This is how an automated check proves delivery end to end: send, then\n * `GET /sends/:id/wait?status=delivered`.\n */\n router.post(\n '/templates/:slug/send',\n wrap(async (req, res) => {\n const tpl = await loadTemplate(res, String(req.params.slug))\n if (!tpl) return\n const contactId = typeof req.body?.contactId === 'string' ? req.body.contactId : ''\n if (!contactId) return res.status(400).json({ error: 'validation_failed', message: 'contactId is required' })\n const contact = await loadContact(res, contactId)\n if (!contact) return\n if (!guardTestContact(res, contact)) return\n if (!tpl.body?.html && !tpl.body?.mjml) {\n return res.status(409).json({ error: 'not_published', message: 'template has no published body' })\n }\n const dedupeKey =\n typeof req.body?.dedupeKey === 'string' && req.body.dedupeKey ? String(req.body.dedupeKey) : `agent:${crypto.randomUUID()}`\n const { sendId } = await mailer.sendOneOff({\n templateSlug: tpl.slug,\n externalId: contact.externalId,\n dedupeKey,\n vars: objectOrUndefined(req.body?.vars),\n })\n const dispatchNow = req.body?.dispatch !== 'queue'\n if (dispatchNow) {\n await dispatchSend(new ObjectId(sendId), mailer.getRunnerContext())\n }\n const send = await c.sends.findOne({ _id: new ObjectId(sendId) })\n await mailer.audit({\n actor: actorOf(req),\n action: 'agent.send',\n resource: { collection: 'mailer_sends', id: new ObjectId(sendId), slug: tpl.slug },\n diffSummary: `to=${contact.email} dispatch=${dispatchNow ? 'now' : 'queue'} dedupeKey=${dedupeKey}`,\n })\n res.status(201).json({ sendId, dedupeKey, dispatched: dispatchNow, send: send ? sendSummary(send) : null })\n }),\n )\n\n // ----- Sends ------------------------------------------------------------------\n router.get(\n '/sends/:id/wait',\n wrap(async (req, res) => {\n const id = String(req.params.id)\n if (!ObjectId.isValid(id)) return res.status(400).json({ error: 'bad_id' })\n const target = String(req.query.status ?? 'delivered')\n if (!WAIT_TARGETS.has(target)) {\n return res.status(400).json({ error: 'validation_failed', message: `status must be one of ${[...WAIT_TARGETS].join(', ')}` })\n }\n const timeoutMs = Math.max(0, Math.min(Number(req.query.timeoutMs ?? 30_000) || 0, 55_000))\n const started = Date.now()\n let send: SendDoc | null = null\n let reached = false\n for (;;) {\n send = await c.sends.findOne({ _id: new ObjectId(id) })\n if (!send) return res.status(404).json({ error: 'not_found' })\n reached = waitTargetReached(send, target)\n if (reached || Date.now() - started >= timeoutMs) break\n await sleep(1000)\n }\n const webhookEvents = send.providerMessageId\n ? await c.webhookEvents.find({ providerMessageId: send.providerMessageId }).sort({ receivedAt: 1 }).limit(100).toArray()\n : []\n res.json({ reached, target, waitedMs: Date.now() - started, send: sendSummary(send), webhookEvents })\n }),\n )\n\n router.post(\n '/sends/:id/dispatch',\n wrap(async (req, res) => {\n const id = String(req.params.id)\n if (!ObjectId.isValid(id)) return res.status(400).json({ error: 'bad_id' })\n const send = await c.sends.findOne({ _id: new ObjectId(id) })\n if (!send) return res.status(404).json({ error: 'not_found' })\n const contact = await loadContact(res, send.externalId)\n if (!contact) return\n if (!guardTestContact(res, contact)) return\n await dispatchSend(send._id!, mailer.getRunnerContext())\n const after = await c.sends.findOne({ _id: send._id })\n res.json({ send: after ? sendSummary(after) : null })\n }),\n )\n\n // ----- Flows: simulate / arm / disarm / gate / ungate ----------------------------\n router.post(\n '/flows/:slug/simulate',\n wrap(async (req, res) => {\n const flow = await c.flows.findOne({ slug: String(req.params.slug) })\n if (!flow) return res.status(404).json({ error: 'flow_not_found', slug: String(req.params.slug) })\n const contactId = typeof req.body?.contactId === 'string' ? req.body.contactId : ''\n if (!contactId) return res.status(400).json({ error: 'validation_failed', message: 'contactId is required' })\n const contact = await loadContact(res, contactId)\n if (!contact) return\n let at: Date | undefined\n if (req.body?.at) {\n at = new Date(String(req.body.at))\n if (Number.isNaN(at.getTime())) return res.status(400).json({ error: 'validation_failed', message: 'at must be an ISO date' })\n }\n let steps = undefined as undefined | typeof flow.steps\n if (req.body?.version !== undefined) {\n const v = Number(req.body.version)\n if (v !== flow.version) {\n const snap = await c.flowVersions.findOne({ flowId: flow._id!, version: v })\n if (!snap) return res.status(404).json({ error: 'version_not_found', version: v })\n steps = snap.steps\n }\n }\n const result = await simulateFlow(flow, contact, mailer.getRunnerContext(), {\n at,\n eventProperties: objectOrUndefined(req.body?.eventProperties),\n steps,\n })\n res.json(result)\n }),\n )\n\n router.post(\n '/flows/:slug/arm',\n wrap(async (req, res) => {\n if (req.body?.confirm !== true) {\n return res.status(400).json({\n error: 'confirm_required',\n message: 'arming enables a flow for every future matching event; pass {\"confirm\": true}',\n })\n }\n let since: Date | undefined\n if (req.body?.since) {\n since = new Date(String(req.body.since))\n if (Number.isNaN(since.getTime())) return res.status(400).json({ error: 'validation_failed', message: 'since must be an ISO date' })\n }\n const result = await armFlow(mailer, String(req.params.slug), { actor: actorOf(req), since })\n res.json(result)\n }),\n )\n\n router.post(\n '/flows/:slug/disarm',\n wrap(async (req, res) => {\n res.json(await disarmFlow(mailer, String(req.params.slug), actorOf(req)))\n }),\n )\n\n router.post(\n '/flows/:slug/gate',\n wrap(async (req, res) => {\n const tag = typeof req.body?.tag === 'string' ? req.body.tag : ''\n res.json(await gateFlow(mailer, String(req.params.slug), { tag, actor: actorOf(req) }))\n }),\n )\n\n router.post(\n '/flows/:slug/ungate',\n wrap(async (req, res) => {\n res.json(await ungateFlow(mailer, String(req.params.slug), { actor: actorOf(req) }))\n }),\n )\n\n // ----- Runs: list / inspect / advance / cancel --------------------------------\n router.get(\n '/runs',\n wrap(async (req, res) => {\n const filter: Record<string, unknown> = {}\n if (typeof req.query.externalId === 'string') filter.externalId = req.query.externalId\n if (typeof req.query.flowSlug === 'string') filter.flowSlug = req.query.flowSlug\n if (typeof req.query.status === 'string') filter.status = req.query.status\n const limit = Math.min(Math.max(Number(req.query.limit ?? 50) || 50, 1), 200)\n const runs = await c.flowRuns.find(filter).sort({ enteredAt: -1 }).limit(limit).toArray()\n res.json(runs.map(runSummary))\n }),\n )\n\n router.get(\n '/runs/:id',\n wrap(async (req, res) => {\n const id = String(req.params.id)\n if (!ObjectId.isValid(id)) return res.status(400).json({ error: 'bad_id' })\n const run = await c.flowRuns.findOne({ _id: new ObjectId(id) })\n if (!run) return res.status(404).json({ error: 'not_found' })\n const sends = await c.sends.find({ flowRunId: run._id }).sort({ queuedAt: 1 }).toArray()\n res.json({ run, sends: sends.map(sendSummary) })\n }),\n )\n\n /**\n * Walk a run forward NOW, skipping the waits in front of each step. The\n * published timings stay exactly as they are — only this one run, for this\n * one test contact, is hurried. Each requested step is one actionable\n * transition (condition, branch, send, ...); a wait in the way is completed\n * immediately and does not count. Sends created on the way are dispatched\n * inline so the email actually leaves.\n */\n router.post(\n '/runs/:id/advance',\n wrap(async (req, res) => {\n const id = String(req.params.id)\n if (!ObjectId.isValid(id)) return res.status(400).json({ error: 'bad_id' })\n const run = await c.flowRuns.findOne({ _id: new ObjectId(id) })\n if (!run) return res.status(404).json({ error: 'not_found' })\n const contact = await loadContact(res, run.externalId)\n if (!contact) return\n if (!guardTestContact(res, contact)) return\n if (run.status !== 'active') {\n return res.status(409).json({ error: 'run_not_active', status: run.status, exitReason: run.exitReason })\n }\n const steps = Math.min(Math.max(Number(req.body?.steps ?? 1) || 1, 1), 50)\n const dispatch = req.body?.dispatch !== false\n const ctx = mailer.getRunnerContext()\n const startedAt = new Date()\n const historyBefore = run.history.length\n const actor = actorOf(req)\n\n for (let i = 0; i < steps; i += 1) {\n const advanced = await advanceOnce(run._id!, ctx, actor, c)\n if (!advanced) break\n }\n\n const after = await c.flowRuns.findOne({ _id: run._id })\n const newSends = await c.sends.find({ flowRunId: run._id, queuedAt: { $gte: startedAt } }).toArray()\n if (dispatch) {\n for (const s of newSends) {\n if (s.status === 'queued') await dispatchSend(s._id!, ctx)\n }\n }\n const sends = await c.sends.find({ flowRunId: run._id, queuedAt: { $gte: startedAt } }).toArray()\n await mailer.audit({\n actor,\n action: 'agent.run.advance',\n resource: { collection: 'mailer_flow_runs', id: run._id, slug: run.flowSlug },\n diffSummary: `advanced ${steps} step(s) for ${contact.email}; ${sends.length} send(s) created`,\n })\n res.json({\n run: after ? runSummary(after) : null,\n historyAdded: after ? after.history.slice(historyBefore) : [],\n sends: sends.map(sendSummary),\n })\n }),\n )\n\n router.post(\n '/runs/:id/cancel',\n wrap(async (req, res) => {\n const id = String(req.params.id)\n if (!ObjectId.isValid(id)) return res.status(400).json({ error: 'bad_id' })\n const run = await c.flowRuns.findOne({ _id: new ObjectId(id) })\n if (!run) return res.status(404).json({ error: 'not_found' })\n if (run.status !== 'active') return res.status(409).json({ error: 'run_not_active', status: run.status })\n const actor = actorOf(req)\n // The `aborted_by_host` prefix is what the dispatcher's aborted-run\n // guard looks for, so a send queued between here and its dispatch is\n // cancelled rather than sent.\n await exitFlowRun(run, `aborted_by_host:${actor}`, mailer.getRunnerContext())\n const cancelled = await c.sends.updateMany(\n { flowRunId: run._id, status: 'queued' },\n { $set: { status: 'cancelled', errorMessage: `cancelled: aborted_by_host:${actor}`, updatedAt: new Date() } },\n )\n await mailer.audit({\n actor,\n action: 'agent.run.cancel',\n resource: { collection: 'mailer_flow_runs', id: run._id, slug: run.flowSlug },\n diffSummary: `cancelled run for ${run.externalId}; ${cancelled.modifiedCount} queued send(s) cancelled`,\n })\n const after = await c.flowRuns.findOne({ _id: run._id })\n res.json({ run: after ? runSummary(after) : null, cancelledSends: cancelled.modifiedCount })\n }),\n )\n\n // ----- Events ---------------------------------------------------------------------\n router.post(\n '/events',\n wrap(async (req, res) => {\n const name = typeof req.body?.name === 'string' ? req.body.name : ''\n const externalId = typeof req.body?.externalId === 'string' ? req.body.externalId : ''\n if (!name || !externalId) {\n return res.status(400).json({ error: 'validation_failed', message: 'name and externalId are required' })\n }\n const contact = await loadContact(res, externalId)\n if (!contact) return\n if (!guardTestContact(res, contact)) return\n const dedupeKey = typeof req.body?.dedupeKey === 'string' && req.body.dedupeKey ? req.body.dedupeKey : undefined\n try {\n await mailer.fire(name, externalId, objectOrUndefined(req.body?.properties) ?? {}, dedupeKey)\n } catch (err: any) {\n return res.status(400).json({ error: 'fire_failed', message: String(err?.message ?? err) })\n }\n const latest = await c.events.findOne({ externalId, name }, { sort: { createdAt: -1 } })\n await mailer.audit({\n actor: actorOf(req),\n action: 'agent.event.fire',\n resource: { collection: 'mailer_events', id: latest?._id },\n diffSummary: `${name} for ${contact.email}${dedupeKey ? ` key=${dedupeKey}` : ''}`,\n })\n res.status(201).json({ ok: true, event: latest })\n }),\n )\n\n // ----- Contacts ------------------------------------------------------------------\n router.get(\n '/contacts/by-email/:email',\n wrap(async (req, res) => {\n const contact = await mailer.adapter.getByEmail(String(req.params.email).toLowerCase())\n if (!contact) return res.status(404).json({ error: 'contact_not_found', email: req.params.email })\n res.json(await contactDetail(contact))\n }),\n )\n\n router.get(\n '/contacts/:externalId',\n wrap(async (req, res) => {\n const contact = await loadContact(res, String(req.params.externalId))\n if (!contact) return\n res.json(await contactDetail(contact))\n }),\n )\n\n router.get(\n '/contacts/:externalId/unsubscribe-url',\n wrap(async (req, res) => {\n const contact = await loadContact(res, String(req.params.externalId))\n if (!contact) return\n if (!guardTestContact(res, contact)) return\n res.json({ contact: { externalId: contact.externalId, email: contact.email }, unsubscribeUrl: unsubscribeUrlFor(mailer, contact.email) })\n }),\n )\n\n router.post(\n '/contacts/:externalId/subscribe',\n wrap(async (req, res) => {\n const contact = await loadContact(res, String(req.params.externalId))\n if (!contact) return\n if (!guardTestContact(res, contact)) return\n await mailer.upsertSubscription({ externalId: contact.externalId, source: 'agent' })\n const sub = await c.subscriptions.findOne({ externalId: contact.externalId })\n await mailer.audit({\n actor: actorOf(req),\n action: 'agent.contact.subscribe',\n resource: { collection: 'mailer_subscriptions', id: sub?._id },\n diffSummary: contact.email,\n })\n res.json({ subscription: sub })\n }),\n )\n\n router.post(\n '/contacts/:externalId/unsubscribe',\n wrap(async (req, res) => {\n const contact = await loadContact(res, String(req.params.externalId))\n if (!contact) return\n if (!guardTestContact(res, contact)) return\n await mailer.unsubscribe(contact.email, { scope: 'marketing', reason: 'user_request', source: 'agent' })\n const sub = await c.subscriptions.findOne({ externalId: contact.externalId })\n await mailer.audit({\n actor: actorOf(req),\n action: 'agent.contact.unsubscribe',\n resource: { collection: 'mailer_subscriptions', id: sub?._id },\n diffSummary: contact.email,\n })\n res.json({ subscription: sub })\n }),\n )\n\n /**\n * Put a test contact back to \"never seen\": runs, sends, events and\n * suppressions gone, subscription restored. This is what makes a\n * `trigger.once` flow re-testable with the same address.\n */\n router.post(\n '/contacts/:externalId/reset',\n wrap(async (req, res) => {\n const contact = await loadContact(res, String(req.params.externalId))\n if (!contact) return\n if (!guardTestContact(res, contact)) return\n const b = req.body ?? {}\n const eventFilter: Record<string, unknown> = { externalId: contact.externalId }\n if (Array.isArray(b.events)) eventFilter.name = { $in: b.events.map(String) }\n const doRuns = b.runs !== false\n const doSends = b.sends !== false\n const doEvents = b.events !== false\n const doSuppressions = b.suppressions !== false\n const doSubscribe = b.subscribe !== false\n\n const removed = { runs: 0, sends: 0, events: 0, suppressions: 0 }\n if (doRuns) removed.runs = (await c.flowRuns.deleteMany({ externalId: contact.externalId })).deletedCount\n if (doSends) removed.sends = (await c.sends.deleteMany({ externalId: contact.externalId })).deletedCount\n if (doEvents) removed.events = (await c.events.deleteMany(eventFilter as any)).deletedCount\n if (doSuppressions) removed.suppressions = (await c.suppressions.deleteMany({ email: contact.email })).deletedCount\n if (doSubscribe) await mailer.upsertSubscription({ externalId: contact.externalId, source: 'agent-reset' })\n const subscription = await c.subscriptions.findOne({ externalId: contact.externalId })\n await mailer.audit({\n actor: actorOf(req),\n action: 'agent.contact.reset',\n resource: { collection: 'mailer_subscriptions', id: subscription?._id },\n diffSummary: `${contact.email}: removed ${removed.runs} run(s), ${removed.sends} send(s), ${removed.events} event(s), ${removed.suppressions} suppression(s)${doSubscribe ? '; resubscribed' : ''}`,\n })\n res.json({ contact: { externalId: contact.externalId, email: contact.email }, removed, subscription })\n }),\n )\n\n // ----- Runner + status ---------------------------------------------------------------\n router.post(\n '/tick',\n wrap(async (_req, res) => {\n const started = Date.now()\n await runTick(mailer.getRunnerContext())\n res.json({ ok: true, ms: Date.now() - started })\n }),\n )\n\n router.get(\n '/webhooks/status',\n wrap(async (_req, res) => {\n const dayAgo = new Date(Date.now() - 24 * 60 * 60 * 1000)\n const weekAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000)\n const [last, byType24h, total7d, unprocessed] = await Promise.all([\n c.webhookEvents.findOne({}, { sort: { receivedAt: -1 }, projection: { receivedAt: 1, provider: 1, normalizedType: 1 } }),\n c.webhookEvents\n .aggregate<{ _id: string; n: number }>([{ $match: { receivedAt: { $gte: dayAgo } } }, { $group: { _id: '$normalizedType', n: { $sum: 1 } } }])\n .toArray(),\n c.webhookEvents.countDocuments({ receivedAt: { $gte: weekAgo } }),\n c.webhookEvents.countDocuments({ processed: false }),\n ])\n res.json({\n providers: Object.keys(mailer.providers),\n lastReceivedAt: last?.receivedAt ?? null,\n lastProvider: last?.provider ?? null,\n last24h: Object.fromEntries(byType24h.map((r) => [r._id, r.n])),\n last7d: total7d,\n unprocessed,\n ingestPath: `${mailer.config.publicUrl}/m/webhooks/<provider>`,\n })\n }),\n )\n\n router.get(\n '/status',\n wrap(async (_req, res) => {\n const dayAgo = new Date(Date.now() - 24 * 60 * 60 * 1000)\n const [flows, templates, subscribed, suppressions, activeRuns, sends24h, webhooks24h, lastWebhook, healthDocs, setup] =\n await Promise.all([\n c.flows.find({}, { projection: { slug: 1, enabled: 1, version: 1, lastTriggerScanAt: 1, steps: 1, trigger: 1 } }).sort({ slug: 1 }).toArray(),\n c.templates.find({}, { projection: { slug: 1, kind: 1, publishedAt: 1, 'body.html': 1, fromEmail: 1 } }).sort({ slug: 1 }).toArray(),\n c.subscriptions.countDocuments({ status: 'subscribed' }),\n c.suppressions.estimatedDocumentCount(),\n c.flowRuns.countDocuments({ status: 'active' }),\n c.sends.aggregate<{ _id: string; n: number }>([{ $match: { queuedAt: { $gte: dayAgo } } }, { $group: { _id: '$status', n: { $sum: 1 } } }]).toArray(),\n c.webhookEvents.countDocuments({ receivedAt: { $gte: dayAgo } }),\n c.webhookEvents.findOne({}, { sort: { receivedAt: -1 }, projection: { receivedAt: 1 } }),\n c.health.find({}).limit(500).toArray(),\n runSetupChecks(mailer),\n ])\n const activeByFlow = await c.flowRuns\n .aggregate<{ _id: string; n: number }>([{ $match: { status: 'active' } }, { $group: { _id: '$flowSlug', n: { $sum: 1 } } }])\n .toArray()\n const activeMap = new Map(activeByFlow.map((r) => [r._id, r.n]))\n res.json({\n version: VERSION,\n now: new Date(),\n testContactsConfigured: !!isTestContact,\n setup: setup,\n health: { status: healthDocs.length ? effectiveOverallStatus(healthDocs) : null, aggregate: healthDocs.find((d) => d._id === HEALTH_AGG_ID) ?? null },\n flows: flows.map((f) => ({\n slug: f.slug,\n enabled: f.enabled,\n version: f.version,\n lastTriggerScanAt: f.lastTriggerScanAt ?? null,\n trigger: f.trigger,\n liveSteps: Array.isArray(f.steps) ? f.steps.length : 0,\n gated: Array.isArray(f.steps) && isCanaryGate(f.steps[0]) ? (f.steps[0] as any).test.hasTag : null,\n activeRuns: activeMap.get(f.slug) ?? 0,\n })),\n templates: templates.map((t) => ({\n slug: t.slug,\n kind: t.kind,\n fromEmail: t.fromEmail,\n published: !!(t.body && t.body.html),\n publishedAt: t.publishedAt ?? null,\n })),\n counts: {\n subscribed,\n suppressions,\n activeRuns,\n sendsLast24h: Object.fromEntries(sends24h.map((r) => [r._id, r.n])),\n webhookEventsLast24h: webhooks24h,\n lastWebhookAt: lastWebhook?.receivedAt ?? null,\n },\n })\n }),\n )\n\n // ----- Tail ----------------------------------------------------------------------------\n router.use((req: Request, res: Response) => {\n res.status(404).json({ error: 'not_found', message: `no agent route ${req.method} ${req.path}; GET / lists them` })\n })\n router.use((err: any, req: Request, res: Response, _next: NextFunction) => {\n if (err instanceof FlowOperationError) {\n return res.status(err.status).json({ error: err.code, message: err.message })\n }\n if (err?.name === 'ZodError') {\n return res.status(400).json({ error: 'validation_failed', issues: err.issues })\n }\n logger.error?.({ err: String(err?.message ?? err), path: req.path, method: req.method }, 'mailery agent: request failed')\n if (res.headersSent) return\n res.status(500).json({ error: 'internal', message: String(err?.message ?? err) })\n })\n\n return router\n\n // ----- local helpers that need closure state -------------------------------------------\n async function contactForRender(req: Request, res: Response): Promise<Contact | null> {\n const contactId = typeof req.body?.contactId === 'string' ? req.body.contactId : ''\n if (contactId) return loadContact(res, contactId)\n const sample = req.body?.sampleContact\n if (sample && typeof sample === 'object' && typeof sample.email === 'string') {\n return {\n externalId: String(sample.externalId ?? 'sample-contact'),\n email: sample.email,\n tags: Array.isArray(sample.tags) ? sample.tags.map(String) : [],\n fields: sample.fields && typeof sample.fields === 'object' ? sample.fields : {},\n timezone: typeof sample.timezone === 'string' ? sample.timezone : undefined,\n }\n }\n res.status(400).json({ error: 'validation_failed', message: 'contactId (or a sampleContact with an email) is required' })\n return null\n }\n\n async function contactDetail(contact: Contact) {\n const [subscription, recentEvents, recentSends, runs, suppressions] = await Promise.all([\n c.subscriptions.findOne({ externalId: contact.externalId }),\n c.events.find({ externalId: contact.externalId }).sort({ occurredAt: -1 }).limit(50).toArray(),\n c.sends.find({ externalId: contact.externalId }).sort({ queuedAt: -1 }).limit(50).toArray(),\n c.flowRuns.find({ externalId: contact.externalId }).sort({ enteredAt: -1 }).limit(50).toArray(),\n c.suppressions.find({ email: contact.email }).toArray(),\n ])\n return {\n contact,\n isTestContact: isTestContact ? isTestContact(contact.email) : null,\n subscription,\n suppressions,\n recentEvents,\n recentSends: recentSends.map(sendSummary),\n runs: runs.map(runSummary),\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Verification\n// ---------------------------------------------------------------------------\n\nexport interface VerifyOptions {\n eventProperties?: Record<string, unknown>\n vars?: Record<string, unknown>\n includeRendered?: boolean\n varsSchema?: Record<string, unknown> | null\n}\n\nexport interface VerifyReport {\n ok: boolean\n template: { slug: string; kind: TemplateDoc['kind']; name: string }\n contact: { externalId: string; email: string }\n checks: Check[]\n links: { total: number; sample: string[] }\n rendered:\n | { subject: string; preheader: string; htmlBytes: number; textLength: number; fromEmail: string }\n | { subject: string; preheader: string; html: string; plainText: string; fromEmail: string; fromName: string; replyTo: string | null }\n | null\n}\n\n/** Anything Handlebars left behind: `{{x}}`, `{{#if}}`, `{{{y}}}`. */\nconst PLACEHOLDER_RE = /\\{\\{[^{}]*\\}\\}|\\{\\{\\{[^{}]*\\}\\}\\}/g\nconst HREF_RE = /href\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)')/gi\nconst GMAIL_CLIP_BYTES = 102 * 1024\n\nexport async function verifyTemplate(\n mailer: Mailer,\n tpl: TemplateDoc,\n contact: Contact,\n opts: VerifyOptions = {},\n): Promise<VerifyReport> {\n const checks: Check[] = []\n const push = (id: string, status: Check['status'], detail?: unknown) =>\n checks.push(detail === undefined ? { id, status } : { id, status, detail })\n const base = {\n template: { slug: tpl.slug, kind: tpl.kind, name: tpl.name },\n contact: { externalId: contact.externalId, email: contact.email },\n }\n const finish = (rendered: RenderedTemplate | null, links: string[]): VerifyReport => ({\n ok: checks.every((k) => k.status !== 'fail'),\n ...base,\n checks,\n links: { total: links.length, sample: links.slice(0, 50) },\n rendered: rendered\n ? opts.includeRendered\n ? {\n subject: rendered.subject,\n preheader: rendered.preheader,\n html: rendered.html,\n plainText: rendered.plainText,\n fromEmail: rendered.fromEmail,\n fromName: rendered.fromName,\n replyTo: rendered.replyTo,\n }\n : {\n subject: rendered.subject,\n preheader: rendered.preheader,\n htmlBytes: Buffer.byteLength(rendered.html, 'utf8'),\n textLength: rendered.plainText.trim().length,\n fromEmail: rendered.fromEmail,\n }\n : null,\n })\n\n if (!tpl.body?.html && !tpl.body?.mjml) {\n push('published', 'fail', 'template has no published body (body.html and body.mjml are empty)')\n return finish(null, [])\n }\n push('published', 'pass', { publishedAt: tpl.publishedAt ?? null })\n\n let out: Awaited<ReturnType<typeof renderForContact>>\n try {\n out = await renderForContact(mailer, tpl, contact, {\n reason: 'test',\n eventProperties: opts.eventProperties,\n vars: opts.vars,\n })\n push('vars_resolved', 'pass', { keys: Object.keys(out.resolved) })\n push('render', 'pass')\n } catch (err: any) {\n const message = String(err?.message ?? err)\n push(message.startsWith('varsAdapter') ? 'vars_resolved' : 'render', 'fail', message)\n return finish(null, [])\n }\n const { rendered, unsubscribeUrl } = out\n\n const leftovers = new Set<string>()\n for (const part of [rendered.subject, rendered.preheader, rendered.html, rendered.plainText]) {\n for (const m of part.matchAll(PLACEHOLDER_RE)) leftovers.add(m[0])\n }\n push('unresolved_placeholders', leftovers.size ? 'fail' : 'pass', leftovers.size ? { placeholders: [...leftovers] } : undefined)\n\n // Handlebars renders an unknown path as an EMPTY STRING — no braces are\n // left behind, nothing throws, the recipient just gets a blank where a\n // price or a name should be. So the check that catches this class compares\n // every path the template source references against the object it was\n // actually rendered with.\n const referenced = referencedPaths(\n [tpl.subject, tpl.preheader, tpl.body.html, tpl.body.plainText, tpl.body.mjml ?? ''].join('\\n'),\n Object.keys(mailer.config.handlebarsHelpers ?? {}),\n )\n const missing: string[] = []\n const empty: string[] = []\n for (const path of referenced) {\n const value = lookupPath(out.context, path)\n if (value === undefined) {\n // Reserved render-context keys the package declares but does not yet\n // populate (viewInBrowserUrl, preferenceCenterUrl) render blank by\n // design; that is worth a warning, not a failure.\n const root = path.split('.')[0]!\n if ((RESERVED_VAR_KEYS as readonly string[]).includes(root)) empty.push(path)\n else missing.push(path)\n } else if (value === null || value === '') {\n empty.push(path)\n }\n }\n push('unknown_variables', missing.length ? 'fail' : 'pass', { referenced: referenced.length, missing })\n push('empty_variables', empty.length ? 'warn' : 'pass', { empty })\n\n const links = extractLinks(rendered.html)\n const invalid = links.filter((l) => !/^(https?:\\/\\/|mailto:|tel:)/i.test(l))\n push('links_absolute', invalid.length ? 'fail' : 'pass', { total: links.length, invalid })\n\n if (tpl.kind === 'marketing') {\n push('unsubscribe_link', rendered.html.includes(unsubscribeUrl) ? 'pass' : 'fail', {\n hint: 'a marketing template must reference {{unsubscribeUrl}} in its body',\n })\n if (mailer.config.senderAddress) {\n push('sender_address', rendered.html.includes(mailer.config.senderAddress) ? 'pass' : 'fail', {\n hint: 'CAN-SPAM: reference {{senderAddress}} in the footer',\n })\n }\n }\n\n const text = rendered.plainText.trim()\n push('plain_text', text.length === 0 ? 'fail' : text.length < 40 ? 'warn' : 'pass', { length: text.length })\n\n const subject = rendered.subject.trim()\n push('subject', subject.length === 0 ? 'fail' : subject.length > 78 ? 'warn' : 'pass', { length: subject.length })\n\n if (mailer.config.senderDomains && Object.keys(mailer.config.senderDomains).length > 0) {\n const v = validateSenderDomain(rendered.fromEmail, tpl.kind, mailer.config.senderDomains)\n push('from_domain', v.ok ? 'pass' : 'fail', v.ok ? { fromEmail: rendered.fromEmail } : { fromEmail: rendered.fromEmail, code: v.code, reason: v.reason })\n }\n\n const bytes = Buffer.byteLength(rendered.html, 'utf8')\n push('html_size', bytes > GMAIL_CLIP_BYTES ? 'warn' : 'pass', { bytes, clipAt: GMAIL_CLIP_BYTES })\n\n const lint = lintTemplate(\n {\n subject: tpl.subject,\n preheader: tpl.preheader,\n mjml: tpl.body.mjml ?? '',\n editorJson: tpl.body.editorJson ?? undefined,\n html: tpl.body.html,\n plainText: tpl.body.plainText,\n kind: tpl.kind,\n fromEmail: tpl.fromEmail,\n },\n { senderDomains: mailer.config.senderDomains, varsJsonSchema: opts.varsSchema ?? null },\n )\n push('lint', lint.errors.length ? 'fail' : lint.warnings.length ? 'warn' : 'pass', {\n errors: lint.errors.map((i) => ({ rule: i.rule, message: i.message })),\n warnings: lint.warnings.map((i) => i.rule),\n })\n\n return finish(rendered, links)\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\ninterface RenderForContactOptions {\n reason: 'preview' | 'test'\n eventProperties?: Record<string, unknown>\n vars?: Record<string, unknown>\n}\n\n/**\n * Render a published template for one real contact the way a send would:\n * host vars resolved through the varsAdapter, the contact at the root, a\n * genuinely signed unsubscribe URL. The one difference from a send is that\n * no tracking is applied — nothing here is queued.\n */\nexport async function renderForContact(\n mailer: Mailer,\n tpl: TemplateDoc,\n contact: Contact,\n opts: RenderForContactOptions,\n): Promise<{\n rendered: RenderedTemplate\n resolved: Record<string, unknown>\n unsubscribeUrl: string\n /** The exact object the template was rendered against. */\n context: Record<string, unknown>\n}> {\n let resolved: Record<string, unknown>\n try {\n resolved = await resolveVars(mailer.config.varsAdapter, contact, {\n reason: opts.reason,\n templateSlug: tpl.slug,\n eventProperties: opts.eventProperties,\n })\n } catch (err: any) {\n throw new Error(`varsAdapter.resolve threw: ${String(err?.message ?? err)}`)\n }\n const unsubscribeUrl = unsubscribeUrlFor(mailer, contact.email)\n const context = {\n ...resolved,\n contact,\n vars: opts.vars ?? {},\n event: opts.eventProperties ?? {},\n unsubscribeUrl,\n senderAddress: mailer.config.senderAddress,\n }\n const rendered = await renderTemplate(tpl, context, { helpers: mailer.config.handlebarsHelpers })\n return { rendered, resolved, unsubscribeUrl, context }\n}\n\nexport function unsubscribeUrlFor(mailer: Mailer, email: string): string {\n const expiresAt = new Date(Date.now() + mailer.config.unsubscribeTokenLifetimeDays * 24 * 60 * 60 * 1000)\n const token = signUnsubscribeToken({ email, scope: 'marketing', expiresAt }, mailer.config.unsubscribeSecret)\n return `${mailer.config.publicUrl}/m/unsub/${token}`\n}\n\nexport function extractLinks(html: string): string[] {\n const out: string[] = []\n for (const m of html.matchAll(HREF_RE)) {\n const href = (m[1] ?? m[2] ?? '').trim()\n if (!href || href.startsWith('#')) continue\n out.push(href)\n }\n return out\n}\n\nconst BUILTIN_HELPERS = new Set([\n 'eq', 'ne', 'gt', 'lt', 'gte', 'lte', 'and', 'or', 'not',\n 'formatDate', 'formatNumber', 'formatCurrency', 'pluralize',\n 'if', 'unless', 'each', 'with', 'else', 'lookup', 'log', 'this',\n 'true', 'false', 'null', 'undefined',\n])\nconst MUSTACHE_RE = /\\{\\{\\{?([^{}]*)\\}\\}\\}?/g\nconst BLOCK_SCOPE_RE = /\\{\\{#(each|with)\\b[\\s\\S]*?\\{\\{\\/\\1\\}\\}/g\nconst HTML_COMMENT_RE = /<!--[\\s\\S]*?-->/g\nconst PATH_RE = /^[A-Za-z_$][\\w$]*(?:\\.[A-Za-z_$][\\w$]*)*$/\n\n/**\n * Every dotted path a Handlebars source references outside `#each`/`#with`\n * blocks (whose paths are relative to the iterated item and cannot be\n * resolved against the root context) and outside HTML comments. Helper\n * names, literals, hash keys, `@data` variables and Handlebars comments are\n * skipped.\n */\nexport function referencedPaths(source: string, helperNames: Iterable<string> = []): string[] {\n const helpers = new Set([...BUILTIN_HELPERS, ...helperNames])\n const out = new Set<string>()\n // An HTML comment is rendered too, but nothing in it reaches a reader, so\n // a placeholder mentioned there is documentation, not a reference.\n const scanned = source.replace(HTML_COMMENT_RE, '').replace(BLOCK_SCOPE_RE, '')\n for (const m of scanned.matchAll(MUSTACHE_RE)) {\n let expr = (m[1] ?? '').trim()\n if (!expr || expr.startsWith('!')) continue\n expr = expr.replace(/^[#/^]\\s*/, '').replace(/^else\\b\\s*/, '')\n for (let tok of expr.split(/[\\s()]+/)) {\n if (!tok) continue\n const eq = tok.indexOf('=')\n if (eq > 0) tok = tok.slice(eq + 1)\n if (/^['\"]/.test(tok) || /^-?\\d/.test(tok)) continue\n if (tok.startsWith('@') || tok.startsWith('../') || tok.startsWith('this.')) continue\n if (helpers.has(tok) || !PATH_RE.test(tok)) continue\n out.add(tok)\n }\n }\n return [...out]\n}\n\nexport function lookupPath(ctx: Record<string, unknown>, path: string): unknown {\n let cur: unknown = ctx\n for (const part of path.split('.')) {\n if (cur === null || typeof cur !== 'object') return undefined\n cur = (cur as Record<string, unknown>)[part]\n }\n return cur\n}\n\nfunction testContactMatcher(spec: AgentRouterOptions['testContacts']): ((email: string) => boolean) | null {\n if (!spec) return null\n if (spec instanceof RegExp) return (email) => spec.test(email)\n if (typeof spec === 'function') return (email) => !!spec(email)\n return null\n}\n\nfunction bearerAuth(tokens: AgentToken[]) {\n const hashed = tokens.map((t) => ({ hash: crypto.createHash('sha256').update(t.token).digest(), actor: t.actor }))\n return (req: Request, res: Response, next: NextFunction) => {\n const header = String(req.headers.authorization ?? '')\n const m = /^Bearer\\s+(\\S+)\\s*$/i.exec(header)\n if (!m) {\n return res.status(401).json({ error: 'unauthorized', message: 'send Authorization: Bearer <token>' })\n }\n const presented = crypto.createHash('sha256').update(m[1] ?? '').digest()\n const match = hashed.find((h) => crypto.timingSafeEqual(h.hash, presented))\n if (!match) return res.status(401).json({ error: 'unauthorized', message: 'unknown token' })\n ;(req as any).actor = match.actor\n next()\n }\n}\n\n/**\n * One actionable transition for a run: complete the wait in front of it, if\n * any, then process the step. Returns false once the run is no longer active.\n */\nasync function advanceOnce(\n runId: ObjectId,\n ctx: ReturnType<Mailer['getRunnerContext']>,\n actor: string,\n c: Mailer['collections'],\n): Promise<boolean> {\n for (let hop = 0; hop < 10; hop += 1) {\n const run = await c.flowRuns.findOne({ _id: runId })\n if (!run || run.status !== 'active') return false\n if (run.nextActionAt && run.nextActionAt.getTime() > Date.now()) {\n await c.flowRuns.updateOne(\n { _id: runId, status: 'active' },\n {\n $set: { nextActionAt: new Date(), updatedAt: new Date() },\n $push: {\n history: {\n stepIndex: Math.max(0, run.currentStepIndex - 1),\n action: 'wait_completed',\n at: new Date(),\n details: { forcedBy: actor, scheduledFor: run.nextActionAt },\n },\n },\n },\n )\n }\n const before = (await c.flowRuns.findOne({ _id: runId }))?.history.length ?? 0\n await processOneRunStep(runId, ctx)\n const after = await c.flowRuns.findOne({ _id: runId })\n if (!after) return false\n const last = after.history[after.history.length - 1]\n const progressed = after.history.length > before\n // A wait that just started is not the transition the caller asked for;\n // loop once more to complete it and process what follows.\n if (progressed && last?.action === 'wait_started' && after.status === 'active') continue\n return after.status === 'active' && progressed\n }\n return false\n}\n\nconst WAIT_TARGETS = new Set(['sent', 'delivered', 'opened', 'clicked', 'terminal'])\n\nfunction waitTargetReached(send: SendDoc, target: string): boolean {\n switch (target) {\n case 'sent':\n return send.status === 'sent' || send.status === 'delivered' || !!send.sentAt\n case 'delivered':\n return send.status === 'delivered' || !!send.deliveredAt\n case 'opened':\n return !!send.openedAt\n case 'clicked':\n return !!send.firstClickAt\n case 'terminal':\n return ['delivered', 'bounced', 'failed', 'suppressed', 'cancelled', 'complained'].includes(send.status)\n default:\n return false\n }\n}\n\nfunction sendSummary(s: SendDoc) {\n return {\n id: String(s._id),\n templateSlug: s.templateSlug,\n externalId: s.externalId,\n email: s.emailAtSend,\n kind: s.kind,\n status: s.status,\n provider: s.provider,\n providerMessageId: s.providerMessageId,\n subject: s.subject,\n errorMessage: s.errorMessage,\n flowRunId: s.flowRunId ? String(s.flowRunId) : null,\n queuedAt: s.queuedAt,\n sentAt: s.sentAt,\n deliveredAt: s.deliveredAt,\n openedAt: s.openedAt,\n firstClickAt: s.firstClickAt,\n bounceType: s.bounceType,\n }\n}\n\nfunction runSummary(r: FlowRunDoc) {\n return {\n id: String(r._id),\n flowSlug: r.flowSlug,\n flowVersion: r.flowVersion,\n externalId: r.externalId,\n email: r.emailAtEntry,\n status: r.status,\n currentStepIndex: r.currentStepIndex,\n currentBranchPath: r.currentBranchPath,\n nextActionAt: r.nextActionAt,\n enteredAt: r.enteredAt,\n exitedAt: r.exitedAt,\n exitReason: r.exitReason,\n triggerEvent: r.triggerEvent ?? null,\n history: r.history,\n }\n}\n\nfunction objectOrUndefined(v: unknown): Record<string, unknown> | undefined {\n return v && typeof v === 'object' && !Array.isArray(v) ? (v as Record<string, unknown>) : undefined\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms))\n}\n\ntype Handler = (req: Request, res: Response) => Promise<unknown> | unknown\nfunction wrap(fn: Handler) {\n return (req: Request, res: Response, next: NextFunction) => {\n Promise.resolve(fn(req, res)).catch(next)\n }\n}\n\nconst ENDPOINTS: Array<{ method: string; path: string; summary: string; testContactsOnly?: boolean }> = [\n { method: 'GET', path: '/', summary: 'This listing, the package version and the actor behind the token.' },\n { method: '*', path: '/api/*', summary: 'The full admin JSON API (flows, templates, contacts, sends, health, setup-status, …) with this token as the actor.' },\n { method: 'POST', path: '/templates/:slug/verify', summary: 'Render the published template as a contact ({contactId} or {sampleContact}) and run named checks: placeholders, links, unsubscribe, sender address, plain text, subject, from domain, size, lint. {includeRendered: true} returns the HTML.' },\n { method: 'POST', path: '/templates/verify-all', summary: 'Verify every template (or {slugs}) for each of {contactIds}; a matrix of pass/fail.' },\n { method: 'POST', path: '/templates/:slug/render', summary: 'Render for a contact and return subject, preheader, HTML, plain text, resolved vars and the signed unsubscribe URL.' },\n { method: 'POST', path: '/templates/:slug/send', summary: 'A real send through the pipeline to a test contact ({contactId}); dispatched inline unless {dispatch: \"queue\"}. Returns the sendId.', testContactsOnly: true },\n { method: 'GET', path: '/sends/:id/wait?status=delivered&timeoutMs=30000', summary: 'Long-poll a send until it reaches sent | delivered | opened | clicked | terminal, with its webhook events.' },\n { method: 'POST', path: '/sends/:id/dispatch', summary: 'Dispatch a queued send now (test contacts only).', testContactsOnly: true },\n { method: 'POST', path: '/flows/:slug/simulate', summary: 'Dry-run the flow for {contactId} from {at} with {eventProperties}: the path taken, every gate verdict, projected send times, where it ends. Writes nothing.' },\n { method: 'POST', path: '/flows/:slug/arm', summary: 'Enable the flow for FUTURE events: stamps the trigger watermark ({since} or now) in the same write. Requires {confirm: true}.' },\n { method: 'POST', path: '/flows/:slug/disarm', summary: 'Disable the flow (pause). In-flight runs continue.' },\n { method: 'POST', path: '/flows/:slug/gate', summary: 'Publish a canary version whose first step exits anyone without {tag}.' },\n { method: 'POST', path: '/flows/:slug/ungate', summary: 'Restore the newest ungated version.' },\n { method: 'GET', path: '/runs?externalId=&flowSlug=&status=&limit=', summary: 'List flow runs.' },\n { method: 'GET', path: '/runs/:id', summary: 'One run with its history and sends.' },\n { method: 'POST', path: '/runs/:id/advance', summary: 'Walk a test contact\\'s run forward now, skipping the wait in front of each of {steps} transitions; sends are dispatched inline.', testContactsOnly: true },\n { method: 'POST', path: '/runs/:id/cancel', summary: 'Exit an active run and cancel its queued sends.' },\n { method: 'POST', path: '/events', summary: 'Fire {name} for a test contact {externalId} with {properties} and optional {dedupeKey}.', testContactsOnly: true },\n { method: 'GET', path: '/contacts/:externalId', summary: 'Contact with subscription, suppressions, recent events, sends and runs.' },\n { method: 'GET', path: '/contacts/by-email/:email', summary: 'Same, looked up by email.' },\n { method: 'GET', path: '/contacts/:externalId/unsubscribe-url', summary: 'A signed one-click unsubscribe URL for a test contact, to exercise POST /m/unsub/:token.', testContactsOnly: true },\n { method: 'POST', path: '/contacts/:externalId/subscribe', summary: 'Subscribe a test contact.', testContactsOnly: true },\n { method: 'POST', path: '/contacts/:externalId/unsubscribe', summary: 'Unsubscribe a test contact (marketing scope).', testContactsOnly: true },\n { method: 'POST', path: '/contacts/:externalId/reset', summary: 'Delete a test contact\\'s runs, sends, events ({events: [names]} to narrow) and suppressions, then resubscribe. Each part can be turned off with false.', testContactsOnly: true },\n { method: 'POST', path: '/tick', summary: 'Run the runner tick now (trigger scan, sweeps, outbox, webhook backlog).' },\n { method: 'GET', path: '/webhooks/status', summary: 'Provider webhook ingest: last event received, counts by type (24h), unprocessed backlog.' },\n { method: 'GET', path: '/status', summary: 'One document with setup checks, health, every flow (enabled, version, watermark, gate, active runs), every template, and 24h counts.' },\n]\n","/**\n * Enabling a flow, done safely — and running it against test contacts only.\n *\n * The trigger scan starts from `flow.lastTriggerScanAt ?? flow.createdAt`\n * (triggers.ts). A flow that has never been enabled has a null watermark, so a\n * bare `enabled: true` replays every matching event since the flow document\n * was created: every signup of the past month gets the welcome email in one\n * tick, a week or more late. That is the single most dangerous write in the\n * admin surface, and until 0.16 it was one click (publish, or resume).\n *\n * `armFlow` is the path that flips `enabled` on. It stamps the watermark\n * (default: now) in the SAME update, reports how many events it is choosing\n * to skip, and writes an audit row. `publish` and `resume` in the admin API\n * go through `stampWatermarkIfNull` for the same guarantee.\n *\n * `gateFlow` publishes a canary version whose first step exits anyone\n * without a tag, so the real runner can exercise the real steps in\n * production against test contacts while every real contact enters and\n * exits at step 0 with no send. `ungateFlow` restores the newest ungated\n * version. Runs pin their version, so a contact mid-canary finishes on it.\n */\n\nimport type { Mailer } from '../mailer.js'\nimport type { Collections, FlowDoc } from '../models/index.js'\nimport type { FlowStep } from '../../shared/types.js'\nimport { SCAN_OVERLAP_MS } from './triggers.js'\n\n/** A typed failure the HTTP layer can map to a status code without guessing. */\nexport class FlowOperationError extends Error {\n constructor(\n public readonly code: string,\n message: string,\n public readonly status: number = 400,\n ) {\n super(message)\n this.name = 'FlowOperationError'\n }\n}\n\nexport interface ArmFlowOptions {\n /** Audit actor, e.g. `agent:claude` or `human:jeff@example.com`. */\n actor: string\n /**\n * Watermark to stamp. Defaults to now, which means only events fired AFTER\n * this call enter the flow. Pass an earlier instant only when you mean for\n * the events after it to enter — the result says how many that is.\n */\n since?: Date\n}\n\nexport interface ArmFlowResult {\n slug: string\n version: number\n /** True when this call flipped `enabled` on. */\n armed: boolean\n /** True when the flow was already enabled; nothing was written. */\n alreadyEnabled: boolean\n /** The watermark now on the flow. */\n watermark: Date | null\n eventName: string | null\n /** Events for the trigger name that fired before the watermark and will never enter. */\n skippedEvents: number\n /**\n * Events that WILL enter on the next tick: everything after the watermark,\n * plus anything created inside the scanner's 30-second overlap window just\n * before it.\n */\n pendingEvents: number\n}\n\n/**\n * Stamp `lastTriggerScanAt` when it is null. Used by every code path that\n * turns `enabled` on so a first enable never replays history. A flow that\n * has scanned before keeps its watermark: pausing and resuming deliberately\n * lets the events fired during the pause enter.\n */\nexport async function stampWatermarkIfNull(\n collections: Collections,\n flow: FlowDoc,\n now: Date = new Date(),\n): Promise<Date | null> {\n if (flow.lastTriggerScanAt) return flow.lastTriggerScanAt\n await collections.flows.updateOne(\n { _id: flow._id, lastTriggerScanAt: null },\n { $set: { lastTriggerScanAt: now, updatedAt: now } },\n )\n return now\n}\n\nexport async function armFlow(mailer: Mailer, slug: string, opts: ArmFlowOptions): Promise<ArmFlowResult> {\n const c = mailer.collections\n const flow = await c.flows.findOne({ slug })\n if (!flow) throw new FlowOperationError('not_found', `no flow with slug \"${slug}\"`, 404)\n if (!Array.isArray(flow.steps) || flow.steps.length === 0) {\n throw new FlowOperationError(\n 'no_live_steps',\n `flow \"${slug}\" (v${flow.version}) has no published steps — publish it first; an empty flow completes every run instantly`,\n 409,\n )\n }\n const eventName = flow.trigger?.eventName ?? null\n const now = new Date()\n const watermark = opts.since ?? now\n\n if (flow.enabled) {\n return {\n slug,\n version: flow.version,\n armed: false,\n alreadyEnabled: true,\n watermark: flow.lastTriggerScanAt ?? null,\n eventName,\n skippedEvents: 0,\n pendingEvents: 0,\n }\n }\n\n // The scan re-reads SCAN_OVERLAP_MS of history behind the watermark (its\n // own guard against a concurrent fire() committing slightly out of order),\n // so an event created inside that window before the watermark still\n // enters. Count it as pending, not skipped, so the caller is told the\n // truth: arming \"now\" admits the last half minute of matching events —\n // for a signup flow that is a person who signed up thirty seconds ago,\n // which is right.\n const previous = flow.lastTriggerScanAt ?? flow.createdAt\n const overlapFrom = new Date(watermark.getTime() - SCAN_OVERLAP_MS)\n const [skippedEvents, pendingEvents] = eventName\n ? await Promise.all([\n c.events.countDocuments({ name: eventName, createdAt: { $gt: previous, $lte: overlapFrom } }),\n c.events.countDocuments({ name: eventName, createdAt: { $gt: overlapFrom } }),\n ])\n : [0, 0]\n\n const res = await c.flows.updateOne(\n { _id: flow._id, enabled: false },\n { $set: { enabled: true, lastTriggerScanAt: watermark, updatedAt: now } },\n )\n if (res.modifiedCount === 0) {\n // Raced with another arm. Report the state rather than pretend.\n const again = await c.flows.findOne({ _id: flow._id })\n return {\n slug,\n version: flow.version,\n armed: false,\n alreadyEnabled: !!again?.enabled,\n watermark: again?.lastTriggerScanAt ?? null,\n eventName,\n skippedEvents: 0,\n pendingEvents: 0,\n }\n }\n\n await mailer.audit({\n actor: opts.actor,\n action: 'flow.arm',\n resource: { collection: 'mailer_flows', id: flow._id, slug },\n diffSummary:\n `Enabled v${flow.version} with lastTriggerScanAt=${watermark.toISOString()}` +\n ` (skipped ${skippedEvents} earlier ${eventName ?? 'trigger'} event(s), ${pendingEvents} pending)`,\n })\n\n return {\n slug,\n version: flow.version,\n armed: true,\n alreadyEnabled: false,\n watermark,\n eventName,\n skippedEvents,\n pendingEvents,\n }\n}\n\n/** The inverse: `enabled: false`. In-flight runs continue (that is what pause means). */\nexport async function disarmFlow(mailer: Mailer, slug: string, actor: string): Promise<{ slug: string; disarmed: boolean }> {\n const c = mailer.collections\n const flow = await c.flows.findOne({ slug })\n if (!flow) throw new FlowOperationError('not_found', `no flow with slug \"${slug}\"`, 404)\n if (!flow.enabled) return { slug, disarmed: false }\n await c.flows.updateOne({ _id: flow._id }, { $set: { enabled: false, updatedAt: new Date() } })\n await mailer.audit({\n actor,\n action: 'flow.pause',\n resource: { collection: 'mailer_flows', id: flow._id, slug },\n diffSummary: 'Disarmed (enabled: false); in-flight runs continue',\n })\n return { slug, disarmed: true }\n}\n\n// ---------------------------------------------------------------------------\n// Canary gate\n// ---------------------------------------------------------------------------\n\n/**\n * The gate step. `canaryGate` is a marker the runner ignores (it evaluates\n * the condition like any other) and this module uses to recognise its own\n * work when removing it.\n */\nexport type CanaryGateStep = Extract<FlowStep, { type: 'condition' }> & { canaryGate: true }\n\nexport function isCanaryGate(step: unknown): step is CanaryGateStep {\n const s = step as Partial<CanaryGateStep> | null\n return !!s && s.type === 'condition' && (s as any).canaryGate === true\n}\n\nfunction gateStep(tag: string): CanaryGateStep {\n return { type: 'condition', test: { hasTag: tag }, ifFalse: 'exit', canaryGate: true }\n}\n\nasync function publishVersion(\n mailer: Mailer,\n flow: FlowDoc,\n steps: FlowStep[],\n actor: string,\n summary: string,\n): Promise<{ version: number }> {\n const c = mailer.collections\n const nextVersion = (flow.version ?? 0) + 1\n const now = new Date()\n await c.flowVersions.insertOne({\n flowId: flow._id!,\n version: nextVersion,\n steps,\n trigger: flow.trigger,\n publishedAt: now,\n publishedBy: actor,\n })\n // `enabled` is deliberately untouched: publishing a canary version is not\n // the same decision as turning the flow on. That is armFlow's job.\n await c.flows.updateOne(\n { _id: flow._id },\n { $set: { steps, version: nextVersion, draft: null, publishedAt: now, publishedBy: actor, updatedAt: now } },\n )\n await mailer.audit({\n actor,\n action: 'flow.publish',\n resource: { collection: 'mailer_flows', id: flow._id, slug: flow.slug },\n diffSummary: `Published v${nextVersion}: ${summary}`,\n })\n return { version: nextVersion }\n}\n\nexport interface GateFlowResult {\n slug: string\n version: number\n tag: string\n enabled: boolean\n}\n\nexport async function gateFlow(\n mailer: Mailer,\n slug: string,\n opts: { tag: string; actor: string },\n): Promise<GateFlowResult> {\n const tag = String(opts.tag ?? '').trim()\n if (!tag) throw new FlowOperationError('tag_required', 'a canary tag is required')\n const flow = await mailer.collections.flows.findOne({ slug })\n if (!flow) throw new FlowOperationError('not_found', `no flow with slug \"${slug}\"`, 404)\n const live = Array.isArray(flow.steps) ? flow.steps : []\n if (live.length === 0) {\n throw new FlowOperationError('no_live_steps', `flow \"${slug}\" has no published steps to gate`, 409)\n }\n if (isCanaryGate(live[0])) {\n throw new FlowOperationError(\n 'already_gated',\n `flow \"${slug}\" v${flow.version} is already gated on \"${(live[0].test as { hasTag: string }).hasTag}\" — ungate first`,\n 409,\n )\n }\n // A flow written straight into mailer_flows (a deploy script, a seed) may\n // have no snapshot of its live version, and ungate restores from the\n // snapshots. Make sure the steps being gated can be found again.\n await mailer.collections.flowVersions.updateOne(\n { flowId: flow._id!, version: flow.version },\n {\n $setOnInsert: {\n flowId: flow._id!,\n version: flow.version,\n steps: live,\n trigger: flow.trigger,\n publishedAt: flow.publishedAt ?? flow.updatedAt ?? new Date(),\n publishedBy: flow.publishedBy ?? 'unknown',\n },\n },\n { upsert: true },\n )\n const { version } = await publishVersion(\n mailer,\n flow,\n [gateStep(tag), ...live],\n opts.actor,\n `canary gate on tag \"${tag}\"`,\n )\n return { slug, version, tag, enabled: flow.enabled }\n}\n\nexport interface UngateFlowResult {\n slug: string\n version: number\n /** The version whose steps were restored. */\n restoredFrom: number\n enabled: boolean\n}\n\nexport async function ungateFlow(mailer: Mailer, slug: string, opts: { actor: string }): Promise<UngateFlowResult> {\n const c = mailer.collections\n const flow = await c.flows.findOne({ slug })\n if (!flow) throw new FlowOperationError('not_found', `no flow with slug \"${slug}\"`, 404)\n const live = Array.isArray(flow.steps) ? flow.steps : []\n if (!isCanaryGate(live[0])) {\n throw new FlowOperationError('not_gated', `flow \"${slug}\" v${flow.version} is not gated`, 409)\n }\n const versions = await c.flowVersions.find({ flowId: flow._id! }).sort({ version: -1 }).toArray()\n const clean = versions.find((v) => Array.isArray(v.steps) && v.steps.length > 0 && !isCanaryGate(v.steps[0]))\n if (!clean) {\n throw new FlowOperationError(\n 'no_ungated_version',\n `flow \"${slug}\" has no ungated version in mailer_flow_versions to restore`,\n 409,\n )\n }\n const { version } = await publishVersion(\n mailer,\n flow,\n clean.steps,\n opts.actor,\n `restored steps of v${clean.version} (canary gate removed)`,\n )\n return { slug, version, restoredFrom: clean.version, enabled: flow.enabled }\n}\n","/**\n * Flow simulation: \"what would happen to this contact if the trigger fired\n * now?\" — answered by walking the published steps against the contact's real\n * state (tags, fields, events, sends, subscription) with a virtual clock and\n * WITHOUT writing anything.\n *\n * This is the dry run an operator wants before arming a flow: it shows the\n * branch a contact takes, every gate's verdict, the sends and the wall-clock\n * moment each would go out (waits and delivery windows applied), and where\n * the run ends. It reads the same predicate evaluator the runner uses, so a\n * gate that passes here passes in production — for the state as it is at the\n * moment of the call. Events that would arrive during the run are of course\n * not known, which is why `path[].at` is labelled a projection.\n */\n\nimport { ObjectId } from 'mongodb'\n\nimport type { Contact, FlowStep } from '../../shared/types.js'\nimport type { FlowDoc, FlowRunDoc } from '../models/index.js'\nimport type { RunnerContext } from './index.js'\nimport { evaluatePredicate } from './predicate.js'\nimport { computeDeliveryTime } from './delivery-window.js'\n\nconst MAX_STEPS = 1000\n\nexport interface SimulateOptions {\n /** Virtual \"now\" the simulated run enters at. Defaults to the real now. */\n at?: Date\n /** Properties of the simulated trigger event ({{event.*}}, triggerProperty* predicates). */\n eventProperties?: Record<string, unknown>\n /** Steps to walk. Defaults to the flow's live steps. */\n steps?: FlowStep[]\n}\n\nexport interface SimulatedStep {\n /** Projected wall-clock moment the step is reached. */\n at: Date\n stepIndex: number\n branchPath: Array<number | 'true' | 'false'>\n type: FlowStep['type']\n outcome:\n | 'waited'\n | 'passed'\n | 'skipped_next'\n | 'exited'\n | 'branch_true'\n | 'branch_false'\n | 'send'\n | 'send_deferred'\n | 'tagged'\n | 'event_fired'\n | 'webhook'\n | 'completed'\n detail?: Record<string, unknown>\n}\n\nexport interface SimulationResult {\n flow: { slug: string; version: number; enabled: boolean }\n contact: { externalId: string; email: string }\n enteredAt: Date\n /** Whether the trigger scan would create a run at all, and why not. */\n wouldEnter: { ok: boolean; reasons: string[] }\n path: SimulatedStep[]\n sends: Array<{ templateSlug: string; at: Date; stepIndex: number; branchPath: Array<number | 'true' | 'false'> }>\n terminal: { kind: 'completed' | 'exited' | 'truncated'; reason: string; at: Date }\n /** Projected time from entry to the terminal step. */\n durationMs: number\n}\n\nexport async function simulateFlow(\n flow: FlowDoc,\n contact: Contact,\n ctx: RunnerContext,\n opts: SimulateOptions = {},\n): Promise<SimulationResult> {\n const enteredAt = opts.at ?? new Date()\n const steps = opts.steps ?? flow.steps ?? []\n const eventName = flow.trigger?.eventName ?? 'simulated'\n const eventProperties = opts.eventProperties ?? {}\n\n // --- Would the trigger scan even create a run? -------------------------\n const reasons: string[] = []\n if (!flow.enabled) reasons.push('flow is disabled (enabled: false)')\n const sub = await ctx.collections.subscriptions.findOne({ externalId: contact.externalId })\n if (!sub) reasons.push('contact has no subscription row — the trigger scan requires one')\n else if (sub.status !== 'subscribed') reasons.push(`subscription status is \"${sub.status}\", not \"subscribed\"`)\n if (flow.trigger?.once) {\n const existing = await ctx.collections.flowRuns.findOne(\n { externalId: contact.externalId, flowId: flow._id! },\n { projection: { _id: 1, status: 1 } },\n )\n if (existing) reasons.push(`trigger.once is true and the contact already has a run (${existing.status})`)\n }\n if (steps.length === 0) reasons.push('flow has no live steps — a run would complete immediately')\n\n // --- Walk ----------------------------------------------------------------\n // The synthetic run stands in for what the runner would insert: predicates\n // read `enteredAt` (sinceFlowStart) and `triggerEvent` (triggerProperty*).\n const run: FlowRunDoc = {\n _id: new ObjectId(),\n externalId: contact.externalId,\n flowId: flow._id!,\n flowSlug: flow.slug,\n flowVersion: flow.version,\n emailAtEntry: contact.email,\n triggerEvent: { name: eventName, properties: eventProperties, occurredAt: enteredAt },\n triggerDedupeKey: null,\n enteredAt,\n status: 'active',\n currentStepIndex: 0,\n currentBranchPath: [],\n nextActionAt: enteredAt,\n attemptsForCurrentStep: 0,\n history: [],\n exitedAt: null,\n exitReason: null,\n createdAt: enteredAt,\n updatedAt: enteredAt,\n } as unknown as FlowRunDoc\n\n const path: SimulatedStep[] = []\n const sends: SimulationResult['sends'] = []\n let list: FlowStep[] = steps\n let index = 0\n let branchPath: Array<number | 'true' | 'false'> = []\n let t = enteredAt\n let terminal: SimulationResult['terminal'] | null = null\n\n const record = (type: FlowStep['type'], outcome: SimulatedStep['outcome'], detail?: Record<string, unknown>) => {\n path.push({ at: t, stepIndex: index, branchPath: [...branchPath], type, outcome, ...(detail ? { detail } : {}) })\n }\n const predicateCtx = () => ({\n contact,\n run: { ...run, currentStepIndex: index, currentBranchPath: branchPath, nextActionAt: t },\n collections: ctx.collections,\n now: t,\n botFilter: ctx.config.botFilter,\n })\n\n for (let guard = 0; guard < MAX_STEPS && !terminal; guard += 1) {\n const step = list[index]\n if (!step) {\n terminal = { kind: 'completed', reason: 'sequence_complete', at: t }\n break\n }\n switch (step.type) {\n case 'wait': {\n const ms = unitToMs(step.value, step.unit)\n record('wait', 'waited', { value: step.value, unit: step.unit, until: new Date(t.getTime() + ms) })\n t = new Date(t.getTime() + ms)\n index += 1\n break\n }\n case 'condition': {\n const result = await evaluatePredicate(step.test, predicateCtx())\n if (result) {\n record('condition', 'passed', { test: step.test, result })\n index += 1\n } else if (step.ifFalse === 'continue') {\n record('condition', 'skipped_next', { test: step.test, result })\n index += 2\n } else {\n record('condition', 'exited', { test: step.test, result })\n terminal = { kind: 'exited', reason: 'condition_false', at: t }\n }\n break\n }\n case 'branch': {\n const result = await evaluatePredicate(step.test, predicateCtx())\n record('branch', result ? 'branch_true' : 'branch_false', { test: step.test, result })\n branchPath = [...branchPath, index, result ? 'true' : 'false', 0]\n list = result ? step.ifTrueSteps : step.ifFalseSteps\n index = 0\n break\n }\n case 'send': {\n let at = t\n if (step.delivery) {\n at = computeDeliveryTime(t, step.delivery, contact.timezone)\n }\n if (at.getTime() > t.getTime() + 30_000) {\n record('send', 'send_deferred', { templateSlug: step.templateSlug, delivery: step.delivery, until: at })\n t = at\n }\n record('send', 'send', { templateSlug: step.templateSlug })\n sends.push({ templateSlug: step.templateSlug, at: t, stepIndex: index, branchPath: [...branchPath] })\n index += 1\n break\n }\n case 'tag':\n record('tag', 'tagged', { addTags: step.addTags ?? [], removeTags: step.removeTags ?? [] })\n index += 1\n break\n case 'fire_event':\n record('fire_event', 'event_fired', { eventName: step.eventName })\n index += 1\n break\n case 'webhook':\n record('webhook', 'webhook', { url: step.url, method: step.method ?? 'POST', note: 'not called in simulation' })\n index += 1\n break\n case 'exit':\n record('exit', 'exited', { reason: step.reason ?? 'exit_step' })\n terminal = { kind: 'exited', reason: step.reason ?? 'exit_step', at: t }\n break\n }\n }\n if (!terminal) terminal = { kind: 'truncated', reason: `stopped after ${MAX_STEPS} steps`, at: t }\n\n return {\n flow: { slug: flow.slug, version: flow.version, enabled: flow.enabled },\n contact: { externalId: contact.externalId, email: contact.email },\n enteredAt,\n wouldEnter: { ok: reasons.length === 0, reasons },\n path,\n sends,\n terminal,\n durationMs: terminal.at.getTime() - enteredAt.getTime(),\n }\n}\n\nfunction unitToMs(value: number, unit: 'minutes' | 'hours' | 'days' | 'weeks'): number {\n const m = 60_000\n switch (unit) {\n case 'minutes':\n return value * m\n case 'hours':\n return value * 60 * m\n case 'days':\n return value * 24 * 60 * m\n case 'weeks':\n return value * 7 * 24 * 60 * m\n }\n}\n","/**\n * Inbound DMARC aggregate-report webhook.\n *\n * DMARC RUA reports arrive as email. The usual way to turn that email into an\n * HTTP request is SendGrid Inbound Parse, and until v0.15 the documented setup\n * pointed Inbound Parse at `/admin/mailer/api/dmarc/upload` — a route behind\n * the host's `requireAdmin` guard, which Inbound Parse cannot satisfy. So the\n * documented setup either did not work, or worked because somebody removed the\n * guard from an admin router. This route replaces that advice.\n *\n * ## Read this before enabling it\n *\n * **Inbound Parse does not sign its payloads.** The SendGrid *Event Webhook*\n * does — see `providers/sendgrid.ts`, where signature verification and the\n * replay window live — but Inbound Parse is a different product and offers no\n * signature, no HMAC and no verifiable identity. There is nothing to verify.\n *\n * So this is, structurally, an unauthenticated file-accepting endpoint on a\n * public router, and the design has to own that rather than dress it up:\n *\n * 1. **Off unless configured.** No `dmarcInbound.secret`, no route — not a\n * 404 handler, no route registered at all. An endpoint like this appearing\n * on an upgrade because someone shipped a default would be indefensible.\n * 2. **A shared secret, checked first.** The secret is compared with\n * `timingSafeEqual` before multer is allowed to read a single byte of the\n * body, so an unauthenticated caller cannot make us buffer 10MB.\n * 3. **Hard size and count limits**, matching the admin upload's shape.\n * 4. **A domain cross-check.** A report whose `<policy_published><domain>` is\n * not a domain this deployment sends from is rejected. If the secret leaks,\n * the attacker gets to inject rows about *your* domains, which is bounded\n * and visible, instead of arbitrary garbage.\n * 5. **The existing parser.** `runner/dmarc.ts` already caps decompressed\n * bytes, validates declared-vs-actual sizes, checks compression ratio and\n * guards zip-slip. This route does not parse anything itself.\n *\n * ## Why a shared secret, and where it goes\n *\n * The three options that don't need a signature:\n *\n * - **Source IP allowlist.** Rejected as the primary control. SendGrid does\n * not publish a stable Inbound Parse egress range, and behind a proxy\n * `req.ip` is the proxy's address unless the host has set `trust proxy`\n * correctly — which this library cannot verify and must not assume. An\n * allowlist that silently matches the wrong address either locks out the\n * real sender or admits everyone. Put an allowlist in your ingress if you\n * want one; it is a good second layer and a bad only layer.\n * - **Secret in the path.** Works, and is the fallback, but a URL path is\n * logged by every proxy, load balancer and access log between SendGrid and\n * you. Supported implicitly: nothing stops you making `path` unguessable.\n * - **Secret in the `Authorization` header.** The default and the\n * recommendation. Inbound Parse cannot set custom headers, but its\n * destination URL accepts embedded basic-auth credentials\n * (`https://mailery:SECRET@example.com/m/inbound/dmarc`), which travel as an\n * `Authorization` header rather than in the request line. `Bearer` is\n * accepted too, for hosts forwarding from something other than SendGrid.\n *\n * A leaked secret gets an attacker exactly one capability: inserting DMARC\n * report rows for domains you already send from. No mail is sent, no contact\n * data is touched, nothing is deleted. Rotate it by changing the config value\n * and the Inbound Parse destination URL.\n */\n\nimport { createHash, timingSafeEqual } from 'node:crypto'\nimport type { Request, Response, Router } from 'express'\nimport multer from 'multer'\n\nimport { ingestDmarcAttachment } from '../runner/dmarc.js'\nimport type { Mailer } from '../mailer.js'\nimport { wrap, type RouteLogger } from './wrap.js'\n\n/** One attachment lifted off an inbound request by a `parseInbound` seam. */\nexport interface InboundAttachment {\n filename: string\n buffer: Buffer\n}\n\n/**\n * Pull DMARC attachments out of a provider's inbound-email payload.\n *\n * The seam exists so Mailgun's and Postmark's inbound routes can be added\n * without touching this route's auth, limits or ingest path. Only the SendGrid\n * shape is implemented today.\n */\nexport type InboundParser = (req: Request) => InboundAttachment[]\n\nexport interface DmarcInboundOptions {\n /**\n * Shared secret the caller must present. **Absent or empty → the route is\n * not mounted at all.**\n *\n * Accepted as HTTP Basic (any username; the password is compared) or as\n * `Authorization: Bearer <secret>`. Basic is the one to use with SendGrid\n * Inbound Parse, since it can be embedded in the destination URL and so\n * stays out of access logs.\n */\n secret?: string\n /** Sub-path on the public router. Default `/inbound/dmarc`. */\n path?: string\n /** Per-file cap. Default 10MB, matching the admin upload. */\n maxFileSizeBytes?: number\n /** Attachments accepted per request. Default 10. */\n maxFiles?: number\n /**\n * Domains whose reports are accepted. Defaults to every domain in\n * `senderDomains` plus the `fromDefaults` / `transactionalFromDefaults`\n * addresses. Reports for anything else are rejected.\n *\n * If none of those are configured there is nothing to check against, and the\n * route mounts with the domain gate disabled and a warning — configure\n * `senderDomains` to get it back.\n */\n allowedDomains?: string[]\n /** Override the inbound payload shape. Defaults to SendGrid Inbound Parse. */\n parseInbound?: InboundParser\n}\n\n/** Extensions a DMARC receiver actually sends. */\nconst ALLOWED_EXTENSIONS = ['.zip', '.gz', '.xml']\n\nconst DEFAULT_PATH = '/inbound/dmarc'\nconst DEFAULT_MAX_FILE_BYTES = 10 * 1024 * 1024\nconst DEFAULT_MAX_FILES = 10\n\n/**\n * Mount the inbound route, if it is configured. Returns the mounted path, or\n * null when nothing was mounted — which is the default.\n */\nexport function mountDmarcInbound(\n router: Router,\n mailer: Mailer,\n opts: DmarcInboundOptions | undefined,\n logger: RouteLogger,\n): string | null {\n const secret = opts?.secret\n if (!opts || typeof secret !== 'string' || secret.length === 0) return null\n\n const routePath = opts.path ?? DEFAULT_PATH\n const parseInbound = opts.parseInbound ?? sendgridInboundParser\n const allowedDomains = normalizeDomains(opts.allowedDomains ?? deriveSenderDomains(mailer))\n\n if (allowedDomains.size === 0) {\n logger.warn?.(\n { path: routePath },\n 'mailery: DMARC inbound route mounted without a domain allowlist — set senderDomains (or dmarcInbound.allowedDomains) so a leaked secret cannot inject reports for arbitrary domains',\n )\n }\n\n const upload = multer({\n storage: multer.memoryStorage(),\n limits: {\n fileSize: opts.maxFileSizeBytes ?? DEFAULT_MAX_FILE_BYTES,\n files: opts.maxFiles ?? DEFAULT_MAX_FILES,\n // Inbound Parse sends the whole email as form fields (headers, text,\n // html, ...). We read none of them, but they still have to be bounded.\n fields: 40,\n fieldSize: 1024 * 1024,\n },\n })\n\n // Order is the security control: authenticate, *then* let multer read the\n // body. Reversed, an anonymous caller could make the process buffer the full\n // upload limit per request.\n router.post(\n routePath,\n wrap(logger, (req: Request, res: Response, next) => {\n if (!isAuthorized(req, secret)) {\n logger.warn?.(\n { path: routePath, ip: req.ip },\n 'mailery: DMARC inbound request rejected — bad or missing shared secret',\n )\n // 401 with no WWW-Authenticate challenge: this is a machine endpoint,\n // and prompting a browser for credentials helps nobody.\n res.status(401).json({ error: 'unauthorized' })\n return\n }\n next()\n }),\n (req: Request, res: Response, next: (err?: unknown) => void) => {\n upload.any()(req, res, (err: unknown) => {\n if (!err) return next()\n const code = (err as { code?: string })?.code\n const status = code === 'LIMIT_FILE_SIZE' || code === 'LIMIT_FILE_COUNT' ? 413 : 400\n logger.warn?.({ err, path: routePath }, 'mailery: DMARC inbound upload rejected')\n res.status(status).json({ error: 'upload_rejected', message: String(code ?? 'malformed_multipart') })\n })\n },\n wrap(logger, async (req: Request, res: Response) => {\n let attachments: InboundAttachment[]\n try {\n attachments = parseInbound(req)\n } catch (err) {\n logger.warn?.({ err, path: routePath }, 'mailery: DMARC inbound payload unreadable')\n return res.status(400).json({ error: 'bad_payload' })\n }\n\n const candidates = attachments.filter((a) => hasAllowedExtension(a.filename))\n if (candidates.length === 0) {\n // A RUA mailbox also receives ordinary mail — auto-replies, a human\n // asking a question. Nothing to ingest is not an error, and answering\n // 4xx would make the provider retry it.\n logger.info?.(\n { path: routePath, attachments: attachments.length },\n 'mailery: DMARC inbound message carried no report attachment — ignored',\n )\n return res.status(200).json({ ok: true, ingested: 0, ignored: attachments.length })\n }\n\n const ctx = mailer.getRunnerContext()\n const allowDomain =\n allowedDomains.size === 0 ? undefined : (d: string) => allowedDomains.has(d.toLowerCase())\n\n const ingested: Array<{ reportId: string; domain: string; duplicate: boolean }> = []\n const rejected: Array<{ filename: string; message: string }> = []\n\n for (const file of candidates) {\n try {\n const result = await ingestDmarcAttachment(ctx, file.buffer, file.filename, { allowDomain })\n ingested.push({ reportId: result.reportId, domain: result.domain, duplicate: result.duplicate })\n } catch (err: unknown) {\n const message = String((err as Error)?.message ?? err)\n rejected.push({ filename: file.filename, message })\n logger.warn?.(\n { path: routePath, filename: file.filename, err },\n 'mailery: DMARC inbound attachment rejected',\n )\n }\n }\n\n if (ingested.length === 0) {\n // Nothing usable in a message that claimed to carry a report. 400 so\n // the failure is visible in the provider's activity log rather than\n // disappearing into a 200.\n return res.status(400).json({ error: 'ingest_failed', rejected })\n }\n return res.status(200).json({ ok: true, ingested, rejected })\n }),\n )\n\n return routePath\n}\n\n// ---------------------------------------------------------------------------\n// Authentication\n// ---------------------------------------------------------------------------\n\n/**\n * Constant-time shared-secret check over the `Authorization` header.\n *\n * `timingSafeEqual` throws on a length mismatch, which would itself leak the\n * secret's length, so both sides are hashed to a fixed width first — the same\n * shape the token helpers use.\n */\nexport function isAuthorized(req: Request, secret: string): boolean {\n const presented = extractPresentedSecret(req)\n if (presented === null) return false\n return constantTimeEquals(presented, secret)\n}\n\nfunction extractPresentedSecret(req: Request): string | null {\n const header = req.headers.authorization\n if (typeof header !== 'string') return null\n\n const [scheme, ...rest] = header.split(' ')\n const value = rest.join(' ').trim()\n if (!scheme || value === '') return null\n\n switch (scheme.toLowerCase()) {\n case 'basic': {\n let decoded: string\n try {\n decoded = Buffer.from(value, 'base64').toString('utf8')\n } catch {\n return null\n }\n const sep = decoded.indexOf(':')\n // The username is deliberately ignored: SendGrid's destination URL needs\n // *a* username, and pinning one only adds a way to misconfigure it.\n return sep === -1 ? null : decoded.slice(sep + 1)\n }\n case 'bearer':\n return value\n default:\n return null\n }\n}\n\nfunction constantTimeEquals(a: string, b: string): boolean {\n // sha256 both sides so the comparison is over equal-length buffers no matter\n // what was presented.\n const ha = createHash('sha256').update(a, 'utf8').digest()\n const hb = createHash('sha256').update(b, 'utf8').digest()\n return timingSafeEqual(ha, hb)\n}\n\n// ---------------------------------------------------------------------------\n// Provider payload shapes\n// ---------------------------------------------------------------------------\n\n/**\n * SendGrid Inbound Parse: `multipart/form-data` with the message's fields\n * (`headers`, `from`, `subject`, `text`, ...) plus one file part per\n * attachment, named `attachment1`, `attachment2`, and so on.\n *\n * Read through `multer.any()`, so the field names are not trusted — every file\n * part is a candidate and the extension gate below decides.\n */\nexport const sendgridInboundParser: InboundParser = (req) => {\n const files = (req as unknown as { files?: unknown }).files\n if (!Array.isArray(files)) return []\n return files\n .filter((f): f is Express.Multer.File => Boolean(f) && Buffer.isBuffer((f as Express.Multer.File).buffer))\n .map((f) => ({ filename: safeFilename(f.originalname), buffer: f.buffer }))\n}\n\n/**\n * A provider-supplied filename only ever reaches `extractDmarcXmls`, which\n * reads its extension and nothing else — but it is also logged, so strip path\n * separators and control characters before it goes anywhere.\n */\nfunction safeFilename(raw: unknown): string {\n if (typeof raw !== 'string') return ''\n // eslint-disable-next-line no-control-regex\n return raw.replace(/[\\u0000-\\u001f\\u007f]/g, '').replace(/[\\\\/]/g, '_').slice(0, 255)\n}\n\nfunction hasAllowedExtension(filename: string): boolean {\n const lower = filename.toLowerCase()\n return ALLOWED_EXTENSIONS.some((ext) => lower.endsWith(ext))\n}\n\n// ---------------------------------------------------------------------------\n// Domain allowlist\n// ---------------------------------------------------------------------------\n\nfunction normalizeDomains(domains: Iterable<string>): Set<string> {\n const out = new Set<string>()\n for (const d of domains) {\n if (typeof d !== 'string') continue\n const trimmed = d.trim().toLowerCase().replace(/^\\.+/, '')\n if (trimmed) out.add(trimmed)\n }\n return out\n}\n\n/**\n * Domains this deployment sends from: the `senderDomains` registry plus the\n * From defaults. DMARC reports are published per organizational domain, so a\n * deployment sending from `news.example.com` receives reports whose\n * `policy_published.domain` may be either that or `example.com` — both are\n * included.\n */\nfunction deriveSenderDomains(mailer: Mailer): string[] {\n const out: string[] = []\n const push = (domain: string | undefined) => {\n if (!domain) return\n out.push(domain)\n // The organizational domain the subdomain's DMARC policy is inherited\n // from. Approximated as the last two labels, which is right for\n // `example.com` and over-permissive for a multi-label public suffix like\n // `example.co.uk` — set `dmarcInbound.allowedDomains` explicitly there.\n const labels = domain.split('.')\n if (labels.length > 2) out.push(labels.slice(-2).join('.'))\n }\n\n for (const domain of Object.keys(mailer.config.senderDomains ?? {})) push(domain.toLowerCase())\n push(emailDomain(mailer.config.fromDefaults?.email))\n push(emailDomain(mailer.config.transactionalFromDefaults?.email))\n push(emailDomain(mailer.config.senderAddress))\n return out\n}\n\nfunction emailDomain(email: string | undefined): string | undefined {\n if (typeof email !== 'string') return undefined\n const at = email.lastIndexOf('@')\n if (at === -1) return undefined\n const domain = email.slice(at + 1).trim().toLowerCase()\n return domain || undefined\n}\n","/**\n * Public router — endpoints that must be reachable by email clients and\n * provider webhooks. Mount under your tracking base path (default `/m`).\n *\n * app.use('/m', createPublicRouter(mailer))\n *\n * Routes:\n * GET /open/:sendId.:sig.png — open pixel (records open, returns 1×1 PNG)\n * GET /click/:sendId/:linkId/:sig — click redirect (records click, 302 → target)\n * GET /unsub/:token — confirmation page (one-click POST link)\n * POST /unsub/:token — RFC 8058 one-click unsubscribe\n * POST /webhooks/:provider — inbound provider event webhook\n * POST /inbound/dmarc — inbound DMARC report (opt-in; see below)\n *\n * Every route here is unauthenticated by necessity — mail clients and provider\n * webhook servers cannot present credentials. The one exception is\n * `/inbound/dmarc`, which is **not mounted at all** unless a shared secret is\n * configured; see `api/dmarc-inbound.ts`.\n *\n * `:sig` is a 12-character truncated HMAC issued by `applyTracking`. It is\n * syntactically optional on both tracking routes so that mail delivered before\n * signing existed keeps working — see `checkTrackingSignature`.\n */\n\nimport express, { Router, type Request, type Response } from 'express'\nimport { ObjectId } from 'mongodb'\n\nimport {\n sha256Hex,\n verifyUnsubscribeToken,\n verifyDoiToken,\n verifyTrackingToken,\n type TrackingScope,\n type TrackingTokenParams,\n} from '../tokens.js'\nimport type { Mailer } from '../mailer.js'\nimport type { SendDoc } from '../models/index.js'\nimport { resolveProvider } from '../provider-lookup.js'\nimport { appendPendingUnsub } from '../unsub-journal.js'\nimport { mountDmarcInbound, type DmarcInboundOptions } from './dmarc-inbound.js'\nimport { consoleRouteLogger, wrap, type RouteLogger } from './wrap.js'\n\nexport interface PublicRouterOptions {\n /**\n * Overrides `MailerConfig.pendingUnsubsPath` for this router only.\n *\n * @deprecated Set `pendingUnsubsPath` in `MailerConfig` instead. The tick\n * drain (`drainPendingUnsubscribes`) reads the *config* value, so a path set\n * only here is written but never replayed — which is precisely the bug\n * INVARIANT 8 was carrying. Setting it here without also setting it in\n * config logs a warning at construction time.\n */\n pendingUnsubsPath?: string\n /**\n * Structured logger for public-route failures, pino-style\n * (`logger.error(fields, message)`).\n *\n * Defaults to a `console`-backed logger that reproduces the output this\n * package emitted before the option existed. Pass `{}` to silence.\n */\n logger?: RouteLogger\n /**\n * Inbound DMARC aggregate-report webhook (SendGrid Inbound Parse and\n * friends). **Off unless `secret` is set** — see `api/dmarc-inbound.ts` for\n * why an endpoint that accepts unsigned file uploads must never appear on an\n * upgrade by itself.\n */\n dmarcInbound?: DmarcInboundOptions\n}\n\n// 1×1 transparent PNG (43 bytes)\nconst PIXEL = Buffer.from(\n 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=',\n 'base64',\n)\n\nexport function createPublicRouter(mailer: Mailer, opts: PublicRouterOptions = {}): Router {\n const router = Router()\n const logger = opts.logger ?? consoleRouteLogger\n\n // INVARIANT 8. No filesystem default: see `MailerConfig.pendingUnsubsPath`\n // for why a library cannot pick one, and what happens when it is unset.\n const pendingUnsubsPath = opts.pendingUnsubsPath ?? mailer.config.pendingUnsubsPath ?? null\n if (opts.pendingUnsubsPath && !mailer.config.pendingUnsubsPath) {\n logger.warn?.(\n { path: opts.pendingUnsubsPath },\n 'mailery: pendingUnsubsPath set on the public router but not in MailerConfig — the tick drain will not replay this journal',\n )\n }\n if (!pendingUnsubsPath) {\n logger.warn?.(\n {},\n 'mailery: no pendingUnsubsPath configured — POST /unsub answers 503 when Mongo is unreachable instead of journaling the opt-out',\n )\n }\n\n // Inbound DMARC reports. Mounted only when a secret is configured; the\n // route's own module explains why that is not negotiable. Registered before\n // the body parsers below so nothing consumes its multipart stream, and\n // `mounted` is logged so an operator can see it exists.\n const dmarcInboundPath = mountDmarcInbound(router, mailer, opts.dmarcInbound, logger)\n if (dmarcInboundPath) {\n logger.info?.(\n { path: dmarcInboundPath },\n 'mailery: DMARC inbound route mounted (shared-secret auth; SendGrid Inbound Parse does not sign payloads)',\n )\n }\n\n // Parse JSON for webhooks — capture raw body for signature verification.\n router.use(\n '/webhooks',\n express.json({\n limit: '5mb',\n verify: (req: any, _res, buf) => {\n req.rawBody = buf\n },\n }),\n )\n\n // Pre-parsed JSON for the POST one-click unsubscribe path (RFC 8058 sends a\n // small form/JSON body; we accept either by reading the URL only).\n router.use('/unsub', express.urlencoded({ extended: false }))\n\n // -------------------------------------------------------------------------\n // GET /open/:sendId.png\n // -------------------------------------------------------------------------\n router.get('/open/:sendId.png', wrap(logger, async (req: Request, res: Response) => {\n // The pixel is returned unconditionally, before anything is validated. A\n // rejected signature must look exactly like an accepted one on the wire:\n // any difference (404, empty body, slower response) is an oracle that tells\n // an attacker when a guessed sendId is real.\n res.setHeader('Content-Type', 'image/png')\n res.setHeader('Content-Length', String(PIXEL.length))\n res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0')\n res.status(200).end(PIXEL)\n\n // Async update — never block the response.\n const parsed = splitOpenParam((req.params as any).sendId as string)\n if (!parsed) return\n const { id, sig } = parsed\n if (!ObjectId.isValid(id)) return\n const sendId = new ObjectId(id)\n\n const verdict = checkTrackingSignature({\n scope: 'open',\n params: { sendId: id },\n sig,\n secret: mailer.config.unsubscribeSecret,\n requireSigned: mailer.config.requireSignedTrackingUrls,\n logger,\n fields: { sendId: id },\n })\n if (verdict === 'rejected') return\n\n try {\n const send = await mailer.collections.sends.findOne(\n { _id: sendId },\n { projection: { openedAt: 1, queuedAt: 1 } },\n )\n if (!send) return\n if (isTrackingExpired(send, mailer.config.trackingUrlLifetimeDays)) {\n logger.warn?.({ sendId: id }, 'mailery: open ignored — tracking URL past trackingUrlLifetimeDays')\n return\n }\n const now = new Date()\n await mailer.collections.sends.updateOne(\n { _id: sendId },\n {\n $set: {\n openedAt: send.openedAt ?? now,\n status: 'delivered' as const,\n },\n $inc: { openCount: 1 },\n // Per-open user agent, so `hasOpenedExcludingBots` has a signal to\n // filter on. Capped: an open pixel can be re-fetched indefinitely\n // (every time the recipient re-opens the mail) and an unbounded\n // array would eventually run the send document into the 16MB limit.\n $push: {\n opens: {\n $each: [{ openedAt: now, userAgent: requestUserAgent(req) }],\n $slice: -MAX_TRACKED_OPENS,\n },\n },\n },\n )\n } catch (err) {\n logger.error?.({ err, sendId: id }, 'mailery: open pixel update failed')\n }\n }))\n\n // -------------------------------------------------------------------------\n // GET /click/:sendId/:linkId\n // -------------------------------------------------------------------------\n router.get('/click/:sendId/:linkId{/:sig}', wrap(logger, async (req: Request, res: Response) => {\n const { sendId: sendIdStr, linkId, sig } = req.params as {\n sendId: string\n linkId: string\n sig?: string\n }\n if (!ObjectId.isValid(sendIdStr)) return res.status(400).end()\n const sendId = new ObjectId(sendIdStr)\n\n // A bad signature is answered with the same 404 an unknown send gets. Any\n // distinct status would confirm \"this sendId exists, keep guessing\".\n const verdict = checkTrackingSignature({\n scope: 'click',\n params: { sendId: sendIdStr, linkId },\n sig,\n secret: mailer.config.unsubscribeSecret,\n requireSigned: mailer.config.requireSignedTrackingUrls,\n logger,\n fields: { sendId: sendIdStr, linkId },\n })\n if (verdict === 'rejected') return res.status(404).end()\n\n const send = await mailer.collections.sends.findOne(\n { _id: sendId },\n { projection: { links: 1, firstClickAt: 1, queuedAt: 1 } },\n )\n if (!send) return res.status(404).end()\n\n if (isTrackingExpired(send, mailer.config.trackingUrlLifetimeDays)) {\n logger.warn?.(\n { sendId: sendIdStr, linkId },\n 'mailery: click rejected — tracking URL past trackingUrlLifetimeDays',\n )\n return res.status(404).end()\n }\n\n const link = (send.links ?? []).find((l) => l.linkId === linkId)\n if (!link) return res.status(404).end()\n\n // Never redirect to a scheme we didn't sanction. The rejected URL is logged\n // but deliberately kept out of the response body — echoing it back would\n // reflect attacker-controlled content from the sending domain's origin.\n if (!isSafeRedirectTarget(link.url)) {\n logger.warn?.(\n { sendId: sendIdStr, linkId, url: link.url },\n 'mailery: click redirect blocked — disallowed URL scheme',\n )\n return res\n .status(400)\n .type('html')\n .send('<!doctype html><html><body><p>This link cannot be opened.</p></body></html>')\n }\n\n res.redirect(302, link.url)\n\n try {\n await mailer.collections.sends.updateOne(\n { _id: sendId },\n {\n $set: { firstClickAt: send.firstClickAt ?? new Date() },\n $inc: { clickCount: 1 },\n $push: {\n clickedLinks: {\n url: link.url,\n linkId,\n clickedAt: new Date(),\n // The bot filter has always read `clickedLinks[].userAgent`; until\n // now nothing ever wrote it, so every click scored as human.\n userAgent: requestUserAgent(req),\n },\n },\n },\n )\n } catch (err) {\n logger.error?.({ err, sendId: sendIdStr, linkId }, 'mailery: click recording failed')\n }\n }))\n\n // -------------------------------------------------------------------------\n // GET + POST /unsub/:token\n // -------------------------------------------------------------------------\n router.get('/unsub/:token', wrap(logger, (req: Request, res: Response) => {\n const decoded = verifyUnsubscribeToken((req.params as any).token, mailer.config.unsubscribeSecret)\n if (!decoded) return sendUnsubError(res, 'Invalid or expired link.')\n\n res.status(200).type('html').send(`<!doctype html>\n<html><head>\n <meta charset=\"utf-8\" />\n <title>Unsubscribe</title>\n <style>body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;max-width:480px;margin:48px auto;padding:0 16px;color:#1c1917;line-height:1.5}h1{font-size:20px}button{padding:10px 18px;background:#dc2626;color:#fff;border:0;border-radius:6px;font-size:14px;cursor:pointer}</style>\n</head><body>\n <h1>Confirm unsubscribe</h1>\n <p>Click the button below to unsubscribe <strong>${escapeHtml(decoded.email)}</strong>${decoded.scope === 'all' ? ' from everything' : ' from marketing emails'}.</p>\n <form method=\"POST\" action=\"${escapeHtml(req.originalUrl)}\">\n <button type=\"submit\">Unsubscribe</button>\n </form>\n</body></html>`)\n }))\n\n /**\n * RFC 8058 one-click unsubscribe.\n *\n * This is the one public route that does *not* answer before doing its work,\n * and INVARIANT 8 is why. \"Return 200 quickly\" and \"never silently drop an\n * opt-out\" are both in that invariant, and answering first can only satisfy\n * the former: the response is already on the wire by the time we learn the\n * write failed, so the recipient is told they are unsubscribed and then\n * keeps receiving mail. Through v0.14 that is exactly what happened, and the\n * 503 the invariant describes was unreachable.\n *\n * So: durability first, within a budget.\n *\n * Mongo write succeeds (typically sub-millisecond) → 200\n * Mongo fails or exceeds `unsubscribeWriteTimeoutMs` → journal → 200\n * no journal configured, or the journal write fails → 503\n *\n * A 503 is not a worse outcome than the old unconditional 200 — it is the\n * same failure, told honestly. The caller (a mail client's one-click\n * infrastructure, or a human on the confirmation page) can retry, and\n * nothing has claimed an unsubscribe that does not exist.\n */\n router.post('/unsub/:token', wrap(logger, async (req: Request, res: Response) => {\n const decoded = verifyUnsubscribeToken((req.params as any).token, mailer.config.unsubscribeSecret)\n if (!decoded) {\n res.status(200).end() // never 5xx; let provider stop retrying\n return\n }\n\n const write = mailer.unsubscribe(decoded.email, {\n scope: decoded.scope,\n reason: 'user_request',\n source: 'one-click',\n })\n\n let dbError: unknown = null\n try {\n await withTimeout(write, mailer.config.unsubscribeWriteTimeoutMs)\n } catch (err) {\n dbError = err ?? new Error('unsubscribe write failed')\n // The write may still land after the timeout. Nothing here depends on\n // whether it does — the journal replay is idempotent — but an unobserved\n // rejection would take the host process down.\n void write.catch(() => {})\n }\n\n if (dbError) {\n if (!pendingUnsubsPath) {\n logger.error?.(\n { err: dbError },\n 'mailery: unsubscribe write failed and no pendingUnsubsPath is configured — answering 503',\n )\n return sendUnsubUnavailable(res)\n }\n try {\n appendPendingUnsub(pendingUnsubsPath, {\n email: decoded.email,\n scope: decoded.scope,\n at: Date.now(),\n })\n logger.warn?.(\n { err: dbError, path: pendingUnsubsPath },\n 'mailery: unsubscribe journaled to disk — will be replayed by the tick drain',\n )\n } catch (diskErr) {\n logger.error?.(\n { err: dbError, diskErr, path: pendingUnsubsPath },\n 'mailery: unsub disk fallback failed — answering 503',\n )\n return sendUnsubUnavailable(res)\n }\n }\n\n res.status(200).type('html').send('<!doctype html><html><body><p>You are unsubscribed.</p></body></html>')\n }))\n\n // -------------------------------------------------------------------------\n // GET /confirm-doi/:token\n // -------------------------------------------------------------------------\n router.get('/confirm-doi/:token', wrap(logger, async (req: Request, res: Response) => {\n const token = (req.params as any).token as string\n const decoded = verifyDoiToken(token, mailer.config.unsubscribeSecret)\n if (!decoded) {\n return res.status(400).type('html').send('<!doctype html><html><body><p>Confirmation link is invalid or expired.</p></body></html>')\n }\n const now = new Date()\n const result = await mailer.collections.subscriptions.updateOne(\n { externalId: decoded.externalId, status: 'pending_doi' },\n {\n $set: {\n status: 'subscribed',\n subscribedAt: now,\n doiConfirmedAt: now,\n doiIp: req.ip ?? null,\n doiUserAgent: (req.headers['user-agent'] as string | undefined) ?? null,\n updatedAt: now,\n },\n },\n )\n if (result.matchedCount === 0) {\n return res.status(200).type('html').send('<!doctype html><html><body><p>Already confirmed. Thanks.</p></body></html>')\n }\n try {\n await mailer.fire('subscription.confirmed', decoded.externalId, {}, `doi-confirmed:${decoded.externalId}`)\n } catch {\n /* swallow — subscription is confirmed regardless */\n }\n return res.status(200).type('html').send('<!doctype html><html><body><p>Thanks — you\\'re subscribed.</p></body></html>')\n }))\n\n // -------------------------------------------------------------------------\n // POST /webhooks/:provider\n // -------------------------------------------------------------------------\n router.post('/webhooks/:provider', wrap(logger, async (req: Request, res: Response) => {\n const providerName = (req.params as any).provider as string\n const provider = resolveProvider(mailer.providers, providerName)\n if (!provider) return res.status(404).end()\n\n const rawBody = (req as any).rawBody as Buffer | undefined\n if (!rawBody) return res.status(400).end()\n\n const headers = lowercaseHeaders(req.headers)\n const valid = await provider.verifyWebhook(rawBody, headers)\n if (!valid) return res.status(401).end()\n\n const events = provider.parseWebhookEvents(req.body, headers)\n\n // Always 200 fast — fail-open, retry inbound is wasted bandwidth.\n res.status(200).end()\n\n // Preserve the original provider payload alongside each normalized event so the\n // audit trail isn't reduced to just our extracted fields. The raw body is the\n // full provider response array; we record it once per parsed event for clarity.\n const rawBodyRef = req.body as unknown\n for (const evt of events) {\n try {\n await mailer.collections.webhookEvents.updateOne(\n { provider: providerName, providerEventId: evt.providerEventId },\n {\n $setOnInsert: {\n provider: providerName,\n providerEventId: evt.providerEventId,\n eventType: evt.type,\n normalizedType: evt.type,\n providerMessageId: evt.providerMessageId,\n email: evt.email,\n occurredAt: evt.occurredAt,\n receivedAt: new Date(),\n processed: false,\n raw: { normalized: evt, providerBody: rawBodyRef },\n },\n },\n { upsert: true },\n )\n } catch (err) {\n logger.error?.(\n { err, provider: providerName, providerEventId: evt.providerEventId },\n 'mailery: webhook dedupe insert failed',\n )\n }\n }\n\n if (events.length > 0) {\n try {\n await mailer.queues.webhook.add('webhook', { provider: providerName })\n } catch {\n /* will be picked up by next tick */\n }\n }\n }))\n\n return router\n}\n\n// ---------------------------------------------------------------------------\n// Tracking-URL verification\n// ---------------------------------------------------------------------------\n\n/** Most recent opens kept per send. See `SendDoc.opens`. */\nconst MAX_TRACKED_OPENS = 50\n\n/** User agents are stored for bot classification only; the tail carries nothing. */\nconst MAX_UA_LENGTH = 256\n\nfunction requestUserAgent(req: Request): string | null {\n const ua = req.headers['user-agent']\n if (typeof ua !== 'string' || ua.trim() === '') return null\n return ua.slice(0, MAX_UA_LENGTH)\n}\n\n/**\n * Split the `:sendId.png` path parameter into id and optional signature.\n *\n * Express hands us everything before the literal `.png`, so a signed pixel\n * arrives as `<objectId>.<sig>` and a legacy one as `<objectId>`. Anything with\n * more dots than that was not produced by `applyTracking` and is dropped\n * outright rather than guessed at.\n */\nfunction splitOpenParam(raw: unknown): { id: string; sig?: string } | null {\n if (typeof raw !== 'string') return null\n const parts = raw.split('.')\n if (parts.length === 1) return { id: parts[0]! }\n if (parts.length === 2) return { id: parts[0]!, sig: parts[1]! }\n return null\n}\n\ntype TrackingVerdict = 'signed' | 'legacy' | 'rejected'\n\n/**\n * Decide whether a tracking hit may be counted.\n *\n * Three cases, and the middle one is the whole backward-compatibility story:\n *\n * signature present + valid → 'signed'\n * signature present + wrong → 'rejected', always, in every mode\n * signature absent → 'rejected' if `requireSignedTrackingUrls`,\n * otherwise 'legacy' — counted, and logged\n *\n * Grace mode exists because mail already in inboxes carries unsigned URLs and\n * will keep being opened for years; hard-rejecting it would silently zero the\n * tracking for every send that predates this change. The per-hit warn is the\n * operator's instrument: watch the legacy rate decay, then set\n * `requireSignedTrackingUrls: true`.\n *\n * A wrong signature is never graced. Grace covers \"this URL predates signing\",\n * not \"this URL was signed by someone who does not have the key\".\n */\nfunction checkTrackingSignature(args: {\n scope: TrackingScope\n params: TrackingTokenParams\n sig: string | undefined\n secret: string\n requireSigned: boolean\n logger: RouteLogger\n fields: Record<string, unknown>\n}): TrackingVerdict {\n const { sig, logger, fields, scope } = args\n\n if (sig === undefined || sig === '') {\n if (args.requireSigned) {\n logger.warn?.(\n { ...fields, scope },\n 'mailery: unsigned tracking URL rejected (requireSignedTrackingUrls)',\n )\n return 'rejected'\n }\n // `info`, not `warn`: in grace mode this fires once per legacy open, which\n // is telemetry rather than a fault. It is the operator's readout for\n // \"has legacy traffic stopped yet?\" — when this line goes quiet, flipping\n // `requireSignedTrackingUrls` to true is safe.\n logger.info?.(\n { ...fields, scope },\n 'mailery: unsigned tracking URL accepted — legacy grace mode',\n )\n return 'legacy'\n }\n\n if (!verifyTrackingToken(sig, scope, args.params, args.secret)) {\n logger.warn?.({ ...fields, scope }, 'mailery: tracking URL signature invalid')\n return 'rejected'\n }\n return 'signed'\n}\n\n/**\n * True when the send is older than `trackingUrlLifetimeDays`.\n *\n * The deadline is derived from the send row rather than embedded in the token:\n * it costs no URL bytes, and changing the config takes effect immediately for\n * mail that has already gone out. A send with no usable `queuedAt` is never\n * treated as expired — losing a real open to a missing timestamp is worse than\n * counting a stale one.\n */\nfunction isTrackingExpired(send: Pick<SendDoc, 'queuedAt'>, lifetimeDays: number, now: Date = new Date()): boolean {\n if (!lifetimeDays || lifetimeDays <= 0) return false\n const queuedAt = send.queuedAt\n if (!(queuedAt instanceof Date) || Number.isNaN(queuedAt.getTime())) return false\n return now.getTime() - queuedAt.getTime() > lifetimeDays * 24 * 60 * 60 * 1000\n}\n\nfunction sendUnsubError(res: Response, msg: string): Response {\n return res.status(400).type('html').send(`<!doctype html><html><body><p>${escapeHtml(msg)}</p></body></html>`)\n}\n\n/**\n * The 503 INVARIANT 8 describes: neither Mongo nor the journal could record\n * the opt-out. `Retry-After` is set because the honest answer to a one-click\n * client is \"come back\", not \"done\".\n */\nfunction sendUnsubUnavailable(res: Response): Response {\n return res\n .status(503)\n .set('Retry-After', '60')\n .type('html')\n .send(\n '<!doctype html><html><body><p>We could not record your unsubscribe right now, ' +\n 'so you are <strong>not</strong> unsubscribed yet. Please try again in a minute.</p></body></html>',\n )\n}\n\n/**\n * Resolve `p`, or reject once `ms` has elapsed.\n *\n * A rejected `p` still settles the race normally; the timer exists for the\n * case that matters here, a Mongo client that is neither resolving nor\n * rejecting because the server it is waiting on is gone. `unref()` keeps a\n * pending timer from holding the process open.\n */\nfunction withTimeout<T>(p: Promise<T>, ms: number): Promise<T> {\n if (!Number.isFinite(ms) || ms <= 0) return p\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => {\n reject(new Error(`timed out after ${ms}ms`))\n }, ms)\n if (typeof timer.unref === 'function') timer.unref()\n p.then(\n (v) => {\n clearTimeout(timer)\n resolve(v)\n },\n (err) => {\n clearTimeout(timer)\n reject(err)\n },\n )\n })\n}\n\nfunction escapeHtml(s: string): string {\n return s\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#39;')\n}\n\n/** Schemes we are willing to bounce a click through. */\nconst ALLOWED_REDIRECT_PROTOCOLS = new Set(['http:', 'https:'])\n\n/**\n * Guard for the click-tracking redirect target.\n *\n * Stored link URLs come out of `applyTracking`, which harvests `href` values\n * from *rendered* HTML — i.e. after Handlebars substitution — so a template\n * that interpolates a variable into an href position can put an arbitrary\n * scheme into the stored URL. Redirecting to it would launch `javascript:` or\n * `data:` from the sending domain's own origin, with the sender's reputation\n * behind it.\n *\n * Parsed with `new URL()` rather than string matching: the URL parser strips\n * tab/newline and lowercases the scheme, so `java\\tscript:` and `JavaScript:`\n * normalize to the same rejected protocol. A protocol-relative `//evil.com`\n * has no scheme and no base here, so parsing throws and it is rejected too.\n */\nfunction isSafeRedirectTarget(raw: unknown): raw is string {\n if (typeof raw !== 'string') return false\n const trimmed = raw.trim()\n if (trimmed === '') return false\n let parsed: URL\n try {\n parsed = new URL(trimmed)\n } catch {\n return false\n }\n return ALLOWED_REDIRECT_PROTOCOLS.has(parsed.protocol)\n}\n\nfunction lowercaseHeaders(h: any): Record<string, string> {\n const out: Record<string, string> = {}\n for (const k of Object.keys(h)) {\n const v = h[k]\n out[k.toLowerCase()] = Array.isArray(v) ? v.join(',') : String(v ?? '')\n }\n return out\n}\n\n// silence unused\nvoid sha256Hex\n","/**\n * Enumerable option lists for the union types in `./types.ts`. Used by the\n * admin client to render dropdowns + by tooling to enumerate the surface.\n *\n * Kept in `shared/` so the client and server agree on the canonical labels +\n * default constructors. Pure data + pure functions — no React, no DOM.\n */\n\nimport type { FlowStep, Predicate, SegmentFilter } from './types.js'\n\n// ---------------------------------------------------------------------------\n// Flow step types\n// ---------------------------------------------------------------------------\n\nexport interface FlowStepKindOption {\n value: FlowStep['type']\n label: string\n /** Icon name from the client's icon set (lookup at render time). */\n icon: string\n /** Visual class on the canvas chip. */\n iconClass: string\n /** One-line description for tooltips / docs generation. */\n description: string\n}\n\nexport const FLOW_STEP_KINDS: readonly FlowStepKindOption[] = [\n { value: 'wait', label: 'Wait', icon: 'Clock', iconClass: 'wait', description: 'Pause the run for a duration before continuing.' },\n { value: 'condition', label: 'Condition', icon: 'Branch', iconClass: 'condition', description: 'Evaluate a predicate. Exit or skip on false.' },\n { value: 'branch', label: 'Branch', icon: 'Branch', iconClass: 'condition', description: 'Evaluate a predicate. Recurse into one of two sub-lists.' },\n { value: 'send', label: 'Send', icon: 'Mail', iconClass: 'send', description: 'Send a template to the contact.' },\n { value: 'tag', label: 'Tag', icon: 'Tag', iconClass: 'tag', description: 'Add or remove tags on the contact.' },\n { value: 'fire_event', label: 'Fire event', icon: 'Activity', iconClass: 'send', description: 'Insert a synthetic event (cross-flow handoff).' },\n { value: 'webhook', label: 'Webhook', icon: 'Webhook', iconClass: 'tag', description: 'POST to an external URL.' },\n { value: 'exit', label: 'Exit', icon: 'Exit', iconClass: 'exit', description: 'End the run with an optional reason.' },\n] as const\n\nexport function defaultFlowStep(type: FlowStep['type']): FlowStep {\n switch (type) {\n case 'wait': return { type: 'wait', value: 1, unit: 'days' }\n case 'condition': return { type: 'condition', test: { hasTag: 'engaged' }, ifFalse: 'exit' }\n case 'branch': return { type: 'branch', test: { hasTag: 'vip' }, ifTrueSteps: [], ifFalseSteps: [] }\n case 'send': return { type: 'send', templateSlug: '' }\n case 'tag': return { type: 'tag', addTags: [], removeTags: [] }\n case 'fire_event': return { type: 'fire_event', eventName: '' }\n case 'webhook': return { type: 'webhook', url: '', method: 'POST' }\n case 'exit': return { type: 'exit' }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Predicate kinds (the union variants of Predicate, minus composites)\n// ---------------------------------------------------------------------------\n\nexport type PredicateKind =\n | 'hasTag'\n | 'notHasTag'\n | 'fieldEquals'\n | 'fieldExists'\n | 'triggerPropertyEquals'\n | 'triggerPropertyTruthy'\n | 'hasFiredEvent'\n | 'notHasFiredEvent'\n | 'subscriptionStatus'\n | 'hasOpened'\n | 'hasClicked'\n | 'hasOpenedExcludingBots'\n | 'hasClickedExcludingBots'\n | 'openedAtLeastN'\n | 'clickedAtLeastN'\n\nexport interface PredicateKindOption {\n value: PredicateKind\n label: string\n /** True when this predicate's signal is noisy (Apple MPP, bot prefetch). */\n noisy?: boolean\n}\n\nexport const PREDICATE_KINDS: readonly PredicateKindOption[] = [\n { value: 'hasTag', label: 'has tag' },\n { value: 'notHasTag', label: 'does NOT have tag' },\n { value: 'fieldEquals', label: 'field equals' },\n { value: 'fieldExists', label: 'field exists' },\n { value: 'triggerPropertyEquals', label: 'trigger property equals' },\n { value: 'triggerPropertyTruthy', label: 'trigger property is set' },\n { value: 'hasFiredEvent', label: 'fired event' },\n { value: 'notHasFiredEvent', label: 'has NOT fired event' },\n { value: 'subscriptionStatus', label: 'subscription status' },\n { value: 'hasOpened', label: 'opened', noisy: true },\n { value: 'hasClicked', label: 'clicked', noisy: true },\n { value: 'hasOpenedExcludingBots', label: 'opened (excl. bots)' },\n { value: 'hasClickedExcludingBots', label: 'clicked (excl. bots)' },\n { value: 'openedAtLeastN', label: 'opened at least N' },\n { value: 'clickedAtLeastN', label: 'clicked at least N' },\n] as const\n\n/** Identify which kind of predicate this object is (or null for composites/unknown). */\nexport function predicateKind(p: Predicate | null | undefined): PredicateKind | null {\n if (!p) return null\n for (const k of PREDICATE_KINDS) {\n if (k.value in (p as object)) return k.value\n }\n return null\n}\n\nexport function defaultPredicate(kind: PredicateKind): Predicate {\n switch (kind) {\n case 'hasTag': return { hasTag: 'engaged' }\n case 'notHasTag': return { notHasTag: 'cold' }\n case 'fieldEquals': return { fieldEquals: { field: 'tier', value: 'Pro' } }\n case 'fieldExists': return { fieldExists: 'tier' }\n case 'triggerPropertyEquals': return { triggerPropertyEquals: { key: 'plan', value: 'pro' } }\n case 'triggerPropertyTruthy': return { triggerPropertyTruthy: 'wasReferred' }\n case 'hasFiredEvent': return { hasFiredEvent: 'Activated app' }\n case 'notHasFiredEvent': return { notHasFiredEvent: 'Cancelled' }\n case 'subscriptionStatus': return { subscriptionStatus: 'subscribed' }\n case 'hasOpened': return { hasOpened: { sinceFlowStart: true } }\n case 'hasClicked': return { hasClicked: { sinceFlowStart: true } }\n case 'hasOpenedExcludingBots': return { hasOpenedExcludingBots: { sinceFlowStart: true } }\n case 'hasClickedExcludingBots': return { hasClickedExcludingBots: { sinceFlowStart: true } }\n case 'openedAtLeastN': return { openedAtLeastN: { count: 1, withinDays: 7 } }\n case 'clickedAtLeastN': return { clickedAtLeastN: { count: 1, withinDays: 7 } }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Segment filter kinds\n// ---------------------------------------------------------------------------\n\nexport type SegmentFilterKind = SegmentFilter['kind']\n\nexport interface SegmentFilterKindOption {\n value: SegmentFilterKind\n label: string\n /** Where the filter is evaluated: host-side via adapter, or mailer-side post-filter. */\n side: 'host' | 'mailer' | 'composite'\n}\n\nexport const SEGMENT_FILTER_KINDS: readonly SegmentFilterKindOption[] = [\n { value: 'subscriptionStatus', label: 'Subscription status', side: 'mailer' },\n { value: 'hasTag', label: 'Has tag', side: 'host' },\n { value: 'notHasTag', label: 'Does NOT have tag', side: 'host' },\n { value: 'fieldEquals', label: 'Field equals', side: 'host' },\n { value: 'fieldIn', label: 'Field in list', side: 'host' },\n { value: 'fieldExists', label: 'Field exists', side: 'host' },\n { value: 'firedEvent', label: 'Fired event', side: 'mailer' },\n { value: 'notFiredEvent', label: 'Has NOT fired event', side: 'mailer' },\n { value: 'subscribedAfter', label: 'Subscribed after', side: 'mailer' },\n { value: 'subscribedBefore', label: 'Subscribed before', side: 'mailer' },\n { value: 'opened', label: 'Opened', side: 'mailer' },\n { value: 'notOpened', label: 'Did NOT open', side: 'mailer' },\n { value: 'any', label: 'Any of (OR)', side: 'composite' },\n { value: 'not', label: 'NOT', side: 'composite' },\n] as const\n\nexport function defaultSegmentFilter(kind: SegmentFilterKind): SegmentFilter {\n switch (kind) {\n case 'subscriptionStatus': return { kind: 'subscriptionStatus', equals: 'subscribed' }\n case 'hasTag': return { kind: 'hasTag', tag: '' }\n case 'notHasTag': return { kind: 'notHasTag', tag: '' }\n case 'fieldEquals': return { kind: 'fieldEquals', field: '', value: '' }\n case 'fieldIn': return { kind: 'fieldIn', field: '', values: [] }\n case 'fieldExists': return { kind: 'fieldExists', field: '' }\n case 'firedEvent': return { kind: 'firedEvent', eventName: '', withinDays: 30 }\n case 'notFiredEvent': return { kind: 'notFiredEvent', eventName: '', withinDays: 90 }\n case 'subscribedAfter': return { kind: 'subscribedAfter', date: new Date(Date.now() - 30 * 86_400_000) }\n case 'subscribedBefore': return { kind: 'subscribedBefore', date: new Date() }\n case 'opened': return { kind: 'opened', withinDays: 14 }\n case 'notOpened': return { kind: 'notOpened', withinDays: 14 }\n case 'any': return { kind: 'any', filters: [] }\n case 'not': return { kind: 'not', filter: { kind: 'hasTag', tag: '' } }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Dedupe policies for event registration\n// ---------------------------------------------------------------------------\n\nexport interface DedupePolicyOption {\n value: 'once-per-contact' | 'once-per-day' | 'every-time'\n label: string\n description: string\n derivedKeyShape: string\n}\n\nexport const DEDUPE_POLICIES: readonly DedupePolicyOption[] = [\n {\n value: 'once-per-contact',\n label: 'Once per contact',\n description: 'Lifecycle markers (Created, Activated)',\n derivedKeyShape: '${externalId}:${eventName}',\n },\n {\n value: 'once-per-day',\n label: 'Once per day',\n description: 'Daily behaviors (Viewed Storyboard)',\n derivedKeyShape: '${externalId}:${eventName}:${YYYY-MM-DD}',\n },\n {\n value: 'every-time',\n label: 'Every time',\n description: 'True every-occurrence events (Imported)',\n derivedKeyShape: '${externalId}:${eventName}:${UUIDv4}',\n },\n] as const\n"]}