@shamanic-technologies/email-domain-contract 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +79 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/schemas.d.ts +242 -0
- package/dist/schemas.d.ts.map +1 -0
- package/dist/schemas.js +166 -0
- package/dist/schemas.js.map +1 -0
- package/dist/types.d.ts +12 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +47 -0
- package/src/index.ts +23 -0
- package/src/schemas.ts +210 -0
- package/src/types.ts +22 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Shamanic Technologies
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# @shamanic-technologies/email-domain-contract
|
|
2
|
+
|
|
3
|
+
Single source of truth for the cross-provider canonical shapes used by the email-domain services:
|
|
4
|
+
|
|
5
|
+
- [postmark-service](https://github.com/shamanic-technologies/postmark-service) — transactional email via Postmark
|
|
6
|
+
- [instantly-service](https://github.com/shamanic-technologies/instantly-service) — broadcast email via Instantly.ai
|
|
7
|
+
- [email-gateway-service](https://github.com/shamanic-technologies/email-gateway-service) — domain-level router + cross-provider stats/status projection
|
|
8
|
+
|
|
9
|
+
## Why this exists
|
|
10
|
+
|
|
11
|
+
The three services historically duplicated Zod schemas (`StatusScope`, `RecipientStats`, `EmailStats`, `RepliesDetail`, `StepStats`, `ChannelStats`, `ProviderStatus`, `GlobalStatus`, `ReplyClassification`). Drift emerged: instantly-service had `cancelled` and `notSending`, postmark-service did not, email-gateway dropped them silently. This package puts the canonical shapes in one place so a change in one service forces a discussion across all of them.
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install @shamanic-technologies/email-domain-contract
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Published to the public npm registry — no `.npmrc` override or auth token needed.
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import {
|
|
25
|
+
StatusScopeSchema,
|
|
26
|
+
RecipientStatsSchema,
|
|
27
|
+
EmailStatsSchema,
|
|
28
|
+
type StatusScope,
|
|
29
|
+
type RecipientStats,
|
|
30
|
+
} from "@shamanic-technologies/email-domain-contract";
|
|
31
|
+
|
|
32
|
+
// Validate at trust boundaries (incoming webhooks, cross-service replies)
|
|
33
|
+
const validated = StatusScopeSchema.parse(rawResponse);
|
|
34
|
+
|
|
35
|
+
// Or type-only when the data was already validated upstream
|
|
36
|
+
function process(scope: StatusScope): void { /* ... */ }
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Exported schemas + types
|
|
40
|
+
|
|
41
|
+
| Schema | Type | Description |
|
|
42
|
+
|--------|------|-------------|
|
|
43
|
+
| `ReplyClassificationSchema` | `ReplyClassification` | `"positive" \| "negative" \| "neutral"` |
|
|
44
|
+
| `RepliesDetailSchema` | `RepliesDetail` | Granular reply breakdown (9 keys) |
|
|
45
|
+
| `RecipientStatsSchema` | `RecipientStats` | Recipient-level stats (COUNT DISTINCT lead) |
|
|
46
|
+
| `StepStatsSchema` | `StepStats` | Per-step breakdown (broadcast sequences) |
|
|
47
|
+
| `EmailStatsSchema` | `EmailStats` | Email-level stats (COUNT *) |
|
|
48
|
+
| `ChannelStatsSchema` | `ChannelStats` | `{ recipientStats, emailStats }` |
|
|
49
|
+
| `StatusScopeSchema` | `StatusScope` | Per-scope delivery state for one recipient |
|
|
50
|
+
| `GlobalStatusSchema` | `GlobalStatus` | Org-wide bounce/unsubscribe signals |
|
|
51
|
+
| `ProviderStatusSchema` | `ProviderStatus` | Full status payload from one provider |
|
|
52
|
+
|
|
53
|
+
## Provider-specific fields
|
|
54
|
+
|
|
55
|
+
Two fields are currently provider-specific:
|
|
56
|
+
|
|
57
|
+
- `cancelled` (on `StatusScope` and `RecipientStats`) — Instantly only (retry-stuck cancellation)
|
|
58
|
+
- `notSending` (on `RecipientStats`) — Instantly only (`not_sending_status` diagnostic)
|
|
59
|
+
|
|
60
|
+
In v1 they are **optional** so postmark-service can return responses without them. v2 will tighten them to **required** once postmark-service ships padding (`cancelled: false`, `notSending: 0`).
|
|
61
|
+
|
|
62
|
+
## Versioning
|
|
63
|
+
|
|
64
|
+
[Semantic Versioning](https://semver.org/). Breaking changes to any schema = major bump. Additions = minor.
|
|
65
|
+
|
|
66
|
+
## Publish
|
|
67
|
+
|
|
68
|
+
Pushing a `v*` tag triggers `.github/workflows/publish.yml`, which runs tests, builds, and publishes to the public npm registry with provenance attestation.
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
npm version major | minor | patch
|
|
72
|
+
git push --follow-tags
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Bootstrap publish uses a granular NPM token stored as the `NPM_TOKEN` repo secret. Once the package exists on the registry, configure [Trusted Publishing](https://docs.npmjs.com/trusted-publishers) on npmjs.com so subsequent releases use OIDC instead — then revoke `NPM_TOKEN`.
|
|
76
|
+
|
|
77
|
+
## License
|
|
78
|
+
|
|
79
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { ReplyClassificationSchema, RepliesDetailSchema, RecipientStatsSchema, StepStatsSchema, EmailStatsSchema, ChannelStatsSchema, StatusScopeSchema, GlobalStatusSchema, ProviderStatusSchema, } from "./schemas";
|
|
2
|
+
export type { ReplyClassification, RepliesDetail, RecipientStats, StepStats, EmailStats, ChannelStats, StatusScope, GlobalStatus, ProviderStatus, } from "./types";
|
|
3
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,yBAAyB,EACzB,mBAAmB,EACnB,oBAAoB,EACpB,eAAe,EACf,gBAAgB,EAChB,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,WAAW,CAAC;AAEnB,YAAY,EACV,mBAAmB,EACnB,aAAa,EACb,cAAc,EACd,SAAS,EACT,UAAU,EACV,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,cAAc,GACf,MAAM,SAAS,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ProviderStatusSchema = exports.GlobalStatusSchema = exports.StatusScopeSchema = exports.ChannelStatsSchema = exports.EmailStatsSchema = exports.StepStatsSchema = exports.RecipientStatsSchema = exports.RepliesDetailSchema = exports.ReplyClassificationSchema = void 0;
|
|
4
|
+
var schemas_1 = require("./schemas");
|
|
5
|
+
Object.defineProperty(exports, "ReplyClassificationSchema", { enumerable: true, get: function () { return schemas_1.ReplyClassificationSchema; } });
|
|
6
|
+
Object.defineProperty(exports, "RepliesDetailSchema", { enumerable: true, get: function () { return schemas_1.RepliesDetailSchema; } });
|
|
7
|
+
Object.defineProperty(exports, "RecipientStatsSchema", { enumerable: true, get: function () { return schemas_1.RecipientStatsSchema; } });
|
|
8
|
+
Object.defineProperty(exports, "StepStatsSchema", { enumerable: true, get: function () { return schemas_1.StepStatsSchema; } });
|
|
9
|
+
Object.defineProperty(exports, "EmailStatsSchema", { enumerable: true, get: function () { return schemas_1.EmailStatsSchema; } });
|
|
10
|
+
Object.defineProperty(exports, "ChannelStatsSchema", { enumerable: true, get: function () { return schemas_1.ChannelStatsSchema; } });
|
|
11
|
+
Object.defineProperty(exports, "StatusScopeSchema", { enumerable: true, get: function () { return schemas_1.StatusScopeSchema; } });
|
|
12
|
+
Object.defineProperty(exports, "GlobalStatusSchema", { enumerable: true, get: function () { return schemas_1.GlobalStatusSchema; } });
|
|
13
|
+
Object.defineProperty(exports, "ProviderStatusSchema", { enumerable: true, get: function () { return schemas_1.ProviderStatusSchema; } });
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,qCAUmB;AATjB,oHAAA,yBAAyB,OAAA;AACzB,8GAAA,mBAAmB,OAAA;AACnB,+GAAA,oBAAoB,OAAA;AACpB,0GAAA,eAAe,OAAA;AACf,2GAAA,gBAAgB,OAAA;AAChB,6GAAA,kBAAkB,OAAA;AAClB,4GAAA,iBAAiB,OAAA;AACjB,6GAAA,kBAAkB,OAAA;AAClB,+GAAA,oBAAoB,OAAA"}
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const ReplyClassificationSchema: z.ZodEnum<{
|
|
3
|
+
positive: "positive";
|
|
4
|
+
negative: "negative";
|
|
5
|
+
neutral: "neutral";
|
|
6
|
+
}>;
|
|
7
|
+
export declare const RepliesDetailSchema: z.ZodObject<{
|
|
8
|
+
interested: z.ZodNumber;
|
|
9
|
+
meetingBooked: z.ZodNumber;
|
|
10
|
+
closed: z.ZodNumber;
|
|
11
|
+
notInterested: z.ZodNumber;
|
|
12
|
+
wrongPerson: z.ZodNumber;
|
|
13
|
+
unsubscribe: z.ZodNumber;
|
|
14
|
+
neutral: z.ZodNumber;
|
|
15
|
+
autoReply: z.ZodNumber;
|
|
16
|
+
outOfOffice: z.ZodNumber;
|
|
17
|
+
}, z.core.$strip>;
|
|
18
|
+
export declare const RecipientStatsSchema: z.ZodObject<{
|
|
19
|
+
contacted: z.ZodNumber;
|
|
20
|
+
sent: z.ZodNumber;
|
|
21
|
+
delivered: z.ZodNumber;
|
|
22
|
+
opened: z.ZodNumber;
|
|
23
|
+
bounced: z.ZodNumber;
|
|
24
|
+
clicked: z.ZodNumber;
|
|
25
|
+
unsubscribed: z.ZodNumber;
|
|
26
|
+
notSending: z.ZodOptional<z.ZodNumber>;
|
|
27
|
+
cancelled: z.ZodOptional<z.ZodNumber>;
|
|
28
|
+
repliesPositive: z.ZodNumber;
|
|
29
|
+
repliesNegative: z.ZodNumber;
|
|
30
|
+
repliesNeutral: z.ZodNumber;
|
|
31
|
+
repliesAutoReply: z.ZodNumber;
|
|
32
|
+
repliesDetail: z.ZodObject<{
|
|
33
|
+
interested: z.ZodNumber;
|
|
34
|
+
meetingBooked: z.ZodNumber;
|
|
35
|
+
closed: z.ZodNumber;
|
|
36
|
+
notInterested: z.ZodNumber;
|
|
37
|
+
wrongPerson: z.ZodNumber;
|
|
38
|
+
unsubscribe: z.ZodNumber;
|
|
39
|
+
neutral: z.ZodNumber;
|
|
40
|
+
autoReply: z.ZodNumber;
|
|
41
|
+
outOfOffice: z.ZodNumber;
|
|
42
|
+
}, z.core.$strip>;
|
|
43
|
+
}, z.core.$strip>;
|
|
44
|
+
export declare const StepStatsSchema: z.ZodObject<{
|
|
45
|
+
step: z.ZodNumber;
|
|
46
|
+
sent: z.ZodNumber;
|
|
47
|
+
delivered: z.ZodNumber;
|
|
48
|
+
opened: z.ZodNumber;
|
|
49
|
+
clicked: z.ZodNumber;
|
|
50
|
+
bounced: z.ZodNumber;
|
|
51
|
+
unsubscribed: z.ZodNumber;
|
|
52
|
+
repliesPositive: z.ZodNumber;
|
|
53
|
+
repliesNegative: z.ZodNumber;
|
|
54
|
+
repliesNeutral: z.ZodNumber;
|
|
55
|
+
repliesAutoReply: z.ZodNumber;
|
|
56
|
+
repliesDetail: z.ZodObject<{
|
|
57
|
+
interested: z.ZodNumber;
|
|
58
|
+
meetingBooked: z.ZodNumber;
|
|
59
|
+
closed: z.ZodNumber;
|
|
60
|
+
notInterested: z.ZodNumber;
|
|
61
|
+
wrongPerson: z.ZodNumber;
|
|
62
|
+
unsubscribe: z.ZodNumber;
|
|
63
|
+
neutral: z.ZodNumber;
|
|
64
|
+
autoReply: z.ZodNumber;
|
|
65
|
+
outOfOffice: z.ZodNumber;
|
|
66
|
+
}, z.core.$strip>;
|
|
67
|
+
}, z.core.$strip>;
|
|
68
|
+
export declare const EmailStatsSchema: z.ZodObject<{
|
|
69
|
+
sent: z.ZodNumber;
|
|
70
|
+
delivered: z.ZodNumber;
|
|
71
|
+
opened: z.ZodNumber;
|
|
72
|
+
clicked: z.ZodNumber;
|
|
73
|
+
bounced: z.ZodNumber;
|
|
74
|
+
unsubscribed: z.ZodNumber;
|
|
75
|
+
stepStats: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
76
|
+
step: z.ZodNumber;
|
|
77
|
+
sent: z.ZodNumber;
|
|
78
|
+
delivered: z.ZodNumber;
|
|
79
|
+
opened: z.ZodNumber;
|
|
80
|
+
clicked: z.ZodNumber;
|
|
81
|
+
bounced: z.ZodNumber;
|
|
82
|
+
unsubscribed: z.ZodNumber;
|
|
83
|
+
repliesPositive: z.ZodNumber;
|
|
84
|
+
repliesNegative: z.ZodNumber;
|
|
85
|
+
repliesNeutral: z.ZodNumber;
|
|
86
|
+
repliesAutoReply: z.ZodNumber;
|
|
87
|
+
repliesDetail: z.ZodObject<{
|
|
88
|
+
interested: z.ZodNumber;
|
|
89
|
+
meetingBooked: z.ZodNumber;
|
|
90
|
+
closed: z.ZodNumber;
|
|
91
|
+
notInterested: z.ZodNumber;
|
|
92
|
+
wrongPerson: z.ZodNumber;
|
|
93
|
+
unsubscribe: z.ZodNumber;
|
|
94
|
+
neutral: z.ZodNumber;
|
|
95
|
+
autoReply: z.ZodNumber;
|
|
96
|
+
outOfOffice: z.ZodNumber;
|
|
97
|
+
}, z.core.$strip>;
|
|
98
|
+
}, z.core.$strip>>>;
|
|
99
|
+
}, z.core.$strip>;
|
|
100
|
+
export declare const ChannelStatsSchema: z.ZodObject<{
|
|
101
|
+
recipientStats: z.ZodObject<{
|
|
102
|
+
contacted: z.ZodNumber;
|
|
103
|
+
sent: z.ZodNumber;
|
|
104
|
+
delivered: z.ZodNumber;
|
|
105
|
+
opened: z.ZodNumber;
|
|
106
|
+
bounced: z.ZodNumber;
|
|
107
|
+
clicked: z.ZodNumber;
|
|
108
|
+
unsubscribed: z.ZodNumber;
|
|
109
|
+
notSending: z.ZodOptional<z.ZodNumber>;
|
|
110
|
+
cancelled: z.ZodOptional<z.ZodNumber>;
|
|
111
|
+
repliesPositive: z.ZodNumber;
|
|
112
|
+
repliesNegative: z.ZodNumber;
|
|
113
|
+
repliesNeutral: z.ZodNumber;
|
|
114
|
+
repliesAutoReply: z.ZodNumber;
|
|
115
|
+
repliesDetail: z.ZodObject<{
|
|
116
|
+
interested: z.ZodNumber;
|
|
117
|
+
meetingBooked: z.ZodNumber;
|
|
118
|
+
closed: z.ZodNumber;
|
|
119
|
+
notInterested: z.ZodNumber;
|
|
120
|
+
wrongPerson: z.ZodNumber;
|
|
121
|
+
unsubscribe: z.ZodNumber;
|
|
122
|
+
neutral: z.ZodNumber;
|
|
123
|
+
autoReply: z.ZodNumber;
|
|
124
|
+
outOfOffice: z.ZodNumber;
|
|
125
|
+
}, z.core.$strip>;
|
|
126
|
+
}, z.core.$strip>;
|
|
127
|
+
emailStats: z.ZodObject<{
|
|
128
|
+
sent: z.ZodNumber;
|
|
129
|
+
delivered: z.ZodNumber;
|
|
130
|
+
opened: z.ZodNumber;
|
|
131
|
+
clicked: z.ZodNumber;
|
|
132
|
+
bounced: z.ZodNumber;
|
|
133
|
+
unsubscribed: z.ZodNumber;
|
|
134
|
+
stepStats: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
135
|
+
step: z.ZodNumber;
|
|
136
|
+
sent: z.ZodNumber;
|
|
137
|
+
delivered: z.ZodNumber;
|
|
138
|
+
opened: z.ZodNumber;
|
|
139
|
+
clicked: z.ZodNumber;
|
|
140
|
+
bounced: z.ZodNumber;
|
|
141
|
+
unsubscribed: z.ZodNumber;
|
|
142
|
+
repliesPositive: z.ZodNumber;
|
|
143
|
+
repliesNegative: z.ZodNumber;
|
|
144
|
+
repliesNeutral: z.ZodNumber;
|
|
145
|
+
repliesAutoReply: z.ZodNumber;
|
|
146
|
+
repliesDetail: z.ZodObject<{
|
|
147
|
+
interested: z.ZodNumber;
|
|
148
|
+
meetingBooked: z.ZodNumber;
|
|
149
|
+
closed: z.ZodNumber;
|
|
150
|
+
notInterested: z.ZodNumber;
|
|
151
|
+
wrongPerson: z.ZodNumber;
|
|
152
|
+
unsubscribe: z.ZodNumber;
|
|
153
|
+
neutral: z.ZodNumber;
|
|
154
|
+
autoReply: z.ZodNumber;
|
|
155
|
+
outOfOffice: z.ZodNumber;
|
|
156
|
+
}, z.core.$strip>;
|
|
157
|
+
}, z.core.$strip>>>;
|
|
158
|
+
}, z.core.$strip>;
|
|
159
|
+
}, z.core.$strip>;
|
|
160
|
+
export declare const StatusScopeSchema: z.ZodObject<{
|
|
161
|
+
contacted: z.ZodBoolean;
|
|
162
|
+
sent: z.ZodBoolean;
|
|
163
|
+
delivered: z.ZodBoolean;
|
|
164
|
+
opened: z.ZodBoolean;
|
|
165
|
+
clicked: z.ZodBoolean;
|
|
166
|
+
replied: z.ZodBoolean;
|
|
167
|
+
replyClassification: z.ZodNullable<z.ZodEnum<{
|
|
168
|
+
positive: "positive";
|
|
169
|
+
negative: "negative";
|
|
170
|
+
neutral: "neutral";
|
|
171
|
+
}>>;
|
|
172
|
+
bounced: z.ZodBoolean;
|
|
173
|
+
unsubscribed: z.ZodBoolean;
|
|
174
|
+
cancelled: z.ZodOptional<z.ZodBoolean>;
|
|
175
|
+
lastDeliveredAt: z.ZodNullable<z.ZodString>;
|
|
176
|
+
}, z.core.$strip>;
|
|
177
|
+
export declare const GlobalStatusSchema: z.ZodObject<{
|
|
178
|
+
email: z.ZodObject<{
|
|
179
|
+
bounced: z.ZodBoolean;
|
|
180
|
+
unsubscribed: z.ZodBoolean;
|
|
181
|
+
}, z.core.$strip>;
|
|
182
|
+
}, z.core.$strip>;
|
|
183
|
+
export declare const ProviderStatusSchema: z.ZodObject<{
|
|
184
|
+
byCampaign: z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
185
|
+
contacted: z.ZodBoolean;
|
|
186
|
+
sent: z.ZodBoolean;
|
|
187
|
+
delivered: z.ZodBoolean;
|
|
188
|
+
opened: z.ZodBoolean;
|
|
189
|
+
clicked: z.ZodBoolean;
|
|
190
|
+
replied: z.ZodBoolean;
|
|
191
|
+
replyClassification: z.ZodNullable<z.ZodEnum<{
|
|
192
|
+
positive: "positive";
|
|
193
|
+
negative: "negative";
|
|
194
|
+
neutral: "neutral";
|
|
195
|
+
}>>;
|
|
196
|
+
bounced: z.ZodBoolean;
|
|
197
|
+
unsubscribed: z.ZodBoolean;
|
|
198
|
+
cancelled: z.ZodOptional<z.ZodBoolean>;
|
|
199
|
+
lastDeliveredAt: z.ZodNullable<z.ZodString>;
|
|
200
|
+
}, z.core.$strip>>>;
|
|
201
|
+
campaign: z.ZodNullable<z.ZodObject<{
|
|
202
|
+
contacted: z.ZodBoolean;
|
|
203
|
+
sent: z.ZodBoolean;
|
|
204
|
+
delivered: z.ZodBoolean;
|
|
205
|
+
opened: z.ZodBoolean;
|
|
206
|
+
clicked: z.ZodBoolean;
|
|
207
|
+
replied: z.ZodBoolean;
|
|
208
|
+
replyClassification: z.ZodNullable<z.ZodEnum<{
|
|
209
|
+
positive: "positive";
|
|
210
|
+
negative: "negative";
|
|
211
|
+
neutral: "neutral";
|
|
212
|
+
}>>;
|
|
213
|
+
bounced: z.ZodBoolean;
|
|
214
|
+
unsubscribed: z.ZodBoolean;
|
|
215
|
+
cancelled: z.ZodOptional<z.ZodBoolean>;
|
|
216
|
+
lastDeliveredAt: z.ZodNullable<z.ZodString>;
|
|
217
|
+
}, z.core.$strip>>;
|
|
218
|
+
brand: z.ZodNullable<z.ZodObject<{
|
|
219
|
+
contacted: z.ZodBoolean;
|
|
220
|
+
sent: z.ZodBoolean;
|
|
221
|
+
delivered: z.ZodBoolean;
|
|
222
|
+
opened: z.ZodBoolean;
|
|
223
|
+
clicked: z.ZodBoolean;
|
|
224
|
+
replied: z.ZodBoolean;
|
|
225
|
+
replyClassification: z.ZodNullable<z.ZodEnum<{
|
|
226
|
+
positive: "positive";
|
|
227
|
+
negative: "negative";
|
|
228
|
+
neutral: "neutral";
|
|
229
|
+
}>>;
|
|
230
|
+
bounced: z.ZodBoolean;
|
|
231
|
+
unsubscribed: z.ZodBoolean;
|
|
232
|
+
cancelled: z.ZodOptional<z.ZodBoolean>;
|
|
233
|
+
lastDeliveredAt: z.ZodNullable<z.ZodString>;
|
|
234
|
+
}, z.core.$strip>>;
|
|
235
|
+
global: z.ZodObject<{
|
|
236
|
+
email: z.ZodObject<{
|
|
237
|
+
bounced: z.ZodBoolean;
|
|
238
|
+
unsubscribed: z.ZodBoolean;
|
|
239
|
+
}, z.core.$strip>;
|
|
240
|
+
}, z.core.$strip>;
|
|
241
|
+
}, z.core.$strip>;
|
|
242
|
+
//# sourceMappingURL=schemas.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB,eAAO,MAAM,yBAAyB;;;;EAIpC,CAAC;AAMH,eAAO,MAAM,mBAAmB;;;;;;;;;;iBAU9B,CAAC;AAMH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;iBAgC/B,CAAC;AAOH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;iBAiB1B,CAAC;AAMH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAiB3B,CAAC;AAMH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAK7B,CAAC;AAOH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;iBAyC5B,CAAC;AAMH,eAAO,MAAM,kBAAkB;;;;;iBAW7B,CAAC;AAMH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAgB/B,CAAC"}
|
package/dist/schemas.js
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ProviderStatusSchema = exports.GlobalStatusSchema = exports.StatusScopeSchema = exports.ChannelStatsSchema = exports.EmailStatsSchema = exports.StepStatsSchema = exports.RecipientStatsSchema = exports.RepliesDetailSchema = exports.ReplyClassificationSchema = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
// Reply classification
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
exports.ReplyClassificationSchema = zod_1.z.enum([
|
|
9
|
+
"positive",
|
|
10
|
+
"negative",
|
|
11
|
+
"neutral",
|
|
12
|
+
]);
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Replies detail — granular reply breakdown by classification
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
exports.RepliesDetailSchema = zod_1.z.object({
|
|
17
|
+
interested: zod_1.z.number().describe("lead_interested events"),
|
|
18
|
+
meetingBooked: zod_1.z.number().describe("lead_meeting_booked events"),
|
|
19
|
+
closed: zod_1.z.number().describe("lead_closed events"),
|
|
20
|
+
notInterested: zod_1.z.number().describe("lead_not_interested events"),
|
|
21
|
+
wrongPerson: zod_1.z.number().describe("lead_wrong_person events"),
|
|
22
|
+
unsubscribe: zod_1.z.number().describe("lead_unsubscribed events"),
|
|
23
|
+
neutral: zod_1.z.number().describe("lead_neutral events"),
|
|
24
|
+
autoReply: zod_1.z.number().describe("auto_reply_received events"),
|
|
25
|
+
outOfOffice: zod_1.z.number().describe("lead_out_of_office events"),
|
|
26
|
+
});
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
// Recipient-level stats (COUNT DISTINCT lead)
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
exports.RecipientStatsSchema = zod_1.z.object({
|
|
31
|
+
contacted: zod_1.z
|
|
32
|
+
.number()
|
|
33
|
+
.describe("Leads added to a campaign / send attempted"),
|
|
34
|
+
sent: zod_1.z.number().describe("Leads with at least 1 email sent (COUNT DISTINCT lead)"),
|
|
35
|
+
delivered: zod_1.z.number().describe("Leads delivered (sent - bounced)"),
|
|
36
|
+
opened: zod_1.z.number().describe("Leads who opened at least 1 email"),
|
|
37
|
+
bounced: zod_1.z.number().describe("Leads with at least 1 bounce"),
|
|
38
|
+
clicked: zod_1.z.number().describe("Leads who clicked at least 1 link"),
|
|
39
|
+
unsubscribed: zod_1.z.number().describe("Leads who unsubscribed"),
|
|
40
|
+
// Provider-specific (instantly-only today; postmark padding follow-up will add).
|
|
41
|
+
notSending: zod_1.z
|
|
42
|
+
.number()
|
|
43
|
+
.optional()
|
|
44
|
+
.describe("Leads in campaigns currently flagged with Instantly's not_sending_status diagnostic. Optional in contract v1; will be required in v2 after postmark padding ships."),
|
|
45
|
+
cancelled: zod_1.z
|
|
46
|
+
.number()
|
|
47
|
+
.optional()
|
|
48
|
+
.describe("Leads whose campaign was cancelled by the retry-stuck job (delivery_status='cancelled'). Optional in contract v1; will be required in v2 after postmark padding ships."),
|
|
49
|
+
repliesPositive: zod_1.z.number().describe("interested + meetingBooked + closed"),
|
|
50
|
+
repliesNegative: zod_1.z
|
|
51
|
+
.number()
|
|
52
|
+
.describe("notInterested + wrongPerson + unsubscribe"),
|
|
53
|
+
repliesNeutral: zod_1.z.number().describe("neutral (lead_neutral events only)"),
|
|
54
|
+
repliesAutoReply: zod_1.z.number().describe("autoReply + outOfOffice"),
|
|
55
|
+
repliesDetail: exports.RepliesDetailSchema.describe("Granular reply breakdown by classification"),
|
|
56
|
+
});
|
|
57
|
+
// ---------------------------------------------------------------------------
|
|
58
|
+
// Step stats — per-step breakdown (used by Instantly broadcast sequences;
|
|
59
|
+
// always empty array for Postmark since transactional has no step concept)
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
exports.StepStatsSchema = zod_1.z.object({
|
|
62
|
+
step: zod_1.z.number().describe("Step number (1-based)"),
|
|
63
|
+
sent: zod_1.z.number().describe("Emails sent at this step"),
|
|
64
|
+
delivered: zod_1.z.number().describe("Delivered at this step (sent - bounced)"),
|
|
65
|
+
opened: zod_1.z.number().describe("Emails opened at this step"),
|
|
66
|
+
clicked: zod_1.z.number().describe("Link clicks at this step"),
|
|
67
|
+
bounced: zod_1.z.number().describe("Emails bounced at this step"),
|
|
68
|
+
unsubscribed: zod_1.z.number().describe("Unsubscribes at this step"),
|
|
69
|
+
repliesPositive: zod_1.z.number().describe("interested + meetingBooked + closed"),
|
|
70
|
+
repliesNegative: zod_1.z
|
|
71
|
+
.number()
|
|
72
|
+
.describe("notInterested + wrongPerson + unsubscribe"),
|
|
73
|
+
repliesNeutral: zod_1.z.number().describe("neutral (lead_neutral events only)"),
|
|
74
|
+
repliesAutoReply: zod_1.z.number().describe("autoReply + outOfOffice"),
|
|
75
|
+
repliesDetail: exports.RepliesDetailSchema.describe("Granular reply breakdown by classification"),
|
|
76
|
+
});
|
|
77
|
+
// ---------------------------------------------------------------------------
|
|
78
|
+
// Email-level stats (COUNT *)
|
|
79
|
+
// ---------------------------------------------------------------------------
|
|
80
|
+
exports.EmailStatsSchema = zod_1.z.object({
|
|
81
|
+
sent: zod_1.z.number().describe("Total emails sent (COUNT *, all steps)"),
|
|
82
|
+
delivered: zod_1.z.number().describe("Total emails delivered (sent - bounced)"),
|
|
83
|
+
opened: zod_1.z
|
|
84
|
+
.number()
|
|
85
|
+
.describe("Unique emails opened at least once (COUNT DISTINCT)"),
|
|
86
|
+
clicked: zod_1.z
|
|
87
|
+
.number()
|
|
88
|
+
.describe("Unique emails with at least 1 click (COUNT DISTINCT)"),
|
|
89
|
+
bounced: zod_1.z.number().describe("Total emails bounced"),
|
|
90
|
+
unsubscribed: zod_1.z.number().describe("Total unsubscribe events"),
|
|
91
|
+
stepStats: zod_1.z
|
|
92
|
+
.array(exports.StepStatsSchema)
|
|
93
|
+
.optional()
|
|
94
|
+
.describe("Per-step breakdown (instantly broadcast only; empty/omitted for postmark transactional)"),
|
|
95
|
+
});
|
|
96
|
+
// ---------------------------------------------------------------------------
|
|
97
|
+
// Channel stats — wraps recipient + email
|
|
98
|
+
// ---------------------------------------------------------------------------
|
|
99
|
+
exports.ChannelStatsSchema = zod_1.z.object({
|
|
100
|
+
recipientStats: exports.RecipientStatsSchema.describe("Recipient-level stats (COUNT DISTINCT lead)"),
|
|
101
|
+
emailStats: exports.EmailStatsSchema.describe("Email-level stats (COUNT *)"),
|
|
102
|
+
});
|
|
103
|
+
// ---------------------------------------------------------------------------
|
|
104
|
+
// Status scope — delivery state for one recipient in a given scope
|
|
105
|
+
// (per-campaign, per-brand aggregate, or per-campaign single)
|
|
106
|
+
// ---------------------------------------------------------------------------
|
|
107
|
+
exports.StatusScopeSchema = zod_1.z.object({
|
|
108
|
+
contacted: zod_1.z
|
|
109
|
+
.boolean()
|
|
110
|
+
.describe("Whether at least one sending exists in this scope"),
|
|
111
|
+
sent: zod_1.z.boolean().describe("Whether an email was sent in this scope"),
|
|
112
|
+
delivered: zod_1.z
|
|
113
|
+
.boolean()
|
|
114
|
+
.describe("Whether an email was delivered in this scope (sent AND not bounced)"),
|
|
115
|
+
opened: zod_1.z
|
|
116
|
+
.boolean()
|
|
117
|
+
.describe("Whether the recipient opened any email in this scope"),
|
|
118
|
+
clicked: zod_1.z
|
|
119
|
+
.boolean()
|
|
120
|
+
.describe("Whether the recipient clicked any link in this scope"),
|
|
121
|
+
replied: zod_1.z
|
|
122
|
+
.boolean()
|
|
123
|
+
.describe("Whether the recipient replied in this scope (always false for postmark — no reply tracking)"),
|
|
124
|
+
replyClassification: exports.ReplyClassificationSchema.nullable().describe("Classification of most recent reply: positive / negative / neutral, or null if no reply (always null for postmark)"),
|
|
125
|
+
bounced: zod_1.z.boolean().describe("Whether an email bounced in this scope"),
|
|
126
|
+
unsubscribed: zod_1.z
|
|
127
|
+
.boolean()
|
|
128
|
+
.describe("Whether the recipient unsubscribed in this scope"),
|
|
129
|
+
// Provider-specific (instantly-only today; postmark padding follow-up).
|
|
130
|
+
cancelled: zod_1.z
|
|
131
|
+
.boolean()
|
|
132
|
+
.optional()
|
|
133
|
+
.describe("Whether the campaign was cancelled by the retry-stuck job. Optional in contract v1; required in v2 after postmark padding ships."),
|
|
134
|
+
lastDeliveredAt: zod_1.z
|
|
135
|
+
.string()
|
|
136
|
+
.nullable()
|
|
137
|
+
.describe("ISO 8601 timestamp of last delivery in this scope; null if none"),
|
|
138
|
+
});
|
|
139
|
+
// ---------------------------------------------------------------------------
|
|
140
|
+
// Global status — org-wide bounce / unsubscribe signals
|
|
141
|
+
// ---------------------------------------------------------------------------
|
|
142
|
+
exports.GlobalStatusSchema = zod_1.z.object({
|
|
143
|
+
email: zod_1.z
|
|
144
|
+
.object({
|
|
145
|
+
bounced: zod_1.z
|
|
146
|
+
.boolean()
|
|
147
|
+
.describe("True if this email bounced anywhere in the org"),
|
|
148
|
+
unsubscribed: zod_1.z
|
|
149
|
+
.boolean()
|
|
150
|
+
.describe("True if this email unsubscribed anywhere in the org"),
|
|
151
|
+
})
|
|
152
|
+
.describe("Global email signals (technical/legal)"),
|
|
153
|
+
});
|
|
154
|
+
// ---------------------------------------------------------------------------
|
|
155
|
+
// Provider status — full status payload from one provider for one email
|
|
156
|
+
// ---------------------------------------------------------------------------
|
|
157
|
+
exports.ProviderStatusSchema = zod_1.z.object({
|
|
158
|
+
byCampaign: zod_1.z
|
|
159
|
+
.record(zod_1.z.string(), exports.StatusScopeSchema)
|
|
160
|
+
.nullable()
|
|
161
|
+
.describe("Per-campaign breakdown keyed by campaignId — present in brand mode, null otherwise"),
|
|
162
|
+
campaign: exports.StatusScopeSchema.nullable().describe("Status scoped to the given campaign — present in campaign mode, null otherwise"),
|
|
163
|
+
brand: exports.StatusScopeSchema.nullable().describe("Aggregated status across all campaigns for the brand — present in brand mode, null otherwise"),
|
|
164
|
+
global: exports.GlobalStatusSchema.describe("Global signals across all brands and campaigns (always present)"),
|
|
165
|
+
});
|
|
166
|
+
//# sourceMappingURL=schemas.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemas.js","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { z } from "zod";
|
|
2
|
+
import { ReplyClassificationSchema, RepliesDetailSchema, RecipientStatsSchema, StepStatsSchema, EmailStatsSchema, ChannelStatsSchema, StatusScopeSchema, GlobalStatusSchema, ProviderStatusSchema } from "./schemas";
|
|
3
|
+
export type ReplyClassification = z.infer<typeof ReplyClassificationSchema>;
|
|
4
|
+
export type RepliesDetail = z.infer<typeof RepliesDetailSchema>;
|
|
5
|
+
export type RecipientStats = z.infer<typeof RecipientStatsSchema>;
|
|
6
|
+
export type StepStats = z.infer<typeof StepStatsSchema>;
|
|
7
|
+
export type EmailStats = z.infer<typeof EmailStatsSchema>;
|
|
8
|
+
export type ChannelStats = z.infer<typeof ChannelStatsSchema>;
|
|
9
|
+
export type StatusScope = z.infer<typeof StatusScopeSchema>;
|
|
10
|
+
export type GlobalStatus = z.infer<typeof GlobalStatusSchema>;
|
|
11
|
+
export type ProviderStatus = z.infer<typeof ProviderStatusSchema>;
|
|
12
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,EACL,yBAAyB,EACzB,mBAAmB,EACnB,oBAAoB,EACpB,eAAe,EACf,gBAAgB,EAChB,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACrB,MAAM,WAAW,CAAC;AAEnB,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAC5E,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAChE,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAClE,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AACxD,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC1D,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAC9D,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAC5D,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAC9D,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@shamanic-technologies/email-domain-contract",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "Shared Zod schemas for the email domain (postmark-service, instantly-service, email-gateway). Single source of truth for cross-provider canonical shapes.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"src"
|
|
10
|
+
],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc",
|
|
13
|
+
"test": "vitest run",
|
|
14
|
+
"prepublishOnly": "npm run build"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"email",
|
|
18
|
+
"zod",
|
|
19
|
+
"contract",
|
|
20
|
+
"schema",
|
|
21
|
+
"postmark",
|
|
22
|
+
"instantly"
|
|
23
|
+
],
|
|
24
|
+
"author": "Shamanic Technologies",
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "git+https://github.com/shamanic-technologies/email-domain-contract.git"
|
|
29
|
+
},
|
|
30
|
+
"bugs": {
|
|
31
|
+
"url": "https://github.com/shamanic-technologies/email-domain-contract/issues"
|
|
32
|
+
},
|
|
33
|
+
"homepage": "https://github.com/shamanic-technologies/email-domain-contract#readme",
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"access": "public",
|
|
36
|
+
"provenance": true
|
|
37
|
+
},
|
|
38
|
+
"peerDependencies": {
|
|
39
|
+
"zod": "^4.0.0"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@types/node": "^22.13.1",
|
|
43
|
+
"typescript": "^5.7.3",
|
|
44
|
+
"vitest": "^3.0.5",
|
|
45
|
+
"zod": "^4.3.6"
|
|
46
|
+
}
|
|
47
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export {
|
|
2
|
+
ReplyClassificationSchema,
|
|
3
|
+
RepliesDetailSchema,
|
|
4
|
+
RecipientStatsSchema,
|
|
5
|
+
StepStatsSchema,
|
|
6
|
+
EmailStatsSchema,
|
|
7
|
+
ChannelStatsSchema,
|
|
8
|
+
StatusScopeSchema,
|
|
9
|
+
GlobalStatusSchema,
|
|
10
|
+
ProviderStatusSchema,
|
|
11
|
+
} from "./schemas";
|
|
12
|
+
|
|
13
|
+
export type {
|
|
14
|
+
ReplyClassification,
|
|
15
|
+
RepliesDetail,
|
|
16
|
+
RecipientStats,
|
|
17
|
+
StepStats,
|
|
18
|
+
EmailStats,
|
|
19
|
+
ChannelStats,
|
|
20
|
+
StatusScope,
|
|
21
|
+
GlobalStatus,
|
|
22
|
+
ProviderStatus,
|
|
23
|
+
} from "./types";
|
package/src/schemas.ts
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// Reply classification
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
|
|
7
|
+
export const ReplyClassificationSchema = z.enum([
|
|
8
|
+
"positive",
|
|
9
|
+
"negative",
|
|
10
|
+
"neutral",
|
|
11
|
+
]);
|
|
12
|
+
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Replies detail — granular reply breakdown by classification
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
|
|
17
|
+
export const RepliesDetailSchema = z.object({
|
|
18
|
+
interested: z.number().describe("lead_interested events"),
|
|
19
|
+
meetingBooked: z.number().describe("lead_meeting_booked events"),
|
|
20
|
+
closed: z.number().describe("lead_closed events"),
|
|
21
|
+
notInterested: z.number().describe("lead_not_interested events"),
|
|
22
|
+
wrongPerson: z.number().describe("lead_wrong_person events"),
|
|
23
|
+
unsubscribe: z.number().describe("lead_unsubscribed events"),
|
|
24
|
+
neutral: z.number().describe("lead_neutral events"),
|
|
25
|
+
autoReply: z.number().describe("auto_reply_received events"),
|
|
26
|
+
outOfOffice: z.number().describe("lead_out_of_office events"),
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
// Recipient-level stats (COUNT DISTINCT lead)
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
|
|
33
|
+
export const RecipientStatsSchema = z.object({
|
|
34
|
+
contacted: z
|
|
35
|
+
.number()
|
|
36
|
+
.describe("Leads added to a campaign / send attempted"),
|
|
37
|
+
sent: z.number().describe("Leads with at least 1 email sent (COUNT DISTINCT lead)"),
|
|
38
|
+
delivered: z.number().describe("Leads delivered (sent - bounced)"),
|
|
39
|
+
opened: z.number().describe("Leads who opened at least 1 email"),
|
|
40
|
+
bounced: z.number().describe("Leads with at least 1 bounce"),
|
|
41
|
+
clicked: z.number().describe("Leads who clicked at least 1 link"),
|
|
42
|
+
unsubscribed: z.number().describe("Leads who unsubscribed"),
|
|
43
|
+
// Provider-specific (instantly-only today; postmark padding follow-up will add).
|
|
44
|
+
notSending: z
|
|
45
|
+
.number()
|
|
46
|
+
.optional()
|
|
47
|
+
.describe(
|
|
48
|
+
"Leads in campaigns currently flagged with Instantly's not_sending_status diagnostic. Optional in contract v1; will be required in v2 after postmark padding ships.",
|
|
49
|
+
),
|
|
50
|
+
cancelled: z
|
|
51
|
+
.number()
|
|
52
|
+
.optional()
|
|
53
|
+
.describe(
|
|
54
|
+
"Leads whose campaign was cancelled by the retry-stuck job (delivery_status='cancelled'). Optional in contract v1; will be required in v2 after postmark padding ships.",
|
|
55
|
+
),
|
|
56
|
+
repliesPositive: z.number().describe("interested + meetingBooked + closed"),
|
|
57
|
+
repliesNegative: z
|
|
58
|
+
.number()
|
|
59
|
+
.describe("notInterested + wrongPerson + unsubscribe"),
|
|
60
|
+
repliesNeutral: z.number().describe("neutral (lead_neutral events only)"),
|
|
61
|
+
repliesAutoReply: z.number().describe("autoReply + outOfOffice"),
|
|
62
|
+
repliesDetail: RepliesDetailSchema.describe(
|
|
63
|
+
"Granular reply breakdown by classification",
|
|
64
|
+
),
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// ---------------------------------------------------------------------------
|
|
68
|
+
// Step stats — per-step breakdown (used by Instantly broadcast sequences;
|
|
69
|
+
// always empty array for Postmark since transactional has no step concept)
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
|
|
72
|
+
export const StepStatsSchema = z.object({
|
|
73
|
+
step: z.number().describe("Step number (1-based)"),
|
|
74
|
+
sent: z.number().describe("Emails sent at this step"),
|
|
75
|
+
delivered: z.number().describe("Delivered at this step (sent - bounced)"),
|
|
76
|
+
opened: z.number().describe("Emails opened at this step"),
|
|
77
|
+
clicked: z.number().describe("Link clicks at this step"),
|
|
78
|
+
bounced: z.number().describe("Emails bounced at this step"),
|
|
79
|
+
unsubscribed: z.number().describe("Unsubscribes at this step"),
|
|
80
|
+
repliesPositive: z.number().describe("interested + meetingBooked + closed"),
|
|
81
|
+
repliesNegative: z
|
|
82
|
+
.number()
|
|
83
|
+
.describe("notInterested + wrongPerson + unsubscribe"),
|
|
84
|
+
repliesNeutral: z.number().describe("neutral (lead_neutral events only)"),
|
|
85
|
+
repliesAutoReply: z.number().describe("autoReply + outOfOffice"),
|
|
86
|
+
repliesDetail: RepliesDetailSchema.describe(
|
|
87
|
+
"Granular reply breakdown by classification",
|
|
88
|
+
),
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// ---------------------------------------------------------------------------
|
|
92
|
+
// Email-level stats (COUNT *)
|
|
93
|
+
// ---------------------------------------------------------------------------
|
|
94
|
+
|
|
95
|
+
export const EmailStatsSchema = z.object({
|
|
96
|
+
sent: z.number().describe("Total emails sent (COUNT *, all steps)"),
|
|
97
|
+
delivered: z.number().describe("Total emails delivered (sent - bounced)"),
|
|
98
|
+
opened: z
|
|
99
|
+
.number()
|
|
100
|
+
.describe("Unique emails opened at least once (COUNT DISTINCT)"),
|
|
101
|
+
clicked: z
|
|
102
|
+
.number()
|
|
103
|
+
.describe("Unique emails with at least 1 click (COUNT DISTINCT)"),
|
|
104
|
+
bounced: z.number().describe("Total emails bounced"),
|
|
105
|
+
unsubscribed: z.number().describe("Total unsubscribe events"),
|
|
106
|
+
stepStats: z
|
|
107
|
+
.array(StepStatsSchema)
|
|
108
|
+
.optional()
|
|
109
|
+
.describe(
|
|
110
|
+
"Per-step breakdown (instantly broadcast only; empty/omitted for postmark transactional)",
|
|
111
|
+
),
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// ---------------------------------------------------------------------------
|
|
115
|
+
// Channel stats — wraps recipient + email
|
|
116
|
+
// ---------------------------------------------------------------------------
|
|
117
|
+
|
|
118
|
+
export const ChannelStatsSchema = z.object({
|
|
119
|
+
recipientStats: RecipientStatsSchema.describe(
|
|
120
|
+
"Recipient-level stats (COUNT DISTINCT lead)",
|
|
121
|
+
),
|
|
122
|
+
emailStats: EmailStatsSchema.describe("Email-level stats (COUNT *)"),
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// ---------------------------------------------------------------------------
|
|
126
|
+
// Status scope — delivery state for one recipient in a given scope
|
|
127
|
+
// (per-campaign, per-brand aggregate, or per-campaign single)
|
|
128
|
+
// ---------------------------------------------------------------------------
|
|
129
|
+
|
|
130
|
+
export const StatusScopeSchema = z.object({
|
|
131
|
+
contacted: z
|
|
132
|
+
.boolean()
|
|
133
|
+
.describe("Whether at least one sending exists in this scope"),
|
|
134
|
+
sent: z.boolean().describe("Whether an email was sent in this scope"),
|
|
135
|
+
delivered: z
|
|
136
|
+
.boolean()
|
|
137
|
+
.describe(
|
|
138
|
+
"Whether an email was delivered in this scope (sent AND not bounced)",
|
|
139
|
+
),
|
|
140
|
+
opened: z
|
|
141
|
+
.boolean()
|
|
142
|
+
.describe("Whether the recipient opened any email in this scope"),
|
|
143
|
+
clicked: z
|
|
144
|
+
.boolean()
|
|
145
|
+
.describe("Whether the recipient clicked any link in this scope"),
|
|
146
|
+
replied: z
|
|
147
|
+
.boolean()
|
|
148
|
+
.describe(
|
|
149
|
+
"Whether the recipient replied in this scope (always false for postmark — no reply tracking)",
|
|
150
|
+
),
|
|
151
|
+
replyClassification: ReplyClassificationSchema.nullable().describe(
|
|
152
|
+
"Classification of most recent reply: positive / negative / neutral, or null if no reply (always null for postmark)",
|
|
153
|
+
),
|
|
154
|
+
bounced: z.boolean().describe("Whether an email bounced in this scope"),
|
|
155
|
+
unsubscribed: z
|
|
156
|
+
.boolean()
|
|
157
|
+
.describe("Whether the recipient unsubscribed in this scope"),
|
|
158
|
+
// Provider-specific (instantly-only today; postmark padding follow-up).
|
|
159
|
+
cancelled: z
|
|
160
|
+
.boolean()
|
|
161
|
+
.optional()
|
|
162
|
+
.describe(
|
|
163
|
+
"Whether the campaign was cancelled by the retry-stuck job. Optional in contract v1; required in v2 after postmark padding ships.",
|
|
164
|
+
),
|
|
165
|
+
lastDeliveredAt: z
|
|
166
|
+
.string()
|
|
167
|
+
.nullable()
|
|
168
|
+
.describe(
|
|
169
|
+
"ISO 8601 timestamp of last delivery in this scope; null if none",
|
|
170
|
+
),
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
// ---------------------------------------------------------------------------
|
|
174
|
+
// Global status — org-wide bounce / unsubscribe signals
|
|
175
|
+
// ---------------------------------------------------------------------------
|
|
176
|
+
|
|
177
|
+
export const GlobalStatusSchema = z.object({
|
|
178
|
+
email: z
|
|
179
|
+
.object({
|
|
180
|
+
bounced: z
|
|
181
|
+
.boolean()
|
|
182
|
+
.describe("True if this email bounced anywhere in the org"),
|
|
183
|
+
unsubscribed: z
|
|
184
|
+
.boolean()
|
|
185
|
+
.describe("True if this email unsubscribed anywhere in the org"),
|
|
186
|
+
})
|
|
187
|
+
.describe("Global email signals (technical/legal)"),
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
// ---------------------------------------------------------------------------
|
|
191
|
+
// Provider status — full status payload from one provider for one email
|
|
192
|
+
// ---------------------------------------------------------------------------
|
|
193
|
+
|
|
194
|
+
export const ProviderStatusSchema = z.object({
|
|
195
|
+
byCampaign: z
|
|
196
|
+
.record(z.string(), StatusScopeSchema)
|
|
197
|
+
.nullable()
|
|
198
|
+
.describe(
|
|
199
|
+
"Per-campaign breakdown keyed by campaignId — present in brand mode, null otherwise",
|
|
200
|
+
),
|
|
201
|
+
campaign: StatusScopeSchema.nullable().describe(
|
|
202
|
+
"Status scoped to the given campaign — present in campaign mode, null otherwise",
|
|
203
|
+
),
|
|
204
|
+
brand: StatusScopeSchema.nullable().describe(
|
|
205
|
+
"Aggregated status across all campaigns for the brand — present in brand mode, null otherwise",
|
|
206
|
+
),
|
|
207
|
+
global: GlobalStatusSchema.describe(
|
|
208
|
+
"Global signals across all brands and campaigns (always present)",
|
|
209
|
+
),
|
|
210
|
+
});
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { z } from "zod";
|
|
2
|
+
import {
|
|
3
|
+
ReplyClassificationSchema,
|
|
4
|
+
RepliesDetailSchema,
|
|
5
|
+
RecipientStatsSchema,
|
|
6
|
+
StepStatsSchema,
|
|
7
|
+
EmailStatsSchema,
|
|
8
|
+
ChannelStatsSchema,
|
|
9
|
+
StatusScopeSchema,
|
|
10
|
+
GlobalStatusSchema,
|
|
11
|
+
ProviderStatusSchema,
|
|
12
|
+
} from "./schemas";
|
|
13
|
+
|
|
14
|
+
export type ReplyClassification = z.infer<typeof ReplyClassificationSchema>;
|
|
15
|
+
export type RepliesDetail = z.infer<typeof RepliesDetailSchema>;
|
|
16
|
+
export type RecipientStats = z.infer<typeof RecipientStatsSchema>;
|
|
17
|
+
export type StepStats = z.infer<typeof StepStatsSchema>;
|
|
18
|
+
export type EmailStats = z.infer<typeof EmailStatsSchema>;
|
|
19
|
+
export type ChannelStats = z.infer<typeof ChannelStatsSchema>;
|
|
20
|
+
export type StatusScope = z.infer<typeof StatusScopeSchema>;
|
|
21
|
+
export type GlobalStatus = z.infer<typeof GlobalStatusSchema>;
|
|
22
|
+
export type ProviderStatus = z.infer<typeof ProviderStatusSchema>;
|