mailery 0.9.0 → 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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 +65 -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 +65 -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 +58 -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 +58 -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
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { R as RunnerContext, N as NormalizedEvent, C as ContactAdapter, a as Contact, A as AdapterFilter, M as MailProvider, S as SendArgs, b as SendResult, c as MailTesterFeedback, d as Mailer, T as TemplateDoc, e as SuppressionScope, D as DeliveryWindow, F as FlowStep, f as SegmentFilter, P as Predicate } from './null-
|
|
2
|
-
export { g as AuditLogDoc, B as BroadcastDoc, h as BroadcastStatus, i as CircuitBreakerThresholds, j as Collections, k as ContactTagDoc, E as EventDoc, l as FlowDoc, m as FlowGoal, n as FlowRunDoc, o as FlowRunStatus, p as FlowVersionDoc, H as HealthDoc, q as HealthStatus, L as LeadDoc, r as MailerConfig, s as NullProvider, O as OutboxDoc, t as RESERVED_VAR_KEYS, u as RedisOptions, v as SegmentDefinition, w as SendDoc, x as SendStatus, y as SenderDomainConfig, z as SenderDomainRegistry, G as SenderDomainValidation, I as SubscriptionDoc, J as SubscriptionStatus, K as SuppressionDoc, Q as SuppressionReason, U as TemplateKind, V as TemplateVersionDoc, W as VarsAdapter, X as VarsResolveInfo, Y as WebhookEventDoc, Z as defineVars, _ as ensureIndexes, $ as getCollections, a0 as validateSenderDomain, a1 as varsJsonSchema } from './null-
|
|
1
|
+
import { R as RunnerContext, N as NormalizedEvent, C as ContactAdapter, a as Contact, A as AdapterFilter, M as MailProvider, S as SendArgs, b as SendResult, c as MailTesterFeedback, d as Mailer, T as TemplateDoc, e as SuppressionScope, D as DeliveryWindow, F as FlowStep, f as SegmentFilter, P as Predicate } from './null-CU_EApC6.cjs';
|
|
2
|
+
export { g as AuditLogDoc, B as BroadcastDoc, h as BroadcastStatus, i as CircuitBreakerThresholds, j as Collections, k as ContactTagDoc, E as EventDoc, l as FlowDoc, m as FlowGoal, n as FlowRunDoc, o as FlowRunStatus, p as FlowVersionDoc, H as HealthDoc, q as HealthStatus, L as LeadDoc, r as MailerConfig, s as NullProvider, O as OutboxDoc, t as RESERVED_VAR_KEYS, u as RedisOptions, v as SegmentDefinition, w as SendDoc, x as SendStatus, y as SenderDomainConfig, z as SenderDomainRegistry, G as SenderDomainValidation, I as SubscriptionDoc, J as SubscriptionStatus, K as SuppressionDoc, Q as SuppressionReason, U as TemplateKind, V as TemplateVersionDoc, W as VarsAdapter, X as VarsResolveInfo, Y as WebhookEventDoc, Z as defineVars, _ as ensureIndexes, $ as getCollections, a0 as validateSenderDomain, a1 as varsJsonSchema } from './null-CU_EApC6.cjs';
|
|
3
3
|
import { ObjectId, Db, Filter } from 'mongodb';
|
|
4
4
|
import { Request, Router } from 'express';
|
|
5
5
|
import Handlebars from 'handlebars';
|
|
@@ -367,7 +367,7 @@ interface FlowStepKindOption {
|
|
|
367
367
|
}
|
|
368
368
|
declare const FLOW_STEP_KINDS: readonly FlowStepKindOption[];
|
|
369
369
|
declare function defaultFlowStep(type: FlowStep['type']): FlowStep;
|
|
370
|
-
type PredicateKind = 'hasTag' | 'notHasTag' | 'fieldEquals' | 'fieldExists' | 'hasFiredEvent' | 'notHasFiredEvent' | 'subscriptionStatus' | 'hasOpened' | 'hasClicked' | 'hasOpenedExcludingBots' | 'hasClickedExcludingBots' | 'openedAtLeastN' | 'clickedAtLeastN';
|
|
370
|
+
type PredicateKind = 'hasTag' | 'notHasTag' | 'fieldEquals' | 'fieldExists' | 'triggerPropertyEquals' | 'triggerPropertyTruthy' | 'hasFiredEvent' | 'notHasFiredEvent' | 'subscriptionStatus' | 'hasOpened' | 'hasClicked' | 'hasOpenedExcludingBots' | 'hasClickedExcludingBots' | 'openedAtLeastN' | 'clickedAtLeastN';
|
|
371
371
|
interface PredicateKindOption {
|
|
372
372
|
value: PredicateKind;
|
|
373
373
|
label: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { R as RunnerContext, N as NormalizedEvent, C as ContactAdapter, a as Contact, A as AdapterFilter, M as MailProvider, S as SendArgs, b as SendResult, c as MailTesterFeedback, d as Mailer, T as TemplateDoc, e as SuppressionScope, D as DeliveryWindow, F as FlowStep, f as SegmentFilter, P as Predicate } from './null-
|
|
2
|
-
export { g as AuditLogDoc, B as BroadcastDoc, h as BroadcastStatus, i as CircuitBreakerThresholds, j as Collections, k as ContactTagDoc, E as EventDoc, l as FlowDoc, m as FlowGoal, n as FlowRunDoc, o as FlowRunStatus, p as FlowVersionDoc, H as HealthDoc, q as HealthStatus, L as LeadDoc, r as MailerConfig, s as NullProvider, O as OutboxDoc, t as RESERVED_VAR_KEYS, u as RedisOptions, v as SegmentDefinition, w as SendDoc, x as SendStatus, y as SenderDomainConfig, z as SenderDomainRegistry, G as SenderDomainValidation, I as SubscriptionDoc, J as SubscriptionStatus, K as SuppressionDoc, Q as SuppressionReason, U as TemplateKind, V as TemplateVersionDoc, W as VarsAdapter, X as VarsResolveInfo, Y as WebhookEventDoc, Z as defineVars, _ as ensureIndexes, $ as getCollections, a0 as validateSenderDomain, a1 as varsJsonSchema } from './null-
|
|
1
|
+
import { R as RunnerContext, N as NormalizedEvent, C as ContactAdapter, a as Contact, A as AdapterFilter, M as MailProvider, S as SendArgs, b as SendResult, c as MailTesterFeedback, d as Mailer, T as TemplateDoc, e as SuppressionScope, D as DeliveryWindow, F as FlowStep, f as SegmentFilter, P as Predicate } from './null-CU_EApC6.js';
|
|
2
|
+
export { g as AuditLogDoc, B as BroadcastDoc, h as BroadcastStatus, i as CircuitBreakerThresholds, j as Collections, k as ContactTagDoc, E as EventDoc, l as FlowDoc, m as FlowGoal, n as FlowRunDoc, o as FlowRunStatus, p as FlowVersionDoc, H as HealthDoc, q as HealthStatus, L as LeadDoc, r as MailerConfig, s as NullProvider, O as OutboxDoc, t as RESERVED_VAR_KEYS, u as RedisOptions, v as SegmentDefinition, w as SendDoc, x as SendStatus, y as SenderDomainConfig, z as SenderDomainRegistry, G as SenderDomainValidation, I as SubscriptionDoc, J as SubscriptionStatus, K as SuppressionDoc, Q as SuppressionReason, U as TemplateKind, V as TemplateVersionDoc, W as VarsAdapter, X as VarsResolveInfo, Y as WebhookEventDoc, Z as defineVars, _ as ensureIndexes, $ as getCollections, a0 as validateSenderDomain, a1 as varsJsonSchema } from './null-CU_EApC6.js';
|
|
3
3
|
import { ObjectId, Db, Filter } from 'mongodb';
|
|
4
4
|
import { Request, Router } from 'express';
|
|
5
5
|
import Handlebars from 'handlebars';
|
|
@@ -367,7 +367,7 @@ interface FlowStepKindOption {
|
|
|
367
367
|
}
|
|
368
368
|
declare const FLOW_STEP_KINDS: readonly FlowStepKindOption[];
|
|
369
369
|
declare function defaultFlowStep(type: FlowStep['type']): FlowStep;
|
|
370
|
-
type PredicateKind = 'hasTag' | 'notHasTag' | 'fieldEquals' | 'fieldExists' | 'hasFiredEvent' | 'notHasFiredEvent' | 'subscriptionStatus' | 'hasOpened' | 'hasClicked' | 'hasOpenedExcludingBots' | 'hasClickedExcludingBots' | 'openedAtLeastN' | 'clickedAtLeastN';
|
|
370
|
+
type PredicateKind = 'hasTag' | 'notHasTag' | 'fieldEquals' | 'fieldExists' | 'triggerPropertyEquals' | 'triggerPropertyTruthy' | 'hasFiredEvent' | 'notHasFiredEvent' | 'subscriptionStatus' | 'hasOpened' | 'hasClicked' | 'hasOpenedExcludingBots' | 'hasClickedExcludingBots' | 'openedAtLeastN' | 'clickedAtLeastN';
|
|
371
371
|
interface PredicateKindOption {
|
|
372
372
|
value: PredicateKind;
|
|
373
373
|
label: string;
|
package/dist/index.js
CHANGED
|
@@ -396,7 +396,25 @@ var tagInputSchema = z.object({
|
|
|
396
396
|
var abortFlowInputSchema = z.object({
|
|
397
397
|
flowSlug: slugSchema,
|
|
398
398
|
externalId: externalIdSchema,
|
|
399
|
-
reason: z.string().min(1).max(200).optional()
|
|
399
|
+
reason: z.string().min(1).max(200).optional(),
|
|
400
|
+
/**
|
|
401
|
+
* Restrict the abort to runs whose trigger event carried these properties —
|
|
402
|
+
* e.g. `{ accountId }` to cancel one account's series while the same
|
|
403
|
+
* contact's other accounts keep running. Omit to abort every active run for
|
|
404
|
+
* the contact on this flow.
|
|
405
|
+
*
|
|
406
|
+
* Keys and values are both constrained because these go straight into a
|
|
407
|
+
* Mongo query. Values are primitives only: an object value like
|
|
408
|
+
* `{ $ne: null }` would reach the query as an OPERATOR and match every
|
|
409
|
+
* scoped run, turning a one-account abort into abort-everything. Hosts
|
|
410
|
+
* typically pass an id from a request body, so treat it as untrusted. The
|
|
411
|
+
* key regex likewise blocks `$`-prefixed keys and dots (a dot would silently
|
|
412
|
+
* extend the path and change match semantics).
|
|
413
|
+
*/
|
|
414
|
+
matchTriggerProperties: z.record(
|
|
415
|
+
z.string().regex(/^[A-Za-z0-9_]+$/),
|
|
416
|
+
z.union([z.string(), z.number(), z.boolean(), z.null()])
|
|
417
|
+
).optional()
|
|
400
418
|
});
|
|
401
419
|
var abortAllFlowsInputSchema = abortFlowInputSchema.omit({ flowSlug: true });
|
|
402
420
|
var sendOneOffInputSchema = z.object({
|
|
@@ -465,6 +483,13 @@ var predicateSchema = z.lazy(
|
|
|
465
483
|
z.object({ notHasTag: z.string() }),
|
|
466
484
|
z.object({ fieldEquals: z.object({ field: z.string(), value: z.unknown() }) }),
|
|
467
485
|
z.object({ fieldExists: z.string() }),
|
|
486
|
+
z.object({
|
|
487
|
+
triggerPropertyEquals: z.object({
|
|
488
|
+
key: z.string().min(1),
|
|
489
|
+
value: z.union([z.string(), z.number(), z.boolean(), z.null()])
|
|
490
|
+
})
|
|
491
|
+
}),
|
|
492
|
+
z.object({ triggerPropertyTruthy: z.string().min(1) }),
|
|
468
493
|
z.object({
|
|
469
494
|
hasFiredEvent: z.string(),
|
|
470
495
|
sinceFlowStart: z.boolean().optional(),
|
|
@@ -1648,6 +1673,12 @@ async function evaluatePredicate(predicate, ctx) {
|
|
|
1648
1673
|
if ("fieldExists" in p) {
|
|
1649
1674
|
return ctx.contact.fields[p.fieldExists] !== void 0;
|
|
1650
1675
|
}
|
|
1676
|
+
if ("triggerPropertyEquals" in p) {
|
|
1677
|
+
return (ctx.run.triggerEvent?.properties ?? {})[p.triggerPropertyEquals.key] === p.triggerPropertyEquals.value;
|
|
1678
|
+
}
|
|
1679
|
+
if ("triggerPropertyTruthy" in p) {
|
|
1680
|
+
return Boolean((ctx.run.triggerEvent?.properties ?? {})[p.triggerPropertyTruthy]);
|
|
1681
|
+
}
|
|
1651
1682
|
if ("subscriptionStatus" in p) {
|
|
1652
1683
|
const sub = await ctx.collections.subscriptions.findOne({ externalId: ctx.contact.externalId });
|
|
1653
1684
|
return sub?.status === p.subscriptionStatus;
|
|
@@ -2254,9 +2285,11 @@ function sha256(s) {
|
|
|
2254
2285
|
}
|
|
2255
2286
|
|
|
2256
2287
|
// src/server/runner/step.ts
|
|
2288
|
+
var DUE_SKEW_MS = 1e3;
|
|
2257
2289
|
async function processOneRunStep(runId, ctx) {
|
|
2258
2290
|
const run = await ctx.collections.flowRuns.findOne({ _id: runId });
|
|
2259
2291
|
if (!run || run.status !== "active") return;
|
|
2292
|
+
if (run.nextActionAt && run.nextActionAt.getTime() > Date.now() + DUE_SKEW_MS) return;
|
|
2260
2293
|
const flow = await ctx.collections.flows.findOne({ _id: run.flowId });
|
|
2261
2294
|
if (!flow) {
|
|
2262
2295
|
await failFlowRun(run, "flow_missing", ctx);
|
|
@@ -2400,7 +2433,14 @@ async function handleFireEvent(run, step, ctx) {
|
|
|
2400
2433
|
await ctx.collections.events.insertOne({
|
|
2401
2434
|
externalId: run.externalId,
|
|
2402
2435
|
name: step.eventName,
|
|
2403
|
-
|
|
2436
|
+
// Inherit the triggering event's properties so a handoff carries the
|
|
2437
|
+
// context that identifies what the run is ABOUT (which account, order,
|
|
2438
|
+
// subscription, ...). A step's `properties` are static — authored once in
|
|
2439
|
+
// the flow definition — so without this a fired event can only ever say
|
|
2440
|
+
// "this contact", losing the scope the originating event supplied, and
|
|
2441
|
+
// the receiving flow has nothing to resolve variables against. Explicit
|
|
2442
|
+
// step.properties win on conflict.
|
|
2443
|
+
properties: { ...run.triggerEvent?.properties ?? {}, ...step.properties ?? {} },
|
|
2404
2444
|
dedupeKey,
|
|
2405
2445
|
occurredAt: /* @__PURE__ */ new Date(),
|
|
2406
2446
|
createdAt: /* @__PURE__ */ new Date()
|
|
@@ -4235,14 +4275,25 @@ var Mailer = class _Mailer {
|
|
|
4235
4275
|
* same handler that processes the business event ("user upgraded").
|
|
4236
4276
|
*/
|
|
4237
4277
|
async abortFlow(flowSlug, externalId, opts = {}) {
|
|
4238
|
-
const parsed = abortFlowInputSchema.parse({
|
|
4278
|
+
const parsed = abortFlowInputSchema.parse({
|
|
4279
|
+
flowSlug,
|
|
4280
|
+
externalId,
|
|
4281
|
+
reason: opts.reason,
|
|
4282
|
+
matchTriggerProperties: opts.matchTriggerProperties
|
|
4283
|
+
});
|
|
4239
4284
|
const flow = await this.collections.flows.findOne(
|
|
4240
4285
|
{ slug: parsed.flowSlug },
|
|
4241
4286
|
{ projection: { _id: 1 } }
|
|
4242
4287
|
);
|
|
4243
4288
|
if (!flow) throw new Error(`abortFlow: unknown flow slug "${parsed.flowSlug}"`);
|
|
4289
|
+
const triggerMatch = Object.fromEntries(
|
|
4290
|
+
Object.entries(parsed.matchTriggerProperties ?? {}).map(([k, v]) => [
|
|
4291
|
+
`triggerEvent.properties.${k}`,
|
|
4292
|
+
v
|
|
4293
|
+
])
|
|
4294
|
+
);
|
|
4244
4295
|
const result = await this.abortActiveRuns(
|
|
4245
|
-
{ externalId: parsed.externalId, flowId: flow._id },
|
|
4296
|
+
{ externalId: parsed.externalId, flowId: flow._id, ...triggerMatch },
|
|
4246
4297
|
parsed.reason ? `aborted_by_host:${parsed.reason}` : "aborted_by_host"
|
|
4247
4298
|
);
|
|
4248
4299
|
if (result.abortedRuns > 0 || result.cancelledSends > 0) {
|
|
@@ -4250,7 +4301,9 @@ var Mailer = class _Mailer {
|
|
|
4250
4301
|
actor: "host",
|
|
4251
4302
|
action: "flow.abort",
|
|
4252
4303
|
resource: { collection: "mailer_flow_runs", slug: parsed.flowSlug },
|
|
4253
|
-
|
|
4304
|
+
// Record the scope: without it a one-account abort and an abort-every-
|
|
4305
|
+
// run-for-this-contact are indistinguishable in the audit trail.
|
|
4306
|
+
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}` : ""}`
|
|
4254
4307
|
});
|
|
4255
4308
|
}
|
|
4256
4309
|
return result;
|
|
@@ -7416,6 +7469,8 @@ var PREDICATE_KINDS = [
|
|
|
7416
7469
|
{ value: "notHasTag", label: "does NOT have tag" },
|
|
7417
7470
|
{ value: "fieldEquals", label: "field equals" },
|
|
7418
7471
|
{ value: "fieldExists", label: "field exists" },
|
|
7472
|
+
{ value: "triggerPropertyEquals", label: "trigger property equals" },
|
|
7473
|
+
{ value: "triggerPropertyTruthy", label: "trigger property is set" },
|
|
7419
7474
|
{ value: "hasFiredEvent", label: "fired event" },
|
|
7420
7475
|
{ value: "notHasFiredEvent", label: "has NOT fired event" },
|
|
7421
7476
|
{ value: "subscriptionStatus", label: "subscription status" },
|
|
@@ -7443,6 +7498,10 @@ function defaultPredicate(kind) {
|
|
|
7443
7498
|
return { fieldEquals: { field: "tier", value: "Pro" } };
|
|
7444
7499
|
case "fieldExists":
|
|
7445
7500
|
return { fieldExists: "tier" };
|
|
7501
|
+
case "triggerPropertyEquals":
|
|
7502
|
+
return { triggerPropertyEquals: { key: "plan", value: "pro" } };
|
|
7503
|
+
case "triggerPropertyTruthy":
|
|
7504
|
+
return { triggerPropertyTruthy: "wasReferred" };
|
|
7446
7505
|
case "hasFiredEvent":
|
|
7447
7506
|
return { hasFiredEvent: "Activated app" };
|
|
7448
7507
|
case "notHasFiredEvent":
|
|
@@ -7533,7 +7592,7 @@ var DEDUPE_POLICIES = [
|
|
|
7533
7592
|
];
|
|
7534
7593
|
|
|
7535
7594
|
// src/server/index.ts
|
|
7536
|
-
var VERSION = "0.
|
|
7595
|
+
var VERSION = "0.10.1" ;
|
|
7537
7596
|
|
|
7538
7597
|
export { DEDUPE_POLICIES, FLOW_STEP_KINDS, Mailer, MongoContactAdapter, NullProvider, PREDICATE_KINDS, RESERVED_VAR_KEYS, SEGMENT_FILTER_KINDS, SendGridProvider, VERSION, applyTracking, applyWebhookEvent, compileMailyTemplate, compileTemplate, computeDeliveryTime, createAdminRouter, createPublicRouter, defaultFlowStep, defaultPredicate, defaultSegmentFilter, defineVars, derivePlaintext, dispatchSend, ensureIndexes, getCollections, predicateKind, processNewlyFiredEventTriggers, processOneRunStep, renderTemplate, runTick, sha256Hex, signUnsubscribeToken, sweepStrandedFlowRuns, validateSenderDomain, varsJsonSchema, verifyUnsubscribeToken };
|
|
7539
7598
|
//# sourceMappingURL=index.js.map
|