mailery 0.9.0 → 0.10.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.
- package/dist/admin/spa/index-BTww-4AA.js +41 -0
- package/dist/admin/spa/index-BTww-4AA.js.map +1 -0
- package/dist/admin/spa/index.html +1 -1
- package/dist/admin/spa/{template-editor-DwMKy5sw.js → template-editor-CrOKLpSw.js} +2 -2
- package/dist/admin/spa/{template-editor-DwMKy5sw.js.map → template-editor-CrOKLpSw.js.map} +1 -1
- package/dist/index.cjs +63 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +63 -6
- package/dist/index.js.map +1 -1
- package/dist/{null-BRSHAxvg.d.cts → null-CU_EApC6.d.cts} +16 -0
- package/dist/{null-BRSHAxvg.d.ts → null-CU_EApC6.d.ts} +16 -0
- package/dist/testing.cjs +56 -5
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +2 -2
- package/dist/testing.d.ts +2 -2
- package/dist/testing.js +56 -5
- package/dist/testing.js.map +1 -1
- package/package.json +1 -1
- package/dist/admin/spa/index-B3ndbezm.js +0 -41
- package/dist/admin/spa/index-B3ndbezm.js.map +0 -1
|
@@ -113,6 +113,21 @@ type Predicate = {
|
|
|
113
113
|
};
|
|
114
114
|
} | {
|
|
115
115
|
fieldExists: string;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Tests a property of the event that STARTED this run, so the answer is
|
|
119
|
+
* per-run rather than per-contact. Use when the gate depends on what the run
|
|
120
|
+
* is about (which account, plan, order) instead of a durable trait of the
|
|
121
|
+
* person: a contact-level tag is shared by every concurrent run and the last
|
|
122
|
+
* writer wins, which silently changes branching in runs already in flight.
|
|
123
|
+
*/
|
|
124
|
+
| {
|
|
125
|
+
triggerPropertyEquals: {
|
|
126
|
+
key: string;
|
|
127
|
+
value: string | number | boolean | null;
|
|
128
|
+
};
|
|
129
|
+
} | {
|
|
130
|
+
triggerPropertyTruthy: string;
|
|
116
131
|
} | {
|
|
117
132
|
hasFiredEvent: string;
|
|
118
133
|
sinceFlowStart?: boolean;
|
|
@@ -1427,6 +1442,7 @@ declare class Mailer {
|
|
|
1427
1442
|
*/
|
|
1428
1443
|
abortFlow(flowSlug: string, externalId: string, opts?: {
|
|
1429
1444
|
reason?: string;
|
|
1445
|
+
matchTriggerProperties?: Record<string, unknown>;
|
|
1430
1446
|
}): Promise<{
|
|
1431
1447
|
abortedRuns: number;
|
|
1432
1448
|
cancelledSends: number;
|
|
@@ -113,6 +113,21 @@ type Predicate = {
|
|
|
113
113
|
};
|
|
114
114
|
} | {
|
|
115
115
|
fieldExists: string;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Tests a property of the event that STARTED this run, so the answer is
|
|
119
|
+
* per-run rather than per-contact. Use when the gate depends on what the run
|
|
120
|
+
* is about (which account, plan, order) instead of a durable trait of the
|
|
121
|
+
* person: a contact-level tag is shared by every concurrent run and the last
|
|
122
|
+
* writer wins, which silently changes branching in runs already in flight.
|
|
123
|
+
*/
|
|
124
|
+
| {
|
|
125
|
+
triggerPropertyEquals: {
|
|
126
|
+
key: string;
|
|
127
|
+
value: string | number | boolean | null;
|
|
128
|
+
};
|
|
129
|
+
} | {
|
|
130
|
+
triggerPropertyTruthy: string;
|
|
116
131
|
} | {
|
|
117
132
|
hasFiredEvent: string;
|
|
118
133
|
sinceFlowStart?: boolean;
|
|
@@ -1427,6 +1442,7 @@ declare class Mailer {
|
|
|
1427
1442
|
*/
|
|
1428
1443
|
abortFlow(flowSlug: string, externalId: string, opts?: {
|
|
1429
1444
|
reason?: string;
|
|
1445
|
+
matchTriggerProperties?: Record<string, unknown>;
|
|
1430
1446
|
}): Promise<{
|
|
1431
1447
|
abortedRuns: number;
|
|
1432
1448
|
cancelledSends: number;
|
package/dist/testing.cjs
CHANGED
|
@@ -14208,7 +14208,25 @@ var tagInputSchema = zod.z.object({
|
|
|
14208
14208
|
var abortFlowInputSchema = zod.z.object({
|
|
14209
14209
|
flowSlug: slugSchema,
|
|
14210
14210
|
externalId: externalIdSchema,
|
|
14211
|
-
reason: zod.z.string().min(1).max(200).optional()
|
|
14211
|
+
reason: zod.z.string().min(1).max(200).optional(),
|
|
14212
|
+
/**
|
|
14213
|
+
* Restrict the abort to runs whose trigger event carried these properties —
|
|
14214
|
+
* e.g. `{ accountId }` to cancel one account's series while the same
|
|
14215
|
+
* contact's other accounts keep running. Omit to abort every active run for
|
|
14216
|
+
* the contact on this flow.
|
|
14217
|
+
*
|
|
14218
|
+
* Keys and values are both constrained because these go straight into a
|
|
14219
|
+
* Mongo query. Values are primitives only: an object value like
|
|
14220
|
+
* `{ $ne: null }` would reach the query as an OPERATOR and match every
|
|
14221
|
+
* scoped run, turning a one-account abort into abort-everything. Hosts
|
|
14222
|
+
* typically pass an id from a request body, so treat it as untrusted. The
|
|
14223
|
+
* key regex likewise blocks `$`-prefixed keys and dots (a dot would silently
|
|
14224
|
+
* extend the path and change match semantics).
|
|
14225
|
+
*/
|
|
14226
|
+
matchTriggerProperties: zod.z.record(
|
|
14227
|
+
zod.z.string().regex(/^[A-Za-z0-9_]+$/),
|
|
14228
|
+
zod.z.union([zod.z.string(), zod.z.number(), zod.z.boolean(), zod.z.null()])
|
|
14229
|
+
).optional()
|
|
14212
14230
|
});
|
|
14213
14231
|
var abortAllFlowsInputSchema = abortFlowInputSchema.omit({ flowSlug: true });
|
|
14214
14232
|
var sendOneOffInputSchema = zod.z.object({
|
|
@@ -14277,6 +14295,13 @@ var predicateSchema = zod.z.lazy(
|
|
|
14277
14295
|
zod.z.object({ notHasTag: zod.z.string() }),
|
|
14278
14296
|
zod.z.object({ fieldEquals: zod.z.object({ field: zod.z.string(), value: zod.z.unknown() }) }),
|
|
14279
14297
|
zod.z.object({ fieldExists: zod.z.string() }),
|
|
14298
|
+
zod.z.object({
|
|
14299
|
+
triggerPropertyEquals: zod.z.object({
|
|
14300
|
+
key: zod.z.string().min(1),
|
|
14301
|
+
value: zod.z.union([zod.z.string(), zod.z.number(), zod.z.boolean(), zod.z.null()])
|
|
14302
|
+
})
|
|
14303
|
+
}),
|
|
14304
|
+
zod.z.object({ triggerPropertyTruthy: zod.z.string().min(1) }),
|
|
14280
14305
|
zod.z.object({
|
|
14281
14306
|
hasFiredEvent: zod.z.string(),
|
|
14282
14307
|
sinceFlowStart: zod.z.boolean().optional(),
|
|
@@ -15367,6 +15392,12 @@ async function evaluatePredicate(predicate, ctx) {
|
|
|
15367
15392
|
if ("fieldExists" in p) {
|
|
15368
15393
|
return ctx.contact.fields[p.fieldExists] !== void 0;
|
|
15369
15394
|
}
|
|
15395
|
+
if ("triggerPropertyEquals" in p) {
|
|
15396
|
+
return (ctx.run.triggerEvent?.properties ?? {})[p.triggerPropertyEquals.key] === p.triggerPropertyEquals.value;
|
|
15397
|
+
}
|
|
15398
|
+
if ("triggerPropertyTruthy" in p) {
|
|
15399
|
+
return Boolean((ctx.run.triggerEvent?.properties ?? {})[p.triggerPropertyTruthy]);
|
|
15400
|
+
}
|
|
15370
15401
|
if ("subscriptionStatus" in p) {
|
|
15371
15402
|
const sub = await ctx.collections.subscriptions.findOne({ externalId: ctx.contact.externalId });
|
|
15372
15403
|
return sub?.status === p.subscriptionStatus;
|
|
@@ -16113,7 +16144,14 @@ async function handleFireEvent(run, step2, ctx) {
|
|
|
16113
16144
|
await ctx.collections.events.insertOne({
|
|
16114
16145
|
externalId: run.externalId,
|
|
16115
16146
|
name: step2.eventName,
|
|
16116
|
-
|
|
16147
|
+
// Inherit the triggering event's properties so a handoff carries the
|
|
16148
|
+
// context that identifies what the run is ABOUT (which account, order,
|
|
16149
|
+
// subscription, ...). A step's `properties` are static — authored once in
|
|
16150
|
+
// the flow definition — so without this a fired event can only ever say
|
|
16151
|
+
// "this contact", losing the scope the originating event supplied, and
|
|
16152
|
+
// the receiving flow has nothing to resolve variables against. Explicit
|
|
16153
|
+
// step.properties win on conflict.
|
|
16154
|
+
properties: { ...run.triggerEvent?.properties ?? {}, ...step2.properties ?? {} },
|
|
16117
16155
|
dedupeKey,
|
|
16118
16156
|
occurredAt: /* @__PURE__ */ new Date(),
|
|
16119
16157
|
createdAt: /* @__PURE__ */ new Date()
|
|
@@ -17676,14 +17714,25 @@ var Mailer = class _Mailer {
|
|
|
17676
17714
|
* same handler that processes the business event ("user upgraded").
|
|
17677
17715
|
*/
|
|
17678
17716
|
async abortFlow(flowSlug, externalId, opts = {}) {
|
|
17679
|
-
const parsed = abortFlowInputSchema.parse({
|
|
17717
|
+
const parsed = abortFlowInputSchema.parse({
|
|
17718
|
+
flowSlug,
|
|
17719
|
+
externalId,
|
|
17720
|
+
reason: opts.reason,
|
|
17721
|
+
matchTriggerProperties: opts.matchTriggerProperties
|
|
17722
|
+
});
|
|
17680
17723
|
const flow = await this.collections.flows.findOne(
|
|
17681
17724
|
{ slug: parsed.flowSlug },
|
|
17682
17725
|
{ projection: { _id: 1 } }
|
|
17683
17726
|
);
|
|
17684
17727
|
if (!flow) throw new Error(`abortFlow: unknown flow slug "${parsed.flowSlug}"`);
|
|
17728
|
+
const triggerMatch = Object.fromEntries(
|
|
17729
|
+
Object.entries(parsed.matchTriggerProperties ?? {}).map(([k, v]) => [
|
|
17730
|
+
`triggerEvent.properties.${k}`,
|
|
17731
|
+
v
|
|
17732
|
+
])
|
|
17733
|
+
);
|
|
17685
17734
|
const result = await this.abortActiveRuns(
|
|
17686
|
-
{ externalId: parsed.externalId, flowId: flow._id },
|
|
17735
|
+
{ externalId: parsed.externalId, flowId: flow._id, ...triggerMatch },
|
|
17687
17736
|
parsed.reason ? `aborted_by_host:${parsed.reason}` : "aborted_by_host"
|
|
17688
17737
|
);
|
|
17689
17738
|
if (result.abortedRuns > 0 || result.cancelledSends > 0) {
|
|
@@ -17691,7 +17740,9 @@ var Mailer = class _Mailer {
|
|
|
17691
17740
|
actor: "host",
|
|
17692
17741
|
action: "flow.abort",
|
|
17693
17742
|
resource: { collection: "mailer_flow_runs", slug: parsed.flowSlug },
|
|
17694
|
-
|
|
17743
|
+
// Record the scope: without it a one-account abort and an abort-every-
|
|
17744
|
+
// run-for-this-contact are indistinguishable in the audit trail.
|
|
17745
|
+
diffSummary: `abortFlow slug=${parsed.flowSlug} externalId=${parsed.externalId} scope=${parsed.matchTriggerProperties ? JSON.stringify(parsed.matchTriggerProperties) : "all"} runs=${result.abortedRuns} sends=${result.cancelledSends}${parsed.reason ? ` reason=${parsed.reason}` : ""}`
|
|
17695
17746
|
});
|
|
17696
17747
|
}
|
|
17697
17748
|
return result;
|