@carlonicora/nextjs-jsonapi 5.2.0 → 5.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/dist/{BlockNoteEditor-EGY4ZAAM.js → BlockNoteEditor-UJ6363LC.js} +19 -19
  2. package/dist/{BlockNoteEditor-EGY4ZAAM.js.map → BlockNoteEditor-UJ6363LC.js.map} +1 -1
  3. package/dist/{BlockNoteEditor-2QJVK2HH.mjs → BlockNoteEditor-WTSQANKI.mjs} +4 -4
  4. package/dist/{BlockNoteViewer-I2MMFH3S.js → BlockNoteViewer-EL4JFB6P.js} +3 -3
  5. package/dist/{BlockNoteViewer-I2MMFH3S.js.map → BlockNoteViewer-EL4JFB6P.js.map} +1 -1
  6. package/dist/{BlockNoteViewer-6BQXJ4TB.mjs → BlockNoteViewer-JVKWJZ6J.mjs} +2 -2
  7. package/dist/billing/index.js +441 -441
  8. package/dist/billing/index.mjs +3 -3
  9. package/dist/{chunk-3VEQ5JZJ.js → chunk-3BAM23VA.js} +847 -847
  10. package/dist/chunk-3BAM23VA.js.map +1 -0
  11. package/dist/{chunk-JEZQTZQ4.mjs → chunk-6WU74VFU.mjs} +2 -2
  12. package/dist/{chunk-S5MQDWWC.js → chunk-CRI4T47Y.js} +736 -176
  13. package/dist/chunk-CRI4T47Y.js.map +1 -0
  14. package/dist/{chunk-75MLT74B.js → chunk-EO75CV76.js} +8 -8
  15. package/dist/{chunk-75MLT74B.js.map → chunk-EO75CV76.js.map} +1 -1
  16. package/dist/{chunk-NPKFMRH5.mjs → chunk-FNTQQFLH.mjs} +2 -2
  17. package/dist/{chunk-HNOWSFM5.mjs → chunk-JQWI62NV.mjs} +563 -3
  18. package/dist/chunk-JQWI62NV.mjs.map +1 -0
  19. package/dist/{chunk-2Z3ZCYXX.mjs → chunk-MIZTWBPX.mjs} +5 -5
  20. package/dist/chunk-MIZTWBPX.mjs.map +1 -0
  21. package/dist/{chunk-YMUPTXOT.mjs → chunk-QKZUE5OF.mjs} +2 -2
  22. package/dist/{chunk-EXICQC4A.js → chunk-QQQE3N2X.js} +3 -3
  23. package/dist/{chunk-EXICQC4A.js.map → chunk-QQQE3N2X.js.map} +1 -1
  24. package/dist/{chunk-THKYH65N.js → chunk-XGTQWBDJ.js} +4 -4
  25. package/dist/{chunk-THKYH65N.js.map → chunk-XGTQWBDJ.js.map} +1 -1
  26. package/dist/client/index.d.mts +6 -39
  27. package/dist/client/index.d.ts +6 -39
  28. package/dist/client/index.js +4 -4
  29. package/dist/client/index.mjs +3 -3
  30. package/dist/components/index.d.mts +2 -2
  31. package/dist/components/index.d.ts +2 -2
  32. package/dist/components/index.js +4 -4
  33. package/dist/components/index.mjs +3 -3
  34. package/dist/contexts/index.js +4 -4
  35. package/dist/contexts/index.mjs +3 -3
  36. package/dist/core/index.d.mts +187 -1
  37. package/dist/core/index.d.ts +187 -1
  38. package/dist/core/index.js +30 -2
  39. package/dist/core/index.js.map +1 -1
  40. package/dist/core/index.mjs +29 -1
  41. package/dist/email-automation-enrollment.fields-BZvF14qx.d.mts +82 -0
  42. package/dist/email-automation-enrollment.fields-Cp3VMzFq.d.ts +82 -0
  43. package/dist/email-automations/index.css +30 -0
  44. package/dist/email-automations/index.css.map +1 -0
  45. package/dist/email-automations/index.d.mts +303 -0
  46. package/dist/email-automations/index.d.ts +303 -0
  47. package/dist/email-automations/index.js +1705 -0
  48. package/dist/email-automations/index.js.map +1 -0
  49. package/dist/email-automations/index.mjs +1705 -0
  50. package/dist/email-automations/index.mjs.map +1 -0
  51. package/dist/features/analytics/index.js +122 -122
  52. package/dist/features/analytics/index.mjs +4 -4
  53. package/dist/features/analytics/server.js +4 -4
  54. package/dist/features/analytics/server.mjs +2 -2
  55. package/dist/features/help/index.js +37 -37
  56. package/dist/features/help/index.mjs +3 -3
  57. package/dist/features/tokenusage/index.js +125 -125
  58. package/dist/features/tokenusage/index.mjs +4 -4
  59. package/dist/index.d.mts +2 -1
  60. package/dist/index.d.ts +2 -1
  61. package/dist/index.js +31 -3
  62. package/dist/index.js.map +1 -1
  63. package/dist/index.mjs +30 -2
  64. package/dist/server/index.js +3 -3
  65. package/dist/server/index.mjs +2 -2
  66. package/dist/types-70acd-8C.d.mts +39 -0
  67. package/dist/types-l8SFleXi.d.ts +39 -0
  68. package/messages/en.json +117 -0
  69. package/messages/it.json +117 -0
  70. package/package.json +11 -1
  71. package/src/components/forms/FormFieldWrapper.tsx +1 -1
  72. package/src/components/forms/FormTextarea.tsx +2 -1
  73. package/src/core/index.ts +8 -0
  74. package/src/core/registry/ModuleRegistry.ts +5 -0
  75. package/src/email-automations/index.ts +5 -0
  76. package/src/features/email-automation/EmailAutomationEnrollmentModule.ts +11 -0
  77. package/src/features/email-automation/EmailAutomationModule.ts +30 -0
  78. package/src/features/email-automation/EmailAutomationStepModule.ts +11 -0
  79. package/src/features/email-automation/EmailAutomationTriggerModule.ts +11 -0
  80. package/src/features/email-automation/components/__tests__/EmailAutomationEditor.spec.tsx +104 -0
  81. package/src/features/email-automation/components/canvas/EmailAutomationActiveSwitch.tsx +49 -0
  82. package/src/features/email-automation/components/canvas/EmailAutomationCanvas.tsx +474 -0
  83. package/src/features/email-automation/components/canvas/EmailAutomationCanvasInspector.tsx +89 -0
  84. package/src/features/email-automation/components/canvas/EmailAutomationCanvasTab.tsx +32 -0
  85. package/src/features/email-automation/components/canvas/__tests__/buildCanvasGraph.spec.ts +67 -0
  86. package/src/features/email-automation/components/canvas/buildCanvasGraph.ts +141 -0
  87. package/src/features/email-automation/components/canvas/edges/DelayEdge.tsx +68 -0
  88. package/src/features/email-automation/components/canvas/nodes/EmailStepNode.tsx +43 -0
  89. package/src/features/email-automation/components/canvas/nodes/TriggerNode.tsx +23 -0
  90. package/src/features/email-automation/components/canvas/shared/CanvasToolbar.tsx +53 -0
  91. package/src/features/email-automation/components/canvas/shared/EmptyCanvas.tsx +11 -0
  92. package/src/features/email-automation/components/canvas/shared/__tests__/autoLayout.spec.ts +42 -0
  93. package/src/features/email-automation/components/canvas/shared/__tests__/longPress.spec.ts +51 -0
  94. package/src/features/email-automation/components/canvas/shared/autoLayout.ts +55 -0
  95. package/src/features/email-automation/components/canvas/shared/index.ts +4 -0
  96. package/src/features/email-automation/components/canvas/shared/longPress.ts +57 -0
  97. package/src/features/email-automation/components/containers/EmailAutomationContainer.tsx +80 -0
  98. package/src/features/email-automation/components/containers/EmailAutomationsListContainer.tsx +27 -0
  99. package/src/features/email-automation/components/forms/EmailAutomationEditor.tsx +153 -0
  100. package/src/features/email-automation/components/forms/EmailStepEditor.tsx +151 -0
  101. package/src/features/email-automation/components/index.ts +15 -0
  102. package/src/features/email-automation/components/lists/EmailAutomationRecipientsList.tsx +90 -0
  103. package/src/features/email-automation/components/lists/EmailAutomationsList.tsx +76 -0
  104. package/src/features/email-automation/components/unsubscribe/EmailUnsubscribe.tsx +99 -0
  105. package/src/features/email-automation/components/unsubscribe/__tests__/EmailUnsubscribe.spec.tsx +55 -0
  106. package/src/features/email-automation/contexts/EmailAutomationContext.tsx +175 -0
  107. package/src/features/email-automation/data/EmailAutomation.ts +87 -0
  108. package/src/features/email-automation/data/EmailAutomationEnrollment.ts +105 -0
  109. package/src/features/email-automation/data/EmailAutomationEnrollmentInterface.ts +18 -0
  110. package/src/features/email-automation/data/EmailAutomationEnrollmentService.ts +31 -0
  111. package/src/features/email-automation/data/EmailAutomationInterface.ts +22 -0
  112. package/src/features/email-automation/data/EmailAutomationService.ts +106 -0
  113. package/src/features/email-automation/data/EmailAutomationStep.ts +104 -0
  114. package/src/features/email-automation/data/EmailAutomationStepInterface.ts +23 -0
  115. package/src/features/email-automation/data/EmailAutomationStepService.ts +80 -0
  116. package/src/features/email-automation/data/EmailAutomationTrigger.ts +28 -0
  117. package/src/features/email-automation/data/EmailAutomationTriggerInterface.ts +6 -0
  118. package/src/features/email-automation/data/__tests__/email-automation-models.spec.ts +103 -0
  119. package/src/features/email-automation/data/email-automation-enrollment.fields.ts +8 -0
  120. package/src/features/email-automation/data/email-automation.fields.ts +9 -0
  121. package/src/features/email-automation/data/index.ts +13 -0
  122. package/src/features/email-automation/hooks/index.ts +2 -0
  123. package/src/features/email-automation/hooks/useEmailAutomationEnrollmentTableStructure.tsx +126 -0
  124. package/src/features/email-automation/hooks/useEmailAutomationTableStructure.tsx +119 -0
  125. package/src/features/email-automation/index.ts +5 -0
  126. package/dist/chunk-2Z3ZCYXX.mjs.map +0 -1
  127. package/dist/chunk-3VEQ5JZJ.js.map +0 -1
  128. package/dist/chunk-HNOWSFM5.mjs.map +0 -1
  129. package/dist/chunk-S5MQDWWC.js.map +0 -1
  130. /package/dist/{BlockNoteEditor-2QJVK2HH.mjs.map → BlockNoteEditor-WTSQANKI.mjs.map} +0 -0
  131. /package/dist/{BlockNoteViewer-6BQXJ4TB.mjs.map → BlockNoteViewer-JVKWJZ6J.mjs.map} +0 -0
  132. /package/dist/{chunk-JEZQTZQ4.mjs.map → chunk-6WU74VFU.mjs.map} +0 -0
  133. /package/dist/{chunk-NPKFMRH5.mjs.map → chunk-FNTQQFLH.mjs.map} +0 -0
  134. /package/dist/{chunk-YMUPTXOT.mjs.map → chunk-QKZUE5OF.mjs.map} +0 -0
@@ -0,0 +1,175 @@
1
+ "use client";
2
+
3
+ import { createContext, ReactNode, useCallback, useContext, useEffect, useMemo, useState } from "react";
4
+ import { v4 } from "uuid";
5
+ import { EmailAutomationInterface } from "../data/EmailAutomationInterface";
6
+ import { EmailAutomationService } from "../data/EmailAutomationService";
7
+ import { EmailAutomationStepInput, EmailAutomationStepInterface } from "../data/EmailAutomationStepInterface";
8
+ import { EmailAutomationStepService } from "../data/EmailAutomationStepService";
9
+ import { EmailAutomationTriggerInterface } from "../data/EmailAutomationTriggerInterface";
10
+
11
+ /** A new step: the provider always sets `automationId` and, when absent, a fresh `id`. */
12
+ export type EmailAutomationStepCreateInput = Omit<EmailAutomationStepInput, "id" | "automationId"> & {
13
+ id?: string;
14
+ automationId?: string;
15
+ };
16
+ /** A step update: the provider always sets `automationId`. */
17
+ export type EmailAutomationStepUpdateInput = Omit<EmailAutomationStepInput, "automationId"> & { automationId?: string };
18
+
19
+ export interface EmailAutomationContextType {
20
+ automation: EmailAutomationInterface | undefined;
21
+ steps: EmailAutomationStepInterface[];
22
+ reload: () => Promise<void>;
23
+ selectedStepId: string | null;
24
+ select: (id: string | null) => void;
25
+ createStep: (input: EmailAutomationStepCreateInput) => Promise<EmailAutomationStepInterface>;
26
+ updateStep: (input: EmailAutomationStepUpdateInput) => Promise<EmailAutomationStepInterface>;
27
+ deleteStep: (id: string) => Promise<void>;
28
+ setNext: (stepId: string, nextStepId: string | null) => Promise<void>;
29
+ updatePosition: (stepId: string, x: number, y: number) => Promise<void>;
30
+ tidy: () => Promise<void>;
31
+ triggers: EmailAutomationTriggerInterface[];
32
+ }
33
+
34
+ const EmailAutomationContext = createContext<EmailAutomationContextType | undefined>(undefined);
35
+
36
+ export type EmailAutomationProviderProps = {
37
+ automationId: string;
38
+ children: ReactNode;
39
+ };
40
+
41
+ export const EmailAutomationProvider = ({ automationId, children }: EmailAutomationProviderProps) => {
42
+ const [automation, setAutomation] = useState<EmailAutomationInterface | undefined>(undefined);
43
+ const [steps, setSteps] = useState<EmailAutomationStepInterface[]>([]);
44
+ const [triggers, setTriggers] = useState<EmailAutomationTriggerInterface[]>([]);
45
+ const [selectedStepId, setSelectedStepId] = useState<string | null>(null);
46
+
47
+ const reload = useCallback(async () => {
48
+ const [loadedAutomation, loadedSteps] = await Promise.all([
49
+ EmailAutomationService.findOne({ id: automationId }),
50
+ EmailAutomationStepService.findByAutomation({ automationId }),
51
+ ]);
52
+ setAutomation(loadedAutomation);
53
+ setSteps(loadedSteps);
54
+ }, [automationId]);
55
+
56
+ useEffect(() => {
57
+ void reload();
58
+ }, [reload]);
59
+
60
+ useEffect(() => {
61
+ let active = true;
62
+ EmailAutomationService.findTriggers()
63
+ .then((list) => {
64
+ if (active) setTriggers(list);
65
+ })
66
+ .catch(() => {});
67
+ return () => {
68
+ active = false;
69
+ };
70
+ }, []);
71
+
72
+ const select = useCallback((id: string | null) => setSelectedStepId(id), []);
73
+
74
+ const createStep = useCallback(
75
+ async (input: EmailAutomationStepCreateInput) => {
76
+ const saved = await EmailAutomationStepService.create({ ...input, id: input.id ?? v4(), automationId });
77
+ await reload();
78
+ return saved;
79
+ },
80
+ [automationId, reload],
81
+ );
82
+
83
+ const updateStep = useCallback(
84
+ async (input: EmailAutomationStepUpdateInput) => {
85
+ const saved = await EmailAutomationStepService.update({ ...input, automationId });
86
+ await reload();
87
+ return saved;
88
+ },
89
+ [automationId, reload],
90
+ );
91
+
92
+ const deleteStep = useCallback(
93
+ async (id: string) => {
94
+ await EmailAutomationStepService.delete({ id });
95
+ if (selectedStepId === id) setSelectedStepId(null);
96
+ await reload();
97
+ },
98
+ [reload, selectedStepId],
99
+ );
100
+
101
+ const setNext = useCallback(
102
+ async (stepId: string, nextStepId: string | null) => {
103
+ if (nextStepId) await EmailAutomationStepService.setNext({ stepId, nextStepId });
104
+ else await EmailAutomationStepService.clearNext({ stepId });
105
+ await reload();
106
+ },
107
+ [reload],
108
+ );
109
+
110
+ // PATCH with the step's current attributes plus the new position: the step
111
+ // input type requires subject and body, and sending them unchanged is a no-op.
112
+ const updatePosition = useCallback(
113
+ async (stepId: string, x: number, y: number) => {
114
+ const step = steps.find((candidate) => candidate.id === stepId);
115
+ if (!step) return;
116
+ await EmailAutomationStepService.update({
117
+ id: step.id,
118
+ automationId,
119
+ subject: step.subject,
120
+ body: step.body,
121
+ delayHours: step.delayHours,
122
+ positionX: x,
123
+ positionY: y,
124
+ });
125
+ await reload();
126
+ },
127
+ [automationId, reload, steps],
128
+ );
129
+
130
+ const tidy = useCallback(async () => {
131
+ await EmailAutomationService.tidy({ id: automationId });
132
+ await reload();
133
+ }, [automationId, reload]);
134
+
135
+ const value = useMemo<EmailAutomationContextType>(
136
+ () => ({
137
+ automation,
138
+ steps,
139
+ reload,
140
+ selectedStepId,
141
+ select,
142
+ createStep,
143
+ updateStep,
144
+ deleteStep,
145
+ setNext,
146
+ updatePosition,
147
+ tidy,
148
+ triggers,
149
+ }),
150
+ [
151
+ automation,
152
+ steps,
153
+ reload,
154
+ selectedStepId,
155
+ select,
156
+ createStep,
157
+ updateStep,
158
+ deleteStep,
159
+ setNext,
160
+ updatePosition,
161
+ tidy,
162
+ triggers,
163
+ ],
164
+ );
165
+
166
+ return <EmailAutomationContext.Provider value={value}>{children}</EmailAutomationContext.Provider>;
167
+ };
168
+
169
+ export const useEmailAutomation = (): EmailAutomationContextType => {
170
+ const context = useContext(EmailAutomationContext);
171
+ if (context === undefined) {
172
+ throw new Error("useEmailAutomation must be used within an EmailAutomationProvider");
173
+ }
174
+ return context;
175
+ };
@@ -0,0 +1,87 @@
1
+ import { AbstractApiData, JsonApiHydratedDataInterface, Modules } from "../../../core";
2
+ import { EmailAutomationInput, EmailAutomationInterface } from "./EmailAutomationInterface";
3
+
4
+ export class EmailAutomation extends AbstractApiData implements EmailAutomationInterface {
5
+ private _name?: string;
6
+ private _trigger?: string;
7
+ private _exitTrigger?: string;
8
+ private _replyTo?: string;
9
+ private _isActive: boolean = false;
10
+ private _stepCount?: number;
11
+ private _activeCount?: number;
12
+ private _completedCount?: number;
13
+ private _unsubscribedCount?: number;
14
+
15
+ get name(): string {
16
+ return this._name ?? "";
17
+ }
18
+
19
+ get trigger(): string | undefined {
20
+ return this._trigger;
21
+ }
22
+
23
+ get exitTrigger(): string | undefined {
24
+ return this._exitTrigger;
25
+ }
26
+
27
+ get replyTo(): string | undefined {
28
+ return this._replyTo;
29
+ }
30
+
31
+ get isActive(): boolean {
32
+ return this._isActive;
33
+ }
34
+
35
+ get stepCount(): number {
36
+ return this._stepCount ?? 0;
37
+ }
38
+
39
+ get activeCount(): number {
40
+ return this._activeCount ?? 0;
41
+ }
42
+
43
+ get completedCount(): number {
44
+ return this._completedCount ?? 0;
45
+ }
46
+
47
+ get unsubscribedCount(): number {
48
+ return this._unsubscribedCount ?? 0;
49
+ }
50
+
51
+ rehydrate(data: JsonApiHydratedDataInterface): this {
52
+ super.rehydrate(data);
53
+
54
+ this._name = data.jsonApi.attributes.name;
55
+ this._trigger = data.jsonApi.attributes.trigger ?? undefined;
56
+ this._exitTrigger = data.jsonApi.attributes.exitTrigger ?? undefined;
57
+ this._replyTo = data.jsonApi.attributes.replyTo ?? undefined;
58
+ this._isActive = data.jsonApi.attributes.isActive === true;
59
+ this._stepCount = data.jsonApi.attributes.stepCount;
60
+ this._activeCount = data.jsonApi.attributes.activeCount;
61
+ this._completedCount = data.jsonApi.attributes.completedCount;
62
+ this._unsubscribedCount = data.jsonApi.attributes.unsubscribedCount;
63
+
64
+ return this;
65
+ }
66
+
67
+ createJsonApi(data: EmailAutomationInput) {
68
+ const response: any = {
69
+ data: {
70
+ type: Modules.EmailAutomation.name,
71
+ id: data.id,
72
+ attributes: {},
73
+ meta: {},
74
+ relationships: {},
75
+ },
76
+ included: [],
77
+ };
78
+
79
+ if (data.name !== undefined) response.data.attributes.name = data.name;
80
+ if (data.trigger !== undefined) response.data.attributes.trigger = data.trigger;
81
+ if (data.exitTrigger !== undefined) response.data.attributes.exitTrigger = data.exitTrigger;
82
+ if (data.replyTo !== undefined) response.data.attributes.replyTo = data.replyTo;
83
+ if (data.isActive !== undefined) response.data.attributes.isActive = data.isActive;
84
+
85
+ return response;
86
+ }
87
+ }
@@ -0,0 +1,105 @@
1
+ import { AbstractApiData, JsonApiHydratedDataInterface, Modules } from "../../../core";
2
+ import {
3
+ EmailAutomationEnrollmentInterface,
4
+ EmailAutomationEnrollmentStatus,
5
+ } from "./EmailAutomationEnrollmentInterface";
6
+ import { EmailAutomationInterface } from "./EmailAutomationInterface";
7
+
8
+ /** JSON:API type of the POST email-automations/unsubscribe/:token request body (not a module: nothing is stored). */
9
+ export const EMAIL_AUTOMATION_UNSUBSCRIBE_TYPE = "email-automation-unsubscribes";
10
+
11
+ export class EmailAutomationEnrollment extends AbstractApiData implements EmailAutomationEnrollmentInterface {
12
+ private _email?: string;
13
+ private _name?: string;
14
+ private _status: EmailAutomationEnrollmentStatus = "active";
15
+ private _enrolledAt?: Date;
16
+ private _nextSendAt?: Date;
17
+ private _finishedAt?: Date;
18
+ private _attempts?: number;
19
+ private _lastError?: string;
20
+ private _currentStepSubject?: string;
21
+ private _sentCount?: number;
22
+ private _automation?: EmailAutomationInterface;
23
+
24
+ get email(): string {
25
+ return this._email ?? "";
26
+ }
27
+
28
+ get name(): string | undefined {
29
+ return this._name;
30
+ }
31
+
32
+ get status(): EmailAutomationEnrollmentStatus {
33
+ return this._status;
34
+ }
35
+
36
+ get enrolledAt(): Date {
37
+ return this._enrolledAt ?? new Date(0);
38
+ }
39
+
40
+ get nextSendAt(): Date | undefined {
41
+ return this._nextSendAt;
42
+ }
43
+
44
+ get finishedAt(): Date | undefined {
45
+ return this._finishedAt;
46
+ }
47
+
48
+ get attempts(): number {
49
+ return this._attempts ?? 0;
50
+ }
51
+
52
+ get lastError(): string | undefined {
53
+ return this._lastError;
54
+ }
55
+
56
+ get currentStepSubject(): string | undefined {
57
+ return this._currentStepSubject;
58
+ }
59
+
60
+ get sentCount(): number {
61
+ return this._sentCount ?? 0;
62
+ }
63
+
64
+ get automation(): EmailAutomationInterface | undefined {
65
+ return this._automation;
66
+ }
67
+
68
+ rehydrate(data: JsonApiHydratedDataInterface): this {
69
+ super.rehydrate(data);
70
+
71
+ const attributes = data.jsonApi.attributes;
72
+ this._email = attributes.email;
73
+ this._name = attributes.name ?? undefined;
74
+ this._status = attributes.status ?? "active";
75
+ this._enrolledAt = attributes.enrolledAt ? new Date(attributes.enrolledAt) : undefined;
76
+ this._nextSendAt = attributes.nextSendAt ? new Date(attributes.nextSendAt) : undefined;
77
+ this._finishedAt = attributes.finishedAt ? new Date(attributes.finishedAt) : undefined;
78
+ this._attempts = attributes.attempts;
79
+ this._lastError = attributes.lastError ?? undefined;
80
+ this._currentStepSubject = attributes.currentStepSubject ?? undefined;
81
+ this._sentCount = attributes.sentCount;
82
+
83
+ this._automation = this._readIncluded(data, "automation", Modules.EmailAutomation) as EmailAutomationInterface;
84
+
85
+ return this;
86
+ }
87
+
88
+ createJsonApi(_data?: any): any {
89
+ throw new Error("EmailAutomationEnrollment is created by the API and cannot be created from the client");
90
+ }
91
+
92
+ /**
93
+ * Body of POST email-automations/unsubscribe/:token.
94
+ */
95
+ createUnsubscribeJsonApi(params: { scope: "automation" | "all" }) {
96
+ return {
97
+ data: {
98
+ type: EMAIL_AUTOMATION_UNSUBSCRIBE_TYPE,
99
+ attributes: {
100
+ scope: params.scope,
101
+ },
102
+ },
103
+ };
104
+ }
105
+ }
@@ -0,0 +1,18 @@
1
+ import { ApiDataInterface } from "../../../core";
2
+ import { EmailAutomationInterface } from "./EmailAutomationInterface";
3
+
4
+ export type EmailAutomationEnrollmentStatus = "active" | "completed" | "unsubscribed" | "exited" | "failed";
5
+
6
+ export interface EmailAutomationEnrollmentInterface extends ApiDataInterface {
7
+ get email(): string;
8
+ get name(): string | undefined;
9
+ get status(): EmailAutomationEnrollmentStatus;
10
+ get enrolledAt(): Date;
11
+ get nextSendAt(): Date | undefined;
12
+ get finishedAt(): Date | undefined;
13
+ get attempts(): number;
14
+ get lastError(): string | undefined;
15
+ get currentStepSubject(): string | undefined;
16
+ get sentCount(): number;
17
+ get automation(): EmailAutomationInterface | undefined;
18
+ }
@@ -0,0 +1,31 @@
1
+ import { AbstractService, EndpointCreator, HttpMethod, Modules } from "../../../core";
2
+ import { EmailAutomationEnrollment } from "./EmailAutomationEnrollment";
3
+ import { EmailAutomationEnrollmentInterface } from "./EmailAutomationEnrollmentInterface";
4
+
5
+ export class EmailAutomationEnrollmentService extends AbstractService {
6
+ /**
7
+ * POST email-automations/unsubscribe/:token (public). The scope travels both as
8
+ * a query parameter and in the body, as the API reads either.
9
+ */
10
+ static async unsubscribe(params: {
11
+ token: string;
12
+ scope: "automation" | "all";
13
+ }): Promise<EmailAutomationEnrollmentInterface> {
14
+ const enrollment = new EmailAutomationEnrollment();
15
+ const endpoint = new EndpointCreator({
16
+ endpoint: Modules.EmailAutomation,
17
+ childEndpoint: "unsubscribe",
18
+ childId: params.token,
19
+ });
20
+
21
+ endpoint.addAdditionalParam("scope", params.scope);
22
+
23
+ return this.callApi<EmailAutomationEnrollmentInterface>({
24
+ type: Modules.EmailAutomationEnrollment,
25
+ method: HttpMethod.POST,
26
+ endpoint: endpoint.generate(),
27
+ input: enrollment.createUnsubscribeJsonApi({ scope: params.scope }),
28
+ overridesJsonApiCreation: true,
29
+ });
30
+ }
31
+ }
@@ -0,0 +1,22 @@
1
+ import { ApiDataInterface } from "../../../core";
2
+
3
+ export type EmailAutomationInput = {
4
+ id: string;
5
+ name: string;
6
+ trigger?: string;
7
+ exitTrigger?: string;
8
+ replyTo?: string;
9
+ isActive?: boolean;
10
+ };
11
+
12
+ export interface EmailAutomationInterface extends ApiDataInterface {
13
+ get name(): string;
14
+ get trigger(): string | undefined;
15
+ get exitTrigger(): string | undefined;
16
+ get replyTo(): string | undefined;
17
+ get isActive(): boolean;
18
+ get stepCount(): number;
19
+ get activeCount(): number;
20
+ get completedCount(): number;
21
+ get unsubscribedCount(): number;
22
+ }
@@ -0,0 +1,106 @@
1
+ import { AbstractService, EndpointCreator, HttpMethod, Modules, NextRef, PreviousRef } from "../../../core";
2
+ import { EmailAutomationEnrollmentInterface } from "./EmailAutomationEnrollmentInterface";
3
+ import { EmailAutomationInput, EmailAutomationInterface } from "./EmailAutomationInterface";
4
+ import { EmailAutomationTriggerInterface } from "./EmailAutomationTriggerInterface";
5
+
6
+ export class EmailAutomationService extends AbstractService {
7
+ static async findMany(params: { next?: NextRef; previous?: PreviousRef } = {}): Promise<EmailAutomationInterface[]> {
8
+ const endpoint = new EndpointCreator({ endpoint: Modules.EmailAutomation });
9
+
10
+ if (Modules.EmailAutomation.inclusions?.lists?.fields)
11
+ endpoint.limitToFields(Modules.EmailAutomation.inclusions.lists.fields);
12
+ if (Modules.EmailAutomation.inclusions?.lists?.types)
13
+ endpoint.limitToType(Modules.EmailAutomation.inclusions.lists.types);
14
+
15
+ return this.callApi<EmailAutomationInterface[]>({
16
+ type: Modules.EmailAutomation,
17
+ method: HttpMethod.GET,
18
+ endpoint: endpoint.generate(),
19
+ next: params.next,
20
+ previous: params.previous,
21
+ });
22
+ }
23
+
24
+ static async findOne(params: { id: string }): Promise<EmailAutomationInterface> {
25
+ return this.callApi<EmailAutomationInterface>({
26
+ type: Modules.EmailAutomation,
27
+ method: HttpMethod.GET,
28
+ endpoint: new EndpointCreator({ endpoint: Modules.EmailAutomation, id: params.id }).generate(),
29
+ });
30
+ }
31
+
32
+ static async create(params: EmailAutomationInput): Promise<EmailAutomationInterface> {
33
+ return this.callApi<EmailAutomationInterface>({
34
+ type: Modules.EmailAutomation,
35
+ method: HttpMethod.POST,
36
+ endpoint: new EndpointCreator({ endpoint: Modules.EmailAutomation }).generate(),
37
+ input: params,
38
+ });
39
+ }
40
+
41
+ static async update(params: EmailAutomationInput): Promise<EmailAutomationInterface> {
42
+ return this.callApi<EmailAutomationInterface>({
43
+ type: Modules.EmailAutomation,
44
+ method: HttpMethod.PATCH,
45
+ endpoint: new EndpointCreator({ endpoint: Modules.EmailAutomation, id: params.id }).generate(),
46
+ input: params,
47
+ });
48
+ }
49
+
50
+ static async delete(params: { id: string }): Promise<void> {
51
+ await this.callApi({
52
+ type: Modules.EmailAutomation,
53
+ method: HttpMethod.DELETE,
54
+ endpoint: new EndpointCreator({ endpoint: Modules.EmailAutomation, id: params.id }).generate(),
55
+ });
56
+ }
57
+
58
+ /**
59
+ * GET email-automations/triggers: the triggers the app declared to the API.
60
+ */
61
+ static async findTriggers(): Promise<EmailAutomationTriggerInterface[]> {
62
+ return this.callApi<EmailAutomationTriggerInterface[]>({
63
+ type: Modules.EmailAutomationTrigger,
64
+ method: HttpMethod.GET,
65
+ endpoint: new EndpointCreator({ endpoint: Modules.EmailAutomation, id: "triggers" }).generate(),
66
+ });
67
+ }
68
+
69
+ /**
70
+ * POST email-automations/:id/tidy: clears every manual step position. Replies 204.
71
+ */
72
+ static async tidy(params: { id: string }): Promise<void> {
73
+ await this.callApi({
74
+ type: Modules.EmailAutomation,
75
+ method: HttpMethod.POST,
76
+ endpoint: new EndpointCreator({
77
+ endpoint: Modules.EmailAutomation,
78
+ id: params.id,
79
+ childEndpoint: "tidy",
80
+ }).generate(),
81
+ });
82
+ }
83
+
84
+ static async findEnrollments(params: {
85
+ automationId: string;
86
+ status?: string;
87
+ next?: NextRef;
88
+ previous?: PreviousRef;
89
+ }): Promise<EmailAutomationEnrollmentInterface[]> {
90
+ const endpoint = new EndpointCreator({
91
+ endpoint: Modules.EmailAutomation,
92
+ id: params.automationId,
93
+ childEndpoint: Modules.EmailAutomationEnrollment,
94
+ });
95
+
96
+ if (params.status) endpoint.addAdditionalParam("status", params.status);
97
+
98
+ return this.callApi<EmailAutomationEnrollmentInterface[]>({
99
+ type: Modules.EmailAutomationEnrollment,
100
+ method: HttpMethod.GET,
101
+ endpoint: endpoint.generate(),
102
+ next: params.next,
103
+ previous: params.previous,
104
+ });
105
+ }
106
+ }
@@ -0,0 +1,104 @@
1
+ import { AbstractApiData, JsonApiHydratedDataInterface, Modules } from "../../../core";
2
+ import { EmailAutomationInterface } from "./EmailAutomationInterface";
3
+ import { EmailAutomationStepInput, EmailAutomationStepInterface } from "./EmailAutomationStepInterface";
4
+
5
+ export class EmailAutomationStep extends AbstractApiData implements EmailAutomationStepInterface {
6
+ private _subject?: string;
7
+ private _body?: string;
8
+ private _delayHours?: number;
9
+ private _positionX?: number;
10
+ private _positionY?: number;
11
+ private _sentCount?: number;
12
+ private _automation?: EmailAutomationInterface;
13
+ private _next?: EmailAutomationStepInterface;
14
+
15
+ get subject(): string {
16
+ return this._subject ?? "";
17
+ }
18
+
19
+ get body(): string {
20
+ return this._body ?? "";
21
+ }
22
+
23
+ get delayHours(): number {
24
+ return this._delayHours ?? 0;
25
+ }
26
+
27
+ get positionX(): number | undefined {
28
+ return this._positionX;
29
+ }
30
+
31
+ get positionY(): number | undefined {
32
+ return this._positionY;
33
+ }
34
+
35
+ get sentCount(): number {
36
+ return this._sentCount ?? 0;
37
+ }
38
+
39
+ get automation(): EmailAutomationInterface | undefined {
40
+ return this._automation;
41
+ }
42
+
43
+ get next(): EmailAutomationStepInterface | undefined {
44
+ return this._next;
45
+ }
46
+
47
+ rehydrate(data: JsonApiHydratedDataInterface): this {
48
+ super.rehydrate(data);
49
+
50
+ this._subject = data.jsonApi.attributes.subject;
51
+ this._body = data.jsonApi.attributes.body;
52
+ this._delayHours = data.jsonApi.attributes.delayHours;
53
+ this._positionX = data.jsonApi.attributes.positionX ?? undefined;
54
+ this._positionY = data.jsonApi.attributes.positionY ?? undefined;
55
+ this._sentCount = data.jsonApi.attributes.sentCount;
56
+
57
+ this._automation = this._readIncluded(data, "automation", Modules.EmailAutomation) as EmailAutomationInterface;
58
+ this._next = this._readIncluded(data, "next", Modules.EmailAutomationStep) as EmailAutomationStepInterface;
59
+
60
+ return this;
61
+ }
62
+
63
+ createJsonApi(data: EmailAutomationStepInput) {
64
+ const response: any = {
65
+ data: {
66
+ type: Modules.EmailAutomationStep.name,
67
+ id: data.id,
68
+ attributes: {},
69
+ meta: {},
70
+ relationships: {},
71
+ },
72
+ included: [],
73
+ };
74
+
75
+ if (data.subject !== undefined) response.data.attributes.subject = data.subject;
76
+ if (data.body !== undefined) response.data.attributes.body = data.body;
77
+ if (data.delayHours !== undefined) response.data.attributes.delayHours = data.delayHours;
78
+ if (data.positionX !== undefined) response.data.attributes.positionX = data.positionX;
79
+ if (data.positionY !== undefined) response.data.attributes.positionY = data.positionY;
80
+
81
+ if (data.automationId) {
82
+ response.data.relationships.automation = {
83
+ data: {
84
+ type: Modules.EmailAutomation.name,
85
+ id: data.automationId,
86
+ },
87
+ };
88
+ }
89
+
90
+ return response;
91
+ }
92
+
93
+ /**
94
+ * Body of POST email-automation-steps/:stepId/next: the step the chain continues to.
95
+ */
96
+ createNextJsonApi(params: { nextStepId: string }) {
97
+ return {
98
+ data: {
99
+ type: Modules.EmailAutomationStep.name,
100
+ id: params.nextStepId,
101
+ },
102
+ };
103
+ }
104
+ }
@@ -0,0 +1,23 @@
1
+ import { ApiDataInterface } from "../../../core";
2
+ import { EmailAutomationInterface } from "./EmailAutomationInterface";
3
+
4
+ export type EmailAutomationStepInput = {
5
+ id: string;
6
+ automationId: string;
7
+ subject: string;
8
+ body: string;
9
+ delayHours?: number;
10
+ positionX?: number;
11
+ positionY?: number;
12
+ };
13
+
14
+ export interface EmailAutomationStepInterface extends ApiDataInterface {
15
+ get subject(): string;
16
+ get body(): string;
17
+ get delayHours(): number;
18
+ get positionX(): number | undefined;
19
+ get positionY(): number | undefined;
20
+ get sentCount(): number;
21
+ get automation(): EmailAutomationInterface | undefined;
22
+ get next(): EmailAutomationStepInterface | undefined;
23
+ }