hazo_notify 5.2.1 → 6.0.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/README.md +38 -6
- package/config/hazo_notify_config.ini +5 -0
- package/dist/lib/adapters/email/config.d.ts.map +1 -1
- package/dist/lib/adapters/email/config.js +7 -6
- package/dist/lib/adapters/email/config.js.map +1 -1
- package/dist/lib/adapters/email/providers/zeptomail_provider.d.ts.map +1 -1
- package/dist/lib/adapters/email/providers/zeptomail_provider.js +11 -19
- package/dist/lib/adapters/email/providers/zeptomail_provider.js.map +1 -1
- package/dist/lib/adapters/email/utils/logger.d.ts +4 -11
- package/dist/lib/adapters/email/utils/logger.d.ts.map +1 -1
- package/dist/lib/adapters/email/utils/logger.js +11 -53
- package/dist/lib/adapters/email/utils/logger.js.map +1 -1
- package/dist/lib/adapters/telegram/config.d.ts.map +1 -1
- package/dist/lib/adapters/telegram/config.js +5 -4
- package/dist/lib/adapters/telegram/config.js.map +1 -1
- package/dist/lib/adapters/telegram/transport.d.ts.map +1 -1
- package/dist/lib/adapters/telegram/transport.js +2 -1
- package/dist/lib/adapters/telegram/transport.js.map +1 -1
- package/dist/lib/config/hazo_notify_config.d.ts +45 -0
- package/dist/lib/config/hazo_notify_config.d.ts.map +1 -0
- package/dist/lib/config/hazo_notify_config.js +82 -0
- package/dist/lib/config/hazo_notify_config.js.map +1 -0
- package/dist/lib/dispatcher/batch-key.js +2 -2
- package/dist/lib/dispatcher/batch-key.js.map +1 -1
- package/dist/lib/dispatcher/index.d.ts.map +1 -1
- package/dist/lib/dispatcher/index.js +6 -3
- package/dist/lib/dispatcher/index.js.map +1 -1
- package/dist/lib/errors.d.ts +30 -0
- package/dist/lib/errors.d.ts.map +1 -0
- package/dist/lib/errors.js +57 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/inbox/connection.d.ts.map +1 -1
- package/dist/lib/inbox/connection.js +4 -3
- package/dist/lib/inbox/connection.js.map +1 -1
- package/dist/lib/inbox/storage.d.ts.map +1 -1
- package/dist/lib/inbox/storage.js +4 -3
- package/dist/lib/inbox/storage.js.map +1 -1
- package/dist/lib/inbox/types.d.ts +3 -1
- package/dist/lib/inbox/types.d.ts.map +1 -1
- package/dist/lib/inbox/worker/flush.d.ts.map +1 -1
- package/dist/lib/inbox/worker/flush.js +56 -50
- package/dist/lib/inbox/worker/flush.js.map +1 -1
- package/dist/lib/inbox/worker/render.d.ts.map +1 -1
- package/dist/lib/inbox/worker/render.js +2 -1
- package/dist/lib/inbox/worker/render.js.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/handler.d.ts.map +1 -1
- package/dist/lib/jobs/handler.js +23 -18
- package/dist/lib/jobs/handler.js.map +1 -1
- 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/lifecycle/default_templates.d.ts.map +1 -1
- package/dist/lib/lifecycle/default_templates.js +36 -0
- package/dist/lib/lifecycle/default_templates.js.map +1 -1
- package/dist/lib/lifecycle/dispatch.d.ts.map +1 -1
- package/dist/lib/lifecycle/dispatch.js +2 -1
- package/dist/lib/lifecycle/dispatch.js.map +1 -1
- package/dist/lib/lifecycle/handler.d.ts.map +1 -1
- package/dist/lib/lifecycle/handler.js +103 -97
- package/dist/lib/lifecycle/handler.js.map +1 -1
- package/dist/lib/lifecycle/scheduler.d.ts.map +1 -1
- package/dist/lib/lifecycle/scheduler.js +2 -1
- package/dist/lib/lifecycle/scheduler.js.map +1 -1
- package/dist/lib/logger.d.ts +2 -0
- package/dist/lib/logger.d.ts.map +1 -0
- package/dist/lib/logger.js +3 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/preferences/storage.d.ts.map +1 -1
- package/dist/lib/preferences/storage.js +7 -2
- package/dist/lib/preferences/storage.js.map +1 -1
- package/dist/lib/preferences/types.d.ts +1 -1
- package/dist/lib/preferences/types.d.ts.map +1 -1
- package/dist/lib/utils.d.ts +1 -2
- package/dist/lib/utils.d.ts.map +1 -1
- package/dist/lib/utils.js +1 -5
- package/dist/lib/utils.js.map +1 -1
- 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 +20 -9
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* @packageDocumentation
|
|
9
9
|
*/
|
|
10
10
|
import { QueryBuilder } from "hazo_connect/server";
|
|
11
|
+
import { NotifyTemplateNotFoundError } from "../../errors.js";
|
|
11
12
|
import { get_template_by_name } from "../../template_manager/db/index.js";
|
|
12
13
|
import { render_handlebars_string } from "../../template_manager/engine/index.js";
|
|
13
14
|
import { getInboxConnection } from "../connection.js";
|
|
@@ -43,7 +44,7 @@ export async function renderForChannel(adapter, row) {
|
|
|
43
44
|
const result = await get_template_by_name(conn, scope_chain, payload.template_name);
|
|
44
45
|
const template = result.data;
|
|
45
46
|
if (!template)
|
|
46
|
-
throw new
|
|
47
|
+
throw new NotifyTemplateNotFoundError(payload.template_name ?? 'unknown');
|
|
47
48
|
const tpl_bodies = template.bodies ?? {};
|
|
48
49
|
const vars = (payload.template_vars ?? {});
|
|
49
50
|
const bodies = {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render.js","sourceRoot":"","sources":["../../../../src/lib/inbox/worker/render.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../../../../src/lib/inbox/worker/render.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,2BAA2B,EAAE,MAAM,iBAAiB,CAAC;AAE9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AAC1E,OAAO,EAAE,wBAAwB,EAAE,MAAM,wCAAwC,CAAC;AAClF,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAItD,sFAAsF;AACtF,wFAAwF;AACxF,oFAAoF;AACpF,8DAA8D;AAC9D,SAAS,yBAAyB,CAAC,OAA2B;IAC5D,OAAO;QACL,KAAK,EAAE,GAAG,EAAE,CAAC,IAAI,YAAY,EAAyD;QACtF,IAAI,EAAE,KAAK,EAAK,EAAW,EAAE,EAAE,CAAC,CAAC,MAAM,OAAO,CAAC,KAAK,CAAC,EAAkB,EAAE,KAAK,CAAC,CAAQ;QACvF,QAAQ,EAAE,KAAK,IAAI,EAAE,GAAG,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC,CAAC,CAAC;QACjG,MAAM,EAAE,KAAK,IAAI,EAAE,GAAG,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC,CAAC,CAAC;QAC7F,MAAM,EAAE,KAAK,IAAI,EAAE,GAAG,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC,CAAC,CAAC;QAC7F,UAAU,EAAE,KAAK,IAAI,EAAE,GAAG,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC,CAAC,CAAC;QACrG,UAAU,EAAE,KAAK,IAAI,EAAE,GAAG,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC,CAAC,CAAC;KACtG,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,OAAuB,EACvB,GAA2D;IAE3D,MAAM,OAAO,GAAG,GAAG,CAAC,OAGnB,CAAC;IAEF,IAAI,CAAC,OAAO,CAAC,aAAa;QAAE,OAAO,EAAE,CAAC;IAEtC,MAAM,IAAI,GAAG,yBAAyB,CAAC,kBAAkB,EAAE,CAAC,CAAC;IAC7D,MAAM,WAAW,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACvD,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IAEpF,MAAM,QAAQ,GAAI,MAA+C,CAAC,IAAI,CAAC;IACvE,IAAI,CAAC,QAAQ;QAAE,MAAM,IAAI,2BAA2B,CAAC,OAAO,CAAC,aAAa,IAAI,SAAS,CAAC,CAAC;IAEzF,MAAM,UAAU,GAAI,QAAgD,CAAC,MAAM,IAAI,EAAE,CAAC;IAClF,MAAM,IAAI,GAAG,CAAC,OAAO,CAAC,aAAa,IAAI,EAAE,CAA4B,CAAC;IACtE,MAAM,MAAM,GAA2B,EAAE,CAAC;IAE1C,KAAK,MAAM,GAAG,IAAI,OAAO,CAAC,YAAY,CAAC,kBAAkB,EAAE,CAAC;QAC1D,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;QAC/B,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpD,MAAM,CAAC,GAAG,CAAC,GAAG,wBAAwB,CAAC,MAAM,EAAE,IAA8B,CAAC,CAAC;QACjF,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,77 @@
|
|
|
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 type { SendTemplateEmailOptions } from "../template_manager/types.js";
|
|
11
|
+
import type { HazoJobHandler } from "./types.js";
|
|
12
|
+
/** Stable job type registered with hazo_jobs. */
|
|
13
|
+
export declare const DIGEST_FLUSH_JOB_TYPE = "hazo_notify.digest_flush";
|
|
14
|
+
/** Payload shape for the digest flush job (all config lives in handler opts). */
|
|
15
|
+
export interface DigestFlushPayload {
|
|
16
|
+
/** Optional cap on rows claimed in one invocation. Overrides handler default. */
|
|
17
|
+
batch_size?: number;
|
|
18
|
+
}
|
|
19
|
+
/** Internal minimal adapter surface used by the handler. */
|
|
20
|
+
export interface DigestAdapter {
|
|
21
|
+
claimRows<T>(opts: {
|
|
22
|
+
table: string;
|
|
23
|
+
where: Record<string, unknown>;
|
|
24
|
+
set: Record<string, unknown>;
|
|
25
|
+
returning: string[];
|
|
26
|
+
limit: number;
|
|
27
|
+
orderBy?: {
|
|
28
|
+
column: string;
|
|
29
|
+
direction: "asc" | "desc";
|
|
30
|
+
};
|
|
31
|
+
}): Promise<T[]>;
|
|
32
|
+
query(builder: unknown, method: string): Promise<unknown[]>;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Injectable send function. Accepts the template options and an adapter cast
|
|
36
|
+
* as `unknown` so callers can pass either a HazoConnectAdapter (production)
|
|
37
|
+
* or a test double.
|
|
38
|
+
*/
|
|
39
|
+
export type DigestSendFn = (options: SendTemplateEmailOptions, hazo_connect: unknown) => Promise<{
|
|
40
|
+
success: boolean;
|
|
41
|
+
}>;
|
|
42
|
+
export interface CreateDigestFlushHandlerOptions {
|
|
43
|
+
/**
|
|
44
|
+
* Given a user_id, returns the recipient address for that user (e.g. email).
|
|
45
|
+
*/
|
|
46
|
+
resolve_recipient: (user_id: string) => Promise<string>;
|
|
47
|
+
/** Template name used when rendering the digest email. */
|
|
48
|
+
template_name: string;
|
|
49
|
+
/** Static variables injected into every template render call. */
|
|
50
|
+
template_variables?: Record<string, string>;
|
|
51
|
+
/** Maximum rows claimed per invocation. Defaults to 500. */
|
|
52
|
+
batch_size?: number;
|
|
53
|
+
/** scope_id forwarded to send_template_email. Defaults to null. */
|
|
54
|
+
scope_id?: string | null;
|
|
55
|
+
/**
|
|
56
|
+
* Injectable adapter for testing. When omitted, `getInboxConnection()` is
|
|
57
|
+
* called at invocation time.
|
|
58
|
+
*/
|
|
59
|
+
_adapter?: DigestAdapter;
|
|
60
|
+
/**
|
|
61
|
+
* Injectable send function for testing. When omitted, `send_template_email`
|
|
62
|
+
* is used.
|
|
63
|
+
*/
|
|
64
|
+
_send?: DigestSendFn;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Factory that creates a hazo_jobs-compatible handler for digest flush.
|
|
68
|
+
*
|
|
69
|
+
* The handler:
|
|
70
|
+
* 1. Claims all deliveries with status='digesting' up to `batch_size`.
|
|
71
|
+
* 2. Enriches each row with user_id from hazo_notify_inbox when not already
|
|
72
|
+
* present on the claimed row.
|
|
73
|
+
* 3. Groups rows by (user_id, channel_id).
|
|
74
|
+
* 4. Fires one `_send` call per group, then marks each row sent/failed.
|
|
75
|
+
*/
|
|
76
|
+
export declare function createDigestFlushHandler(opts: CreateDigestFlushHandlerOptions): HazoJobHandler<DigestFlushPayload>;
|
|
77
|
+
//# sourceMappingURL=digest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"digest.d.ts","sourceRoot":"","sources":["../../../src/lib/jobs/digest.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AAC7E,OAAO,KAAK,EAAW,cAAc,EAAE,MAAM,YAAY,CAAC;AAE1D,iDAAiD;AACjD,eAAO,MAAM,qBAAqB,6BAA6B,CAAC;AAEhE,iFAAiF;AACjF,MAAM,WAAW,kBAAkB;IACjC,iFAAiF;IACjF,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAcD,4DAA4D;AAC5D,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE;QACjB,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC/B,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC7B,SAAS,EAAE,MAAM,EAAE,CAAC;QACpB,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE;YAAE,MAAM,EAAE,MAAM,CAAC;YAAC,SAAS,EAAE,KAAK,GAAG,MAAM,CAAA;SAAE,CAAC;KACzD,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;IACjB,KAAK,CACH,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;CACvB;AAED;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG,CACzB,OAAO,EAAE,wBAAwB,EACjC,YAAY,EAAE,OAAO,KAClB,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAEnC,MAAM,WAAW,+BAA+B;IAC9C;;OAEG;IACH,iBAAiB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAExD,0DAA0D;IAC1D,aAAa,EAAE,MAAM,CAAC;IAEtB,iEAAiE;IACjE,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAE5C,4DAA4D;IAC5D,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,mEAAmE;IACnE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAEzB;;;OAGG;IACH,QAAQ,CAAC,EAAE,aAAa,CAAC;IAEzB;;;OAGG;IACH,KAAK,CAAC,EAAE,YAAY,CAAC;CACtB;AAED;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,+BAA+B,GACpC,cAAc,CAAC,kBAAkB,CAAC,CA0IpC"}
|
|
@@ -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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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/lib/jobs/handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;
|
|
1
|
+
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/lib/jobs/handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC1E,OAAO,KAAK,EACV,cAAc,EACd,oBAAoB,EACrB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,8BAA8B;IAC7C,oFAAoF;IACpF,gBAAgB,EAAE,YAAY,CAAC,kBAAkB,CAAC,CAAC;IACnD,0EAA0E;IAC1E,oBAAoB,CAAC,EAAE,YAAY,CAAC,sBAAsB,CAAC,CAAC;IAC5D,qEAAqE;IACrE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,wDAAwD;IACxD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,wDAAwD;IACxD,MAAM,CAAC,EAAE,YAAY,CAAC,QAAQ,CAAC,CAAC;CACjC;AAED,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,8BAA8B,GACnC,cAAc,CAAC,oBAAoB,EAAE,WAAW,CAAC,CAiCnD"}
|
package/dist/lib/jobs/handler.js
CHANGED
|
@@ -7,30 +7,35 @@
|
|
|
7
7
|
*
|
|
8
8
|
* @packageDocumentation
|
|
9
9
|
*/
|
|
10
|
+
import { withContext, getContext } from 'hazo_core';
|
|
10
11
|
import { flushChannelOnce } from "../inbox/worker/flush.js";
|
|
11
12
|
export function createInboxFlushHandler(opts) {
|
|
12
13
|
const default_batch_size = opts.batch_size ?? 50;
|
|
13
14
|
const concurrency = opts.concurrency ?? 4;
|
|
14
15
|
return async function inbox_flush_handler(job, log) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
batchSize
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
16
|
+
const correlationId = getContext()?.correlationId
|
|
17
|
+
?? `notify_flush_${job.id}`;
|
|
18
|
+
return withContext({ correlationId }, async () => {
|
|
19
|
+
// SQLite-backed hazo_jobs stores payload as a JSON string and does not
|
|
20
|
+
// currently deserialize it before invoking handlers. Parse defensively so
|
|
21
|
+
// the handler works on both SQLite (string payload) and Postgres (JSONB
|
|
22
|
+
// object payload).
|
|
23
|
+
const payload = typeof job.payload === "string"
|
|
24
|
+
? JSON.parse(job.payload)
|
|
25
|
+
: job.payload;
|
|
26
|
+
const channel_id = payload.channel_id;
|
|
27
|
+
const batchSize = payload.batch_size ?? default_batch_size;
|
|
28
|
+
log?.info?.('inbox_flush.start', { channel_id, batchSize });
|
|
29
|
+
const result = await flushChannelOnce(channel_id, {
|
|
30
|
+
batchSize,
|
|
31
|
+
concurrency,
|
|
32
|
+
resolveRecipient: opts.resolveRecipient,
|
|
33
|
+
resolveScopeBranding: opts.resolveScopeBranding,
|
|
34
|
+
logger: opts.logger,
|
|
35
|
+
});
|
|
36
|
+
log?.info?.('inbox_flush.done', { channel_id, ...result });
|
|
37
|
+
return result;
|
|
31
38
|
});
|
|
32
|
-
log?.info?.(`[hazo_notify] inbox_flush done channel=${channel_id} processed=${result.processed} sent=${result.sent} failed=${result.failed} retried=${result.retried}`);
|
|
33
|
-
return result;
|
|
34
39
|
};
|
|
35
40
|
}
|
|
36
41
|
//# sourceMappingURL=handler.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../../../src/lib/jobs/handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAoB5D,MAAM,UAAU,uBAAuB,CACrC,IAAoC;IAEpC,MAAM,kBAAkB,GAAG,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC;IACjD,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,CAAC,CAAC;IAE1C,OAAO,KAAK,UAAU,mBAAmB,CAAC,GAAG,EAAE,GAAG;QAChD,uEAAuE;
|
|
1
|
+
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../../../src/lib/jobs/handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAoB5D,MAAM,UAAU,uBAAuB,CACrC,IAAoC;IAEpC,MAAM,kBAAkB,GAAG,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC;IACjD,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,CAAC,CAAC;IAE1C,OAAO,KAAK,UAAU,mBAAmB,CAAC,GAAG,EAAE,GAAG;QAChD,MAAM,aAAa,GAAG,UAAU,EAAE,EAAE,aAAmC;eAClE,gBAAgB,GAAG,CAAC,EAAE,EAAE,CAAC;QAC9B,OAAO,WAAW,CAAC,EAAE,aAAa,EAAE,EAAE,KAAK,IAAI,EAAE;YAC/C,uEAAuE;YACvE,0EAA0E;YAC1E,wEAAwE;YACxE,mBAAmB;YACnB,MAAM,OAAO,GACX,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ;gBAC7B,CAAC,CAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAA0B;gBACnD,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC;YAClB,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;YACtC,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,IAAI,kBAAkB,CAAC;YAE3D,GAAG,EAAE,IAAI,EAAE,CAAC,mBAAmB,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC,CAAC;YAE5D,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,UAAU,EAAE;gBAChD,SAAS;gBACT,WAAW;gBACX,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;gBACvC,oBAAoB,EAAE,IAAI,CAAC,oBAAoB;gBAC/C,MAAM,EAAE,IAAI,CAAC,MAAM;aACpB,CAAC,CAAC;YAEH,GAAG,EAAE,IAAI,EAAE,CAAC,kBAAkB,EAAE,EAAE,UAAU,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC;YAC3D,OAAO,MAAM,CAAC;QAChB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC"}
|
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":"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,
|
|
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"}
|
|
@@ -156,5 +156,41 @@ export const lifecycleDefaultTemplates = [
|
|
|
156
156
|
{ variable_name: 'stop_tips_url', variable_description: 'Signed URL for opt-out' },
|
|
157
157
|
],
|
|
158
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
|
+
},
|
|
159
195
|
];
|
|
160
196
|
//# sourceMappingURL=default_templates.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"default_templates.js","sourceRoot":"","sources":["../../../src/lib/lifecycle/default_templates.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"default_templates.js","sourceRoot":"","sources":["../../../src/lib/lifecycle/default_templates.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,8EAA8E;AAC9E,kCAAkC;AAClC,8EAA8E;AAE9E,MAAM,SAAS,GAAG;;;;;;;;;;;;;;;;;;;;QAoBV,CAAC;AAET,MAAM,SAAS,GAAG;;;;;;;;;;;sDAWoC,CAAC;AAEvD,8EAA8E;AAC9E,wBAAwB;AACxB,8EAA8E;AAE9E,MAAM,cAAc,GAAiC;IACnD,EAAE,aAAa,EAAE,YAAY,EAAE,oBAAoB,EAAE,wBAAwB,EAAE;IAC/E,EAAE,aAAa,EAAE,UAAU,EAAE,oBAAoB,EAAE,kBAAkB,EAAE;IACvE,EAAE,aAAa,EAAE,UAAU,EAAE,oBAAoB,EAAE,gBAAgB,EAAE;IACrE,EAAE,aAAa,EAAE,MAAM,EAAE,oBAAoB,EAAE,sBAAsB,EAAE;IACvE,EAAE,aAAa,EAAE,SAAS,EAAE,oBAAoB,EAAE,oBAAoB,EAAE;IACxE,EAAE,aAAa,EAAE,WAAW,EAAE,oBAAoB,EAAE,6BAA6B,EAAE;IACnF,EAAE,aAAa,EAAE,SAAS,EAAE,oBAAoB,EAAE,oBAAoB,EAAE;IACxE,EAAE,aAAa,EAAE,QAAQ,EAAE,oBAAoB,EAAE,2BAA2B,EAAE;IAC9E,EAAE,aAAa,EAAE,eAAe,EAAE,oBAAoB,EAAE,wBAAwB,EAAE;IAClF,EAAE,aAAa,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,yCAAyC,EAAE;CACzG,CAAC;AAEF,8EAA8E;AAC9E,qBAAqB;AACrB,8EAA8E;AAE9E,MAAM,CAAC,MAAM,yBAAyB,GAA6B;IACjE,aAAa;IACb;QACE,aAAa,EAAE,mBAAmB;QAClC,cAAc,EAAE,SAAS;QACzB,QAAQ,EAAE,WAAW;QACrB,MAAM,EAAE;YACN,IAAI,EAAE,SAAS;YACf,IAAI,EAAE,SAAS;SAChB;QACD,SAAS,EAAE;YACT,GAAG,cAAc;YACjB,EAAE,aAAa,EAAE,WAAW,EAAE,oBAAoB,EAAE,4BAA4B,EAAE;YAClF,EAAE,aAAa,EAAE,WAAW,EAAE,oBAAoB,EAAE,4BAA4B,EAAE;SACnF;KACF;IAED,kBAAkB;IAClB;QACE,aAAa,EAAE,wBAAwB;QACvC,cAAc,EAAE,uBAAuB;QACvC,QAAQ,EAAE,WAAW;QACrB,MAAM,EAAE;YACN,IAAI,EAAE,SAAS;YACf,IAAI,EAAE,SAAS;SAChB;QACD,SAAS,EAAE,cAAc;KAC1B;IAED,yBAAyB;IACzB;QACE,aAAa,EAAE,+BAA+B;QAC9C,cAAc,EAAE,gCAAgC;QAChD,QAAQ,EAAE,WAAW;QACrB,MAAM,EAAE;YACN,IAAI,EAAE,SAAS;YACf,IAAI,EAAE,SAAS;SAChB;QACD,SAAS,EAAE,cAAc;KAC1B;IAED,mBAAmB;IACnB;QACE,aAAa,EAAE,yBAAyB;QACxC,cAAc,EAAE,2BAA2B;QAC3C,QAAQ,EAAE,WAAW;QACrB,MAAM,EAAE;YACN,IAAI,EAAE,SAAS;YACf,IAAI,EAAE,SAAS;SAChB;QACD,SAAS,EAAE,cAAc;KAC1B;IAED,8BAA8B;IAC9B;QACE,aAAa,EAAE,kCAAkC;QACjD,cAAc,EAAE,2BAA2B;QAC3C,QAAQ,EAAE,WAAW;QACrB,MAAM,EAAE;YACN,IAAI,EAAE,SAAS;YACf,IAAI,EAAE,SAAS;SAChB;QACD,SAAS,EAAE,cAAc;KAC1B;IAED,6BAA6B;IAC7B;QACE,aAAa,EAAE,iCAAiC;QAChD,cAAc,EAAE,mBAAmB;QACnC,QAAQ,EAAE,WAAW;QACrB,MAAM,EAAE;YACN,IAAI,EAAE,SAAS;YACf,IAAI,EAAE,SAAS;SAChB;QACD,SAAS,EAAE,cAAc;KAC1B;IAED,uCAAuC;IACvC;QACE,aAAa,EAAE,2CAA2C;QAC1D,cAAc,EAAE,4BAA4B;QAC5C,QAAQ,EAAE,WAAW;QACrB,MAAM,EAAE;YACN,IAAI,EAAE,SAAS;YACf,IAAI,EAAE,SAAS;SAChB;QACD,SAAS,EAAE;YACT,GAAG,cAAc;YACjB,EAAE,aAAa,EAAE,cAAc,EAAE,oBAAoB,EAAE,qCAAqC,EAAE;SAC/F;KACF;IAED,iCAAiC;IACjC;QACE,aAAa,EAAE,4BAA4B;QAC3C,cAAc,EAAE,uCAAuC;QACvD,QAAQ,EAAE,WAAW;QACrB,MAAM,EAAE;YACN,IAAI,EAAE,0GAA0G;YAChH,IAAI,EAAE,gDAAgD;SACvD;QACD,SAAS,EAAE;YACT,EAAE,aAAa,EAAE,eAAe,EAAE,oBAAoB,EAAE,wBAAwB,EAAE;SACnF;KACF;IAED,kBAAkB;IAClB;QACE,aAAa,EAAE,cAAc;QAC7B,cAAc,EAAE,cAAc;QAC9B,QAAQ,EAAE,QAAQ;QAClB,MAAM,EAAE;YACN,IAAI,EAAE;;;;;;;;;;;;;;;;;QAiBJ;YACF,IAAI,EAAE;;;;iCAIqB;SAC5B;QACD,SAAS,EAAE;YACT,EAAE,aAAa,EAAE,cAAc,EAAE,oBAAoB,EAAE,+CAA+C,EAAE;YACxG,EAAE,aAAa,EAAE,YAAY,EAAE,oBAAoB,EAAE,0CAA0C,EAAE;YACjG,EAAE,aAAa,EAAE,aAAa,EAAE,oBAAoB,EAAE,iCAAiC,EAAE;SAC1F;KACF;CACF,CAAC"}
|
|
@@ -1 +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;
|
|
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;AAGxE,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,CAmB3E"}
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* @packageDocumentation
|
|
12
12
|
*/
|
|
13
13
|
import { send_template_email } from '../template_manager/template_manager.js';
|
|
14
|
+
import { NotifySendFailedError } from '../errors.js';
|
|
14
15
|
/**
|
|
15
16
|
* Dispatch a lifecycle email step.
|
|
16
17
|
*
|
|
@@ -26,7 +27,7 @@ export async function dispatchStep(opts) {
|
|
|
26
27
|
...(opts.subject_override ? { subject: opts.subject_override } : {}),
|
|
27
28
|
}, opts.hazo_connect);
|
|
28
29
|
if (!result.success) {
|
|
29
|
-
throw new
|
|
30
|
+
throw new NotifySendFailedError('email', result.error ?? `send_template_email failed for template '${opts.template_name}'`, { template_name: opts.template_name });
|
|
30
31
|
}
|
|
31
32
|
}
|
|
32
33
|
//# sourceMappingURL=dispatch.js.map
|
|
@@ -1 +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;
|
|
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;AAE9E,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAmBrD;;;;;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,qBAAqB,CAC7B,OAAO,EACP,MAAM,CAAC,KAAK,IAAI,4CAA4C,IAAI,CAAC,aAAa,GAAG,EACjF,EAAE,aAAa,EAAE,IAAI,CAAC,aAAa,EAAE,CACtC,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/lib/lifecycle/handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;
|
|
1
|
+
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/lib/lifecycle/handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAQH,OAAO,KAAK,EAGV,cAAc,EACd,yBAAyB,EACzB,oBAAoB,EACrB,MAAM,YAAY,CAAC;AAEpB;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,yBAAyB,EAC/B,cAAc,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GACnD,cAAc,CAAC,oBAAoB,CAAC,CA+ItC"}
|