notifkit 0.1.5 → 0.1.6
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/index.d.mts +6 -6
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{main-BFre2-HQ.mjs → main-BnIX5nfp.mjs} +2 -2
- package/dist/{main-BFre2-HQ.mjs.map → main-BnIX5nfp.mjs.map} +1 -1
- package/dist/{main-BOPMYqsW.mjs → main-CWGEKpLU.mjs} +2 -2
- package/dist/{main-BOPMYqsW.mjs.map → main-CWGEKpLU.mjs.map} +1 -1
- package/dist/{main-DvgJSm11.mjs → main-Cwu4iQXc.mjs} +2 -2
- package/dist/{main-DvgJSm11.mjs.map → main-Cwu4iQXc.mjs.map} +1 -1
- package/dist/{main-BNJtzY61.mjs → main-DDbquL89.mjs} +2 -2
- package/dist/{main-BNJtzY61.mjs.map → main-DDbquL89.mjs.map} +1 -1
- package/dist/{main-40zwq6b0.mjs → main-Db2f2-sW.mjs} +2 -2
- package/dist/{main-40zwq6b0.mjs.map → main-Db2f2-sW.mjs.map} +1 -1
- package/dist/{main-CiigNpsP.mjs → main-DdLzptZE.mjs} +2 -2
- package/dist/{main-CiigNpsP.mjs.map → main-DdLzptZE.mjs.map} +1 -1
- package/dist/{main-DmCPcxOc.mjs → main-DfrrNKp9.mjs} +2 -2
- package/dist/{main-DmCPcxOc.mjs.map → main-DfrrNKp9.mjs.map} +1 -1
- package/dist/{main-DeNFQ-UL.mjs → main-DsDkyBZi.mjs} +2 -2
- package/dist/{main-DeNFQ-UL.mjs.map → main-DsDkyBZi.mjs.map} +1 -1
- package/dist/{src-vG79L-8m.mjs → src-CpUnBl_M.mjs} +18 -18
- package/dist/src-CpUnBl_M.mjs.map +1 -0
- package/package.json +1 -1
- package/src/config/index.ts +5 -1
- package/dist/src-vG79L-8m.mjs.map +0 -1
package/dist/index.d.mts
CHANGED
|
@@ -461,6 +461,7 @@ declare const NotificationEnrichedPayloadSchema: z.ZodObject<{
|
|
|
461
461
|
channel: "push" | "email" | "sms" | "webhook" | "telegram" | "discord" | "whatsapp" | "slack" | "in-app";
|
|
462
462
|
priority: "low" | "normal" | "high" | "critical";
|
|
463
463
|
projectId: string;
|
|
464
|
+
rawEventId: string;
|
|
464
465
|
recipientId: string;
|
|
465
466
|
templateVariables: Record<string, unknown>;
|
|
466
467
|
recipient: {
|
|
@@ -484,7 +485,6 @@ declare const NotificationEnrichedPayloadSchema: z.ZodObject<{
|
|
|
484
485
|
pushToken?: string | undefined;
|
|
485
486
|
pushTokens?: string[] | undefined;
|
|
486
487
|
};
|
|
487
|
-
rawEventId: string;
|
|
488
488
|
aiPrompts?: Record<string, string> | undefined;
|
|
489
489
|
templateId?: string | undefined;
|
|
490
490
|
campaignId?: string | undefined;
|
|
@@ -494,6 +494,7 @@ declare const NotificationEnrichedPayloadSchema: z.ZodObject<{
|
|
|
494
494
|
channel: "push" | "email" | "sms" | "webhook" | "telegram" | "discord" | "whatsapp" | "slack" | "in-app";
|
|
495
495
|
priority: "low" | "normal" | "high" | "critical";
|
|
496
496
|
projectId: string;
|
|
497
|
+
rawEventId: string;
|
|
497
498
|
recipientId: string;
|
|
498
499
|
templateVariables: Record<string, unknown>;
|
|
499
500
|
recipient: {
|
|
@@ -517,7 +518,6 @@ declare const NotificationEnrichedPayloadSchema: z.ZodObject<{
|
|
|
517
518
|
pushTokens?: string[] | undefined;
|
|
518
519
|
locale?: string | undefined;
|
|
519
520
|
};
|
|
520
|
-
rawEventId: string;
|
|
521
521
|
aiPrompts?: Record<string, string> | undefined;
|
|
522
522
|
templateId?: string | undefined;
|
|
523
523
|
campaignId?: string | undefined;
|
|
@@ -735,9 +735,9 @@ declare const NotificationDispatchedPayloadSchema: z.ZodObject<{
|
|
|
735
735
|
priority: "low" | "normal" | "high" | "critical";
|
|
736
736
|
projectId: string;
|
|
737
737
|
taskId: string;
|
|
738
|
-
enrichedEventId: string;
|
|
739
738
|
recipientId: string;
|
|
740
739
|
templateVariables: Record<string, unknown>;
|
|
740
|
+
enrichedEventId: string;
|
|
741
741
|
renderedContent: {
|
|
742
742
|
content: Record<string, unknown>;
|
|
743
743
|
attachments?: {
|
|
@@ -783,8 +783,8 @@ declare const NotificationDispatchedPayloadSchema: z.ZodObject<{
|
|
|
783
783
|
priority: "low" | "normal" | "high" | "critical";
|
|
784
784
|
projectId: string;
|
|
785
785
|
taskId: string;
|
|
786
|
-
enrichedEventId: string;
|
|
787
786
|
recipientId: string;
|
|
787
|
+
enrichedEventId: string;
|
|
788
788
|
renderedContent: {
|
|
789
789
|
content: Record<string, unknown>;
|
|
790
790
|
attachments?: {
|
|
@@ -1041,7 +1041,6 @@ declare const NotificationAiPendingPayloadSchema: z.ZodObject<{
|
|
|
1041
1041
|
priority: "low" | "normal" | "high" | "critical";
|
|
1042
1042
|
aiPrompts: Record<string, string>;
|
|
1043
1043
|
projectId: string;
|
|
1044
|
-
enrichedEventId: string;
|
|
1045
1044
|
recipientId: string;
|
|
1046
1045
|
templateVariables: Record<string, unknown>;
|
|
1047
1046
|
recipient: {
|
|
@@ -1065,6 +1064,7 @@ declare const NotificationAiPendingPayloadSchema: z.ZodObject<{
|
|
|
1065
1064
|
pushToken?: string | undefined;
|
|
1066
1065
|
pushTokens?: string[] | undefined;
|
|
1067
1066
|
};
|
|
1067
|
+
enrichedEventId: string;
|
|
1068
1068
|
templateId?: string | undefined;
|
|
1069
1069
|
scheduledAt?: string | undefined;
|
|
1070
1070
|
fallbackChain?: ("push" | "email" | "sms" | "webhook" | "telegram" | "discord" | "whatsapp" | "slack" | "in-app")[] | undefined;
|
|
@@ -1073,7 +1073,6 @@ declare const NotificationAiPendingPayloadSchema: z.ZodObject<{
|
|
|
1073
1073
|
priority: "low" | "normal" | "high" | "critical";
|
|
1074
1074
|
aiPrompts: Record<string, string>;
|
|
1075
1075
|
projectId: string;
|
|
1076
|
-
enrichedEventId: string;
|
|
1077
1076
|
recipientId: string;
|
|
1078
1077
|
templateVariables: Record<string, unknown>;
|
|
1079
1078
|
recipient: {
|
|
@@ -1097,6 +1096,7 @@ declare const NotificationAiPendingPayloadSchema: z.ZodObject<{
|
|
|
1097
1096
|
pushTokens?: string[] | undefined;
|
|
1098
1097
|
locale?: string | undefined;
|
|
1099
1098
|
};
|
|
1099
|
+
enrichedEventId: string;
|
|
1100
1100
|
templateId?: string | undefined;
|
|
1101
1101
|
scheduledAt?: string | undefined;
|
|
1102
1102
|
fallbackChain?: ("push" | "email" | "sms" | "webhook" | "telegram" | "discord" | "whatsapp" | "slack" | "in-app")[] | undefined;
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/config/index.ts","../src/contracts/common.ts","../src/contracts/metadata.ts","../src/contracts/events/notification-requested.ts","../src/contracts/events/notification-created.ts","../src/contracts/events/notification-enriched.ts","../src/contracts/events/notification-scheduled.ts","../src/contracts/events/notification-dispatched.ts","../src/contracts/events/notification-delivered.ts","../src/contracts/events/notification-failed.ts","../src/contracts/events/notification-skipped.ts","../src/contracts/events/notification-canceled.ts","../src/contracts/events/notification-ai-pending.ts","../src/contracts/registry.ts","../src/contracts/envelope.ts","../src/contracts/streams.ts","../src/contracts/helpers.ts","../src/contracts/sdk.ts","../src/db/schema.ts","../src/db/index.ts","../src/idempotency/index.ts","../src/logger/index.ts","../src/metrics/index.ts","../src/queue/index.ts","../src/rate-limiter/index.ts","../src/redis/index.ts","../src/repositories/index.ts","../src/shared/events.ts","../src/shared/cache.ts","../src/shared/utils.ts","../src/shared/semaphore.ts","../src/shared/batch-processor.ts","../src/shared/circuit-breaker.ts","../src/shared/dataloader.ts","../src/workers/health.ts","../src/workers/index.ts","../src/shared/index.ts","../src/templates/render.ts","../src/templates/cache.ts","../src/templates/index.ts","../src/transport/index.ts","../src/unsubscribe/index.ts","../src/workflows/sdk.ts","../src/workflows/registry.ts","../src/client.ts","../src/server.ts"],"mappings":"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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAmBnB,kBAAkB,EAAE,aAAa;cAEhC,sBAAoB,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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"}
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/config/index.ts","../src/contracts/common.ts","../src/contracts/metadata.ts","../src/contracts/events/notification-requested.ts","../src/contracts/events/notification-created.ts","../src/contracts/events/notification-enriched.ts","../src/contracts/events/notification-scheduled.ts","../src/contracts/events/notification-dispatched.ts","../src/contracts/events/notification-delivered.ts","../src/contracts/events/notification-failed.ts","../src/contracts/events/notification-skipped.ts","../src/contracts/events/notification-canceled.ts","../src/contracts/events/notification-ai-pending.ts","../src/contracts/registry.ts","../src/contracts/envelope.ts","../src/contracts/streams.ts","../src/contracts/helpers.ts","../src/contracts/sdk.ts","../src/db/schema.ts","../src/db/index.ts","../src/idempotency/index.ts","../src/logger/index.ts","../src/metrics/index.ts","../src/queue/index.ts","../src/rate-limiter/index.ts","../src/redis/index.ts","../src/repositories/index.ts","../src/shared/events.ts","../src/shared/cache.ts","../src/shared/utils.ts","../src/shared/semaphore.ts","../src/shared/batch-processor.ts","../src/shared/circuit-breaker.ts","../src/shared/dataloader.ts","../src/workers/health.ts","../src/workers/index.ts","../src/shared/index.ts","../src/templates/render.ts","../src/templates/cache.ts","../src/templates/index.ts","../src/transport/index.ts","../src/unsubscribe/index.ts","../src/workflows/sdk.ts","../src/workflows/registry.ts","../src/client.ts","../src/server.ts"],"mappings":";;;;;;;;;iBAOgB,QAAQ;iBAKR,YAAY,gBAAgB,YAC1C,QAAQ,SACR,gBACC,EAAE,OAAO;cAkBC,kBAAgB,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAiCjB,aAAa,EAAE,aAAa;iBAIxB,gBAAgB,QAAQ;iBAIxB,eAAe,OAAM,OAAO,aAA2B;UAOtD;EACf;EACA;;UAGe;EACf,UAAU;;EAEV;;EAEA;;EAEA;;cAGW;;;;;iBAQG,YAAY,QAAQ;iBAIpB,eAAe;;;cC1GlB,2BAAyB,EAAA;KAW1B,sBAAsB,EAAE,aAAa;cAEpC,4BAA0B,EAAA;KAC3B,uBAAuB,EAAE,aAAa;cAErC,0BAAwB,EAAA;KASzB,qBAAqB,EAAE,aAAa;;;cCzBnC,qBAAmB,EAAA;;;;;;;;;;;;;;;;;;;KAOpB,gBAAgB,EAAE,aAAa;;;;;;;;;;;cCE9B,0BAAwB,EAAA,+BAAA,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAKzB,qBAAqB,EAAE,aAAa;cAEnC,oCAAkC,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAiBnC,+BAA+B,EAAE,aAAa;;;cChC7C,kCAAgC,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAUjC,6BAA6B,EAAE,aAAa;;;cCV3C,wBAAsB,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAyBvB,mBAAmB,EAAE,aAAa;cAEjC,mCAAiC,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAelC,8BAA8B,EAAE,aAAa;;;cC3C5C,oCAAkC,EAAA;;;;;;;;;;;;;;;;KAMnC,+BAA+B,EAAE,aAAa;;;cCJ7C,uBAAqB,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAYtB,kBAAkB,EAAE,aAAa;cAEhC,uBAAqB,EAAA;;;;;;;;;;;;;KAKtB,kBAAkB,EAAE,aAAa;cAEhC,qCAAmC,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAmBpC,gCAAgC,EAAE,aAAa;;;cCzC9C,oCAAkC,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAanC,+BAA+B,EAAE,aAAa;;;cCb7C,iCAA+B,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAehC,4BAA4B,EAAE,aAAa;;;cChB1C,kCAAgC,EAAA;;;;;;;;;;;;;;;;KAMjC,6BAA6B,EAAE,aAAa;;;cCN3C,mCAAiC,EAAA;;;;;;;;;;KAIlC,8BAA8B,EAAE,aAAa;;;cCF5C,oCAAkC,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAanC,+BAA+B,EAAE,aAAa;;;;;;;;;;;;;;;UCMzC;EACf,0BAA0B;EAC1B,wBAAwB;EACxB,yBAAyB;EACzB,0BAA0B;EAC1B,2BAA2B;EAC3B,0BAA0B;EAC1B,uBAAuB;EACvB,wBAAwB;EACxB,yBAAyB;EACzB,2BAA2B;;KAGjB,uBAAuB;KAEvB,YAAY;EAAO;EAAe,MAAM;;EAAQ;EAAgB,OAAO;;cAEtE;mBACM;EAEjB,OAAO,cAAc,QAAQ;EAO7B,UAAU,eAAe;EAIzB,IAAI;EAIJ;EAIA,aAAa,UAAU,gBAAgB,MAAM,GAAG,mBAAmB,gBAAgB;EAMnF,iBAAiB,UAAU,gBACzB,MAAM,GACN,mBACC,YAAY,gBAAgB;;cAgBpB,UAAQ;;;;;;;cC/ER,qBAAmB,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAOpB,gBAAgB,EAAE,aAAa;;KAG/B,mBAAmB,UAAU,kBAAkB,KACzD;EAGA,MAAM;EACN,SAAS,gBAAgB;;KAIf,cAAc;cACb,mBAAiB,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAClB,sBAAsB;cACrB,2BAAyB,EAAA;;;;;;;;;;;;;;;;;;;;;cC9BzB;;;;;;;;;;;;;;;;cAiBA;cAMA;cAMA;KAKD,qBAAqB,sBAAsB;;;;;;;cAQ1C;;;;;;;;KAQD,wBAAwB,8BAA8B;cAErD;;;;;;;;;KASD,wBAAwB,8BAA8B;;;iBCxDlD,iBACd,cACA,SAAS,yBACT,gBACA,mBACC,KAAK;;;cCDK,kBAAgB,EAAA;;;;;;;;;;KAIjB,aAAa,EAAE,aAAa;cAE3B,mBAAiB,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAKlB,cAAc,EAAE,aAAa;;cAK5B,sBAAoB,EAAA;KAUrB,iBAAiB,EAAE,aAAa;;;;;cAa/B,eAAa,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAUd,eAAe,EAAE,aAAa;;cAG7B,kBAAgB,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KASjB,kBAAkB,EAAE,aAAa;;cAGhC,kBAAgB,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAKjB,kBAAkB,EAAE,aAAa;cAIhC,gBAAc,EAAA;;;;;;;;;;;;;;;;;;;KAUf,gBAAgB,EAAE,aAAa;cAE9B,qBAAmB,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAGpB,qBAAqB,EAAE,aAAa;;cAKnC,kBAAgB,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAUjB,aAAa,EAAE,aAAa;cA0C3B,qBAAmB,EAAA,WAAA,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAgBpB,qBAAqB,EAAE,aAAa;;;;;;;;cASnC,6BAA2B,EAAA,WAAA,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAS5B,sBAAsB,EAAE,aAAa;cAIpC,uBAAqB,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAKtB,uBAAuB,EAAE,aAAa;cAIrC,mBAAiB,EAAA;;;;;;;;;;KAIlB,mBAAmB,EAAE,aAAa;cAEjC,oBAAkB,EAAA,iCAAA,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAmBnB,kBAAkB,EAAE,aAAa;cAEhC,sBAAoB,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAIrB,sBAAsB,EAAE,aAAa;cAIpC,qBAAmB,EAAA;;;;;;;;;;;;;KAKpB,qBAAqB,EAAE,aAAa;;;;cC9NnC,2CAAW;cAYX,wCAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YAAR;;;;;;;;;;;;;;;cASA,qCAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YAAL;;;;;;;;;;;;;;;;;YAAA;;;;;;;;;;;;;;;cAeA,8CAAc;cAEd,8CAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YAAd;;;;;;;;;;;;;;;cAUA,4CAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAeZ,4CAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YAAZ;;;;;;;;;;;;;;;cAmBA,sDAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cActB,oDAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAepB,uDAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAevB,0CAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAeV,yCAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YAAT;;;;;;;;;;;;;;;cAkBA,2CAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YAAX;;;;;;;;;;;;;;;;;;;;;;;;cA6DA,4CAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YAAZ;;;;;;;;;;;;;;;cA6BA,kDAAkB;cAOlB,mDAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YAAnB;;;;;;;;;;;;;;;cAcA,iDAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YAAjB;;;;;;;;;;;;;;;;;YAAA;;;;;;;;;;;;;;;cAgBA,6CAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YAAb;;;;;;;;;;;;;;;cAmBA,+CAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YAAf;;;;;;;;;;;;;;;;;YAAA;;;;;;;;;;;;;;;cAyBA,8CAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YAAd;;;;;;;;;;;;;;;cAcA,iDAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YAAjB;;;;;;;;;;;;;;;cAQA,2CAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAAnB;;;;;;;;;;;;;cACA,2CAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAAnB;;;;;;;;;;;;;cAEA,iDAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAAzB;;;;;;;;;;;;;cACA,iDAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAAzB;;;;;;;;;;;;;cAEA,wCAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAAhB;;;;;;;;;;;;;;;;;UAAA;;;;;;;;;;;;;cACA,wCAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAAhB;;;;;;;;;;;;;;;;;UAAA;;;;;;;;;;;;;cAEA,+CAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cACvB,+CAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAEvB,+CAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAAvB;;;;;;;;;;;;;cACA,+CAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAAvB;;;;;;;;;;;;;cAEA,yDAAiC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cACjC,yDAAiC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAEjC,uDAA+B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAC/B,uDAA+B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAE/B,8CAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAAtB;;;;;;;;;;;;;cACA,8CAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAAtB;;;;;;;;;;;;;cAEA,+CAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAAvB;;;;;;;;;;;;;cACA,+CAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAAvB;;;;;;;;;;;;;cAEA,oDAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAA5B;;;;;;;;;;;;;;;;;UAAA;;;;;;;;;;;;;cACA,oDAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAA5B;;;;;;;;;;;;;;;;;UAAA;;;;;;;;;;;;;cAEA,gDAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAAxB;;;;;;;;;;;;;cACA,gDAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAAxB;;;;;;;;;;;;;cAEA,kDAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAA1B;;;;;;;;;;;;;;;;;UAAA;;;;;;;;;;;;;cACA,kDAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAA1B;;;;;;;;;;;;;;;;;UAAA;;;;;;;;;;;;;cAEA,kDAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAA1B;;;;;;;;;;;;;cACA,kDAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAA1B;;;;;;;;;;;;;cAEA,oDAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAA5B;;;;;;;;;;;;;cACA,oDAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAA5B;;;;;;;;;;;;;;;KCrZD,MAAM,SAAS;KACf,KAAK,0BAA0B;UAE1B;EACf;EACA;EACA;EACA;EACA,SAAS;;UAGM;EACf,KAAK;EACL,IAAI;;;;;;;iBAQU,iBACd,KACA,iBACA,gBACA,oBACA,UACC,kBAAkB;iBAyBC,cAAc,IAAI,KAAE;;;UCxDzB;EACf,OAAO;EACP;EACA;;;;;;;cAQW;mBACM;mBACA;mBACA;EAEL,cAAE,OAAO,WAAW,cAAuB;UAM/C;;EAKF,aAAa,YAAY,4BAA4B;;EAOrD,cAAc,YAAY,4BAA4B;EAKtD,YAAY,aAAa;;EAKzB,OAAO,aAAa;;;;KC5ChB;KAEA,SAAS;UAEJ;EACf;EACA,QAAQ;EACR;EACA,UAAU;;iBAGI,eAAe,MAAM,OAAgB,QAAQ,WAAW,gBAAgB;iBAoCxE,cAAc,QAAQ,QAAQ,oBAAoB;iBAIlD,YAAY,QAAQ,QAAQ,SAAS,0BAA0B;iBAI/D,YAAY,QAAQ,QAAQ,UAAU,0BAA0B;;;cCpDnE;;;;;;;;;iBA6CG,sBAAkB,WAAA;;;UCpCjB;EACf;EACA,OAAO;;EAEP;;UAGe;EACf;EACA;EACA;EACA;;EAEA,QAAQ;;UAiCO;EACf,OAAO;EACP,QAAQ;EACR,SAAS;EACT;;cAGW;mBACM;mBACA;mBACA;mBACA;EAEL,cAAE,OAAO,QAAQ,QAAQ,UAAU;EAOzC,QAAQ,SAAS,KAAK,mCAAmC;UA2BjD;EAsBR,aACJ,UAAU,KAAK,qCACd;IAAU;IAAsB;;;UAkDpB;EACf,OAAO;EACP,QAAQ,aAAa;EACrB,OAAO;EACP;EACA,YAAY;EACZ,SAAS;EACT;EACA;;cAKW;WACF,OAAO;mBACC;mBACA;mBACA;mBACA;mBACA;mBACA;mBACA;mBACA;UACT;EAEI,cACV,OACA,QACA,OACA,UACA,WACA,QACA,WACA,WACC;EAYG,eAAe;EAkBd,aAAa,eAAe;EAyF7B,IAAI,8BAA8B,kBAAkB;EAQpD,KAAK,mBAAmB,OAAO,aAAa,kBAAkB;EAiC9D,QAAQ;;UAcC;EACf,OAAO;EACP,QAAQ,aAAa;EACrB,OAAO;EACP;EACA,SAAS;;cAGE;mBACM;mBACA;mBACA;mBACA;mBACA;EAEL,cAAE,OAAO,QAAQ,OAAO,UAAU,UAAU;EAQlD,mBAAmB;;EAanB,kBAAkB,gBAAa,SAAS,aAAa,QAAQ;EAwB7D,UAAU,mBAAmB,iBAAa,QAAQ;;;;UC5bzC;EACf;EACA;EACA;;;;;;UASe;EACf;EACA;;UAQe;EACf;EACA;;;;;;;;;;;;cAaW;mBAaQ;mBAZF;;;;;;;;;mBASA;EAGE,YAAA,OAAO,sBAAsB,QAAQ,mCACpD,SAAgB,UAAkB;;;;;EAShC,IAAI,oBAAoB,QAAQ;EAiCtC,WAAW;EAOX;;UASe;EACf,OAAO;EACP;EACA;;UAGe;;EAEf;;EAEA;;EAEA;;cAaW;mBACM;mBACA;mBACA;EAEL,cAAE,OAAO,YAAgB,eAAmB;;;;;;;;EAalD,MACJ,mBACA,gBACA,mBACA,UAAS,uBACR,QAAQ;;;;UC/JI;EACf;EACA;EACA,SAAS;EACT,eAAe,QAAQ;;cAGZ;WACF,QAAQ;mBAEA;UACT;EAEI,cAAE,KAAK,MAAmB,QAAQ,gBAAgB;EAkCxD,eAAe;EASf,cAAc;;;;UCnCL;EACf;EACA;EACA;EACA;;UAGe,mBAAmB;EAClC;EACA,aAAa;;UAGE;EACf;EACA;EACA,SAAS;EACT;EACA,aAAa;EACb;;UAGe;EACf;EACA;EACA;EACA;;EAEA,YAAY;;KAGF;UAEK;EACf;EACA;EACA;EACA,UAAU;EACV;;UAGe;EACf;EACA;EACA;;cAKW;mBACkB;EAAA,YAAA,IAAI;EAE3B,SAAS,mBAAmB,iBAAiB,QAAQ;EAiBrD,eAAe,mBAAmB,iBAAiB,QAAQ;EAuD3D,iBAAiB,mBAAmB,oBAAoB,QAAQ;EA2EhE,WACJ,mBACA;IACE;IACA;IACA;IACA;IACA;IACA,aAAa;MAEd;EA0FG,eACJ,mBACA,WAAW;IACT;IACA;IACA;IACA;IACA;IACA,aAAa;OAEd;EA8JG,cACJ,mBACA,gBACA;IACE;IACA;IACA;IACA;IACA,cAAc;MAEf;EAsFG,OAAO,mBAAmB,iBAAiB;EAQ3C,KACJ,mBACA,eACA,iBACA;IACE;IACA;IACA;IACA;IACA;MAED;IAAU,OAAO;IAAe;;EA4D7B,mBAAmB,mBAAmB,sBAAsB;EAU5D,iBAAiB,mBAAmB,oBAAoB;;cAmBnD;mBACkB;EAAA,YAAA,IAAI;EAE3B,UAAU,mBAAmB,gBAAgB,oBAAoB;EAMjE,aAAa,mBAAmB,iBAAiB,QAAQ;;cAuBpD;mBACkB;EAAA,YAAA,IAAI;EAE3B,aAAa,mBAAmB,iBAAiB,QAAQ;;EAyCzD,oBACJ,mBACA,oBACC,QAAQ,YAAY;EAqCjB,OACJ,mBACA,gBACA,SAAS,gBACT,gBACA,cAAa,cACZ;EAyCG,WACJ,mBACA,cAAc;IACZ;IACA,SAAS;IACT;IACA,cAAc;OAEf;;;;;;EA0EG,WACJ,mBACA,gBACA,SAAS,gBACT,iBACC;EAsBG,OACJ,mBACA,gBACA,SAAS,gBACT,iBACC;;cAwBQ;mBACkB;EAAA,YAAA,IAAI;EAE3B,SAAS,mBAAmB,aAAa,QAAQ;EAgBjD,KAAK,oBAAoB,QAAQ;EAWjC,WAAW,mBAAmB,sBAAsB;EA6BpD,OAAO,mBAAmB,aAAa;;cAWlC;mBACkB;EAAA,YAAA,IAAI;EAE3B,QAAQ;EAcR,OAAO,aAAa;;;;;EA2BpB,qBACJ,aACC;IAAU;IAA8B;;EAarC,eACJ,YACA;IACE;IACA;IACA;MAED;EASG,aACJ,mBACA,iBACA,+BACC;IAAU;;EAQP,YAAY,oBAAoB;EAYhC,aAAa,mBAAmB,gBAAgB;;cAW3C;mBACkB;EAAA,YAAA,IAAI;EAE3B,gBAAgB,oBAAoB;EAQpC,YAAY,mBAAmB,qBAAqB;EAyBpD,eAAe,mBAAmB,qBAAqB;;cAsBlD;mBACkB;EAAA,YAAA,IAAI;EAE3B,aAAa,oBAAoB;;;;cCltC5B,eAAa;;;cCFb,SAAS,GAAG;UACf;mBACS;mBACA;EAEL,YAAA,kBAAwB;EAKpC,IAAI,KAAK,IAAI;EAeb,IAAI,KAAK,GAAG,OAAO,GAAG;EActB,OAAO,KAAK;EAIZ;;;;iBC3Cc,kBACd;;;;;;;;;;;iBAgBc,gBAAgB;cAKnB;cAcA;;cAcA;;cAQA;;;cC1DA;mBAIkB;UAHrB;UACA;EAEqB,YAAA;EAEvB,WAAW;EAUjB;MAaI;;;;UC7BW,UAAU,GAAG;EAC5B,MAAM;EACN,UAAU,OAAO;EACjB,SAAS;;cAGE,eAAe,GAAG;mBAMV;mBACA;mBACA;UAPX;UACA;UACA;EAGW,YAAA,iBACA,mBACA,UAAU,OAAO,QAAQ,QAAQ;EAGpD,IAAI,MAAM,IAAI,QAAQ;EAkBhB,SAAS;;;;UCnCA;EACf;EACA;;KAGG;cAEQ;UACH;UACA;UACA;;UAEA;mBACS;mBACA;EAEL,YAAA,SAAS;EAKf,QAAQ,GAAG,cAAc,QAAQ,KAAK,QAAQ;UAkC5C;UAKA;EAUR,YAAY;;;;cCtED,WAAW,GAAG;mBAKI;UAJrB;UACA;UACA;EAEqB,YAAA,cAAc,MAAM,QAAQ,SAAS,IAAI;EAEtE,KAAK,KAAK,IAAI,QAAQ;;;;iBCJR,oBACd,qBACA,QAAQ,YACR;EAAS,mBAAmB;EAAkB;GAC9C,QAAQ,QACR,sBACC,OAAO;;;cCDG,0BAA0B;WAC5B;EACG,YAAA;;KAMF;UAEK;EACf,OAAO;EACP;EACA;EACA;EACA;EACA;;UAGe;EACf,UAAU;EACV,gBAAgB;EAChB,QAAQ;EACR;EACA;EACA;;uBAKoB;qBACD,QAAQ;mBAEV;mBACA;mBACA;mBACA;mBACA;UAET;UACA;UACA;UACA;UACA;UACA;UACA;UACA;mBACS;mBACA;UACT;EAEI,cACV,UACA,gBACA,QACA,aACA,oBACA,uBACC;qBAUgB,QAAQ,SAAS,eAAe,mBAAmB;EAEhE,SAAS;UAcD;EAuBR,QAAQ;EAqBR,WAAW;EA+BjB,UAAU;UAaI;UAqEN;UAUA;;;;iBCjQM;iBAIA,MAAM,aAAa;cAItB,iBAAiB;WACnB;EAEG,YAAA,iBAAiB,cAAc,UAAU;;cAO1C,wBAAwB;WAC1B,SAAS;EAEN,YAAA,iBAAiB,SAAS,0BAA0B,UAAU;;;;iBCvB5D,WAAW;;iBAUX,aAAa;iBAMb,YACd,cACA,WAAW,yBACX;;;;;;;;KAmBU;iBAwEI,mBACd;EAAc;sBACd,mBAAmB;EAChB,SAAS;;;;cC9GD;mBAGkB;UAFrB;EAEqB,YAAA,cAAc;EAErC,kBAAkB,mBAAmB,aAAU;EAYrD,WAAW,mBAAmB;EAI9B,cAAc;EAId;;;;UCtBe;EACf;EACA,mBAAmB;EACnB;EACA;EACA;;KAGU,oBAAoB,KAAK,oBAAoB;cAanD;mBACa;;;;;EAMjB,SAAS,mBAAmB,UAAU;;EAKtC,OAAO,KAAK,kBAAkB;EAM9B,IAAI;EAIJ;;cAeW,kBAAgB;iBAEb,eAAe,KAAK,kBAAkB;;;UC3DrC;EACf;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA,YAAY;;;;;;EAMZ;;;;;;;;EAQA;;EAEA,WAAW;;UAGI;WACN,SAAS;WACT;IAAW;IAAe;;EACnC,KAAK,MAAM,gCAAgC,QAAQ;EAEnD;;;;;;;;EAQA,0BACE,OAAO,oBACJ;EACL,iBACE,iBACA,SAAS,kDACN;EACL,gBACE,WACA,kBACA,UAAU,kDACP,QAAQ;;cAKT;mBACa;EAEjB,SAAS,WAAW,WAAW;EAQ/B,IAAI,SAAS,sBAAsB;EAKnC,OAAO,SAAS,sBAAsB;EAKtC;;cAKW,mBAAiB;iBAEd,kBAAkB,WAAW,WAAW;;;;;;;;;;;;;;;;;UC5EvC;;EAEf;;EAEA;EACA;;EAEA;;EAEA;;;;;;;;;iBAsBc,qBAAqB,OAAO,kBAAkB;;;;;;;;iBAoB9C,uBAAuB,eAAe,iBAAiB;UAmCtD;EACf,OAAO;EACP;;EAEA;;;;;;;;;;iBAWc,wBAAwB,SAAS,2BAA2B;;;cChH/D,8BAA8B;EAEhC;EACA;EADA,YAAA,iCACA;;UAOM;EACf;IAAQ;;GACP;;UAGc;EACf,MAAM;EACN,OAAO;;;UAIQ;EACf;EACA;EACA;;UAGe;EACf,OAAO,SAAS,sBAAsB,QAAQ;EAC9C,KAAK,mBAAmB;EACxB,aACE,mBACA;IAAY;IAAkB,QAAQ;MACrC;EACH,IAAI,GAAG,cAAc,UAAU,QAAQ,KAAK,IAAI,QAAQ;;;;;;;;;iBAU1C,kBACd,MAAM,qBACN,yBACC;;;;;;;;iBAkCa,uBACd,MAAM,qBACN,wBACA,mBACA,0BACC;;;KC1FE,mBAAmB,KAAK,oBAAoB;cAE3C;UACI;EAER,SAAS,cAAc,SAAS;EAIhC,IAAI,eAAe;;cAKR,kBAAgB;iBAEb,SAAS,cAAc,SAAS;;;UCN/B;EACf;EACA,UAAU;EACV,YAAY;EACZ;;cAGW;mBACM;mBACA;mBACA;EAEL,YAAA,SAAS;UAUP;;EAsBR,cAAc,OAAO,qBAAqB;IAAU;;;EAKpD,QAAQ,OAAO,eAAe;IAAU;;;EAKxC,WAAW,YAAY,OAAO,kBAAkB;IAAU;;;EAK1D,WAAW,aAAa;;EAKxB,WACJ,gBACA,OAAO,kBACN;IAAU;IAAgB;IAAiB;;;EAKxC,cAAc,gBAAgB,iBAAiB,iBAAiB;;EAKhE,OACJ,OAAO,qBACN;IAAU;IAAmB;IAAwB;;;EAKlD,gBACJ,OAAO,uBACN;IAAU;IAAmB;;;EAK1B,eAAe,OAAO,sBAAsB;IAAU;;;EAKtD,YAAY,OAAO,mBAAmB;IAAU;IAAmB;;;EAKnE,QAAQ;IAAU;;;EAUlB,cAAc;IAClB;IACA;MACE;IAAU;;;EASR,YAAY,qBAAqB;;EAKjC,eAAe,qBAAqB;;EAKpC,oBAAoB;IACxB;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;MACE;IAAU;IAAa;;;EAqBrB,UAAU;IACd;IACA;IACA;IACA;IACA;IACA;IACA;MACE;IAAU;IAAc;;;EActB,eAAe,aAAa;;EAK5B,gBAAgB,iBAAiB;IAAU;;;EAK3C,gBAAgB;IAAU;;;EAK1B,cAAc,aAAa;;EAK3B,iBACJ,YACA;IAAU;MACT;IAAU;IAAY;IAAgB;;;EAKnC,gBAAgB,aAAa;IAAU;;;EAKvC,iBAAiB,YAAY,gBAAgB;;EAK7C,cAAc,YAAY,OAAO,qBAAqB;IAAU;;;EAKhE,gBAAgB;IAAU;;;EAO1B,cAAc;IAClB;IACA;IACA;IACA,iBAAiB;IACjB,iBAAiB;IACjB;MACE;IACF;MACE;MACA;MACA;MACA;;;;EA0BE,iBAAiB,mBAAmB;IACxC;IACA,QAAQ;IACR,WAAW,eAAe;IAC1B;IACA;;;EAQI,iBAAiB;IACrB;IACA;IACA;IACA;MACE;IAAU;;;EAWR,kBAAkB;IACtB;IACA;IACA;MACE;IAAU;IAAiB;IAAgB;;;EAKzC,kBAAkB,iBAAiB,iBAAiB;;EAUpD,sBAAsB,iBAAiB;IAAU;IAAgB;;;EAKjE,mBAAmB,iBAAiB;IAAU;;;EAK9C,wBAAwB;IAAU;;;EAOlC,QAAQ,aAAa;;EAKrB,eAAe,aAAa;;EAK5B,mBAAmB,aAAa;;EAKhC,sBACJ,YACA,aAAa,sBACZ;IAAU;IAAY;;;EAOnB,iBAAiB;IAAU;;;EAK3B,YAAY,aAAa;;EAOzB,mBAAmB;;EAKnB,oBAAoB;;EAKpB,kBAAkB;IAAU;;;EAK5B,iBAAiB,aAAa;IAAU;IAAkB;;;EAK1D,iBAAiB,aAAa;IAAU;;;;;UClZ/B;EACf;EACA;EACA;EACA;EACA;EACA;EAGA,YAAY;EACZ;EACA,UAAU;EACV;EACA;IACE;;EAEF;IACE;;;cAIS,uBAAuB;UAC1B;UACA;UACA;UACA;UACA;UACA;UACA;UACA;EAEI,YAAA,SAAS;EA4Bf,SAAK;EAiJL,QAAI"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
|
-
import { $ as childLogger, $t as PUBSUB_CHANNELS, A as ProjectSettingsCache, At as NotificationRequestedPayloadSchema, B as LUA_RELEASE_LOCK, Bt as QuietHoursSchema, C as ProjectRepository, Ct as DeliveryOptionsSchema, D as WorkflowRepository, Dt as NotificationEnrichedPayloadSchema, E as UserRepository, Et as NotificationScheduledPayloadSchema, F as sleep, Ft as CreateWorkflowSchema, G as normaliseTarget, Gt as UpdateUserSchema, H as LUA_SCHEDULER_CLAIM, Ht as TemplateSchema, I as DataLoader, It as IngestEventSchema, J as PendingMessageScanner, Jt as buildStreamEvent, K as LRUCache, Kt as WorkflowNotifyPayloadSchema, L as CircuitBreaker, Lt as InlineUserSchema, M as AppError, Mt as AddContactSchema, N as ValidationError, Nt as AddUserSchema, O as Redis, Ot as RecipientProfileSchema, P as generateId, Pt as ContactChannelSchema, Q as metrics, Qt as OUTBOUND_STREAMS, R as BatchProcessor, Rt as NotifyRequestSchema, S as PreferenceRepository, St as NotificationDeliveredPayloadSchema, T as TemplateRepository, Tt as RenderedContentSchema, U as LUA_SCHEDULER_POLL, Ut as TriggerWorkflowSchema, V as LUA_RENEW_LOCK, Vt as SyncTemplatesSchema, W as getPriorityBucket, Wt as UpdateProjectSchema, X as StreamProducer, Xt as ENRICHED_STREAMS, Y as StreamConsumer, Yt as CONSUMER_GROUPS, Z as getMetricsRegistry, Zt as INBOUND_STREAMS, _ as escapeHeader, _n as setGlobalConfig, a as SuspendExecutionError, an as registry, at as runMigrations, b as renderWithTemplate, bt as NotificationSkippedPayloadSchema, c as BaseWorker, cn as NotificationPrioritySchema, d as buildUnsubscribeHeaders, dn as baseConfigSchema, en as STREAMS, et as createLogger, f as signUnsubscribeToken, fn as getAiConfig, g as TemplateCache, gn as setAiConfig, h as templateRegistry, hn as readBaseConfig, i as workflowRegistry, in as EventRegistry, it as createDatabase, j as UserThrottle, jt as NotificationTargetSchema, k as RedisClient, kt as NotificationCreatedPayloadSchema, l as NonRetryableError, ln as NotificationStatusSchema, m as renderTemplate, mn as parseConfig, n as NotifkitClient, nn as StreamEventMetadataSchema, nt as withRequestId, o as buildStepNotifyPayload, on as EventMetadataSchema, p as verifyUnsubscribeToken, pn as loadEnv, q as globalEmitter, qt as WorkflowStepSchema, r as workflow, rn as StreamEventSchema, rt as IdempotencyGuard, s as resolveStepTarget, sn as NotificationChannelSchema, t as NotifkitServer, tn as EventEnvelopeSchema, tt as withContext, u as startHealthReporter, un as AI_DEFAULTS, v as escapeHtml, vt as NotificationAiPendingPayloadSchema, w as SegmentRepository, wt as NotificationDispatchedPayloadSchema, x as ContactRepository, xt as NotificationFailedPayloadSchema, y as interpolate, yt as NotificationCanceledPayloadSchema, z as AsyncSemaphore, zt as PreferencesSchema } from "./src-
|
|
2
|
+
import { $ as childLogger, $t as PUBSUB_CHANNELS, A as ProjectSettingsCache, At as NotificationRequestedPayloadSchema, B as LUA_RELEASE_LOCK, Bt as QuietHoursSchema, C as ProjectRepository, Ct as DeliveryOptionsSchema, D as WorkflowRepository, Dt as NotificationEnrichedPayloadSchema, E as UserRepository, Et as NotificationScheduledPayloadSchema, F as sleep, Ft as CreateWorkflowSchema, G as normaliseTarget, Gt as UpdateUserSchema, H as LUA_SCHEDULER_CLAIM, Ht as TemplateSchema, I as DataLoader, It as IngestEventSchema, J as PendingMessageScanner, Jt as buildStreamEvent, K as LRUCache, Kt as WorkflowNotifyPayloadSchema, L as CircuitBreaker, Lt as InlineUserSchema, M as AppError, Mt as AddContactSchema, N as ValidationError, Nt as AddUserSchema, O as Redis, Ot as RecipientProfileSchema, P as generateId, Pt as ContactChannelSchema, Q as metrics, Qt as OUTBOUND_STREAMS, R as BatchProcessor, Rt as NotifyRequestSchema, S as PreferenceRepository, St as NotificationDeliveredPayloadSchema, T as TemplateRepository, Tt as RenderedContentSchema, U as LUA_SCHEDULER_POLL, Ut as TriggerWorkflowSchema, V as LUA_RENEW_LOCK, Vt as SyncTemplatesSchema, W as getPriorityBucket, Wt as UpdateProjectSchema, X as StreamProducer, Xt as ENRICHED_STREAMS, Y as StreamConsumer, Yt as CONSUMER_GROUPS, Z as getMetricsRegistry, Zt as INBOUND_STREAMS, _ as escapeHeader, _n as setGlobalConfig, a as SuspendExecutionError, an as registry, at as runMigrations, b as renderWithTemplate, bt as NotificationSkippedPayloadSchema, c as BaseWorker, cn as NotificationPrioritySchema, d as buildUnsubscribeHeaders, dn as baseConfigSchema, en as STREAMS, et as createLogger, f as signUnsubscribeToken, fn as getAiConfig, g as TemplateCache, gn as setAiConfig, h as templateRegistry, hn as readBaseConfig, i as workflowRegistry, in as EventRegistry, it as createDatabase, j as UserThrottle, jt as NotificationTargetSchema, k as RedisClient, kt as NotificationCreatedPayloadSchema, l as NonRetryableError, ln as NotificationStatusSchema, m as renderTemplate, mn as parseConfig, n as NotifkitClient, nn as StreamEventMetadataSchema, nt as withRequestId, o as buildStepNotifyPayload, on as EventMetadataSchema, p as verifyUnsubscribeToken, pn as loadEnv, q as globalEmitter, qt as WorkflowStepSchema, r as workflow, rn as StreamEventSchema, rt as IdempotencyGuard, s as resolveStepTarget, sn as NotificationChannelSchema, t as NotifkitServer, tn as EventEnvelopeSchema, tt as withContext, u as startHealthReporter, un as AI_DEFAULTS, v as escapeHtml, vt as NotificationAiPendingPayloadSchema, w as SegmentRepository, wt as NotificationDispatchedPayloadSchema, x as ContactRepository, xt as NotificationFailedPayloadSchema, y as interpolate, yt as NotificationCanceledPayloadSchema, z as AsyncSemaphore, zt as PreferencesSchema } from "./src-CpUnBl_M.mjs";
|
|
3
3
|
//#region src/transport/index.ts
|
|
4
4
|
var transport_exports = /* @__PURE__ */ __exportAll({
|
|
5
5
|
registerTransport: () => registerTransport,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { B as LUA_RELEASE_LOCK, J as PendingMessageScanner, Jt as buildStreamEvent, U as LUA_SCHEDULER_POLL, V as LUA_RENEW_LOCK, X as StreamProducer, Y as StreamConsumer, Yt as CONSUMER_GROUPS, _t as workflowWaiters, a as SuspendExecutionError, c as BaseWorker, en as STREAMS, et as createLogger, gt as workflowSteps, hn as readBaseConfig, ht as workflowInstances, i as workflowRegistry, it as createDatabase, k as RedisClient, mt as workflowDefinitions, o as buildStepNotifyPayload, pn as loadEnv, u as startHealthReporter } from "./src-
|
|
1
|
+
import { B as LUA_RELEASE_LOCK, J as PendingMessageScanner, Jt as buildStreamEvent, U as LUA_SCHEDULER_POLL, V as LUA_RENEW_LOCK, X as StreamProducer, Y as StreamConsumer, Yt as CONSUMER_GROUPS, _t as workflowWaiters, a as SuspendExecutionError, c as BaseWorker, en as STREAMS, et as createLogger, gt as workflowSteps, hn as readBaseConfig, ht as workflowInstances, i as workflowRegistry, it as createDatabase, k as RedisClient, mt as workflowDefinitions, o as buildStepNotifyPayload, pn as loadEnv, u as startHealthReporter } from "./src-CpUnBl_M.mjs";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import { and, eq } from "drizzle-orm";
|
|
4
4
|
//#region src/services/workflow/main.ts
|
|
@@ -389,4 +389,4 @@ async function stopWorkflowWorker() {
|
|
|
389
389
|
//#endregion
|
|
390
390
|
export { startWorkflowWorker, stopWorkflowWorker };
|
|
391
391
|
|
|
392
|
-
//# sourceMappingURL=main-
|
|
392
|
+
//# sourceMappingURL=main-BnIX5nfp.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main-BFre2-HQ.mjs","names":["sql"],"sources":["../src/services/workflow/main.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { loadEnv, readBaseConfig } from \"@/index.js\";\nimport { createLogger } from \"@/index.js\";\nimport { RedisClient, type Redis } from \"@/index.js\";\nimport {\n StreamConsumer,\n PendingMessageScanner,\n StreamProducer,\n type StreamMessage,\n} from \"@/index.js\";\nimport { BaseWorker } from \"@/index.js\";\nimport { STREAMS, CONSUMER_GROUPS, buildStreamEvent } from \"@/index.js\";\nimport { type StreamName } from \"@/contracts/streams.js\";\nimport { createDatabase } from \"@/db/index.js\";\nimport {\n workflowInstances,\n workflowSteps,\n workflowWaiters,\n workflowDefinitions,\n} from \"@/db/schema.js\";\nimport { eq, and } from \"drizzle-orm\";\nimport {\n workflowRegistry,\n SuspendExecutionError,\n buildStepNotifyPayload,\n type WorkflowContext,\n type WorkflowStepContext,\n} from \"@/workflows/index.js\";\nimport {\n type WorkerOptions,\n LUA_SCHEDULER_POLL,\n LUA_RELEASE_LOCK,\n LUA_RENEW_LOCK,\n} from \"@/shared/index.js\";\nimport { startHealthReporter } from \"@/workers/index.js\";\n\n/** How long a workflow instance lock is held before it self-expires. */\nconst WORKFLOW_LOCK_TTL_SECONDS = 60;\n/** Renew the lock well inside its TTL so long-running handlers keep it. */\nconst WORKFLOW_LOCK_RENEW_MS = (WORKFLOW_LOCK_TTL_SECONDS / 3) * 1000;\n/** How long a claimed workflow timer stays invisible to other pollers. */\nconst WORKFLOW_TIMER_VISIBILITY_MS = 60_000;\n\nloadEnv();\nconst config = readBaseConfig();\nlet logger: ReturnType<typeof createLogger>;\nlet redis: RedisClient;\nlet sql: any;\nlet db: any;\n\nlet consumer: StreamConsumer;\nlet pendingScanner: PendingMessageScanner;\nlet worker: BaseWorker;\nlet healthInterval: NodeJS.Timeout | null = null;\nlet pollInterval: NodeJS.Timeout | null = null;\nlet reaperInterval: NodeJS.Timeout | null = null;\n\nlet notificationProducer: StreamProducer;\nlet workflowProducer: StreamProducer;\n\nexport interface WorkflowWorkerOptions extends WorkerOptions {\n redis: Redis;\n db: any;\n workflowProducer: any;\n notificationProducer: any;\n}\n\nexport class WorkflowWorker extends BaseWorker {\n private readonly redisCli: Redis;\n private readonly dbConn: any;\n private readonly workflowProducer: any;\n private readonly notificationProducer: any;\n\n private eventBuffer: {\n producer: any;\n event: any;\n resolve: (result?: { messageId: string; notificationId: string }) => void;\n reject: (err: any) => void;\n }[] = [];\n private flushTimer: NodeJS.Timeout | null = null;\n\n constructor(options: WorkflowWorkerOptions) {\n super(options);\n this.redisCli = options.redis;\n this.dbConn = options.db;\n this.workflowProducer = options.workflowProducer;\n this.notificationProducer = options.notificationProducer;\n\n this.flushTimer = setInterval(() => void this.flushWorkerBuffers(), 100);\n }\n\n override async stop(): Promise<void> {\n if (this.flushTimer) {\n clearInterval(this.flushTimer);\n this.flushTimer = null;\n }\n await this.flushWorkerBuffers();\n await super.stop();\n }\n\n private async flushWorkerBuffers(): Promise<void> {\n if (this.eventBuffer.length === 0) return;\n\n const events = this.eventBuffer;\n this.eventBuffer = [];\n\n try {\n const byProducer = new Map<any, typeof events>();\n for (const item of events) {\n if (!byProducer.has(item.producer)) byProducer.set(item.producer, []);\n byProducer.get(item.producer)!.push(item);\n }\n\n for (const [producer, batch] of byProducer) {\n const { messageIds, eventIds } = await producer.publishBatch(batch.map((b) => b.event));\n for (let i = 0; i < batch.length; i++) {\n const mId = messageIds[i];\n const eId = eventIds[i];\n if (mId && eId) batch[i]!.resolve({ messageId: mId, notificationId: eId });\n }\n }\n } catch (err: any) {\n this.logger.error({ err }, \"failed to flush workflow worker buffer\");\n for (const e of events) e.reject(err);\n }\n }\n\n async process(message: StreamMessage): Promise<void> {\n const { event } = message;\n const publishPromises: Promise<void>[] = [];\n\n if (event.type !== \"workflow.triggered\" && event.type !== \"workflow.resumed\") {\n return;\n }\n\n const payload = event.payload as any;\n const name = payload.name;\n const instanceId = payload.instanceId;\n\n if (!name || !instanceId || !payload.projectId) {\n this.logger.warn(\"Missing name, instanceId, or projectId in workflow event\");\n return;\n }\n\n let handler = workflowRegistry.get(name);\n if (!handler) {\n // Fallback: check dynamic JSON workflows\n const defRows = await this.dbConn\n .select()\n .from(workflowDefinitions)\n .where(\n and(\n eq(workflowDefinitions.projectId, payload.projectId),\n eq(workflowDefinitions.name, name),\n ),\n )\n .limit(1);\n\n if (defRows.length === 0) {\n this.logger.warn(\n { name, projectId: payload.projectId },\n \"No handler or dynamic definition found for workflow\",\n );\n return;\n }\n\n const def = defRows[0];\n handler = async ({ step }) => {\n const steps = def.steps as any[];\n for (const stepDef of steps) {\n if (stepDef.action === \"notify\") {\n // A payload target wins; naming none inherits the instance user.\n await step.notify(stepDef.payload);\n } else if (stepDef.action === \"wait\") {\n await step.wait(stepDef.duration);\n } else if (stepDef.action === \"waitForEvent\") {\n await step.waitForEvent(stepDef.event, stepDef.options);\n } else {\n this.logger.warn(\n { action: (stepDef as any)?.action, name },\n \"unknown workflow step action\",\n );\n }\n }\n };\n }\n\n const lockKey = `lock:workflow:${instanceId}`;\n const lockToken = randomUUID();\n const acquired = await this.redisCli.set(\n lockKey,\n lockToken,\n \"EX\",\n WORKFLOW_LOCK_TTL_SECONDS,\n \"NX\",\n );\n if (!acquired) {\n this.logger.info({ instanceId }, \"Workflow is locked by another process, skipping\");\n return;\n }\n\n // Keep the lock alive while the handler runs; without this a handler that\n // outlives the TTL lets a second resume execute the same steps in parallel.\n const renewTimer = setInterval(() => {\n void this.redisCli\n .eval(LUA_RENEW_LOCK, 1, lockKey, lockToken, String(WORKFLOW_LOCK_TTL_SECONDS))\n .catch((err: unknown) => {\n this.logger.warn({ err, instanceId }, \"failed to renew workflow lock\");\n });\n }, WORKFLOW_LOCK_RENEW_MS);\n\n try {\n let instance = (\n await this.dbConn\n .select()\n .from(workflowInstances)\n .where(eq(workflowInstances.id, instanceId))\n .limit(1)\n )[0];\n if (!instance) {\n const rows = await this.dbConn\n .insert(workflowInstances)\n .values({\n id: instanceId,\n projectId: payload.projectId,\n name: name,\n status: \"pending\",\n input: payload.input || {},\n })\n .returning();\n instance = rows[0]!;\n }\n\n if (instance.status !== \"pending\") {\n this.logger.info({ instanceId }, \"Workflow is not pending, skipping\");\n return;\n }\n\n await this.dbConn\n .update(workflowInstances)\n .set({ status: \"running\" })\n .where(eq(workflowInstances.id, instanceId));\n\n // Load existing steps\n const existingSteps = await this.dbConn\n .select()\n .from(workflowSteps)\n .where(eq(workflowSteps.instanceId, instanceId));\n const stepOutputMap = new Map<string, any>();\n for (const s of existingSteps) {\n stepOutputMap.set(s.stepIndex, s.output);\n }\n\n let currentStepIndex = 0;\n\n const stepProxy: WorkflowStepContext = {\n notify: async (args) => {\n const stepId = String(currentStepIndex++);\n if (stepOutputMap.has(stepId)) return stepOutputMap.get(stepId);\n\n // The step payload is the same shape as notify(), but the wire event\n // is not — translate rather than spread.\n const requested = buildStepNotifyPayload(\n args,\n instance!.input,\n payload.projectId,\n `wf-${instanceId}-${stepId}`,\n );\n\n const result = await new Promise<{ messageId: string; notificationId: string }>(\n (resolve, reject) => {\n this.eventBuffer.push({\n producer: this.notificationProducer,\n event: buildStreamEvent(\n \"notification.requested\",\n requested as unknown as Record<string, unknown>,\n \"workflow\",\n event.metadata.traceId,\n ),\n resolve: resolve as any,\n reject,\n });\n },\n );\n\n const output = {\n success: true,\n messageId: result.messageId,\n notificationId: result.notificationId,\n };\n\n await this.dbConn.insert(workflowSteps).values({\n instanceId: instance!.id,\n projectId: payload.projectId,\n stepIndex: stepId,\n action: \"notify\",\n output,\n });\n\n return output;\n },\n wait: async (duration) => {\n const stepId = String(currentStepIndex++);\n if (stepOutputMap.has(stepId)) return;\n\n // Simple duration parse (e.g. '2h' -> ms)\n let ms = 0;\n if (duration.endsWith(\"d\")) ms = parseInt(duration) * 24 * 60 * 60 * 1000;\n else if (duration.endsWith(\"h\")) ms = parseInt(duration) * 60 * 60 * 1000;\n else if (duration.endsWith(\"m\")) ms = parseInt(duration) * 60 * 1000;\n else if (duration.endsWith(\"s\")) ms = parseInt(duration) * 1000;\n else throw new Error(`Invalid wait duration: ${duration}`);\n\n const resumeAt = Date.now() + ms;\n\n // Persist the wake-up signal before committing the suspended state.\n // If the process dies after this point the source event is retried;\n // if it dies after the database write, the timer is already durable.\n await this.redisCli.zadd(\n \"notif:workflow:timers\",\n resumeAt,\n JSON.stringify({\n instanceId: instance!.id,\n name: instance!.name,\n projectId: payload.projectId,\n input: instance!.input,\n }),\n );\n\n await this.dbConn.insert(workflowSteps).values({\n instanceId: instance!.id,\n projectId: payload.projectId,\n stepIndex: stepId,\n action: \"wait\",\n output: { scheduledAt: resumeAt },\n });\n\n throw new SuspendExecutionError(\"wait\", { duration });\n },\n waitForEvent: async (eventName, options) => {\n const stepId = String(currentStepIndex++);\n if (stepOutputMap.has(stepId)) {\n const out = stepOutputMap.get(stepId);\n if (out && typeof out === \"object\" && (out as any).timedOut === true) {\n return null;\n }\n return out;\n }\n\n options = options || {};\n options.timeout = options.timeout || \"24h\";\n options.match = options.match || {};\n\n let ms = 0;\n if (options.timeout.endsWith(\"d\")) ms = parseInt(options.timeout) * 24 * 60 * 60 * 1000;\n else if (options.timeout.endsWith(\"h\")) ms = parseInt(options.timeout) * 60 * 60 * 1000;\n else if (options.timeout.endsWith(\"m\")) ms = parseInt(options.timeout) * 60 * 1000;\n else if (options.timeout.endsWith(\"s\")) ms = parseInt(options.timeout) * 1000;\n else throw new Error(`Invalid waitForEvent timeout: ${options.timeout}`);\n\n const resumeAt = Date.now() + ms;\n\n await this.redisCli.zadd(\n \"notif:workflow:timers\",\n resumeAt,\n JSON.stringify({\n instanceId: instance!.id,\n name: instance!.name,\n projectId: payload.projectId,\n input: instance!.input,\n isEventTimeout: true,\n eventName,\n stepId,\n }),\n );\n\n // Register waiter\n await this.dbConn.insert(workflowWaiters).values({\n instanceId: instance!.id,\n projectId: payload.projectId,\n eventName: eventName,\n matchCriteria: options.match,\n expiresAt: new Date(resumeAt),\n });\n\n // Register step as pending event\n await this.dbConn.insert(workflowSteps).values({\n instanceId: instance!.id,\n projectId: payload.projectId,\n stepIndex: stepId,\n action: \"waitForEvent\",\n output: null, // this will be updated by event worker or timeout\n });\n\n throw new SuspendExecutionError(\"waitForEvent\", { eventName });\n },\n run: async (stepName, fn) => {\n const stepId = String(currentStepIndex++);\n if (stepOutputMap.has(stepId)) return stepOutputMap.get(stepId);\n\n const result = await fn();\n await this.dbConn.insert(workflowSteps).values({\n instanceId: instance!.id,\n projectId: payload.projectId,\n stepIndex: stepId,\n action: \"run\",\n output: result,\n });\n return result;\n },\n };\n\n const ctx: WorkflowContext = {\n step: stepProxy,\n event: (instance!.input as any) || { user: { id: \"unknown\" } },\n };\n\n try {\n await handler(ctx);\n // If we reach here, workflow completed\n await this.dbConn\n .update(workflowInstances)\n .set({ status: \"completed\" })\n .where(eq(workflowInstances.id, instance!.id));\n this.logger.info({ instanceId: instance!.id }, \"Workflow completed successfully\");\n } catch (err: any) {\n if (err instanceof SuspendExecutionError || err.name === \"SuspendExecutionError\") {\n await this.dbConn\n .update(workflowInstances)\n .set({ status: \"pending\" })\n .where(eq(workflowInstances.id, instance!.id));\n this.logger.info({ instanceId: instance!.id, reason: err.reason }, \"Workflow suspended\");\n } else {\n this.logger.error({ err, instanceId: instance!.id }, \"Workflow failed\");\n await this.dbConn\n .update(workflowInstances)\n .set({ status: \"failed\" })\n .where(eq(workflowInstances.id, instance!.id));\n }\n }\n } finally {\n clearInterval(renewTimer);\n // Compare-and-delete: never release a lock a later process re-acquired.\n await this.redisCli.eval(LUA_RELEASE_LOCK, 1, lockKey, lockToken);\n }\n\n await Promise.all(publishPromises);\n }\n}\n\nexport function __injectForTests(r: any, d: any, wp: any, np: any) {\n redis = r;\n db = d;\n workflowProducer = wp;\n notificationProducer = np;\n}\n\nexport async function startWorkflowWorker() {\n logger = createLogger({ name: \"workflow-worker\", level: config.LOG_LEVEL });\n redis = new RedisClient({ url: config.REDIS_URL, name: \"workflow\", logger });\n const dbData = createDatabase({ url: config.DATABASE_URL, applicationName: \"workflow\", logger });\n sql = dbData.sql;\n db = dbData.db;\n notificationProducer = new StreamProducer({\n redis: redis.native,\n stream: STREAMS.INBOUND_NORMAL,\n logger,\n });\n workflowProducer = new StreamProducer({\n redis: redis.native,\n stream: STREAMS.WORKFLOW_INBOUND,\n logger,\n });\n consumer = new StreamConsumer({\n redis: redis.native,\n stream: STREAMS.WORKFLOW_INBOUND as StreamName,\n group: CONSUMER_GROUPS.WORKFLOW as any,\n consumer: `workflow-${process.pid}`,\n dlqStream: STREAMS.DEAD_LETTER,\n batchSize: config.WORKER_CONCURRENCY,\n logger,\n });\n\n pendingScanner = new PendingMessageScanner({\n redis: redis.native,\n stream: STREAMS.WORKFLOW_INBOUND as StreamName,\n group: CONSUMER_GROUPS.WORKFLOW as any,\n consumer: `workflow-${process.pid}`,\n logger,\n });\n\n worker = new WorkflowWorker({\n consumer,\n pendingScanner,\n logger,\n concurrency: config.WORKER_CONCURRENCY,\n redis: redis.native,\n db,\n workflowProducer,\n notificationProducer,\n });\n\n // Polling loop for timers\n pollInterval = setInterval(() => {\n void (async () => {\n try {\n const now = Date.now();\n const tasks = (await redis.native.eval(\n LUA_SCHEDULER_POLL,\n 1,\n \"notif:workflow:timers\",\n now,\n 100,\n WORKFLOW_TIMER_VISIBILITY_MS,\n )) as string[];\n\n for (const taskStr of tasks) {\n const task = JSON.parse(taskStr);\n\n // Check if workflow is already completed/failed\n const inst = (\n await db\n .select()\n .from(workflowInstances)\n .where(eq(workflowInstances.id, task.instanceId))\n .limit(1)\n )[0];\n if (!inst || inst.status === \"completed\" || inst.status === \"failed\") {\n await redis.native.zrem(\"notif:workflow:timers\", taskStr);\n continue;\n }\n // A timer can be observed while the worker is still persisting the\n // corresponding suspension. Leave the claimed member in place; its\n // visibility timeout will make it eligible once the instance becomes\n // pending instead of losing the wake-up signal.\n if (inst.status === \"running\") continue;\n\n if (task.isEventTimeout) {\n // It's a timeout for waitForEvent. Clean up only this step's waiter\n const deleted = await db\n .delete(workflowWaiters)\n .where(\n and(\n eq(workflowWaiters.instanceId, task.instanceId),\n eq(workflowWaiters.eventName, task.eventName),\n ),\n )\n .returning();\n\n // If the waiter was already deleted (by EventWorker when event arrived before timeout),\n // this timer is stale. Clean up from Redis and skip re-resuming the workflow.\n if (deleted.length === 0) {\n await redis.native.zrem(\"notif:workflow:timers\", taskStr);\n continue;\n }\n\n // Record timedOut state on the pending waitForEvent step\n const steps = await db\n .select()\n .from(workflowSteps)\n .where(\n and(\n eq(workflowSteps.instanceId, task.instanceId),\n eq(workflowSteps.action, \"waitForEvent\"),\n ),\n );\n const pendingStep = steps.find((s: any) => s.output === null);\n if (pendingStep) {\n await db\n .update(workflowSteps)\n .set({ output: { timedOut: true } })\n .where(eq(workflowSteps.id, pendingStep.id));\n }\n }\n\n await workflowProducer.publish(\n buildStreamEvent(\"workflow.resumed\", task, \"scheduler\", undefined),\n );\n await redis.native.zrem(\"notif:workflow:timers\", taskStr);\n logger.info({ instanceId: task.instanceId }, \"Workflow resumed from timer\");\n }\n } catch (err) {\n logger.error({ err }, \"error in workflow polling loop\");\n }\n })();\n }, 5000);\n\n reaperInterval = setInterval(() => {\n void (async () => {\n try {\n const runningInstances = await db\n .select({ id: workflowInstances.id })\n .from(workflowInstances)\n .where(eq(workflowInstances.status, \"running\"));\n for (const inst of runningInstances) {\n const lockKey = `lock:workflow:${inst.id}`;\n const hasLock = await redis.native.exists(lockKey);\n if (!hasLock) {\n await db\n .update(workflowInstances)\n .set({ status: \"pending\" })\n .where(eq(workflowInstances.id, inst.id));\n logger.info({ instanceId: inst.id }, \"Reaped stuck workflow instance (lock expired)\");\n }\n }\n } catch (err) {\n logger.error({ err }, \"error in stuck workflow reaper\");\n }\n })();\n }, 60000);\n\n healthInterval = startHealthReporter(\"workflow\", worker, redis, logger);\n\n logger.info(\"workflow worker starting\");\n await worker.start();\n}\n\nexport async function stopWorkflowWorker(): Promise<void> {\n logger?.info(\"shutdown initiated\");\n if (healthInterval) clearInterval(healthInterval);\n if (pollInterval) clearInterval(pollInterval);\n if (reaperInterval) clearInterval(reaperInterval);\n if (worker) await worker.stop();\n if (sql) await sql.end();\n if (redis) await redis.disconnect();\n logger?.info(\"workflow worker stopped\");\n}\n"],"mappings":";;;;;AAqCA,MAAM,4BAA4B;;AAElC,MAAM,yBAA0B,4BAA4B,IAAK;;AAEjE,MAAM,+BAA+B;AAErC,QAAQ;AACR,MAAM,SAAS,eAAe;AAC9B,IAAI;AACJ,IAAI;AACJ,IAAIA;AACJ,IAAI;AAEJ,IAAI;AACJ,IAAI;AACJ,IAAI;AACJ,IAAI,iBAAwC;AAC5C,IAAI,eAAsC;AAC1C,IAAI,iBAAwC;AAE5C,IAAI;AACJ,IAAI;AASJ,IAAa,iBAAb,cAAoC,WAAW;CAC7C;CACA;CACA;CACA;CAEA,cAKM,CAAC;CACP,aAA4C;CAE5C,YAAY,SAAgC;EAC1C,MAAM,OAAO;EACb,KAAK,WAAW,QAAQ;EACxB,KAAK,SAAS,QAAQ;EACtB,KAAK,mBAAmB,QAAQ;EAChC,KAAK,uBAAuB,QAAQ;EAEpC,KAAK,aAAa,kBAAkB,KAAK,KAAK,mBAAmB,GAAG,GAAG;CACzE;CAEA,MAAe,OAAsB;EACnC,IAAI,KAAK,YAAY;GACnB,cAAc,KAAK,UAAU;GAC7B,KAAK,aAAa;EACpB;EACA,MAAM,KAAK,mBAAmB;EAC9B,MAAM,MAAM,KAAK;CACnB;CAEA,MAAc,qBAAoC;EAChD,IAAI,KAAK,YAAY,WAAW,GAAG;EAEnC,MAAM,SAAS,KAAK;EACpB,KAAK,cAAc,CAAC;EAEpB,IAAI;GACF,MAAM,6BAAa,IAAI,IAAwB;GAC/C,KAAK,MAAM,QAAQ,QAAQ;IACzB,IAAI,CAAC,WAAW,IAAI,KAAK,QAAQ,GAAG,WAAW,IAAI,KAAK,UAAU,CAAC,CAAC;IACpE,WAAW,IAAI,KAAK,QAAQ,CAAC,CAAE,KAAK,IAAI;GAC1C;GAEA,KAAK,MAAM,CAAC,UAAU,UAAU,YAAY;IAC1C,MAAM,EAAE,YAAY,aAAa,MAAM,SAAS,aAAa,MAAM,KAAK,MAAM,EAAE,KAAK,CAAC;IACtF,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;KACrC,MAAM,MAAM,WAAW;KACvB,MAAM,MAAM,SAAS;KACrB,IAAI,OAAO,KAAK,MAAM,EAAE,CAAE,QAAQ;MAAE,WAAW;MAAK,gBAAgB;KAAI,CAAC;IAC3E;GACF;EACF,SAAS,KAAU;GACjB,KAAK,OAAO,MAAM,EAAE,IAAI,GAAG,wCAAwC;GACnE,KAAK,MAAM,KAAK,QAAQ,EAAE,OAAO,GAAG;EACtC;CACF;CAEA,MAAM,QAAQ,SAAuC;EACnD,MAAM,EAAE,UAAU;EAClB,MAAM,kBAAmC,CAAC;EAE1C,IAAI,MAAM,SAAS,wBAAwB,MAAM,SAAS,oBACxD;EAGF,MAAM,UAAU,MAAM;EACtB,MAAM,OAAO,QAAQ;EACrB,MAAM,aAAa,QAAQ;EAE3B,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,QAAQ,WAAW;GAC9C,KAAK,OAAO,KAAK,0DAA0D;GAC3E;EACF;EAEA,IAAI,UAAU,iBAAiB,IAAI,IAAI;EACvC,IAAI,CAAC,SAAS;GAEZ,MAAM,UAAU,MAAM,KAAK,OACxB,OAAO,CAAC,CACR,KAAK,mBAAmB,CAAC,CACzB,MACC,IACE,GAAG,oBAAoB,WAAW,QAAQ,SAAS,GACnD,GAAG,oBAAoB,MAAM,IAAI,CACnC,CACF,CAAC,CACA,MAAM,CAAC;GAEV,IAAI,QAAQ,WAAW,GAAG;IACxB,KAAK,OAAO,KACV;KAAE;KAAM,WAAW,QAAQ;IAAU,GACrC,qDACF;IACA;GACF;GAEA,MAAM,MAAM,QAAQ;GACpB,UAAU,OAAO,EAAE,WAAW;IAC5B,MAAM,QAAQ,IAAI;IAClB,KAAK,MAAM,WAAW,OACpB,IAAI,QAAQ,WAAW,UAErB,MAAM,KAAK,OAAO,QAAQ,OAAO;SAC5B,IAAI,QAAQ,WAAW,QAC5B,MAAM,KAAK,KAAK,QAAQ,QAAQ;SAC3B,IAAI,QAAQ,WAAW,gBAC5B,MAAM,KAAK,aAAa,QAAQ,OAAO,QAAQ,OAAO;SAEtD,KAAK,OAAO,KACV;KAAE,QAAS,SAAiB;KAAQ;IAAK,GACzC,8BACF;GAGN;EACF;EAEA,MAAM,UAAU,iBAAiB;EACjC,MAAM,YAAY,WAAW;EAQ7B,IAAI,CAAC,MAPkB,KAAK,SAAS,IACnC,SACA,WACA,MACA,2BACA,IACF,GACe;GACb,KAAK,OAAO,KAAK,EAAE,WAAW,GAAG,iDAAiD;GAClF;EACF;EAIA,MAAM,aAAa,kBAAkB;GACnC,KAAU,SACP,KAAK,gBAAgB,GAAG,SAAS,WAAW,OAAO,yBAAyB,CAAC,CAAC,CAC9E,OAAO,QAAiB;IACvB,KAAK,OAAO,KAAK;KAAE;KAAK;IAAW,GAAG,+BAA+B;GACvE,CAAC;EACL,GAAG,sBAAsB;EAEzB,IAAI;GACF,IAAI,YACF,MAAM,KAAK,OACR,OAAO,CAAC,CACR,KAAK,iBAAiB,CAAC,CACvB,MAAM,GAAG,kBAAkB,IAAI,UAAU,CAAC,CAAC,CAC3C,MAAM,CAAC,EAAA,CACV;GACF,IAAI,CAAC,UAWH,YAAW,MAVQ,KAAK,OACrB,OAAO,iBAAiB,CAAC,CACzB,OAAO;IACN,IAAI;IACJ,WAAW,QAAQ;IACb;IACN,QAAQ;IACR,OAAO,QAAQ,SAAS,CAAC;GAC3B,CAAC,CAAC,CACD,UAAU,EAAA,CACG;GAGlB,IAAI,SAAS,WAAW,WAAW;IACjC,KAAK,OAAO,KAAK,EAAE,WAAW,GAAG,mCAAmC;IACpE;GACF;GAEA,MAAM,KAAK,OACR,OAAO,iBAAiB,CAAC,CACzB,IAAI,EAAE,QAAQ,UAAU,CAAC,CAAC,CAC1B,MAAM,GAAG,kBAAkB,IAAI,UAAU,CAAC;GAG7C,MAAM,gBAAgB,MAAM,KAAK,OAC9B,OAAO,CAAC,CACR,KAAK,aAAa,CAAC,CACnB,MAAM,GAAG,cAAc,YAAY,UAAU,CAAC;GACjD,MAAM,gCAAgB,IAAI,IAAiB;GAC3C,KAAK,MAAM,KAAK,eACd,cAAc,IAAI,EAAE,WAAW,EAAE,MAAM;GAGzC,IAAI,mBAAmB;GA+JvB,MAAM,MAAuB;IAC3B,MAAM;KA7JN,QAAQ,OAAO,SAAS;MACtB,MAAM,SAAS,OAAO,kBAAkB;MACxC,IAAI,cAAc,IAAI,MAAM,GAAG,OAAO,cAAc,IAAI,MAAM;MAI9D,MAAM,YAAY,uBAChB,MACA,SAAU,OACV,QAAQ,WACR,MAAM,WAAW,GAAG,QACtB;MAEA,MAAM,SAAS,MAAM,IAAI,SACtB,SAAS,WAAW;OACnB,KAAK,YAAY,KAAK;QACpB,UAAU,KAAK;QACf,OAAO,iBACL,0BACA,WACA,YACA,MAAM,SAAS,OACjB;QACS;QACT;OACF,CAAC;MACH,CACF;MAEA,MAAM,SAAS;OACb,SAAS;OACT,WAAW,OAAO;OAClB,gBAAgB,OAAO;MACzB;MAEA,MAAM,KAAK,OAAO,OAAO,aAAa,CAAC,CAAC,OAAO;OAC7C,YAAY,SAAU;OACtB,WAAW,QAAQ;OACnB,WAAW;OACX,QAAQ;OACR;MACF,CAAC;MAED,OAAO;KACT;KACA,MAAM,OAAO,aAAa;MACxB,MAAM,SAAS,OAAO,kBAAkB;MACxC,IAAI,cAAc,IAAI,MAAM,GAAG;MAG/B,IAAI,KAAK;MACT,IAAI,SAAS,SAAS,GAAG,GAAG,KAAK,SAAS,QAAQ,IAAI,KAAK,KAAK,KAAK;WAChE,IAAI,SAAS,SAAS,GAAG,GAAG,KAAK,SAAS,QAAQ,IAAI,KAAK,KAAK;WAChE,IAAI,SAAS,SAAS,GAAG,GAAG,KAAK,SAAS,QAAQ,IAAI,KAAK;WAC3D,IAAI,SAAS,SAAS,GAAG,GAAG,KAAK,SAAS,QAAQ,IAAI;WACtD,MAAM,IAAI,MAAM,0BAA0B,UAAU;MAEzD,MAAM,WAAW,KAAK,IAAI,IAAI;MAK9B,MAAM,KAAK,SAAS,KAClB,yBACA,UACA,KAAK,UAAU;OACb,YAAY,SAAU;OACtB,MAAM,SAAU;OAChB,WAAW,QAAQ;OACnB,OAAO,SAAU;MACnB,CAAC,CACH;MAEA,MAAM,KAAK,OAAO,OAAO,aAAa,CAAC,CAAC,OAAO;OAC7C,YAAY,SAAU;OACtB,WAAW,QAAQ;OACnB,WAAW;OACX,QAAQ;OACR,QAAQ,EAAE,aAAa,SAAS;MAClC,CAAC;MAED,MAAM,IAAI,sBAAsB,QAAQ,EAAE,SAAS,CAAC;KACtD;KACA,cAAc,OAAO,WAAW,YAAY;MAC1C,MAAM,SAAS,OAAO,kBAAkB;MACxC,IAAI,cAAc,IAAI,MAAM,GAAG;OAC7B,MAAM,MAAM,cAAc,IAAI,MAAM;OACpC,IAAI,OAAO,OAAO,QAAQ,YAAa,IAAY,aAAa,MAC9D,OAAO;OAET,OAAO;MACT;MAEA,UAAU,WAAW,CAAC;MACtB,QAAQ,UAAU,QAAQ,WAAW;MACrC,QAAQ,QAAQ,QAAQ,SAAS,CAAC;MAElC,IAAI,KAAK;MACT,IAAI,QAAQ,QAAQ,SAAS,GAAG,GAAG,KAAK,SAAS,QAAQ,OAAO,IAAI,KAAK,KAAK,KAAK;WAC9E,IAAI,QAAQ,QAAQ,SAAS,GAAG,GAAG,KAAK,SAAS,QAAQ,OAAO,IAAI,KAAK,KAAK;WAC9E,IAAI,QAAQ,QAAQ,SAAS,GAAG,GAAG,KAAK,SAAS,QAAQ,OAAO,IAAI,KAAK;WACzE,IAAI,QAAQ,QAAQ,SAAS,GAAG,GAAG,KAAK,SAAS,QAAQ,OAAO,IAAI;WACpE,MAAM,IAAI,MAAM,iCAAiC,QAAQ,SAAS;MAEvE,MAAM,WAAW,KAAK,IAAI,IAAI;MAE9B,MAAM,KAAK,SAAS,KAClB,yBACA,UACA,KAAK,UAAU;OACb,YAAY,SAAU;OACtB,MAAM,SAAU;OAChB,WAAW,QAAQ;OACnB,OAAO,SAAU;OACjB,gBAAgB;OAChB;OACA;MACF,CAAC,CACH;MAGA,MAAM,KAAK,OAAO,OAAO,eAAe,CAAC,CAAC,OAAO;OAC/C,YAAY,SAAU;OACtB,WAAW,QAAQ;OACR;OACX,eAAe,QAAQ;OACvB,WAAW,IAAI,KAAK,QAAQ;MAC9B,CAAC;MAGD,MAAM,KAAK,OAAO,OAAO,aAAa,CAAC,CAAC,OAAO;OAC7C,YAAY,SAAU;OACtB,WAAW,QAAQ;OACnB,WAAW;OACX,QAAQ;OACR,QAAQ;MACV,CAAC;MAED,MAAM,IAAI,sBAAsB,gBAAgB,EAAE,UAAU,CAAC;KAC/D;KACA,KAAK,OAAO,UAAU,OAAO;MAC3B,MAAM,SAAS,OAAO,kBAAkB;MACxC,IAAI,cAAc,IAAI,MAAM,GAAG,OAAO,cAAc,IAAI,MAAM;MAE9D,MAAM,SAAS,MAAM,GAAG;MACxB,MAAM,KAAK,OAAO,OAAO,aAAa,CAAC,CAAC,OAAO;OAC7C,YAAY,SAAU;OACtB,WAAW,QAAQ;OACnB,WAAW;OACX,QAAQ;OACR,QAAQ;MACV,CAAC;MACD,OAAO;KACT;IAIc;IACd,OAAQ,SAAU,SAAiB,EAAE,MAAM,EAAE,IAAI,UAAU,EAAE;GAC/D;GAEA,IAAI;IACF,MAAM,QAAQ,GAAG;IAEjB,MAAM,KAAK,OACR,OAAO,iBAAiB,CAAC,CACzB,IAAI,EAAE,QAAQ,YAAY,CAAC,CAAC,CAC5B,MAAM,GAAG,kBAAkB,IAAI,SAAU,EAAE,CAAC;IAC/C,KAAK,OAAO,KAAK,EAAE,YAAY,SAAU,GAAG,GAAG,iCAAiC;GAClF,SAAS,KAAU;IACjB,IAAI,eAAe,yBAAyB,IAAI,SAAS,yBAAyB;KAChF,MAAM,KAAK,OACR,OAAO,iBAAiB,CAAC,CACzB,IAAI,EAAE,QAAQ,UAAU,CAAC,CAAC,CAC1B,MAAM,GAAG,kBAAkB,IAAI,SAAU,EAAE,CAAC;KAC/C,KAAK,OAAO,KAAK;MAAE,YAAY,SAAU;MAAI,QAAQ,IAAI;KAAO,GAAG,oBAAoB;IACzF,OAAO;KACL,KAAK,OAAO,MAAM;MAAE;MAAK,YAAY,SAAU;KAAG,GAAG,iBAAiB;KACtE,MAAM,KAAK,OACR,OAAO,iBAAiB,CAAC,CACzB,IAAI,EAAE,QAAQ,SAAS,CAAC,CAAC,CACzB,MAAM,GAAG,kBAAkB,IAAI,SAAU,EAAE,CAAC;IACjD;GACF;EACF,UAAU;GACR,cAAc,UAAU;GAExB,MAAM,KAAK,SAAS,KAAK,kBAAkB,GAAG,SAAS,SAAS;EAClE;EAEA,MAAM,QAAQ,IAAI,eAAe;CACnC;AACF;AASA,eAAsB,sBAAsB;CAC1C,SAAS,aAAa;EAAE,MAAM;EAAmB,OAAO,OAAO;CAAU,CAAC;CAC1E,QAAQ,IAAI,YAAY;EAAE,KAAK,OAAO;EAAW,MAAM;EAAY;CAAO,CAAC;CAC3E,MAAM,SAAS,eAAe;EAAE,KAAK,OAAO;EAAc,iBAAiB;EAAY;CAAO,CAAC;CAC/F,QAAM,OAAO;CACb,KAAK,OAAO;CACZ,uBAAuB,IAAI,eAAe;EACxC,OAAO,MAAM;EACb,QAAQ,QAAQ;EAChB;CACF,CAAC;CACD,mBAAmB,IAAI,eAAe;EACpC,OAAO,MAAM;EACb,QAAQ,QAAQ;EAChB;CACF,CAAC;CACD,WAAW,IAAI,eAAe;EAC5B,OAAO,MAAM;EACb,QAAQ,QAAQ;EAChB,OAAO,gBAAgB;EACvB,UAAU,YAAY,QAAQ;EAC9B,WAAW,QAAQ;EACnB,WAAW,OAAO;EAClB;CACF,CAAC;CAED,iBAAiB,IAAI,sBAAsB;EACzC,OAAO,MAAM;EACb,QAAQ,QAAQ;EAChB,OAAO,gBAAgB;EACvB,UAAU,YAAY,QAAQ;EAC9B;CACF,CAAC;CAED,SAAS,IAAI,eAAe;EAC1B;EACA;EACA;EACA,aAAa,OAAO;EACpB,OAAO,MAAM;EACb;EACA;EACA;CACF,CAAC;CAGD,eAAe,kBAAkB;EAC/B,CAAM,YAAY;GAChB,IAAI;IACF,MAAM,MAAM,KAAK,IAAI;IACrB,MAAM,QAAS,MAAM,MAAM,OAAO,KAChC,oBACA,GACA,yBACA,KACA,KACA,4BACF;IAEA,KAAK,MAAM,WAAW,OAAO;KAC3B,MAAM,OAAO,KAAK,MAAM,OAAO;KAG/B,MAAM,QACJ,MAAM,GACH,OAAO,CAAC,CACR,KAAK,iBAAiB,CAAC,CACvB,MAAM,GAAG,kBAAkB,IAAI,KAAK,UAAU,CAAC,CAAC,CAChD,MAAM,CAAC,EAAA,CACV;KACF,IAAI,CAAC,QAAQ,KAAK,WAAW,eAAe,KAAK,WAAW,UAAU;MACpE,MAAM,MAAM,OAAO,KAAK,yBAAyB,OAAO;MACxD;KACF;KAKA,IAAI,KAAK,WAAW,WAAW;KAE/B,IAAI,KAAK,gBAAgB;MAcvB,KAAI,MAZkB,GACnB,OAAO,eAAe,CAAC,CACvB,MACC,IACE,GAAG,gBAAgB,YAAY,KAAK,UAAU,GAC9C,GAAG,gBAAgB,WAAW,KAAK,SAAS,CAC9C,CACF,CAAC,CACA,UAAU,EAAA,CAID,WAAW,GAAG;OACxB,MAAM,MAAM,OAAO,KAAK,yBAAyB,OAAO;OACxD;MACF;MAYA,MAAM,eAAc,MATA,GACjB,OAAO,CAAC,CACR,KAAK,aAAa,CAAC,CACnB,MACC,IACE,GAAG,cAAc,YAAY,KAAK,UAAU,GAC5C,GAAG,cAAc,QAAQ,cAAc,CACzC,CACF,EAAA,CACwB,MAAM,MAAW,EAAE,WAAW,IAAI;MAC5D,IAAI,aACF,MAAM,GACH,OAAO,aAAa,CAAC,CACrB,IAAI,EAAE,QAAQ,EAAE,UAAU,KAAK,EAAE,CAAC,CAAC,CACnC,MAAM,GAAG,cAAc,IAAI,YAAY,EAAE,CAAC;KAEjD;KAEA,MAAM,iBAAiB,QACrB,iBAAiB,oBAAoB,MAAM,aAAa,KAAA,CAAS,CACnE;KACA,MAAM,MAAM,OAAO,KAAK,yBAAyB,OAAO;KACxD,OAAO,KAAK,EAAE,YAAY,KAAK,WAAW,GAAG,6BAA6B;IAC5E;GACF,SAAS,KAAK;IACZ,OAAO,MAAM,EAAE,IAAI,GAAG,gCAAgC;GACxD;EACF,EAAA,CAAG;CACL,GAAG,GAAI;CAEP,iBAAiB,kBAAkB;EACjC,CAAM,YAAY;GAChB,IAAI;IACF,MAAM,mBAAmB,MAAM,GAC5B,OAAO,EAAE,IAAI,kBAAkB,GAAG,CAAC,CAAC,CACpC,KAAK,iBAAiB,CAAC,CACvB,MAAM,GAAG,kBAAkB,QAAQ,SAAS,CAAC;IAChD,KAAK,MAAM,QAAQ,kBAAkB;KACnC,MAAM,UAAU,iBAAiB,KAAK;KAEtC,IAAI,CAAC,MADiB,MAAM,OAAO,OAAO,OAAO,GACnC;MACZ,MAAM,GACH,OAAO,iBAAiB,CAAC,CACzB,IAAI,EAAE,QAAQ,UAAU,CAAC,CAAC,CAC1B,MAAM,GAAG,kBAAkB,IAAI,KAAK,EAAE,CAAC;MAC1C,OAAO,KAAK,EAAE,YAAY,KAAK,GAAG,GAAG,+CAA+C;KACtF;IACF;GACF,SAAS,KAAK;IACZ,OAAO,MAAM,EAAE,IAAI,GAAG,gCAAgC;GACxD;EACF,EAAA,CAAG;CACL,GAAG,GAAK;CAER,iBAAiB,oBAAoB,YAAY,QAAQ,OAAO,MAAM;CAEtE,OAAO,KAAK,0BAA0B;CACtC,MAAM,OAAO,MAAM;AACrB;AAEA,eAAsB,qBAAoC;CACxD,QAAQ,KAAK,oBAAoB;CACjC,IAAI,gBAAgB,cAAc,cAAc;CAChD,IAAI,cAAc,cAAc,YAAY;CAC5C,IAAI,gBAAgB,cAAc,cAAc;CAChD,IAAI,QAAQ,MAAM,OAAO,KAAK;CAC9B,IAAIA,OAAK,MAAMA,MAAI,IAAI;CACvB,IAAI,OAAO,MAAM,MAAM,WAAW;CAClC,QAAQ,KAAK,yBAAyB;AACxC"}
|
|
1
|
+
{"version":3,"file":"main-BnIX5nfp.mjs","names":["sql"],"sources":["../src/services/workflow/main.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { loadEnv, readBaseConfig } from \"@/index.js\";\nimport { createLogger } from \"@/index.js\";\nimport { RedisClient, type Redis } from \"@/index.js\";\nimport {\n StreamConsumer,\n PendingMessageScanner,\n StreamProducer,\n type StreamMessage,\n} from \"@/index.js\";\nimport { BaseWorker } from \"@/index.js\";\nimport { STREAMS, CONSUMER_GROUPS, buildStreamEvent } from \"@/index.js\";\nimport { type StreamName } from \"@/contracts/streams.js\";\nimport { createDatabase } from \"@/db/index.js\";\nimport {\n workflowInstances,\n workflowSteps,\n workflowWaiters,\n workflowDefinitions,\n} from \"@/db/schema.js\";\nimport { eq, and } from \"drizzle-orm\";\nimport {\n workflowRegistry,\n SuspendExecutionError,\n buildStepNotifyPayload,\n type WorkflowContext,\n type WorkflowStepContext,\n} from \"@/workflows/index.js\";\nimport {\n type WorkerOptions,\n LUA_SCHEDULER_POLL,\n LUA_RELEASE_LOCK,\n LUA_RENEW_LOCK,\n} from \"@/shared/index.js\";\nimport { startHealthReporter } from \"@/workers/index.js\";\n\n/** How long a workflow instance lock is held before it self-expires. */\nconst WORKFLOW_LOCK_TTL_SECONDS = 60;\n/** Renew the lock well inside its TTL so long-running handlers keep it. */\nconst WORKFLOW_LOCK_RENEW_MS = (WORKFLOW_LOCK_TTL_SECONDS / 3) * 1000;\n/** How long a claimed workflow timer stays invisible to other pollers. */\nconst WORKFLOW_TIMER_VISIBILITY_MS = 60_000;\n\nloadEnv();\nconst config = readBaseConfig();\nlet logger: ReturnType<typeof createLogger>;\nlet redis: RedisClient;\nlet sql: any;\nlet db: any;\n\nlet consumer: StreamConsumer;\nlet pendingScanner: PendingMessageScanner;\nlet worker: BaseWorker;\nlet healthInterval: NodeJS.Timeout | null = null;\nlet pollInterval: NodeJS.Timeout | null = null;\nlet reaperInterval: NodeJS.Timeout | null = null;\n\nlet notificationProducer: StreamProducer;\nlet workflowProducer: StreamProducer;\n\nexport interface WorkflowWorkerOptions extends WorkerOptions {\n redis: Redis;\n db: any;\n workflowProducer: any;\n notificationProducer: any;\n}\n\nexport class WorkflowWorker extends BaseWorker {\n private readonly redisCli: Redis;\n private readonly dbConn: any;\n private readonly workflowProducer: any;\n private readonly notificationProducer: any;\n\n private eventBuffer: {\n producer: any;\n event: any;\n resolve: (result?: { messageId: string; notificationId: string }) => void;\n reject: (err: any) => void;\n }[] = [];\n private flushTimer: NodeJS.Timeout | null = null;\n\n constructor(options: WorkflowWorkerOptions) {\n super(options);\n this.redisCli = options.redis;\n this.dbConn = options.db;\n this.workflowProducer = options.workflowProducer;\n this.notificationProducer = options.notificationProducer;\n\n this.flushTimer = setInterval(() => void this.flushWorkerBuffers(), 100);\n }\n\n override async stop(): Promise<void> {\n if (this.flushTimer) {\n clearInterval(this.flushTimer);\n this.flushTimer = null;\n }\n await this.flushWorkerBuffers();\n await super.stop();\n }\n\n private async flushWorkerBuffers(): Promise<void> {\n if (this.eventBuffer.length === 0) return;\n\n const events = this.eventBuffer;\n this.eventBuffer = [];\n\n try {\n const byProducer = new Map<any, typeof events>();\n for (const item of events) {\n if (!byProducer.has(item.producer)) byProducer.set(item.producer, []);\n byProducer.get(item.producer)!.push(item);\n }\n\n for (const [producer, batch] of byProducer) {\n const { messageIds, eventIds } = await producer.publishBatch(batch.map((b) => b.event));\n for (let i = 0; i < batch.length; i++) {\n const mId = messageIds[i];\n const eId = eventIds[i];\n if (mId && eId) batch[i]!.resolve({ messageId: mId, notificationId: eId });\n }\n }\n } catch (err: any) {\n this.logger.error({ err }, \"failed to flush workflow worker buffer\");\n for (const e of events) e.reject(err);\n }\n }\n\n async process(message: StreamMessage): Promise<void> {\n const { event } = message;\n const publishPromises: Promise<void>[] = [];\n\n if (event.type !== \"workflow.triggered\" && event.type !== \"workflow.resumed\") {\n return;\n }\n\n const payload = event.payload as any;\n const name = payload.name;\n const instanceId = payload.instanceId;\n\n if (!name || !instanceId || !payload.projectId) {\n this.logger.warn(\"Missing name, instanceId, or projectId in workflow event\");\n return;\n }\n\n let handler = workflowRegistry.get(name);\n if (!handler) {\n // Fallback: check dynamic JSON workflows\n const defRows = await this.dbConn\n .select()\n .from(workflowDefinitions)\n .where(\n and(\n eq(workflowDefinitions.projectId, payload.projectId),\n eq(workflowDefinitions.name, name),\n ),\n )\n .limit(1);\n\n if (defRows.length === 0) {\n this.logger.warn(\n { name, projectId: payload.projectId },\n \"No handler or dynamic definition found for workflow\",\n );\n return;\n }\n\n const def = defRows[0];\n handler = async ({ step }) => {\n const steps = def.steps as any[];\n for (const stepDef of steps) {\n if (stepDef.action === \"notify\") {\n // A payload target wins; naming none inherits the instance user.\n await step.notify(stepDef.payload);\n } else if (stepDef.action === \"wait\") {\n await step.wait(stepDef.duration);\n } else if (stepDef.action === \"waitForEvent\") {\n await step.waitForEvent(stepDef.event, stepDef.options);\n } else {\n this.logger.warn(\n { action: (stepDef as any)?.action, name },\n \"unknown workflow step action\",\n );\n }\n }\n };\n }\n\n const lockKey = `lock:workflow:${instanceId}`;\n const lockToken = randomUUID();\n const acquired = await this.redisCli.set(\n lockKey,\n lockToken,\n \"EX\",\n WORKFLOW_LOCK_TTL_SECONDS,\n \"NX\",\n );\n if (!acquired) {\n this.logger.info({ instanceId }, \"Workflow is locked by another process, skipping\");\n return;\n }\n\n // Keep the lock alive while the handler runs; without this a handler that\n // outlives the TTL lets a second resume execute the same steps in parallel.\n const renewTimer = setInterval(() => {\n void this.redisCli\n .eval(LUA_RENEW_LOCK, 1, lockKey, lockToken, String(WORKFLOW_LOCK_TTL_SECONDS))\n .catch((err: unknown) => {\n this.logger.warn({ err, instanceId }, \"failed to renew workflow lock\");\n });\n }, WORKFLOW_LOCK_RENEW_MS);\n\n try {\n let instance = (\n await this.dbConn\n .select()\n .from(workflowInstances)\n .where(eq(workflowInstances.id, instanceId))\n .limit(1)\n )[0];\n if (!instance) {\n const rows = await this.dbConn\n .insert(workflowInstances)\n .values({\n id: instanceId,\n projectId: payload.projectId,\n name: name,\n status: \"pending\",\n input: payload.input || {},\n })\n .returning();\n instance = rows[0]!;\n }\n\n if (instance.status !== \"pending\") {\n this.logger.info({ instanceId }, \"Workflow is not pending, skipping\");\n return;\n }\n\n await this.dbConn\n .update(workflowInstances)\n .set({ status: \"running\" })\n .where(eq(workflowInstances.id, instanceId));\n\n // Load existing steps\n const existingSteps = await this.dbConn\n .select()\n .from(workflowSteps)\n .where(eq(workflowSteps.instanceId, instanceId));\n const stepOutputMap = new Map<string, any>();\n for (const s of existingSteps) {\n stepOutputMap.set(s.stepIndex, s.output);\n }\n\n let currentStepIndex = 0;\n\n const stepProxy: WorkflowStepContext = {\n notify: async (args) => {\n const stepId = String(currentStepIndex++);\n if (stepOutputMap.has(stepId)) return stepOutputMap.get(stepId);\n\n // The step payload is the same shape as notify(), but the wire event\n // is not — translate rather than spread.\n const requested = buildStepNotifyPayload(\n args,\n instance!.input,\n payload.projectId,\n `wf-${instanceId}-${stepId}`,\n );\n\n const result = await new Promise<{ messageId: string; notificationId: string }>(\n (resolve, reject) => {\n this.eventBuffer.push({\n producer: this.notificationProducer,\n event: buildStreamEvent(\n \"notification.requested\",\n requested as unknown as Record<string, unknown>,\n \"workflow\",\n event.metadata.traceId,\n ),\n resolve: resolve as any,\n reject,\n });\n },\n );\n\n const output = {\n success: true,\n messageId: result.messageId,\n notificationId: result.notificationId,\n };\n\n await this.dbConn.insert(workflowSteps).values({\n instanceId: instance!.id,\n projectId: payload.projectId,\n stepIndex: stepId,\n action: \"notify\",\n output,\n });\n\n return output;\n },\n wait: async (duration) => {\n const stepId = String(currentStepIndex++);\n if (stepOutputMap.has(stepId)) return;\n\n // Simple duration parse (e.g. '2h' -> ms)\n let ms = 0;\n if (duration.endsWith(\"d\")) ms = parseInt(duration) * 24 * 60 * 60 * 1000;\n else if (duration.endsWith(\"h\")) ms = parseInt(duration) * 60 * 60 * 1000;\n else if (duration.endsWith(\"m\")) ms = parseInt(duration) * 60 * 1000;\n else if (duration.endsWith(\"s\")) ms = parseInt(duration) * 1000;\n else throw new Error(`Invalid wait duration: ${duration}`);\n\n const resumeAt = Date.now() + ms;\n\n // Persist the wake-up signal before committing the suspended state.\n // If the process dies after this point the source event is retried;\n // if it dies after the database write, the timer is already durable.\n await this.redisCli.zadd(\n \"notif:workflow:timers\",\n resumeAt,\n JSON.stringify({\n instanceId: instance!.id,\n name: instance!.name,\n projectId: payload.projectId,\n input: instance!.input,\n }),\n );\n\n await this.dbConn.insert(workflowSteps).values({\n instanceId: instance!.id,\n projectId: payload.projectId,\n stepIndex: stepId,\n action: \"wait\",\n output: { scheduledAt: resumeAt },\n });\n\n throw new SuspendExecutionError(\"wait\", { duration });\n },\n waitForEvent: async (eventName, options) => {\n const stepId = String(currentStepIndex++);\n if (stepOutputMap.has(stepId)) {\n const out = stepOutputMap.get(stepId);\n if (out && typeof out === \"object\" && (out as any).timedOut === true) {\n return null;\n }\n return out;\n }\n\n options = options || {};\n options.timeout = options.timeout || \"24h\";\n options.match = options.match || {};\n\n let ms = 0;\n if (options.timeout.endsWith(\"d\")) ms = parseInt(options.timeout) * 24 * 60 * 60 * 1000;\n else if (options.timeout.endsWith(\"h\")) ms = parseInt(options.timeout) * 60 * 60 * 1000;\n else if (options.timeout.endsWith(\"m\")) ms = parseInt(options.timeout) * 60 * 1000;\n else if (options.timeout.endsWith(\"s\")) ms = parseInt(options.timeout) * 1000;\n else throw new Error(`Invalid waitForEvent timeout: ${options.timeout}`);\n\n const resumeAt = Date.now() + ms;\n\n await this.redisCli.zadd(\n \"notif:workflow:timers\",\n resumeAt,\n JSON.stringify({\n instanceId: instance!.id,\n name: instance!.name,\n projectId: payload.projectId,\n input: instance!.input,\n isEventTimeout: true,\n eventName,\n stepId,\n }),\n );\n\n // Register waiter\n await this.dbConn.insert(workflowWaiters).values({\n instanceId: instance!.id,\n projectId: payload.projectId,\n eventName: eventName,\n matchCriteria: options.match,\n expiresAt: new Date(resumeAt),\n });\n\n // Register step as pending event\n await this.dbConn.insert(workflowSteps).values({\n instanceId: instance!.id,\n projectId: payload.projectId,\n stepIndex: stepId,\n action: \"waitForEvent\",\n output: null, // this will be updated by event worker or timeout\n });\n\n throw new SuspendExecutionError(\"waitForEvent\", { eventName });\n },\n run: async (stepName, fn) => {\n const stepId = String(currentStepIndex++);\n if (stepOutputMap.has(stepId)) return stepOutputMap.get(stepId);\n\n const result = await fn();\n await this.dbConn.insert(workflowSteps).values({\n instanceId: instance!.id,\n projectId: payload.projectId,\n stepIndex: stepId,\n action: \"run\",\n output: result,\n });\n return result;\n },\n };\n\n const ctx: WorkflowContext = {\n step: stepProxy,\n event: (instance!.input as any) || { user: { id: \"unknown\" } },\n };\n\n try {\n await handler(ctx);\n // If we reach here, workflow completed\n await this.dbConn\n .update(workflowInstances)\n .set({ status: \"completed\" })\n .where(eq(workflowInstances.id, instance!.id));\n this.logger.info({ instanceId: instance!.id }, \"Workflow completed successfully\");\n } catch (err: any) {\n if (err instanceof SuspendExecutionError || err.name === \"SuspendExecutionError\") {\n await this.dbConn\n .update(workflowInstances)\n .set({ status: \"pending\" })\n .where(eq(workflowInstances.id, instance!.id));\n this.logger.info({ instanceId: instance!.id, reason: err.reason }, \"Workflow suspended\");\n } else {\n this.logger.error({ err, instanceId: instance!.id }, \"Workflow failed\");\n await this.dbConn\n .update(workflowInstances)\n .set({ status: \"failed\" })\n .where(eq(workflowInstances.id, instance!.id));\n }\n }\n } finally {\n clearInterval(renewTimer);\n // Compare-and-delete: never release a lock a later process re-acquired.\n await this.redisCli.eval(LUA_RELEASE_LOCK, 1, lockKey, lockToken);\n }\n\n await Promise.all(publishPromises);\n }\n}\n\nexport function __injectForTests(r: any, d: any, wp: any, np: any) {\n redis = r;\n db = d;\n workflowProducer = wp;\n notificationProducer = np;\n}\n\nexport async function startWorkflowWorker() {\n logger = createLogger({ name: \"workflow-worker\", level: config.LOG_LEVEL });\n redis = new RedisClient({ url: config.REDIS_URL, name: \"workflow\", logger });\n const dbData = createDatabase({ url: config.DATABASE_URL, applicationName: \"workflow\", logger });\n sql = dbData.sql;\n db = dbData.db;\n notificationProducer = new StreamProducer({\n redis: redis.native,\n stream: STREAMS.INBOUND_NORMAL,\n logger,\n });\n workflowProducer = new StreamProducer({\n redis: redis.native,\n stream: STREAMS.WORKFLOW_INBOUND,\n logger,\n });\n consumer = new StreamConsumer({\n redis: redis.native,\n stream: STREAMS.WORKFLOW_INBOUND as StreamName,\n group: CONSUMER_GROUPS.WORKFLOW as any,\n consumer: `workflow-${process.pid}`,\n dlqStream: STREAMS.DEAD_LETTER,\n batchSize: config.WORKER_CONCURRENCY,\n logger,\n });\n\n pendingScanner = new PendingMessageScanner({\n redis: redis.native,\n stream: STREAMS.WORKFLOW_INBOUND as StreamName,\n group: CONSUMER_GROUPS.WORKFLOW as any,\n consumer: `workflow-${process.pid}`,\n logger,\n });\n\n worker = new WorkflowWorker({\n consumer,\n pendingScanner,\n logger,\n concurrency: config.WORKER_CONCURRENCY,\n redis: redis.native,\n db,\n workflowProducer,\n notificationProducer,\n });\n\n // Polling loop for timers\n pollInterval = setInterval(() => {\n void (async () => {\n try {\n const now = Date.now();\n const tasks = (await redis.native.eval(\n LUA_SCHEDULER_POLL,\n 1,\n \"notif:workflow:timers\",\n now,\n 100,\n WORKFLOW_TIMER_VISIBILITY_MS,\n )) as string[];\n\n for (const taskStr of tasks) {\n const task = JSON.parse(taskStr);\n\n // Check if workflow is already completed/failed\n const inst = (\n await db\n .select()\n .from(workflowInstances)\n .where(eq(workflowInstances.id, task.instanceId))\n .limit(1)\n )[0];\n if (!inst || inst.status === \"completed\" || inst.status === \"failed\") {\n await redis.native.zrem(\"notif:workflow:timers\", taskStr);\n continue;\n }\n // A timer can be observed while the worker is still persisting the\n // corresponding suspension. Leave the claimed member in place; its\n // visibility timeout will make it eligible once the instance becomes\n // pending instead of losing the wake-up signal.\n if (inst.status === \"running\") continue;\n\n if (task.isEventTimeout) {\n // It's a timeout for waitForEvent. Clean up only this step's waiter\n const deleted = await db\n .delete(workflowWaiters)\n .where(\n and(\n eq(workflowWaiters.instanceId, task.instanceId),\n eq(workflowWaiters.eventName, task.eventName),\n ),\n )\n .returning();\n\n // If the waiter was already deleted (by EventWorker when event arrived before timeout),\n // this timer is stale. Clean up from Redis and skip re-resuming the workflow.\n if (deleted.length === 0) {\n await redis.native.zrem(\"notif:workflow:timers\", taskStr);\n continue;\n }\n\n // Record timedOut state on the pending waitForEvent step\n const steps = await db\n .select()\n .from(workflowSteps)\n .where(\n and(\n eq(workflowSteps.instanceId, task.instanceId),\n eq(workflowSteps.action, \"waitForEvent\"),\n ),\n );\n const pendingStep = steps.find((s: any) => s.output === null);\n if (pendingStep) {\n await db\n .update(workflowSteps)\n .set({ output: { timedOut: true } })\n .where(eq(workflowSteps.id, pendingStep.id));\n }\n }\n\n await workflowProducer.publish(\n buildStreamEvent(\"workflow.resumed\", task, \"scheduler\", undefined),\n );\n await redis.native.zrem(\"notif:workflow:timers\", taskStr);\n logger.info({ instanceId: task.instanceId }, \"Workflow resumed from timer\");\n }\n } catch (err) {\n logger.error({ err }, \"error in workflow polling loop\");\n }\n })();\n }, 5000);\n\n reaperInterval = setInterval(() => {\n void (async () => {\n try {\n const runningInstances = await db\n .select({ id: workflowInstances.id })\n .from(workflowInstances)\n .where(eq(workflowInstances.status, \"running\"));\n for (const inst of runningInstances) {\n const lockKey = `lock:workflow:${inst.id}`;\n const hasLock = await redis.native.exists(lockKey);\n if (!hasLock) {\n await db\n .update(workflowInstances)\n .set({ status: \"pending\" })\n .where(eq(workflowInstances.id, inst.id));\n logger.info({ instanceId: inst.id }, \"Reaped stuck workflow instance (lock expired)\");\n }\n }\n } catch (err) {\n logger.error({ err }, \"error in stuck workflow reaper\");\n }\n })();\n }, 60000);\n\n healthInterval = startHealthReporter(\"workflow\", worker, redis, logger);\n\n logger.info(\"workflow worker starting\");\n await worker.start();\n}\n\nexport async function stopWorkflowWorker(): Promise<void> {\n logger?.info(\"shutdown initiated\");\n if (healthInterval) clearInterval(healthInterval);\n if (pollInterval) clearInterval(pollInterval);\n if (reaperInterval) clearInterval(reaperInterval);\n if (worker) await worker.stop();\n if (sql) await sql.end();\n if (redis) await redis.disconnect();\n logger?.info(\"workflow worker stopped\");\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $t as PUBSUB_CHANNELS, A as ProjectSettingsCache, C as ProjectRepository, G as normaliseTarget, I as DataLoader, J as PendingMessageScanner, Jt as buildStreamEvent, T as TemplateRepository, W as getPriorityBucket, X as StreamProducer, Xt as ENRICHED_STREAMS, Y as StreamConsumer, Yt as CONSUMER_GROUPS, an as registry, b as renderWithTemplate, c as BaseWorker, d as buildUnsubscribeHeaders, dt as suppressions, en as STREAMS, et as createLogger, g as TemplateCache, hn as readBaseConfig, it as createDatabase, j as UserThrottle, k as RedisClient, pn as loadEnv, q as globalEmitter, rt as IdempotencyGuard, u as startHealthReporter, ut as scheduledPayloads, x as ContactRepository } from "./src-
|
|
1
|
+
import { $t as PUBSUB_CHANNELS, A as ProjectSettingsCache, C as ProjectRepository, G as normaliseTarget, I as DataLoader, J as PendingMessageScanner, Jt as buildStreamEvent, T as TemplateRepository, W as getPriorityBucket, X as StreamProducer, Xt as ENRICHED_STREAMS, Y as StreamConsumer, Yt as CONSUMER_GROUPS, an as registry, b as renderWithTemplate, c as BaseWorker, d as buildUnsubscribeHeaders, dt as suppressions, en as STREAMS, et as createLogger, g as TemplateCache, hn as readBaseConfig, it as createDatabase, j as UserThrottle, k as RedisClient, pn as loadEnv, q as globalEmitter, rt as IdempotencyGuard, u as startHealthReporter, ut as scheduledPayloads, x as ContactRepository } from "./src-CpUnBl_M.mjs";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import { and, eq } from "drizzle-orm";
|
|
4
4
|
//#region src/services/engine/main.ts
|
|
@@ -568,4 +568,4 @@ async function stopEngineWorker() {
|
|
|
568
568
|
//#endregion
|
|
569
569
|
export { startEngineWorker, stopEngineWorker };
|
|
570
570
|
|
|
571
|
-
//# sourceMappingURL=main-
|
|
571
|
+
//# sourceMappingURL=main-CWGEKpLU.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main-BOPMYqsW.mjs","names":["sql"],"sources":["../src/services/engine/main.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { loadEnv, readBaseConfig } from \"@/index.js\";\nimport { createLogger } from \"@/index.js\";\nimport { RedisClient, type Redis } from \"@/index.js\";\nimport {\n StreamConsumer,\n PendingMessageScanner,\n StreamProducer,\n type StreamMessage,\n} from \"@/index.js\";\nimport { BaseWorker } from \"@/index.js\";\nimport {\n STREAMS,\n ENRICHED_STREAMS,\n CONSUMER_GROUPS,\n PUBSUB_CHANNELS,\n registry,\n buildStreamEvent,\n type NotificationEnrichedPayload,\n type NotificationDispatchedPayload,\n} from \"@/index.js\";\nimport { type StreamName } from \"@/contracts/streams.js\";\nimport { IdempotencyGuard } from \"@/index.js\";\nimport { UserThrottle, ProjectSettingsCache } from \"@/index.js\";\nimport { TemplateRepository, ContactRepository, ProjectRepository } from \"@/index.js\";\nimport { createDatabase } from \"@/db/index.js\";\nimport { scheduledPayloads, suppressions } from \"@/db/schema.js\";\nimport { and, eq } from \"drizzle-orm\";\nimport {\n getPriorityBucket,\n globalEmitter,\n normaliseTarget,\n type WorkerOptions,\n DataLoader,\n} from \"@/shared/index.js\";\nimport { renderWithTemplate, TemplateCache } from \"@/templates/index.js\";\nimport { buildUnsubscribeHeaders } from \"@/unsubscribe/index.js\";\nimport { startHealthReporter } from \"@/workers/index.js\";\n\nfunction localTimeToUtc(\n year: number,\n month: number,\n day: number,\n hour: number,\n minute: number,\n second: number,\n timezone: string,\n): Date {\n let utcMs = Date.UTC(year, month - 1, day, hour, minute, second);\n const formatter = new Intl.DateTimeFormat(\"en-US\", {\n timeZone: timezone,\n year: \"numeric\",\n month: \"2-digit\",\n day: \"2-digit\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n second: \"2-digit\",\n hour12: false,\n });\n\n for (let iter = 0; iter < 3; iter++) {\n const parts = formatter.formatToParts(new Date(utcMs));\n const pYear = parseInt(parts.find((p) => p.type === \"year\")?.value ?? \"0\", 10);\n const pMonth = parseInt(parts.find((p) => p.type === \"month\")?.value ?? \"0\", 10);\n const pDay = parseInt(parts.find((p) => p.type === \"day\")?.value ?? \"0\", 10);\n const pHour = parseInt(parts.find((p) => p.type === \"hour\")?.value ?? \"0\", 10);\n const pMin = parseInt(parts.find((p) => p.type === \"minute\")?.value ?? \"0\", 10);\n const pSec = parseInt(parts.find((p) => p.type === \"second\")?.value ?? \"0\", 10);\n\n const targetMs = Date.UTC(year, month - 1, day, hour, minute, second);\n const actualMs = Date.UTC(pYear, pMonth - 1, pDay, pHour, pMin, pSec);\n const diff = targetMs - actualMs;\n if (diff === 0) break;\n utcMs += diff;\n }\n return new Date(utcMs);\n}\n\nexport function isInQuietHours(\n timezone: string,\n quietHours: { start: string; end: string }[],\n fromDate: Date = new Date(),\n): { inQuietHours: boolean; nextActiveTime?: Date } {\n if (!quietHours || quietHours.length === 0) {\n return { inQuietHours: false };\n }\n\n const checkWindowAt = (date: Date) => {\n let parts: Intl.DateTimeFormatPart[];\n try {\n const formatter = new Intl.DateTimeFormat(\"en-US\", {\n timeZone: timezone,\n year: \"numeric\",\n month: \"2-digit\",\n day: \"2-digit\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n second: \"2-digit\",\n hour12: false,\n });\n parts = formatter.formatToParts(date);\n } catch {\n return null;\n }\n\n const year = parseInt(parts.find((p) => p.type === \"year\")?.value ?? \"0\", 10);\n const month = parseInt(parts.find((p) => p.type === \"month\")?.value ?? \"0\", 10);\n const day = parseInt(parts.find((p) => p.type === \"day\")?.value ?? \"0\", 10);\n const currentHour = parseInt(parts.find((p) => p.type === \"hour\")?.value ?? \"0\", 10);\n const currentMin = parseInt(parts.find((p) => p.type === \"minute\")?.value ?? \"0\", 10);\n\n const currentMinutes = currentHour * 60 + currentMin;\n\n for (const window of quietHours) {\n const [startH, startM] = window.start.split(\":\").map(Number);\n const [endH, endM] = window.end.split(\":\").map(Number);\n\n if (startH === undefined || startM === undefined || endH === undefined || endM === undefined)\n continue;\n\n const startMinutes = startH * 60 + startM;\n const endMinutes = endH * 60 + endM;\n\n let inWindow = false;\n if (startMinutes <= endMinutes) {\n inWindow = currentMinutes >= startMinutes && currentMinutes < endMinutes;\n } else {\n inWindow = currentMinutes >= startMinutes || currentMinutes < endMinutes;\n }\n\n if (inWindow) {\n let targetYear = year;\n let targetMonth = month;\n let targetDay = day;\n\n if (currentMinutes >= endMinutes) {\n const nextDay = new Date(Date.UTC(year, month - 1, day + 1));\n targetYear = nextDay.getUTCFullYear();\n targetMonth = nextDay.getUTCMonth() + 1;\n targetDay = nextDay.getUTCDate();\n }\n\n const nextActive = localTimeToUtc(\n targetYear,\n targetMonth,\n targetDay,\n endH,\n endM,\n 0,\n timezone,\n );\n return { inQuietHours: true, nextActiveTime: nextActive };\n }\n }\n return { inQuietHours: false };\n };\n\n let initialCheck = checkWindowAt(fromDate);\n if (!initialCheck || !initialCheck.inQuietHours) {\n return { inQuietHours: false };\n }\n\n // Chained / overlapping quiet hours intervals\n let candidateTime = initialCheck.nextActiveTime!;\n for (let i = 0; i < 10; i++) {\n const subsequentCheck = checkWindowAt(candidateTime);\n if (subsequentCheck && subsequentCheck.inQuietHours && subsequentCheck.nextActiveTime) {\n if (subsequentCheck.nextActiveTime.getTime() <= candidateTime.getTime()) {\n break;\n }\n candidateTime = subsequentCheck.nextActiveTime;\n } else {\n break;\n }\n }\n\n return { inQuietHours: true, nextActiveTime: candidateTime };\n}\n\n// ─── Bootstrap ─────────────────────────────────────────────────────────────\n\nloadEnv();\nconst config = readBaseConfig();\n\nlet logger: ReturnType<typeof createLogger>;\nlet redis: RedisClient;\nlet sql: any;\nlet db: any;\nlet templateRepo: TemplateRepository;\n\nlet templateCache: TemplateCache;\n\nlet consumer: StreamConsumer;\nlet pendingScanner: PendingMessageScanner;\nlet worker: BaseWorker;\nlet healthInterval: NodeJS.Timeout | null = null;\n\nexport interface EngineWorkerOptions extends WorkerOptions {\n registry: any;\n idempotency: any;\n throttle: any;\n projectSettings: ProjectSettingsCache;\n redis: Redis;\n templateCache: TemplateCache;\n aiPendingProducer: any;\n scheduledProducer: any;\n outboundProducers: any;\n globalEmitter: any;\n contactRepo: any;\n db: any;\n}\n\nexport class EngineWorker extends BaseWorker {\n private readonly registry: any;\n private readonly idempotency: any;\n private readonly throttle: any;\n private readonly projectSettings: ProjectSettingsCache;\n private readonly redisCli: Redis;\n private readonly templateCache: TemplateCache;\n private readonly aiPendingProducer: any;\n private readonly scheduledProducer: any;\n private readonly outboundProducers: any;\n private readonly globalEmitter: any;\n private readonly contactRepo: any;\n private readonly db: any;\n\n constructor(options: EngineWorkerOptions) {\n super(options);\n this.registry = options.registry;\n this.idempotency = options.idempotency;\n this.throttle = options.throttle;\n this.projectSettings = options.projectSettings;\n this.redisCli = options.redis;\n this.templateCache = options.templateCache;\n this.aiPendingProducer = options.aiPendingProducer;\n this.scheduledProducer = options.scheduledProducer;\n this.outboundProducers = options.outboundProducers;\n this.globalEmitter = options.globalEmitter;\n this.contactRepo = options.contactRepo;\n this.db = options.db;\n }\n\n private readonly contactsLoader = new DataLoader<\n { projectId: string; recipientId: string },\n any[]\n >(async (keys) => {\n const byProject = new Map<string, string[]>();\n for (const key of keys) {\n if (!byProject.has(key.projectId)) byProject.set(key.projectId, []);\n byProject.get(key.projectId)!.push(key.recipientId);\n }\n\n const resultsByProjectAndUser = new Map<string, Map<string, any[]>>();\n for (const [projectId, userIds] of byProject) {\n const activeContactsMap = await this.contactRepo.findActiveByUserIds(projectId, userIds);\n resultsByProjectAndUser.set(projectId, activeContactsMap);\n }\n\n return keys.map((key) => {\n const projectMap = resultsByProjectAndUser.get(key.projectId);\n if (!projectMap) return [];\n return projectMap.get(key.recipientId) || [];\n });\n });\n\n /**\n * Suppressed destinations for one (project, channel), as a normalised set.\n *\n * Loaded per project+channel rather than per address: a campaign is thousands\n * of messages against one channel, so this collapses to a single query for\n * the whole batch. Cached for the loader's lifetime of a tick, which means a\n * suppression written mid-batch takes effect on the next batch — acceptable,\n * since the webhook that writes it is itself minutes behind the send.\n */\n private readonly suppressionsLoader = new DataLoader<\n { projectId: string; channel: string },\n Set<string>\n >(async (keys) => {\n const results = new Map<string, Set<string>>();\n for (const key of keys) {\n const cacheKey = `${key.projectId}:${key.channel}`;\n if (results.has(cacheKey)) continue;\n try {\n const rows = await this.db\n .select({ target: suppressions.target })\n .from(suppressions)\n .where(\n and(\n eq(suppressions.projectId, key.projectId),\n eq(suppressions.channel, key.channel as any),\n ),\n );\n results.set(\n cacheKey,\n new Set(rows.map((r: { target: string }) => normaliseTarget(r.target))),\n );\n } catch (err) {\n // A suppression lookup that fails must not silently become \"nothing\n // is suppressed\" — that would resume mailing people who opted out.\n this.logger.error(\n { err, projectId: key.projectId, channel: key.channel },\n \"suppression lookup failed — holding message\",\n );\n throw err;\n }\n }\n return keys.map((key) => results.get(`${key.projectId}:${key.channel}`) ?? new Set<string>());\n });\n\n async process(message: StreamMessage): Promise<void> {\n const { event } = message;\n\n const payloadResult = this.registry.safeParsePayload(\"notification.enriched\", event.payload);\n if (!payloadResult.success) {\n this.logger.warn(\n { messageId: message.id, issues: payloadResult.error.issues },\n \"invalid notification.enriched payload — skipping\",\n );\n return;\n }\n\n const enriched = payloadResult.data as NotificationEnrichedPayload;\n\n // Idempotency\n const idempotencyKey = `${enriched.rawEventId}:${enriched.recipientId}:${enriched.channel}`;\n let customTtl: number | undefined;\n if (enriched.scheduledAt) {\n const msUntil = new Date(enriched.scheduledAt).getTime() - Date.now();\n if (msUntil > 0) {\n // base 24h (86400) + schedule time\n customTtl = 86400 + Math.ceil(msUntil / 1000);\n }\n }\n\n if (!(await this.idempotency.checkAndMark(idempotencyKey, 60))) {\n this.logger.debug({ messageId: message.id, eventId: event.id }, \"duplicate — skipping\");\n return;\n }\n\n try {\n // Opt-in check\n if (enriched.recipient.preferences.optedOut) {\n this.logger.info(\n { messageId: message.id, recipientId: enriched.recipientId, eventType: event.type },\n \"user opted out — dropping\",\n );\n this.globalEmitter.emit(\"notification:skipped\", {\n projectId: enriched.projectId,\n eventId: event.id,\n recipientId: enriched.recipientId,\n reason: \"user_opted_out\",\n });\n await this.idempotency.markProcessed(idempotencyKey, customTtl);\n return;\n }\n\n if (enriched.recipient.preferences.channels?.includes(enriched.channel)) {\n this.logger.info(\n { messageId: message.id, recipientId: enriched.recipientId, channel: enriched.channel },\n \"user disabled notification channel — dropping\",\n );\n this.globalEmitter.emit(\"notification:skipped\", {\n projectId: enriched.projectId,\n eventId: event.id,\n recipientId: enriched.recipientId,\n reason: \"channel_disabled\",\n });\n await this.idempotency.markProcessed(idempotencyKey, customTtl);\n return;\n }\n\n // Quiet hours check\n const qh = enriched.recipient.preferences.quietHours;\n if (qh && qh.length > 0 && enriched.priority !== \"critical\") {\n const qhResult = isInQuietHours(enriched.recipient.timezone, qh);\n if (qhResult.inQuietHours && qhResult.nextActiveTime) {\n this.logger.info(\n {\n messageId: message.id,\n recipientId: enriched.recipientId,\n nextActiveTime: qhResult.nextActiveTime.toISOString(),\n },\n \"user is in quiet hours — deferring notification\",\n );\n enriched.scheduledAt = qhResult.nextActiveTime.toISOString();\n }\n }\n\n // Rate limit. Per-project overrides win over the process-wide default;\n // a lookup failure must not drop the notification, so fall back rather\n // than propagate.\n let projectThrottle: { throttleLimit: number | null; throttleWindowHours: number | null } = {\n throttleLimit: null,\n throttleWindowHours: null,\n };\n try {\n projectThrottle = await this.projectSettings.get(enriched.projectId);\n } catch (err) {\n this.logger.warn(\n { err, projectId: enriched.projectId },\n \"could not read project throttle settings — falling back to the global default\",\n );\n }\n\n const throttleResult = await this.throttle.check(\n enriched.projectId,\n enriched.recipientId,\n enriched.priority,\n {\n limit: projectThrottle.throttleLimit,\n windowHours: projectThrottle.throttleWindowHours,\n scheduledAt: enriched.scheduledAt,\n },\n );\n if (!throttleResult.allowed) {\n this.logger.info(\n {\n messageId: message.id,\n recipientId: enriched.recipientId,\n count: throttleResult.count,\n limit: throttleResult.limit,\n priority: enriched.priority,\n },\n \"user throttled — dropping\",\n );\n this.globalEmitter.emit(\n \"notification:throttled\",\n enriched.recipientId,\n throttleResult.count,\n );\n await this.idempotency.markProcessed(idempotencyKey, customTtl);\n return;\n }\n\n // Gather AI Prompts\n // Gather AI Prompts\n let dbTemplate = null;\n if (enriched.templateId) {\n dbTemplate = await this.templateCache.getCachedTemplate(\n enriched.projectId,\n enriched.templateId,\n );\n if (!dbTemplate) {\n this.logger.warn(\n { messageId: message.id, templateId: enriched.templateId },\n \"template not found — dropping\",\n );\n this.globalEmitter.emit(\"notification:skipped\", {\n projectId: enriched.projectId,\n eventId: event.id,\n recipientId: enriched.recipientId,\n reason: \"template_not_found\",\n });\n await this.idempotency.markProcessed(idempotencyKey, customTtl);\n return;\n }\n }\n const aiPrompts = {\n ...(dbTemplate?.aiPrompts ?? {}),\n ...(enriched.aiPrompts ?? {}),\n };\n\n // Drives whether this message gets an unsubscribe header, and what the\n // resulting opt-out applies to.\n const templateTopics: string[] = dbTemplate?.topics ?? [];\n\n if (Object.keys(aiPrompts).length > 0) {\n const aiPendingPayload = {\n projectId: enriched.projectId,\n enrichedEventId: event.id,\n recipientId: enriched.recipientId,\n channel: enriched.channel,\n priority: enriched.priority,\n templateId: enriched.templateId,\n templateVariables: enriched.templateVariables,\n recipient: enriched.recipient,\n aiPrompts,\n scheduledAt: enriched.scheduledAt,\n fallbackChain: enriched.fallbackChain,\n };\n\n const aiPendingEnvelope = buildStreamEvent(\n \"notification.ai_pending\",\n aiPendingPayload as Record<string, unknown>,\n \"engine\",\n event.metadata.traceId,\n );\n\n await this.aiPendingProducer.publish(aiPendingEnvelope);\n this.logger.info(\n {\n messageId: message.id,\n eventId: event.id,\n recipientId: enriched.recipientId,\n traceId: event.metadata.traceId,\n },\n \"task routed to AI worker\",\n );\n await this.idempotency.markProcessed(idempotencyKey, customTtl);\n return;\n }\n\n // Render template\n const rendered = renderWithTemplate(dbTemplate, enriched.templateVariables);\n\n const allContacts = await this.contactsLoader.load({\n projectId: enriched.projectId,\n recipientId: enriched.recipientId,\n });\n const activeContacts = allContacts.filter(\n (c: any) => c.channel === enriched.channel && c.active,\n );\n\n if (activeContacts.length === 0) {\n this.logger.info(\n { messageId: message.id, recipientId: enriched.recipientId, channel: enriched.channel },\n \"no active contacts for channel — dropping\",\n );\n this.globalEmitter.emit(\"notification:skipped\", {\n projectId: enriched.projectId,\n eventId: event.id,\n recipientId: enriched.recipientId,\n reason: \"no_active_contacts\",\n });\n await this.idempotency.markProcessed(idempotencyKey, customTtl);\n return;\n }\n\n const suppressedTargets = await this.suppressionsLoader.load({\n projectId: enriched.projectId,\n channel: enriched.channel,\n });\n\n for (const contact of activeContacts) {\n if (contact.preferences?.optedOut) {\n continue;\n }\n\n // A suppression outranks every other gate, `critical` included: it\n // records that the person asked us to stop, or that the address is\n // dead. Sending anyway is what gets a domain blocked.\n if (contact.target && suppressedTargets.has(normaliseTarget(contact.target))) {\n this.logger.info(\n {\n messageId: message.id,\n recipientId: enriched.recipientId,\n channel: enriched.channel,\n },\n \"destination suppressed — dropping\",\n );\n this.globalEmitter.emit(\"notification:skipped\", {\n projectId: enriched.projectId,\n eventId: event.id,\n recipientId: enriched.recipientId,\n reason: \"suppressed\",\n });\n continue;\n }\n\n const taskId = `${enriched.rawEventId}:${contact.id || randomUUID()}`;\n const resolvedDestination = contact.target;\n\n // One-click unsubscribe headers, but only on mail that should carry\n // them. A template with no topic is transactional by this codebase's\n // own convention — a password reset, a receipt — and putting an\n // unsubscribe button on those invites people to switch off mail they\n // actually need, with no topic to scope the opt-out to anyway.\n if (\n enriched.channel === \"email\" &&\n templateTopics.length > 0 &&\n !config.UNSUBSCRIBE_SECRET\n ) {\n this.logger.warn(\n { projectId: enriched.projectId, recipientId: enriched.recipientId },\n \"UNSUBSCRIBE_SECRET is not configured — email sent without RFC 8058 one-click unsubscribe headers\",\n );\n }\n\n const unsubscribeHeaders =\n enriched.channel === \"email\" &&\n templateTopics.length > 0 &&\n config.UNSUBSCRIBE_SECRET &&\n config.PUBLIC_URL &&\n resolvedDestination\n ? buildUnsubscribeHeaders({\n claim: {\n projectId: enriched.projectId,\n userId: enriched.recipientId,\n channel: enriched.channel,\n target: resolvedDestination,\n topics: templateTopics,\n },\n secret: config.UNSUBSCRIBE_SECRET,\n publicUrl: config.PUBLIC_URL,\n })\n : undefined;\n\n const taskPayload: NotificationDispatchedPayload = {\n projectId: enriched.projectId,\n taskId,\n enrichedEventId: event.id,\n recipientId: enriched.recipientId,\n channel: enriched.channel,\n priority: enriched.priority,\n templateId: enriched.templateId,\n templateVariables: enriched.templateVariables,\n aiPrompts: enriched.aiPrompts,\n recipient: enriched.recipient,\n renderedContent: rendered,\n destination: resolvedDestination,\n deliveryOptions: {\n maxAttempts: 3,\n timeoutMs: 10_000,\n ...(unsubscribeHeaders ? { headers: unsubscribeHeaders } : {}),\n },\n fallbackChain: enriched.fallbackChain,\n campaignId: enriched.campaignId,\n };\n\n const envelope = buildStreamEvent(\n \"notification.dispatched\",\n taskPayload as Record<string, unknown>,\n \"engine\",\n event.metadata.traceId,\n );\n\n // Route by scheduledAt\n const now = Date.now();\n const scheduledAt = enriched.scheduledAt ? new Date(enriched.scheduledAt).getTime() : now;\n\n if (scheduledAt > now) {\n await this.db\n .insert(scheduledPayloads)\n .values({\n taskId,\n payload: {\n ...taskPayload,\n scheduledAt: enriched.scheduledAt,\n },\n })\n .onConflictDoNothing();\n\n const scheduledEnvelope = buildStreamEvent(\n \"notification.scheduled\",\n {\n projectId: enriched.projectId,\n enrichedEventId: event.id,\n taskId,\n scheduledAt: enriched.scheduledAt!,\n },\n \"engine\",\n event.metadata.traceId,\n );\n\n await this.scheduledProducer.publish(scheduledEnvelope);\n this.logger.info(\n {\n messageId: message.id,\n taskId,\n scheduledAt: enriched.scheduledAt,\n traceId: event.metadata.traceId,\n },\n \"task scheduled and payload cached\",\n );\n } else {\n const p = getPriorityBucket(enriched.priority);\n const outboundProducer = this.outboundProducers[p] ?? this.outboundProducers[\"normal\"]!;\n\n await outboundProducer.publish(envelope);\n this.logger.info(\n {\n messageId: message.id,\n taskId,\n recipientId: enriched.recipientId,\n traceId: event.metadata.traceId,\n },\n \"task dispatched\",\n );\n }\n }\n await this.idempotency.markProcessed(idempotencyKey, customTtl);\n } catch (err) {\n await this.idempotency.unmark(idempotencyKey).catch(() => {});\n throw err;\n }\n }\n}\n\nlet subscriber: any = null;\n\nexport async function startEngineWorker() {\n logger = createLogger({ name: \"engine\", level: config.LOG_LEVEL });\n redis = new RedisClient({ url: config.REDIS_URL, name: \"engine\", logger });\n const dbData = createDatabase({ url: config.DATABASE_URL, applicationName: \"engine\", logger });\n sql = dbData.sql;\n db = dbData.db;\n templateRepo = new TemplateRepository(db);\n templateCache = new TemplateCache(templateRepo);\n const contactRepo = new ContactRepository(db);\n consumer = new StreamConsumer({\n redis: redis.native,\n stream: ENRICHED_STREAMS as unknown as StreamName[],\n group: CONSUMER_GROUPS.ENGINE,\n consumer: `engine-${process.pid}`,\n dlqStream: STREAMS.DEAD_LETTER,\n batchSize: config.WORKER_CONCURRENCY,\n logger,\n });\n\n pendingScanner = new PendingMessageScanner({\n redis: redis.native,\n stream: ENRICHED_STREAMS as unknown as StreamName[],\n group: CONSUMER_GROUPS.ENGINE,\n consumer: `engine-${process.pid}`,\n logger,\n });\n\n const outboundProducers = {\n critical: new StreamProducer({\n redis: redis.native,\n stream: STREAMS.OUTBOUND_CRITICAL,\n logger,\n }),\n normal: new StreamProducer({ redis: redis.native, stream: STREAMS.OUTBOUND_NORMAL, logger }),\n low: new StreamProducer({ redis: redis.native, stream: STREAMS.OUTBOUND_LOW, logger }),\n };\n\n const scheduledProducer = new StreamProducer({\n redis: redis.native,\n stream: STREAMS.SCHEDULED,\n logger,\n });\n\n const aiPendingProducer = new StreamProducer({\n redis: redis.native,\n stream: STREAMS.AI_PENDING,\n logger,\n });\n\n const idempotency = new IdempotencyGuard({\n redis: redis.native,\n keyPrefix: \"notif:processed:engine\",\n ttlSeconds: 86_400,\n });\n\n const throttle = new UserThrottle({\n redis: redis.native,\n maxPerHour: parseInt(process.env.RATE_LIMIT_PER_HOUR || \"100\", 10),\n });\n\n // Per-project throttle overrides, cached because this is read once per\n // notification. Stale entries expire on their own; the pub/sub subscriber\n // below only makes an admin's change take effect sooner.\n const projectRepo = new ProjectRepository(db);\n const projectSettings = new ProjectSettingsCache((projectId) =>\n projectRepo.findThrottleSettings(projectId),\n );\n\n // ─── Stage 2: Decision Engine ───────────────────────────────────────────────\n //\n // Pipeline:\n // 1. Parse payload as notification.enriched\n // 2. Idempotency check\n // 3. Check user opt-in (from enriched recipient.preferences)\n // 4. Apply per-user hourly rate limit\n // 5. Render template using user locale\n // 6. Route: if scheduledAt is future → SCHEDULED; else → OUTBOUND\n\n worker = new EngineWorker({\n consumer,\n pendingScanner,\n logger,\n concurrency: config.WORKER_CONCURRENCY,\n registry,\n idempotency,\n throttle,\n projectSettings,\n redis: redis.native,\n templateCache,\n aiPendingProducer,\n scheduledProducer,\n outboundProducers,\n globalEmitter,\n contactRepo,\n db,\n });\n\n subscriber = redis.native.duplicate();\n await subscriber.subscribe(\n PUBSUB_CHANNELS.TEMPLATE_INVALIDATED,\n PUBSUB_CHANNELS.PROJECT_INVALIDATED,\n );\n subscriber.on(\"message\", (channel: string, message: string) => {\n if (channel === PUBSUB_CHANNELS.TEMPLATE_INVALIDATED) {\n templateCache.invalidateKey(message);\n logger.info({ cacheKey: message }, \"invalidated template cache\");\n } else if (channel === PUBSUB_CHANNELS.PROJECT_INVALIDATED) {\n projectSettings.invalidate(message);\n logger.info({ projectId: message }, \"invalidated project settings cache\");\n }\n });\n\n // ─── Health check interval ──────────────────────────────────────────────────\n\n healthInterval = startHealthReporter(\"engine\", worker, redis, logger);\n\n logger.info({ env: config.NODE_ENV }, \"engine starting\");\n await worker.start();\n}\n\n// ─── Shutdown ──────────────────────────────────────────────────────────────\n\nexport async function stopEngineWorker(): Promise<void> {\n logger?.info(\"shutdown initiated\");\n if (healthInterval) {\n clearInterval(healthInterval);\n healthInterval = null;\n }\n if (subscriber) {\n subscriber.disconnect();\n subscriber = null;\n }\n if (worker) await worker.stop();\n if (sql) await sql.end();\n if (redis) await redis.disconnect();\n logger?.info(\"engine stopped\");\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"main-CWGEKpLU.mjs","names":["sql"],"sources":["../src/services/engine/main.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { loadEnv, readBaseConfig } from \"@/index.js\";\nimport { createLogger } from \"@/index.js\";\nimport { RedisClient, type Redis } from \"@/index.js\";\nimport {\n StreamConsumer,\n PendingMessageScanner,\n StreamProducer,\n type StreamMessage,\n} from \"@/index.js\";\nimport { BaseWorker } from \"@/index.js\";\nimport {\n STREAMS,\n ENRICHED_STREAMS,\n CONSUMER_GROUPS,\n PUBSUB_CHANNELS,\n registry,\n buildStreamEvent,\n type NotificationEnrichedPayload,\n type NotificationDispatchedPayload,\n} from \"@/index.js\";\nimport { type StreamName } from \"@/contracts/streams.js\";\nimport { IdempotencyGuard } from \"@/index.js\";\nimport { UserThrottle, ProjectSettingsCache } from \"@/index.js\";\nimport { TemplateRepository, ContactRepository, ProjectRepository } from \"@/index.js\";\nimport { createDatabase } from \"@/db/index.js\";\nimport { scheduledPayloads, suppressions } from \"@/db/schema.js\";\nimport { and, eq } from \"drizzle-orm\";\nimport {\n getPriorityBucket,\n globalEmitter,\n normaliseTarget,\n type WorkerOptions,\n DataLoader,\n} from \"@/shared/index.js\";\nimport { renderWithTemplate, TemplateCache } from \"@/templates/index.js\";\nimport { buildUnsubscribeHeaders } from \"@/unsubscribe/index.js\";\nimport { startHealthReporter } from \"@/workers/index.js\";\n\nfunction localTimeToUtc(\n year: number,\n month: number,\n day: number,\n hour: number,\n minute: number,\n second: number,\n timezone: string,\n): Date {\n let utcMs = Date.UTC(year, month - 1, day, hour, minute, second);\n const formatter = new Intl.DateTimeFormat(\"en-US\", {\n timeZone: timezone,\n year: \"numeric\",\n month: \"2-digit\",\n day: \"2-digit\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n second: \"2-digit\",\n hour12: false,\n });\n\n for (let iter = 0; iter < 3; iter++) {\n const parts = formatter.formatToParts(new Date(utcMs));\n const pYear = parseInt(parts.find((p) => p.type === \"year\")?.value ?? \"0\", 10);\n const pMonth = parseInt(parts.find((p) => p.type === \"month\")?.value ?? \"0\", 10);\n const pDay = parseInt(parts.find((p) => p.type === \"day\")?.value ?? \"0\", 10);\n const pHour = parseInt(parts.find((p) => p.type === \"hour\")?.value ?? \"0\", 10);\n const pMin = parseInt(parts.find((p) => p.type === \"minute\")?.value ?? \"0\", 10);\n const pSec = parseInt(parts.find((p) => p.type === \"second\")?.value ?? \"0\", 10);\n\n const targetMs = Date.UTC(year, month - 1, day, hour, minute, second);\n const actualMs = Date.UTC(pYear, pMonth - 1, pDay, pHour, pMin, pSec);\n const diff = targetMs - actualMs;\n if (diff === 0) break;\n utcMs += diff;\n }\n return new Date(utcMs);\n}\n\nexport function isInQuietHours(\n timezone: string,\n quietHours: { start: string; end: string }[],\n fromDate: Date = new Date(),\n): { inQuietHours: boolean; nextActiveTime?: Date } {\n if (!quietHours || quietHours.length === 0) {\n return { inQuietHours: false };\n }\n\n const checkWindowAt = (date: Date) => {\n let parts: Intl.DateTimeFormatPart[];\n try {\n const formatter = new Intl.DateTimeFormat(\"en-US\", {\n timeZone: timezone,\n year: \"numeric\",\n month: \"2-digit\",\n day: \"2-digit\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n second: \"2-digit\",\n hour12: false,\n });\n parts = formatter.formatToParts(date);\n } catch {\n return null;\n }\n\n const year = parseInt(parts.find((p) => p.type === \"year\")?.value ?? \"0\", 10);\n const month = parseInt(parts.find((p) => p.type === \"month\")?.value ?? \"0\", 10);\n const day = parseInt(parts.find((p) => p.type === \"day\")?.value ?? \"0\", 10);\n const currentHour = parseInt(parts.find((p) => p.type === \"hour\")?.value ?? \"0\", 10);\n const currentMin = parseInt(parts.find((p) => p.type === \"minute\")?.value ?? \"0\", 10);\n\n const currentMinutes = currentHour * 60 + currentMin;\n\n for (const window of quietHours) {\n const [startH, startM] = window.start.split(\":\").map(Number);\n const [endH, endM] = window.end.split(\":\").map(Number);\n\n if (startH === undefined || startM === undefined || endH === undefined || endM === undefined)\n continue;\n\n const startMinutes = startH * 60 + startM;\n const endMinutes = endH * 60 + endM;\n\n let inWindow = false;\n if (startMinutes <= endMinutes) {\n inWindow = currentMinutes >= startMinutes && currentMinutes < endMinutes;\n } else {\n inWindow = currentMinutes >= startMinutes || currentMinutes < endMinutes;\n }\n\n if (inWindow) {\n let targetYear = year;\n let targetMonth = month;\n let targetDay = day;\n\n if (currentMinutes >= endMinutes) {\n const nextDay = new Date(Date.UTC(year, month - 1, day + 1));\n targetYear = nextDay.getUTCFullYear();\n targetMonth = nextDay.getUTCMonth() + 1;\n targetDay = nextDay.getUTCDate();\n }\n\n const nextActive = localTimeToUtc(\n targetYear,\n targetMonth,\n targetDay,\n endH,\n endM,\n 0,\n timezone,\n );\n return { inQuietHours: true, nextActiveTime: nextActive };\n }\n }\n return { inQuietHours: false };\n };\n\n let initialCheck = checkWindowAt(fromDate);\n if (!initialCheck || !initialCheck.inQuietHours) {\n return { inQuietHours: false };\n }\n\n // Chained / overlapping quiet hours intervals\n let candidateTime = initialCheck.nextActiveTime!;\n for (let i = 0; i < 10; i++) {\n const subsequentCheck = checkWindowAt(candidateTime);\n if (subsequentCheck && subsequentCheck.inQuietHours && subsequentCheck.nextActiveTime) {\n if (subsequentCheck.nextActiveTime.getTime() <= candidateTime.getTime()) {\n break;\n }\n candidateTime = subsequentCheck.nextActiveTime;\n } else {\n break;\n }\n }\n\n return { inQuietHours: true, nextActiveTime: candidateTime };\n}\n\n// ─── Bootstrap ─────────────────────────────────────────────────────────────\n\nloadEnv();\nconst config = readBaseConfig();\n\nlet logger: ReturnType<typeof createLogger>;\nlet redis: RedisClient;\nlet sql: any;\nlet db: any;\nlet templateRepo: TemplateRepository;\n\nlet templateCache: TemplateCache;\n\nlet consumer: StreamConsumer;\nlet pendingScanner: PendingMessageScanner;\nlet worker: BaseWorker;\nlet healthInterval: NodeJS.Timeout | null = null;\n\nexport interface EngineWorkerOptions extends WorkerOptions {\n registry: any;\n idempotency: any;\n throttle: any;\n projectSettings: ProjectSettingsCache;\n redis: Redis;\n templateCache: TemplateCache;\n aiPendingProducer: any;\n scheduledProducer: any;\n outboundProducers: any;\n globalEmitter: any;\n contactRepo: any;\n db: any;\n}\n\nexport class EngineWorker extends BaseWorker {\n private readonly registry: any;\n private readonly idempotency: any;\n private readonly throttle: any;\n private readonly projectSettings: ProjectSettingsCache;\n private readonly redisCli: Redis;\n private readonly templateCache: TemplateCache;\n private readonly aiPendingProducer: any;\n private readonly scheduledProducer: any;\n private readonly outboundProducers: any;\n private readonly globalEmitter: any;\n private readonly contactRepo: any;\n private readonly db: any;\n\n constructor(options: EngineWorkerOptions) {\n super(options);\n this.registry = options.registry;\n this.idempotency = options.idempotency;\n this.throttle = options.throttle;\n this.projectSettings = options.projectSettings;\n this.redisCli = options.redis;\n this.templateCache = options.templateCache;\n this.aiPendingProducer = options.aiPendingProducer;\n this.scheduledProducer = options.scheduledProducer;\n this.outboundProducers = options.outboundProducers;\n this.globalEmitter = options.globalEmitter;\n this.contactRepo = options.contactRepo;\n this.db = options.db;\n }\n\n private readonly contactsLoader = new DataLoader<\n { projectId: string; recipientId: string },\n any[]\n >(async (keys) => {\n const byProject = new Map<string, string[]>();\n for (const key of keys) {\n if (!byProject.has(key.projectId)) byProject.set(key.projectId, []);\n byProject.get(key.projectId)!.push(key.recipientId);\n }\n\n const resultsByProjectAndUser = new Map<string, Map<string, any[]>>();\n for (const [projectId, userIds] of byProject) {\n const activeContactsMap = await this.contactRepo.findActiveByUserIds(projectId, userIds);\n resultsByProjectAndUser.set(projectId, activeContactsMap);\n }\n\n return keys.map((key) => {\n const projectMap = resultsByProjectAndUser.get(key.projectId);\n if (!projectMap) return [];\n return projectMap.get(key.recipientId) || [];\n });\n });\n\n /**\n * Suppressed destinations for one (project, channel), as a normalised set.\n *\n * Loaded per project+channel rather than per address: a campaign is thousands\n * of messages against one channel, so this collapses to a single query for\n * the whole batch. Cached for the loader's lifetime of a tick, which means a\n * suppression written mid-batch takes effect on the next batch — acceptable,\n * since the webhook that writes it is itself minutes behind the send.\n */\n private readonly suppressionsLoader = new DataLoader<\n { projectId: string; channel: string },\n Set<string>\n >(async (keys) => {\n const results = new Map<string, Set<string>>();\n for (const key of keys) {\n const cacheKey = `${key.projectId}:${key.channel}`;\n if (results.has(cacheKey)) continue;\n try {\n const rows = await this.db\n .select({ target: suppressions.target })\n .from(suppressions)\n .where(\n and(\n eq(suppressions.projectId, key.projectId),\n eq(suppressions.channel, key.channel as any),\n ),\n );\n results.set(\n cacheKey,\n new Set(rows.map((r: { target: string }) => normaliseTarget(r.target))),\n );\n } catch (err) {\n // A suppression lookup that fails must not silently become \"nothing\n // is suppressed\" — that would resume mailing people who opted out.\n this.logger.error(\n { err, projectId: key.projectId, channel: key.channel },\n \"suppression lookup failed — holding message\",\n );\n throw err;\n }\n }\n return keys.map((key) => results.get(`${key.projectId}:${key.channel}`) ?? new Set<string>());\n });\n\n async process(message: StreamMessage): Promise<void> {\n const { event } = message;\n\n const payloadResult = this.registry.safeParsePayload(\"notification.enriched\", event.payload);\n if (!payloadResult.success) {\n this.logger.warn(\n { messageId: message.id, issues: payloadResult.error.issues },\n \"invalid notification.enriched payload — skipping\",\n );\n return;\n }\n\n const enriched = payloadResult.data as NotificationEnrichedPayload;\n\n // Idempotency\n const idempotencyKey = `${enriched.rawEventId}:${enriched.recipientId}:${enriched.channel}`;\n let customTtl: number | undefined;\n if (enriched.scheduledAt) {\n const msUntil = new Date(enriched.scheduledAt).getTime() - Date.now();\n if (msUntil > 0) {\n // base 24h (86400) + schedule time\n customTtl = 86400 + Math.ceil(msUntil / 1000);\n }\n }\n\n if (!(await this.idempotency.checkAndMark(idempotencyKey, 60))) {\n this.logger.debug({ messageId: message.id, eventId: event.id }, \"duplicate — skipping\");\n return;\n }\n\n try {\n // Opt-in check\n if (enriched.recipient.preferences.optedOut) {\n this.logger.info(\n { messageId: message.id, recipientId: enriched.recipientId, eventType: event.type },\n \"user opted out — dropping\",\n );\n this.globalEmitter.emit(\"notification:skipped\", {\n projectId: enriched.projectId,\n eventId: event.id,\n recipientId: enriched.recipientId,\n reason: \"user_opted_out\",\n });\n await this.idempotency.markProcessed(idempotencyKey, customTtl);\n return;\n }\n\n if (enriched.recipient.preferences.channels?.includes(enriched.channel)) {\n this.logger.info(\n { messageId: message.id, recipientId: enriched.recipientId, channel: enriched.channel },\n \"user disabled notification channel — dropping\",\n );\n this.globalEmitter.emit(\"notification:skipped\", {\n projectId: enriched.projectId,\n eventId: event.id,\n recipientId: enriched.recipientId,\n reason: \"channel_disabled\",\n });\n await this.idempotency.markProcessed(idempotencyKey, customTtl);\n return;\n }\n\n // Quiet hours check\n const qh = enriched.recipient.preferences.quietHours;\n if (qh && qh.length > 0 && enriched.priority !== \"critical\") {\n const qhResult = isInQuietHours(enriched.recipient.timezone, qh);\n if (qhResult.inQuietHours && qhResult.nextActiveTime) {\n this.logger.info(\n {\n messageId: message.id,\n recipientId: enriched.recipientId,\n nextActiveTime: qhResult.nextActiveTime.toISOString(),\n },\n \"user is in quiet hours — deferring notification\",\n );\n enriched.scheduledAt = qhResult.nextActiveTime.toISOString();\n }\n }\n\n // Rate limit. Per-project overrides win over the process-wide default;\n // a lookup failure must not drop the notification, so fall back rather\n // than propagate.\n let projectThrottle: { throttleLimit: number | null; throttleWindowHours: number | null } = {\n throttleLimit: null,\n throttleWindowHours: null,\n };\n try {\n projectThrottle = await this.projectSettings.get(enriched.projectId);\n } catch (err) {\n this.logger.warn(\n { err, projectId: enriched.projectId },\n \"could not read project throttle settings — falling back to the global default\",\n );\n }\n\n const throttleResult = await this.throttle.check(\n enriched.projectId,\n enriched.recipientId,\n enriched.priority,\n {\n limit: projectThrottle.throttleLimit,\n windowHours: projectThrottle.throttleWindowHours,\n scheduledAt: enriched.scheduledAt,\n },\n );\n if (!throttleResult.allowed) {\n this.logger.info(\n {\n messageId: message.id,\n recipientId: enriched.recipientId,\n count: throttleResult.count,\n limit: throttleResult.limit,\n priority: enriched.priority,\n },\n \"user throttled — dropping\",\n );\n this.globalEmitter.emit(\n \"notification:throttled\",\n enriched.recipientId,\n throttleResult.count,\n );\n await this.idempotency.markProcessed(idempotencyKey, customTtl);\n return;\n }\n\n // Gather AI Prompts\n // Gather AI Prompts\n let dbTemplate = null;\n if (enriched.templateId) {\n dbTemplate = await this.templateCache.getCachedTemplate(\n enriched.projectId,\n enriched.templateId,\n );\n if (!dbTemplate) {\n this.logger.warn(\n { messageId: message.id, templateId: enriched.templateId },\n \"template not found — dropping\",\n );\n this.globalEmitter.emit(\"notification:skipped\", {\n projectId: enriched.projectId,\n eventId: event.id,\n recipientId: enriched.recipientId,\n reason: \"template_not_found\",\n });\n await this.idempotency.markProcessed(idempotencyKey, customTtl);\n return;\n }\n }\n const aiPrompts = {\n ...(dbTemplate?.aiPrompts ?? {}),\n ...(enriched.aiPrompts ?? {}),\n };\n\n // Drives whether this message gets an unsubscribe header, and what the\n // resulting opt-out applies to.\n const templateTopics: string[] = dbTemplate?.topics ?? [];\n\n if (Object.keys(aiPrompts).length > 0) {\n const aiPendingPayload = {\n projectId: enriched.projectId,\n enrichedEventId: event.id,\n recipientId: enriched.recipientId,\n channel: enriched.channel,\n priority: enriched.priority,\n templateId: enriched.templateId,\n templateVariables: enriched.templateVariables,\n recipient: enriched.recipient,\n aiPrompts,\n scheduledAt: enriched.scheduledAt,\n fallbackChain: enriched.fallbackChain,\n };\n\n const aiPendingEnvelope = buildStreamEvent(\n \"notification.ai_pending\",\n aiPendingPayload as Record<string, unknown>,\n \"engine\",\n event.metadata.traceId,\n );\n\n await this.aiPendingProducer.publish(aiPendingEnvelope);\n this.logger.info(\n {\n messageId: message.id,\n eventId: event.id,\n recipientId: enriched.recipientId,\n traceId: event.metadata.traceId,\n },\n \"task routed to AI worker\",\n );\n await this.idempotency.markProcessed(idempotencyKey, customTtl);\n return;\n }\n\n // Render template\n const rendered = renderWithTemplate(dbTemplate, enriched.templateVariables);\n\n const allContacts = await this.contactsLoader.load({\n projectId: enriched.projectId,\n recipientId: enriched.recipientId,\n });\n const activeContacts = allContacts.filter(\n (c: any) => c.channel === enriched.channel && c.active,\n );\n\n if (activeContacts.length === 0) {\n this.logger.info(\n { messageId: message.id, recipientId: enriched.recipientId, channel: enriched.channel },\n \"no active contacts for channel — dropping\",\n );\n this.globalEmitter.emit(\"notification:skipped\", {\n projectId: enriched.projectId,\n eventId: event.id,\n recipientId: enriched.recipientId,\n reason: \"no_active_contacts\",\n });\n await this.idempotency.markProcessed(idempotencyKey, customTtl);\n return;\n }\n\n const suppressedTargets = await this.suppressionsLoader.load({\n projectId: enriched.projectId,\n channel: enriched.channel,\n });\n\n for (const contact of activeContacts) {\n if (contact.preferences?.optedOut) {\n continue;\n }\n\n // A suppression outranks every other gate, `critical` included: it\n // records that the person asked us to stop, or that the address is\n // dead. Sending anyway is what gets a domain blocked.\n if (contact.target && suppressedTargets.has(normaliseTarget(contact.target))) {\n this.logger.info(\n {\n messageId: message.id,\n recipientId: enriched.recipientId,\n channel: enriched.channel,\n },\n \"destination suppressed — dropping\",\n );\n this.globalEmitter.emit(\"notification:skipped\", {\n projectId: enriched.projectId,\n eventId: event.id,\n recipientId: enriched.recipientId,\n reason: \"suppressed\",\n });\n continue;\n }\n\n const taskId = `${enriched.rawEventId}:${contact.id || randomUUID()}`;\n const resolvedDestination = contact.target;\n\n // One-click unsubscribe headers, but only on mail that should carry\n // them. A template with no topic is transactional by this codebase's\n // own convention — a password reset, a receipt — and putting an\n // unsubscribe button on those invites people to switch off mail they\n // actually need, with no topic to scope the opt-out to anyway.\n if (\n enriched.channel === \"email\" &&\n templateTopics.length > 0 &&\n !config.UNSUBSCRIBE_SECRET\n ) {\n this.logger.warn(\n { projectId: enriched.projectId, recipientId: enriched.recipientId },\n \"UNSUBSCRIBE_SECRET is not configured — email sent without RFC 8058 one-click unsubscribe headers\",\n );\n }\n\n const unsubscribeHeaders =\n enriched.channel === \"email\" &&\n templateTopics.length > 0 &&\n config.UNSUBSCRIBE_SECRET &&\n config.PUBLIC_URL &&\n resolvedDestination\n ? buildUnsubscribeHeaders({\n claim: {\n projectId: enriched.projectId,\n userId: enriched.recipientId,\n channel: enriched.channel,\n target: resolvedDestination,\n topics: templateTopics,\n },\n secret: config.UNSUBSCRIBE_SECRET,\n publicUrl: config.PUBLIC_URL,\n })\n : undefined;\n\n const taskPayload: NotificationDispatchedPayload = {\n projectId: enriched.projectId,\n taskId,\n enrichedEventId: event.id,\n recipientId: enriched.recipientId,\n channel: enriched.channel,\n priority: enriched.priority,\n templateId: enriched.templateId,\n templateVariables: enriched.templateVariables,\n aiPrompts: enriched.aiPrompts,\n recipient: enriched.recipient,\n renderedContent: rendered,\n destination: resolvedDestination,\n deliveryOptions: {\n maxAttempts: 3,\n timeoutMs: 10_000,\n ...(unsubscribeHeaders ? { headers: unsubscribeHeaders } : {}),\n },\n fallbackChain: enriched.fallbackChain,\n campaignId: enriched.campaignId,\n };\n\n const envelope = buildStreamEvent(\n \"notification.dispatched\",\n taskPayload as Record<string, unknown>,\n \"engine\",\n event.metadata.traceId,\n );\n\n // Route by scheduledAt\n const now = Date.now();\n const scheduledAt = enriched.scheduledAt ? new Date(enriched.scheduledAt).getTime() : now;\n\n if (scheduledAt > now) {\n await this.db\n .insert(scheduledPayloads)\n .values({\n taskId,\n payload: {\n ...taskPayload,\n scheduledAt: enriched.scheduledAt,\n },\n })\n .onConflictDoNothing();\n\n const scheduledEnvelope = buildStreamEvent(\n \"notification.scheduled\",\n {\n projectId: enriched.projectId,\n enrichedEventId: event.id,\n taskId,\n scheduledAt: enriched.scheduledAt!,\n },\n \"engine\",\n event.metadata.traceId,\n );\n\n await this.scheduledProducer.publish(scheduledEnvelope);\n this.logger.info(\n {\n messageId: message.id,\n taskId,\n scheduledAt: enriched.scheduledAt,\n traceId: event.metadata.traceId,\n },\n \"task scheduled and payload cached\",\n );\n } else {\n const p = getPriorityBucket(enriched.priority);\n const outboundProducer = this.outboundProducers[p] ?? this.outboundProducers[\"normal\"]!;\n\n await outboundProducer.publish(envelope);\n this.logger.info(\n {\n messageId: message.id,\n taskId,\n recipientId: enriched.recipientId,\n traceId: event.metadata.traceId,\n },\n \"task dispatched\",\n );\n }\n }\n await this.idempotency.markProcessed(idempotencyKey, customTtl);\n } catch (err) {\n await this.idempotency.unmark(idempotencyKey).catch(() => {});\n throw err;\n }\n }\n}\n\nlet subscriber: any = null;\n\nexport async function startEngineWorker() {\n logger = createLogger({ name: \"engine\", level: config.LOG_LEVEL });\n redis = new RedisClient({ url: config.REDIS_URL, name: \"engine\", logger });\n const dbData = createDatabase({ url: config.DATABASE_URL, applicationName: \"engine\", logger });\n sql = dbData.sql;\n db = dbData.db;\n templateRepo = new TemplateRepository(db);\n templateCache = new TemplateCache(templateRepo);\n const contactRepo = new ContactRepository(db);\n consumer = new StreamConsumer({\n redis: redis.native,\n stream: ENRICHED_STREAMS as unknown as StreamName[],\n group: CONSUMER_GROUPS.ENGINE,\n consumer: `engine-${process.pid}`,\n dlqStream: STREAMS.DEAD_LETTER,\n batchSize: config.WORKER_CONCURRENCY,\n logger,\n });\n\n pendingScanner = new PendingMessageScanner({\n redis: redis.native,\n stream: ENRICHED_STREAMS as unknown as StreamName[],\n group: CONSUMER_GROUPS.ENGINE,\n consumer: `engine-${process.pid}`,\n logger,\n });\n\n const outboundProducers = {\n critical: new StreamProducer({\n redis: redis.native,\n stream: STREAMS.OUTBOUND_CRITICAL,\n logger,\n }),\n normal: new StreamProducer({ redis: redis.native, stream: STREAMS.OUTBOUND_NORMAL, logger }),\n low: new StreamProducer({ redis: redis.native, stream: STREAMS.OUTBOUND_LOW, logger }),\n };\n\n const scheduledProducer = new StreamProducer({\n redis: redis.native,\n stream: STREAMS.SCHEDULED,\n logger,\n });\n\n const aiPendingProducer = new StreamProducer({\n redis: redis.native,\n stream: STREAMS.AI_PENDING,\n logger,\n });\n\n const idempotency = new IdempotencyGuard({\n redis: redis.native,\n keyPrefix: \"notif:processed:engine\",\n ttlSeconds: 86_400,\n });\n\n const throttle = new UserThrottle({\n redis: redis.native,\n maxPerHour: parseInt(process.env.RATE_LIMIT_PER_HOUR || \"100\", 10),\n });\n\n // Per-project throttle overrides, cached because this is read once per\n // notification. Stale entries expire on their own; the pub/sub subscriber\n // below only makes an admin's change take effect sooner.\n const projectRepo = new ProjectRepository(db);\n const projectSettings = new ProjectSettingsCache((projectId) =>\n projectRepo.findThrottleSettings(projectId),\n );\n\n // ─── Stage 2: Decision Engine ───────────────────────────────────────────────\n //\n // Pipeline:\n // 1. Parse payload as notification.enriched\n // 2. Idempotency check\n // 3. Check user opt-in (from enriched recipient.preferences)\n // 4. Apply per-user hourly rate limit\n // 5. Render template using user locale\n // 6. Route: if scheduledAt is future → SCHEDULED; else → OUTBOUND\n\n worker = new EngineWorker({\n consumer,\n pendingScanner,\n logger,\n concurrency: config.WORKER_CONCURRENCY,\n registry,\n idempotency,\n throttle,\n projectSettings,\n redis: redis.native,\n templateCache,\n aiPendingProducer,\n scheduledProducer,\n outboundProducers,\n globalEmitter,\n contactRepo,\n db,\n });\n\n subscriber = redis.native.duplicate();\n await subscriber.subscribe(\n PUBSUB_CHANNELS.TEMPLATE_INVALIDATED,\n PUBSUB_CHANNELS.PROJECT_INVALIDATED,\n );\n subscriber.on(\"message\", (channel: string, message: string) => {\n if (channel === PUBSUB_CHANNELS.TEMPLATE_INVALIDATED) {\n templateCache.invalidateKey(message);\n logger.info({ cacheKey: message }, \"invalidated template cache\");\n } else if (channel === PUBSUB_CHANNELS.PROJECT_INVALIDATED) {\n projectSettings.invalidate(message);\n logger.info({ projectId: message }, \"invalidated project settings cache\");\n }\n });\n\n // ─── Health check interval ──────────────────────────────────────────────────\n\n healthInterval = startHealthReporter(\"engine\", worker, redis, logger);\n\n logger.info({ env: config.NODE_ENV }, \"engine starting\");\n await worker.start();\n}\n\n// ─── Shutdown ──────────────────────────────────────────────────────────────\n\nexport async function stopEngineWorker(): Promise<void> {\n logger?.info(\"shutdown initiated\");\n if (healthInterval) {\n clearInterval(healthInterval);\n healthInterval = null;\n }\n if (subscriber) {\n subscriber.disconnect();\n subscriber = null;\n }\n if (worker) await worker.stop();\n if (sql) await sql.end();\n if (redis) await redis.disconnect();\n logger?.info(\"engine stopped\");\n}\n"],"mappings":"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"}
|