hazo_notify 5.0.1 → 5.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +42 -10
- package/dist/components/notification_bell/index.d.ts +11 -1
- package/dist/components/notification_bell/index.d.ts.map +1 -1
- package/dist/components/notification_bell/index.js +33 -1
- package/dist/components/notification_bell/index.js.map +1 -1
- package/dist/lib/adapters/email/adapter.d.ts +2 -0
- package/dist/lib/adapters/email/adapter.d.ts.map +1 -1
- package/dist/lib/adapters/email/adapter.js +53 -22
- package/dist/lib/adapters/email/adapter.js.map +1 -1
- package/dist/lib/adapters/webhook/adapter.d.ts +10 -0
- package/dist/lib/adapters/webhook/adapter.d.ts.map +1 -0
- package/dist/lib/adapters/webhook/adapter.js +90 -0
- package/dist/lib/adapters/webhook/adapter.js.map +1 -0
- package/dist/lib/adapters/webhook/index.d.ts +8 -0
- package/dist/lib/adapters/webhook/index.d.ts.map +1 -0
- package/dist/lib/adapters/webhook/index.js +3 -0
- package/dist/lib/adapters/webhook/index.js.map +1 -0
- package/dist/lib/adapters/webhook/types.d.ts +45 -0
- package/dist/lib/adapters/webhook/types.d.ts.map +1 -0
- package/dist/lib/adapters/webhook/types.js +12 -0
- package/dist/lib/adapters/webhook/types.js.map +1 -0
- package/dist/lib/api/inbox.d.ts +32 -0
- package/dist/lib/api/inbox.d.ts.map +1 -1
- package/dist/lib/api/inbox.js +68 -0
- package/dist/lib/api/inbox.js.map +1 -1
- package/dist/lib/dispatcher/index.d.ts +2 -2
- package/dist/lib/dispatcher/index.d.ts.map +1 -1
- package/dist/lib/dispatcher/index.js +30 -8
- package/dist/lib/dispatcher/index.js.map +1 -1
- package/dist/lib/inbox/broadcaster.d.ts +44 -0
- package/dist/lib/inbox/broadcaster.d.ts.map +1 -0
- package/dist/lib/inbox/broadcaster.js +62 -0
- package/dist/lib/inbox/broadcaster.js.map +1 -0
- package/dist/lib/inbox/index.d.ts +2 -0
- package/dist/lib/inbox/index.d.ts.map +1 -1
- package/dist/lib/inbox/index.js +1 -0
- package/dist/lib/inbox/index.js.map +1 -1
- package/dist/lib/inbox/storage.d.ts.map +1 -1
- package/dist/lib/inbox/storage.js +8 -2
- package/dist/lib/inbox/storage.js.map +1 -1
- package/dist/lib/inbox/types.d.ts +10 -1
- package/dist/lib/inbox/types.d.ts.map +1 -1
- package/dist/lib/jobs/digest.d.ts +77 -0
- package/dist/lib/jobs/digest.d.ts.map +1 -0
- package/dist/lib/jobs/digest.js +127 -0
- package/dist/lib/jobs/digest.js.map +1 -0
- package/dist/lib/jobs/index.d.ts +2 -0
- package/dist/lib/jobs/index.d.ts.map +1 -1
- package/dist/lib/jobs/index.js +1 -0
- package/dist/lib/jobs/index.js.map +1 -1
- package/dist/lib/jobs/submit.d.ts.map +1 -1
- package/dist/lib/jobs/submit.js +1 -0
- package/dist/lib/jobs/submit.js.map +1 -1
- package/dist/lib/jobs/types.d.ts +1 -0
- package/dist/lib/jobs/types.d.ts.map +1 -1
- package/dist/lib/lifecycle/default_templates.d.ts +9 -0
- package/dist/lib/lifecycle/default_templates.d.ts.map +1 -0
- package/dist/lib/lifecycle/default_templates.js +196 -0
- package/dist/lib/lifecycle/default_templates.js.map +1 -0
- package/dist/lib/lifecycle/dispatch.d.ts +37 -0
- package/dist/lib/lifecycle/dispatch.d.ts.map +1 -0
- package/dist/lib/lifecycle/dispatch.js +32 -0
- package/dist/lib/lifecycle/dispatch.js.map +1 -0
- package/dist/lib/lifecycle/events.d.ts +34 -0
- package/dist/lib/lifecycle/events.d.ts.map +1 -0
- package/dist/lib/lifecycle/events.js +118 -0
- package/dist/lib/lifecycle/events.js.map +1 -0
- package/dist/lib/lifecycle/handler.d.ts +29 -0
- package/dist/lib/lifecycle/handler.d.ts.map +1 -0
- package/dist/lib/lifecycle/handler.js +145 -0
- package/dist/lib/lifecycle/handler.js.map +1 -0
- package/dist/lib/lifecycle/index.d.ts +23 -0
- package/dist/lib/lifecycle/index.d.ts.map +1 -0
- package/dist/lib/lifecycle/index.js +21 -0
- package/dist/lib/lifecycle/index.js.map +1 -0
- package/dist/lib/lifecycle/register.d.ts +29 -0
- package/dist/lib/lifecycle/register.d.ts.map +1 -0
- package/dist/lib/lifecycle/register.js +29 -0
- package/dist/lib/lifecycle/register.js.map +1 -0
- package/dist/lib/lifecycle/resolver.d.ts +22 -0
- package/dist/lib/lifecycle/resolver.d.ts.map +1 -0
- package/dist/lib/lifecycle/resolver.js +105 -0
- package/dist/lib/lifecycle/resolver.js.map +1 -0
- package/dist/lib/lifecycle/scheduler.d.ts +27 -0
- package/dist/lib/lifecycle/scheduler.d.ts.map +1 -0
- package/dist/lib/lifecycle/scheduler.js +108 -0
- package/dist/lib/lifecycle/scheduler.js.map +1 -0
- package/dist/lib/lifecycle/status.d.ts +39 -0
- package/dist/lib/lifecycle/status.d.ts.map +1 -0
- package/dist/lib/lifecycle/status.js +67 -0
- package/dist/lib/lifecycle/status.js.map +1 -0
- package/dist/lib/lifecycle/types.d.ts +165 -0
- package/dist/lib/lifecycle/types.d.ts.map +1 -0
- package/dist/lib/lifecycle/types.js +11 -0
- package/dist/lib/lifecycle/types.js.map +1 -0
- package/dist/lib/preferences/index.d.ts +3 -0
- package/dist/lib/preferences/index.d.ts.map +1 -0
- package/dist/lib/preferences/index.js +3 -0
- package/dist/lib/preferences/index.js.map +1 -0
- package/dist/lib/preferences/storage.d.ts +33 -0
- package/dist/lib/preferences/storage.d.ts.map +1 -0
- package/dist/lib/preferences/storage.js +129 -0
- package/dist/lib/preferences/storage.js.map +1 -0
- package/dist/lib/preferences/types.d.ts +59 -0
- package/dist/lib/preferences/types.d.ts.map +1 -0
- package/dist/lib/preferences/types.js +20 -0
- package/dist/lib/preferences/types.js.map +1 -0
- package/dist/lib/template_manager/db/template_repository.d.ts +4 -1
- package/dist/lib/template_manager/db/template_repository.d.ts.map +1 -1
- package/dist/lib/template_manager/db/template_repository.js +17 -1
- package/dist/lib/template_manager/db/template_repository.js.map +1 -1
- package/dist/lib/template_manager/types.d.ts +1 -0
- package/dist/lib/template_manager/types.d.ts.map +1 -1
- package/migrations/008_lifecycle_status.pg.sql +27 -0
- package/migrations/008_lifecycle_status.sqlite.sql +24 -0
- package/migrations/009_templates_locale.pg.sql +6 -0
- package/migrations/009_templates_locale.sqlite.sql +4 -0
- package/migrations/010_preferences.pg.sql +26 -0
- package/migrations/010_preferences.sqlite.sql +32 -0
- package/migrations/011_digest_status.pg.sql +21 -0
- package/migrations/011_digest_status.sqlite.sql +43 -0
- package/migrations/012_preferences_digest.pg.sql +12 -0
- package/migrations/012_preferences_digest.sqlite.sql +51 -0
- package/package.json +15 -3
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Digest flush job handler factory.
|
|
3
|
+
*
|
|
4
|
+
* Claims all channel_deliveries rows with status='digesting', groups them by
|
|
5
|
+
* (user_id, channel_id), and fires one `send` call per group. Intended to be
|
|
6
|
+
* registered with hazo_jobs against `DIGEST_FLUSH_JOB_TYPE`.
|
|
7
|
+
*
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
import { QueryBuilder } from "hazo_connect/server";
|
|
11
|
+
import { getInboxConnection } from "../inbox/connection.js";
|
|
12
|
+
import { send_template_email } from "../template_manager/template_manager.js";
|
|
13
|
+
/** Stable job type registered with hazo_jobs. */
|
|
14
|
+
export const DIGEST_FLUSH_JOB_TYPE = "hazo_notify.digest_flush";
|
|
15
|
+
/**
|
|
16
|
+
* Factory that creates a hazo_jobs-compatible handler for digest flush.
|
|
17
|
+
*
|
|
18
|
+
* The handler:
|
|
19
|
+
* 1. Claims all deliveries with status='digesting' up to `batch_size`.
|
|
20
|
+
* 2. Enriches each row with user_id from hazo_notify_inbox when not already
|
|
21
|
+
* present on the claimed row.
|
|
22
|
+
* 3. Groups rows by (user_id, channel_id).
|
|
23
|
+
* 4. Fires one `_send` call per group, then marks each row sent/failed.
|
|
24
|
+
*/
|
|
25
|
+
export function createDigestFlushHandler(opts) {
|
|
26
|
+
const default_batch_size = opts.batch_size ?? 500;
|
|
27
|
+
return async function digest_flush_handler(job) {
|
|
28
|
+
const payload = typeof job.payload === "string"
|
|
29
|
+
? JSON.parse(job.payload)
|
|
30
|
+
: (job.payload ?? {});
|
|
31
|
+
const batch_size = payload.batch_size ?? default_batch_size;
|
|
32
|
+
// Resolve adapter: injected (tests) or live connection.
|
|
33
|
+
const adapter = opts._adapter ?? getInboxConnection();
|
|
34
|
+
// Resolve send function: injected (tests) or real send_template_email.
|
|
35
|
+
// The `hazo_connect` arg is typed as `unknown` in DigestSendFn so the
|
|
36
|
+
// handler works with both the real HazoConnectAdapter (production) and test
|
|
37
|
+
// doubles. The production wrapper casts through `unknown` to satisfy
|
|
38
|
+
// send_template_email's HazoConnectInstance parameter — both types expose
|
|
39
|
+
// an equivalent query surface in practice.
|
|
40
|
+
const send_fn = opts._send ??
|
|
41
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
42
|
+
((options, hazo_connect) => send_template_email(options, hazo_connect));
|
|
43
|
+
// --- Step 1: Claim digesting rows ---
|
|
44
|
+
const claimed_rows = await adapter.claimRows({
|
|
45
|
+
table: "hazo_notify_channel_deliveries",
|
|
46
|
+
where: { status: "digesting" },
|
|
47
|
+
set: {
|
|
48
|
+
attempt_count: { increment: 1 },
|
|
49
|
+
updated_at: { $now: true },
|
|
50
|
+
},
|
|
51
|
+
returning: ["id", "inbox_id", "channel_id", "payload"],
|
|
52
|
+
limit: batch_size,
|
|
53
|
+
orderBy: { column: "created_at", direction: "asc" },
|
|
54
|
+
});
|
|
55
|
+
if (claimed_rows.length === 0)
|
|
56
|
+
return;
|
|
57
|
+
// --- Step 2: Enrich rows with user_id ---
|
|
58
|
+
const enriched = await Promise.all(claimed_rows.map(async (row) => {
|
|
59
|
+
// If the claimed row already carries user_id (e.g. from a mock or a
|
|
60
|
+
// JOIN-capable adapter), use it directly — no extra query needed.
|
|
61
|
+
if (row.user_id) {
|
|
62
|
+
return row;
|
|
63
|
+
}
|
|
64
|
+
// Otherwise look up user_id from the originating inbox row.
|
|
65
|
+
const inbox_rows = (await adapter.query(new QueryBuilder()
|
|
66
|
+
.from("hazo_notify_inbox")
|
|
67
|
+
.select("user_id")
|
|
68
|
+
.where("id", "eq", row.inbox_id), "GET"));
|
|
69
|
+
return {
|
|
70
|
+
...row,
|
|
71
|
+
user_id: inbox_rows[0]?.user_id ?? "unknown",
|
|
72
|
+
};
|
|
73
|
+
}));
|
|
74
|
+
// --- Step 3: Group by (user_id, channel_id) ---
|
|
75
|
+
const groups = new Map();
|
|
76
|
+
for (const row of enriched) {
|
|
77
|
+
const key = `${row.user_id}::${row.channel_id}`;
|
|
78
|
+
const group = groups.get(key) ?? [];
|
|
79
|
+
group.push(row);
|
|
80
|
+
groups.set(key, group);
|
|
81
|
+
}
|
|
82
|
+
// --- Step 4: Send once per group, then mark rows sent/failed ---
|
|
83
|
+
await Promise.all(Array.from(groups.entries()).map(async ([, rows]) => {
|
|
84
|
+
const { user_id, channel_id } = rows[0];
|
|
85
|
+
const row_ids = rows.map((r) => r.id);
|
|
86
|
+
let send_succeeded = false;
|
|
87
|
+
try {
|
|
88
|
+
const recipient = await opts.resolve_recipient(user_id);
|
|
89
|
+
const row_payloads = rows.map((r) => typeof r.payload === "string"
|
|
90
|
+
? JSON.parse(r.payload)
|
|
91
|
+
: (r.payload ?? {}));
|
|
92
|
+
const variables = {
|
|
93
|
+
user_id,
|
|
94
|
+
channel_id,
|
|
95
|
+
digest_count: String(rows.length),
|
|
96
|
+
digest_date: new Date().toISOString().slice(0, 10),
|
|
97
|
+
...opts.template_variables,
|
|
98
|
+
};
|
|
99
|
+
const result = await send_fn({
|
|
100
|
+
template_name: opts.template_name,
|
|
101
|
+
variables,
|
|
102
|
+
to: recipient,
|
|
103
|
+
scope_id: opts.scope_id ?? null,
|
|
104
|
+
}, adapter);
|
|
105
|
+
send_succeeded = result.success;
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
send_succeeded = false;
|
|
109
|
+
}
|
|
110
|
+
// Mark each row in the group as sent or failed.
|
|
111
|
+
const new_status = send_succeeded ? "sent" : "failed";
|
|
112
|
+
const finalized_at = new Date().toISOString();
|
|
113
|
+
await Promise.all(row_ids.map((id) => adapter.claimRows({
|
|
114
|
+
table: "hazo_notify_channel_deliveries",
|
|
115
|
+
where: { id },
|
|
116
|
+
set: {
|
|
117
|
+
status: new_status,
|
|
118
|
+
finalized_at,
|
|
119
|
+
updated_at: { $now: true },
|
|
120
|
+
},
|
|
121
|
+
returning: ["id"],
|
|
122
|
+
limit: 1,
|
|
123
|
+
})));
|
|
124
|
+
}));
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=digest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"digest.js","sourceRoot":"","sources":["../../../src/lib/jobs/digest.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/jobs/index.d.ts
CHANGED
|
@@ -13,4 +13,6 @@ export { createInboxFlushHandler } from "./handler.js";
|
|
|
13
13
|
export type { CreateInboxFlushHandlerOptions } from "./handler.js";
|
|
14
14
|
export { submitInboxFlushJobs } from "./submit.js";
|
|
15
15
|
export type { SubmitInboxFlushJobsParams } from "./submit.js";
|
|
16
|
+
export { DIGEST_FLUSH_JOB_TYPE, createDigestFlushHandler, } from "./digest.js";
|
|
17
|
+
export type { DigestFlushPayload, CreateDigestFlushHandlerOptions, } from "./digest.js";
|
|
16
18
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/jobs/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACL,oBAAoB,GACrB,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,oBAAoB,EACpB,OAAO,EACP,aAAa,EACb,cAAc,EACd,iBAAiB,GAClB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AACvD,YAAY,EAAE,8BAA8B,EAAE,MAAM,cAAc,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,YAAY,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/jobs/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACL,oBAAoB,GACrB,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,oBAAoB,EACpB,OAAO,EACP,aAAa,EACb,cAAc,EACd,iBAAiB,GAClB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AACvD,YAAY,EAAE,8BAA8B,EAAE,MAAM,cAAc,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,YAAY,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,EACL,qBAAqB,EACrB,wBAAwB,GACzB,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,kBAAkB,EAClB,+BAA+B,GAChC,MAAM,aAAa,CAAC"}
|
package/dist/lib/jobs/index.js
CHANGED
|
@@ -10,4 +10,5 @@
|
|
|
10
10
|
export { INBOX_FLUSH_JOB_TYPE, } from "./types.js";
|
|
11
11
|
export { createInboxFlushHandler } from "./handler.js";
|
|
12
12
|
export { submitInboxFlushJobs } from "./submit.js";
|
|
13
|
+
export { DIGEST_FLUSH_JOB_TYPE, createDigestFlushHandler, } from "./digest.js";
|
|
13
14
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lib/jobs/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACL,oBAAoB,GACrB,MAAM,YAAY,CAAC;AAQpB,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAEvD,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lib/jobs/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACL,oBAAoB,GACrB,MAAM,YAAY,CAAC;AAQpB,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAEvD,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAEnD,OAAO,EACL,qBAAqB,EACrB,wBAAwB,GACzB,MAAM,aAAa,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"submit.d.ts","sourceRoot":"","sources":["../../../src/lib/jobs/submit.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EACV,iBAAiB,EAElB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,0BAA0B;IACzC,yDAAyD;IACzD,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,yDAAyD;IACzD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,iBAAiB,EACvB,MAAM,EAAE,0BAA0B,GACjC,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"submit.d.ts","sourceRoot":"","sources":["../../../src/lib/jobs/submit.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EACV,iBAAiB,EAElB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,0BAA0B;IACzC,yDAAyD;IACzD,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,yDAAyD;IACzD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,iBAAiB,EACvB,MAAM,EAAE,0BAA0B,GACjC,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAe/B"}
|
package/dist/lib/jobs/submit.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"submit.js","sourceRoot":"","sources":["../../../src/lib/jobs/submit.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAalD,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,IAAuB,EACvB,MAAkC;IAElC,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,KAAK,MAAM,UAAU,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACzC,MAAM,OAAO,GACX,MAAM,CAAC,UAAU,IAAI,IAAI;YACvB,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE;YAC/C,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC;QACrB,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC;YAClC,IAAI,EAAE,oBAAoB;YAC1B,OAAO;SACR,CAAC,CAAC;QACH,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACrB,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,CAAC;AACpB,CAAC"}
|
|
1
|
+
{"version":3,"file":"submit.js","sourceRoot":"","sources":["../../../src/lib/jobs/submit.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAalD,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,IAAuB,EACvB,MAAkC;IAElC,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,KAAK,MAAM,UAAU,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACzC,MAAM,OAAO,GACX,MAAM,CAAC,UAAU,IAAI,IAAI;YACvB,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE;YAC/C,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC;QACrB,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC;YAClC,IAAI,EAAE,oBAAoB;YAC1B,WAAW,EAAE,eAAe,UAAU,EAAE;YACxC,OAAO;SACR,CAAC,CAAC;QACH,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACrB,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,CAAC;AACpB,CAAC"}
|
package/dist/lib/jobs/types.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/lib/jobs/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,iDAAiD;AACjD,eAAO,MAAM,oBAAoB,4BAA4B,CAAC;AAE9D,yDAAyD;AACzD,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,0DAA0D;AAC1D,MAAM,WAAW,OAAO,CAAC,CAAC,GAAG,OAAO;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,CAAC,CAAC;CACZ;AAED,0EAA0E;AAC1E,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;IACpC,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;IACpC,KAAK,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;CACtC;AAED,yDAAyD;AACzD,MAAM,MAAM,cAAc,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,OAAO,IAAI,CACrD,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,EACf,GAAG,CAAC,EAAE,aAAa,KAChB,OAAO,CAAC,CAAC,CAAC,CAAC;AAEhB,0DAA0D;AAC1D,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,IAAI,EAAE;QACX,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAChC"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/lib/jobs/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,iDAAiD;AACjD,eAAO,MAAM,oBAAoB,4BAA4B,CAAC;AAE9D,yDAAyD;AACzD,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,0DAA0D;AAC1D,MAAM,WAAW,OAAO,CAAC,CAAC,GAAG,OAAO;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,CAAC,CAAC;CACZ;AAED,0EAA0E;AAC1E,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;IACpC,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;IACpC,KAAK,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;CACtC;AAED,yDAAyD;AACzD,MAAM,MAAM,cAAc,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,OAAO,IAAI,CACrD,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,EACf,GAAG,CAAC,EAAE,aAAa,KAChB,OAAO,CAAC,CAAC,CAAC,CAAC;AAEhB,0DAA0D;AAC1D,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,IAAI,EAAE;QACX,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAChC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default system template manifests for the lifecycle module.
|
|
3
|
+
*
|
|
4
|
+
* Consumers call `sync_system_templates(hazo_connect, lifecycleDefaultTemplates)`
|
|
5
|
+
* at boot to upsert these templates into the database.
|
|
6
|
+
*/
|
|
7
|
+
import type { SystemTemplateManifest } from '../template_manager/types.js';
|
|
8
|
+
export declare const lifecycleDefaultTemplates: SystemTemplateManifest[];
|
|
9
|
+
//# sourceMappingURL=default_templates.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"default_templates.d.ts","sourceRoot":"","sources":["../../../src/lib/lifecycle/default_templates.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,sBAAsB,EAA8B,MAAM,8BAA8B,CAAC;AA8DvG,eAAO,MAAM,yBAAyB,EAAE,sBAAsB,EA8I7D,CAAC"}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default system template manifests for the lifecycle module.
|
|
3
|
+
*
|
|
4
|
+
* Consumers call `sync_system_templates(hazo_connect, lifecycleDefaultTemplates)`
|
|
5
|
+
* at boot to upsert these templates into the database.
|
|
6
|
+
*/
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
// Shared HTML/text body templates
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
const MAIN_HTML = `<!doctype html>
|
|
11
|
+
<html lang="en">
|
|
12
|
+
<head><meta charset="utf-8" /><meta name="viewport" content="width=device-width" /><title>{{headline}}</title></head>
|
|
13
|
+
<body style="margin:0;background:#f9f9f9;font-family:Arial,sans-serif;color:#1a1a1a;">
|
|
14
|
+
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="background:#f9f9f9;padding:32px 16px;">
|
|
15
|
+
<tr><td align="center">
|
|
16
|
+
<table role="presentation" width="520" cellpadding="0" cellspacing="0" style="background:#ffffff;border:1px solid #e5e5e5;border-radius:12px;padding:32px;max-width:520px;">
|
|
17
|
+
<tr><td>
|
|
18
|
+
<div style="font-size:20px;font-weight:600;color:#333;margin-bottom:16px;">{{app_name}}</div>
|
|
19
|
+
<h1 style="font-size:22px;line-height:1.25;color:#1a1a1a;font-weight:600;margin:0 0 16px;">{{headline}}</h1>
|
|
20
|
+
<p style="font-size:16px;line-height:1.6;color:#1a1a1a;margin:0 0 24px;">{{body}}</p>
|
|
21
|
+
<p style="margin:0 0 24px;"><a href="{{{cta_url}}}" style="display:inline-block;background:#3730a3;color:#ffffff;text-decoration:none;font-weight:600;font-size:15px;padding:12px 22px;border-radius:8px;">{{cta_label}}</a></p>
|
|
22
|
+
<p style="font-size:14px;line-height:1.6;color:#1a1a1a;margin:0;">{{signoff}}</p>
|
|
23
|
+
</td></tr>
|
|
24
|
+
</table>
|
|
25
|
+
<p style="font-size:12px;line-height:1.5;color:#888;max-width:520px;margin:18px auto 0;text-align:center;">{{footer}}</p>
|
|
26
|
+
<p style="font-size:12px;line-height:1.5;color:#888;max-width:520px;margin:8px auto 0;text-align:center;">{{{stop_tips_url_html}}}</p>
|
|
27
|
+
</td></tr>
|
|
28
|
+
</table>
|
|
29
|
+
</body>
|
|
30
|
+
</html>`;
|
|
31
|
+
const MAIN_TEXT = `{{headline}}
|
|
32
|
+
|
|
33
|
+
{{body}}
|
|
34
|
+
|
|
35
|
+
{{cta_label}}: {{{cta_url}}}
|
|
36
|
+
|
|
37
|
+
{{signoff}}
|
|
38
|
+
|
|
39
|
+
{{footer}}
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
Don't want these tips? Unsubscribe: {{stop_tips_url}}`;
|
|
43
|
+
// ---------------------------------------------------------------------------
|
|
44
|
+
// Shared variable lists
|
|
45
|
+
// ---------------------------------------------------------------------------
|
|
46
|
+
const MAIN_VARIABLES = [
|
|
47
|
+
{ variable_name: 'first_name', variable_description: "Recipient's first name" },
|
|
48
|
+
{ variable_name: 'app_name', variable_description: 'Application name' },
|
|
49
|
+
{ variable_name: 'headline', variable_description: 'Email headline' },
|
|
50
|
+
{ variable_name: 'body', variable_description: 'Email body paragraph' },
|
|
51
|
+
{ variable_name: 'cta_url', variable_description: 'Call-to-action URL' },
|
|
52
|
+
{ variable_name: 'cta_label', variable_description: 'Call-to-action button label' },
|
|
53
|
+
{ variable_name: 'signoff', variable_description: 'Closing salutation' },
|
|
54
|
+
{ variable_name: 'footer', variable_description: 'Footer legal/contact text' },
|
|
55
|
+
{ variable_name: 'stop_tips_url', variable_description: 'Signed URL for opt-out' },
|
|
56
|
+
{ variable_name: 'stop_tips_url_html', variable_description: 'Pre-rendered HTML opt-out link fragment' },
|
|
57
|
+
];
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
// Template manifests
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
export const lifecycleDefaultTemplates = [
|
|
62
|
+
// 1. Welcome
|
|
63
|
+
{
|
|
64
|
+
template_name: 'lifecycle-welcome',
|
|
65
|
+
template_label: 'Welcome',
|
|
66
|
+
category: 'Lifecycle',
|
|
67
|
+
bodies: {
|
|
68
|
+
html: MAIN_HTML,
|
|
69
|
+
text: MAIN_TEXT,
|
|
70
|
+
},
|
|
71
|
+
variables: [
|
|
72
|
+
...MAIN_VARIABLES,
|
|
73
|
+
{ variable_name: 'subject_a', variable_description: 'A/B subject line variant A' },
|
|
74
|
+
{ variable_name: 'subject_b', variable_description: 'A/B subject line variant B' },
|
|
75
|
+
],
|
|
76
|
+
},
|
|
77
|
+
// 2. Tree waiting
|
|
78
|
+
{
|
|
79
|
+
template_name: 'lifecycle-tree-waiting',
|
|
80
|
+
template_label: 'Your space is waiting',
|
|
81
|
+
category: 'Lifecycle',
|
|
82
|
+
bodies: {
|
|
83
|
+
html: MAIN_HTML,
|
|
84
|
+
text: MAIN_TEXT,
|
|
85
|
+
},
|
|
86
|
+
variables: MAIN_VARIABLES,
|
|
87
|
+
},
|
|
88
|
+
// 3. Bring existing tree
|
|
89
|
+
{
|
|
90
|
+
template_name: 'lifecycle-bring-existing-tree',
|
|
91
|
+
template_label: 'Already have a tree elsewhere?',
|
|
92
|
+
category: 'Lifecycle',
|
|
93
|
+
bodies: {
|
|
94
|
+
html: MAIN_HTML,
|
|
95
|
+
text: MAIN_TEXT,
|
|
96
|
+
},
|
|
97
|
+
variables: MAIN_VARIABLES,
|
|
98
|
+
},
|
|
99
|
+
// 4. Invite family
|
|
100
|
+
{
|
|
101
|
+
template_name: 'lifecycle-invite-family',
|
|
102
|
+
template_label: "Don't keep it to yourself",
|
|
103
|
+
category: 'Lifecycle',
|
|
104
|
+
bodies: {
|
|
105
|
+
html: MAIN_HTML,
|
|
106
|
+
text: MAIN_TEXT,
|
|
107
|
+
},
|
|
108
|
+
variables: MAIN_VARIABLES,
|
|
109
|
+
},
|
|
110
|
+
// 5. Milestone — map unlocked
|
|
111
|
+
{
|
|
112
|
+
template_name: 'lifecycle-milestone-map-unlocked',
|
|
113
|
+
template_label: 'Your family is on the map',
|
|
114
|
+
category: 'Lifecycle',
|
|
115
|
+
bodies: {
|
|
116
|
+
html: MAIN_HTML,
|
|
117
|
+
text: MAIN_TEXT,
|
|
118
|
+
},
|
|
119
|
+
variables: MAIN_VARIABLES,
|
|
120
|
+
},
|
|
121
|
+
// 6. Milestone — first photo
|
|
122
|
+
{
|
|
123
|
+
template_name: 'lifecycle-milestone-first-photo',
|
|
124
|
+
template_label: 'First photo is up',
|
|
125
|
+
category: 'Lifecycle',
|
|
126
|
+
bodies: {
|
|
127
|
+
html: MAIN_HTML,
|
|
128
|
+
text: MAIN_TEXT,
|
|
129
|
+
},
|
|
130
|
+
variables: MAIN_VARIABLES,
|
|
131
|
+
},
|
|
132
|
+
// 7. Milestone — first invite accepted
|
|
133
|
+
{
|
|
134
|
+
template_name: 'lifecycle-milestone-first-invite-accepted',
|
|
135
|
+
template_label: "You've got family with you",
|
|
136
|
+
category: 'Lifecycle',
|
|
137
|
+
bodies: {
|
|
138
|
+
html: MAIN_HTML,
|
|
139
|
+
text: MAIN_TEXT,
|
|
140
|
+
},
|
|
141
|
+
variables: [
|
|
142
|
+
...MAIN_VARIABLES,
|
|
143
|
+
{ variable_name: 'invitee_name', variable_description: 'Name of the invited user who joined' },
|
|
144
|
+
],
|
|
145
|
+
},
|
|
146
|
+
// 8. Footer fragment — stop tips
|
|
147
|
+
{
|
|
148
|
+
template_name: 'lifecycle-footer-stop-tips',
|
|
149
|
+
template_label: 'Stop lifecycle tips (footer fragment)',
|
|
150
|
+
category: 'Lifecycle',
|
|
151
|
+
bodies: {
|
|
152
|
+
html: `<p style="font-size:12px;color:#888;">Don't want these tips? <a href="{{{stop_tips_url}}}">Stop</a>.</p>`,
|
|
153
|
+
text: `Don't want these tips? Stop: {{stop_tips_url}}`,
|
|
154
|
+
},
|
|
155
|
+
variables: [
|
|
156
|
+
{ variable_name: 'stop_tips_url', variable_description: 'Signed URL for opt-out' },
|
|
157
|
+
],
|
|
158
|
+
},
|
|
159
|
+
// 9. Daily digest
|
|
160
|
+
{
|
|
161
|
+
template_name: 'digest_daily',
|
|
162
|
+
template_label: 'Daily Digest',
|
|
163
|
+
category: 'System',
|
|
164
|
+
bodies: {
|
|
165
|
+
html: `<!doctype html>
|
|
166
|
+
<html lang="en">
|
|
167
|
+
<head><meta charset="utf-8" /><meta name="viewport" content="width=device-width" /><title>Daily Digest</title></head>
|
|
168
|
+
<body style="margin:0;background:#f9f9f9;font-family:Arial,sans-serif;color:#1a1a1a;">
|
|
169
|
+
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="background:#f9f9f9;padding:32px 16px;">
|
|
170
|
+
<tr><td align="center">
|
|
171
|
+
<table role="presentation" width="520" cellpadding="0" cellspacing="0" style="background:#ffffff;border:1px solid #e5e5e5;border-radius:12px;padding:32px;max-width:520px;">
|
|
172
|
+
<tr><td>
|
|
173
|
+
<h1 style="font-size:22px;line-height:1.25;color:#1a1a1a;font-weight:600;margin:0 0 16px;">Daily Digest</h1>
|
|
174
|
+
<p style="font-size:15px;line-height:1.6;color:#1a1a1a;margin:0 0 16px;">Hello,</p>
|
|
175
|
+
<p style="font-size:15px;line-height:1.6;color:#1a1a1a;margin:0 0 24px;">You have <strong>{{digest_count}}</strong> pending notification(s) for <strong>{{channel_id}}</strong> on <strong>{{digest_date}}</strong>.</p>
|
|
176
|
+
<p style="font-size:14px;line-height:1.6;color:#666;margin:0;">Visit your inbox to review them.</p>
|
|
177
|
+
</td></tr>
|
|
178
|
+
</table>
|
|
179
|
+
</td></tr>
|
|
180
|
+
</table>
|
|
181
|
+
</body>
|
|
182
|
+
</html>`,
|
|
183
|
+
text: `Daily Digest
|
|
184
|
+
|
|
185
|
+
You have {{digest_count}} pending notification(s) for {{channel_id}} on {{digest_date}}.
|
|
186
|
+
|
|
187
|
+
Visit your inbox to review them.`,
|
|
188
|
+
},
|
|
189
|
+
variables: [
|
|
190
|
+
{ variable_name: 'digest_count', variable_description: 'Number of pending notifications in the digest' },
|
|
191
|
+
{ variable_name: 'channel_id', variable_description: 'Channel identifier (e.g., email, in_app)' },
|
|
192
|
+
{ variable_name: 'digest_date', variable_description: 'Date of the digest (YYYY-MM-DD)' },
|
|
193
|
+
],
|
|
194
|
+
},
|
|
195
|
+
];
|
|
196
|
+
//# sourceMappingURL=default_templates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"default_templates.js","sourceRoot":"","sources":["../../../src/lib/lifecycle/default_templates.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dispatch wrapper for lifecycle email steps.
|
|
3
|
+
*
|
|
4
|
+
* Wraps `send_template_email` with lifecycle-specific context. In v1,
|
|
5
|
+
* locale resolution happens at the template-lookup level via
|
|
6
|
+
* `get_template_by_name` (which accepts an optional `locale` param).
|
|
7
|
+
* `send_template_email` does not currently expose a `locale` parameter, so
|
|
8
|
+
* the `locale` option here is noted for future use — template resolution will
|
|
9
|
+
* fall back to the default locale until that param is threaded through.
|
|
10
|
+
*
|
|
11
|
+
* @packageDocumentation
|
|
12
|
+
*/
|
|
13
|
+
import type { HazoConnectInstance } from '../template_manager/types.js';
|
|
14
|
+
export interface DispatchStepOptions {
|
|
15
|
+
hazo_connect: HazoConnectInstance;
|
|
16
|
+
user_id: string;
|
|
17
|
+
template_name: string;
|
|
18
|
+
variables: Record<string, string>;
|
|
19
|
+
to: string;
|
|
20
|
+
scope_id?: string | null;
|
|
21
|
+
/**
|
|
22
|
+
* Locale hint. v1: not yet forwarded to send_template_email (which does not
|
|
23
|
+
* accept locale). Template resolution defaults to the global locale.
|
|
24
|
+
* TODO: thread through once send_template_email exposes a locale param.
|
|
25
|
+
*/
|
|
26
|
+
locale?: string | null;
|
|
27
|
+
/** Override the template's stored subject line (used for A/B testing). */
|
|
28
|
+
subject_override?: string | null;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Dispatch a lifecycle email step.
|
|
32
|
+
*
|
|
33
|
+
* Throws if `send_template_email` returns a non-success response so callers
|
|
34
|
+
* can catch and mark the status row as failed.
|
|
35
|
+
*/
|
|
36
|
+
export declare function dispatchStep(opts: DispatchStepOptions): Promise<void>;
|
|
37
|
+
//# sourceMappingURL=dispatch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../../../src/lib/lifecycle/dispatch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAExE,MAAM,WAAW,mBAAmB;IAClC,YAAY,EAAE,mBAAmB,CAAC;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,0EAA0E;IAC1E,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB3E"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dispatch wrapper for lifecycle email steps.
|
|
3
|
+
*
|
|
4
|
+
* Wraps `send_template_email` with lifecycle-specific context. In v1,
|
|
5
|
+
* locale resolution happens at the template-lookup level via
|
|
6
|
+
* `get_template_by_name` (which accepts an optional `locale` param).
|
|
7
|
+
* `send_template_email` does not currently expose a `locale` parameter, so
|
|
8
|
+
* the `locale` option here is noted for future use — template resolution will
|
|
9
|
+
* fall back to the default locale until that param is threaded through.
|
|
10
|
+
*
|
|
11
|
+
* @packageDocumentation
|
|
12
|
+
*/
|
|
13
|
+
import { send_template_email } from '../template_manager/template_manager.js';
|
|
14
|
+
/**
|
|
15
|
+
* Dispatch a lifecycle email step.
|
|
16
|
+
*
|
|
17
|
+
* Throws if `send_template_email` returns a non-success response so callers
|
|
18
|
+
* can catch and mark the status row as failed.
|
|
19
|
+
*/
|
|
20
|
+
export async function dispatchStep(opts) {
|
|
21
|
+
const result = await send_template_email({
|
|
22
|
+
template_name: opts.template_name,
|
|
23
|
+
variables: opts.variables,
|
|
24
|
+
to: opts.to,
|
|
25
|
+
scope_id: opts.scope_id ?? null,
|
|
26
|
+
...(opts.subject_override ? { subject: opts.subject_override } : {}),
|
|
27
|
+
}, opts.hazo_connect);
|
|
28
|
+
if (!result.success) {
|
|
29
|
+
throw new Error(result.error ?? `send_template_email failed for template '${opts.template_name}'`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=dispatch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatch.js","sourceRoot":"","sources":["../../../src/lib/lifecycle/dispatch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,yCAAyC,CAAC;AAoB9E;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAyB;IAC1D,MAAM,MAAM,GAAG,MAAM,mBAAmB,CACtC;QACE,aAAa,EAAE,IAAI,CAAC,aAAa;QACjC,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,EAAE,EAAE,IAAI,CAAC,EAAE;QACX,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,IAAI;QAC/B,GAAG,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACrE,EACD,IAAI,CAAC,YAAY,CAClB,CAAC;IAEF,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CACb,MAAM,CAAC,KAAK,IAAI,4CAA4C,IAAI,CAAC,aAAa,GAAG,CAClF,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `recordEvent` implementation for lifecycle sequences.
|
|
3
|
+
*
|
|
4
|
+
* When a product event fires (e.g. "user_added_first_person"), this module
|
|
5
|
+
* scans all sequences for matching event-triggered steps, loads their status
|
|
6
|
+
* rows, and dispatches any that are still in `scheduled` state.
|
|
7
|
+
*
|
|
8
|
+
* Deduplication contract:
|
|
9
|
+
* - If the status row is 'sent' → no-op (already dispatched).
|
|
10
|
+
* - If the status row is not found → no-op (user never started the sequence).
|
|
11
|
+
* - If the status row is 'skipped' or 'failed' → no-op (terminal state).
|
|
12
|
+
* - Only 'scheduled' rows trigger dispatch.
|
|
13
|
+
*
|
|
14
|
+
* @packageDocumentation
|
|
15
|
+
*/
|
|
16
|
+
import type { LifecycleSchedulerOptions } from './types.js';
|
|
17
|
+
/**
|
|
18
|
+
* Fire all event-triggered steps whose `event_kind` matches the emitted event.
|
|
19
|
+
*
|
|
20
|
+
* Scans every sequence in `opts.sequences` (or only `sequence_id` if supplied)
|
|
21
|
+
* for steps with `trigger.kind === 'event' && trigger.event_kind === event_kind`.
|
|
22
|
+
* For each match, loads the status row and dispatches if status is `scheduled`.
|
|
23
|
+
*
|
|
24
|
+
* @param opts - Scheduler options (hazo_connect, resolvers, sequences, etc.)
|
|
25
|
+
* @param get_user_email - Async function that resolves the email address for user_id.
|
|
26
|
+
* @param params - Event parameters from the caller.
|
|
27
|
+
*/
|
|
28
|
+
export declare function recordEvent(opts: LifecycleSchedulerOptions, get_user_email: (user_id: string) => Promise<string>, params: {
|
|
29
|
+
user_id: string;
|
|
30
|
+
event_kind: string;
|
|
31
|
+
sequence_id?: string;
|
|
32
|
+
payload?: Record<string, unknown>;
|
|
33
|
+
}): Promise<void>;
|
|
34
|
+
//# sourceMappingURL=events.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../../src/lib/lifecycle/events.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAMH,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAE5D;;;;;;;;;;GAUG;AACH,wBAAsB,WAAW,CAC/B,IAAI,EAAE,yBAAyB,EAC/B,cAAc,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,EACpD,MAAM,EAAE;IACN,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC,GACA,OAAO,CAAC,IAAI,CAAC,CAgHf"}
|