deepline 0.3.394 → 0.3.396
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/bundling-sources/sdk/src/client.ts +30 -162
- package/dist/bundling-sources/sdk/src/index.ts +1 -0
- package/dist/bundling-sources/sdk/src/plays/play-description.ts +167 -0
- package/dist/bundling-sources/sdk/src/release.ts +1 -1
- package/dist/bundling-sources/sdk/src/types.ts +1 -0
- package/dist/bundling-sources/shared_libs/observability/scheduled-jobs.json +1 -1
- package/dist/cli/{auth-OSXDAVCF.mjs → auth-3LTD62VL.mjs} +4 -4
- package/dist/cli/auth-562JPKOM.js +39 -0
- package/dist/cli/{billing-ZNNKX3UR.mjs → billing-DP7ZAJBO.mjs} +5 -4
- package/dist/cli/{billing-EKLYOXUY.js → billing-PA5OXEM5.js} +76 -75
- package/dist/cli/{chunk-BP33SIZF.mjs → chunk-23GAA3YO.mjs} +1 -1
- package/dist/cli/{chunk-KI635JN4.js → chunk-2VOLOWYZ.js} +1087 -1056
- package/dist/cli/{chunk-XXUDVEXK.mjs → chunk-3T4MCB5R.mjs} +1026 -995
- package/dist/cli/{chunk-VB6KECLU.mjs → chunk-5WNJF2T3.mjs} +102 -36
- package/dist/cli/{chunk-KIUMEOM5.js → chunk-772W2SAU.js} +8 -8
- package/dist/cli/{chunk-2MDDA7A4.js → chunk-7Z66NHUC.js} +26 -26
- package/dist/cli/{chunk-M57J2SK4.mjs → chunk-AUYXWELC.mjs} +2 -2
- package/dist/cli/{chunk-354JCXA2.js → chunk-AVHLATII.js} +50 -50
- package/dist/cli/{chunk-MLPU5SMZ.js → chunk-DC6LTULT.js} +2 -2
- package/dist/cli/chunk-EIMG75BT.mjs +130 -0
- package/dist/cli/{chunk-6YAUMG27.js → chunk-GNN4MY5X.js} +1 -1
- package/dist/cli/{chunk-UXFSWG3Q.mjs → chunk-I4T4XAA2.mjs} +4 -4
- package/dist/cli/{chunk-MFB2VKBO.mjs → chunk-JCN4DHF7.mjs} +2 -2
- package/dist/cli/{chunk-VK6FYZLP.js → chunk-KAEZNPUM.js} +23 -8
- package/dist/cli/chunk-KXMNM4AQ.js +130 -0
- package/dist/cli/{chunk-XRQ2AQL7.mjs → chunk-LOGGNW4H.mjs} +2 -2
- package/dist/cli/{chunk-RDXFGPJU.js → chunk-LWERJUKN.js} +218 -218
- package/dist/cli/{chunk-QIQBYKLB.js → chunk-ME6XRFLY.js} +15 -15
- package/dist/cli/{chunk-JHIJIHFB.mjs → chunk-MR6XCBQJ.mjs} +23 -131
- package/dist/cli/{chunk-TJI2EN6K.mjs → chunk-NHB5YUCS.mjs} +1 -1
- package/dist/cli/{chunk-ZMVJSS6N.js → chunk-NSOTASOP.js} +101 -35
- package/dist/cli/{chunk-ZYBGA4AR.mjs → chunk-QHGPA362.mjs} +18 -3
- package/dist/cli/{chunk-4P27AXEA.js → chunk-RMTASUAK.js} +65 -65
- package/dist/cli/{chunk-KGNTKMRG.js → chunk-RTO5QZWT.js} +6 -6
- package/dist/cli/{chunk-X63FDZJZ.mjs → chunk-TLQ3FZOC.mjs} +3 -3
- package/dist/cli/{chunk-CS6RAIVY.js → chunk-V7UP2F4U.js} +4 -4
- package/dist/cli/{chunk-FJGW5GXU.mjs → chunk-VE3U3SQC.mjs} +1 -1
- package/dist/cli/{chunk-E23BQ5SC.js → chunk-WQJJNIMQ.js} +241 -349
- package/dist/cli/{chunk-NR3DFKNF.mjs → chunk-XKZXO7D3.mjs} +1 -1
- package/dist/cli/{csv-5AXRB35H.mjs → csv-RLRR74RQ.mjs} +3 -3
- package/dist/cli/{csv-LU7O75WE.js → csv-TF576S77.js} +12 -12
- package/dist/cli/{db-F7YTFKVM.js → db-FDBJUTFO.js} +30 -29
- package/dist/cli/{db-7XP5UWEW.mjs → db-XORGNBIC.mjs} +5 -4
- package/dist/cli/{describe-K4ES5LIL.mjs → describe-6O2ENKTP.mjs} +86 -67
- package/dist/cli/{describe-FRH32RDV.js → describe-EFWNECHI.js} +100 -81
- package/dist/cli/{executions-RZV5XPT2.js → executions-SFYAXPF4.js} +7 -6
- package/dist/cli/{executions-IEHEHJUO.mjs → executions-YPP7WR77.mjs} +5 -4
- package/dist/cli/{feedback-3P65QTX3.js → feedback-5UZFYMGB.js} +7 -7
- package/dist/cli/{feedback-FPUVZBAN.mjs → feedback-RBGA5ARU.mjs} +3 -3
- package/dist/cli/git-5LDY5ZID.js +23 -0
- package/dist/cli/{git-GLVVP7TY.mjs → git-IRSAJEK2.mjs} +4 -4
- package/dist/cli/index.js +93 -93
- package/dist/cli/index.mjs +42 -42
- package/dist/cli/{legacy-noops-XKSGZR7Q.js → legacy-noops-CVAOQY2F.js} +7 -7
- package/dist/cli/{legacy-noops-3MOI6NBM.mjs → legacy-noops-NA7N6ZOU.mjs} +4 -4
- package/dist/cli/{monitors-NZ2DYNST.js → monitors-4OMRXCXP.js} +86 -85
- package/dist/cli/{monitors-FTBGNEFG.mjs → monitors-ILZ2XHYG.mjs} +5 -4
- package/dist/cli/{org-V2J5RBCN.mjs → org-QDDXAE3J.mjs} +5 -4
- package/dist/cli/{org-MCKDQXIV.js → org-YGNJDD2X.js} +65 -64
- package/dist/cli/{chunk-RBJYWRCF.js → play-L535H26U.js} +270 -325
- package/dist/cli/{chunk-5BB2RGAX.mjs → play-VT6OHB2D.mjs} +77 -132
- package/dist/cli/{providers-2JEZ2264.js → providers-GPZ6PQAL.js} +8 -7
- package/dist/cli/{providers-I6RQJZFZ.mjs → providers-KG4W5MPK.mjs} +5 -4
- package/dist/cli/{quickstart-BIDQDMO4.mjs → quickstart-2JDGTXIG.mjs} +3 -3
- package/dist/cli/{quickstart-GJ2RPDU3.js → quickstart-UI27S5LO.js} +5 -5
- package/dist/cli/search-MGWROZ33.js +28 -0
- package/dist/cli/{search-ELRXFWG5.mjs → search-PW3RAUX7.mjs} +6 -5
- package/dist/cli/{secrets-SQXGZXIC.mjs → secrets-HNOMK5A2.mjs} +5 -4
- package/dist/cli/{secrets-53IT6VXD.js → secrets-WFAXOUZE.js} +14 -13
- package/dist/cli/{sessions-CAV5M77Y.js → sessions-366KROUA.js} +5 -5
- package/dist/cli/{sessions-2X5QF7SL.mjs → sessions-XLX3E5UO.mjs} +4 -4
- package/dist/cli/{settings-532WNAZO.js → settings-GADAG2UK.js} +75 -74
- package/dist/cli/{settings-7P67VGCJ.mjs → settings-YNZ4YKCH.mjs} +8 -7
- package/dist/cli/{setup-QGGBV2LE.mjs → setup-PSEHIUXO.mjs} +6 -6
- package/dist/cli/{setup-6L2VSUWJ.js → setup-R5YO7GT6.js} +41 -41
- package/dist/cli/skills-JF2LPEGM.js +28 -0
- package/dist/cli/{skills-3FE62WBG.mjs → skills-LTQBP6CZ.mjs} +4 -4
- package/dist/cli/tools-CP2PEFRN.js +34 -0
- package/dist/cli/{tools-DMR25DEF.mjs → tools-UAXDWU63.mjs} +11 -18
- package/dist/cli/update-HZHZOU6C.js +28 -0
- package/dist/cli/{update-6RZMHJZP.mjs → update-SMNIBIMS.mjs} +6 -6
- package/dist/cli/{workflow-TX4F2PIX.js → workflow-AOQVZHMD.js} +16 -15
- package/dist/cli/{workflow-L2DQRE6R.mjs → workflow-IKGMBGF6.mjs} +6 -5
- package/dist/{client-C3O1Ipf3.d.ts → client-Bgis7F6-.d.ts} +22 -12
- package/dist/{client-BktIPdIj.d.mts → client-DiGl8ska.d.mts} +22 -12
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +11 -10
- package/dist/index.mjs +9 -8
- package/dist/install-integrity.json +83 -78
- package/dist/plays/play-description.d.mts +6 -0
- package/dist/plays/play-description.d.ts +6 -0
- package/dist/plays/play-description.js +11 -0
- package/dist/plays/play-description.mjs +11 -0
- package/dist/plays/run-request.d.mts +1 -1
- package/dist/plays/run-request.d.ts +1 -1
- package/dist/release.d.mts +1 -1
- package/dist/release.d.ts +1 -1
- package/dist/release.js +2 -2
- package/dist/release.mjs +1 -1
- package/package.json +6 -1
- package/dist/cli/auth-IHKISLJQ.js +0 -39
- package/dist/cli/git-MFFAWVVX.js +0 -23
- package/dist/cli/play-AJFGME3B.mjs +0 -158
- package/dist/cli/play-WLSN2EO2.js +0 -158
- package/dist/cli/search-5VN4YD4I.js +0 -27
- package/dist/cli/skills-S6NPZAN7.js +0 -28
- package/dist/cli/tools-647RLXQS.js +0 -41
- package/dist/cli/update-WVTSC3EM.js +0 -28
- package/dist/cli/{chunk-KZZC33PY.mjs → chunk-H5KLUGY7.mjs} +214 -214
|
@@ -1,217 +1,3 @@
|
|
|
1
|
-
// ../plays/email-status.ts
|
|
2
|
-
var nullable = (type) => ({ type: [type, "null"] });
|
|
3
|
-
var oneOf = (values) => ({ type: "string", enum: values });
|
|
4
|
-
var EMAIL_STATUS_JSON_SCHEMA = {
|
|
5
|
-
type: "object",
|
|
6
|
-
required: [
|
|
7
|
-
"verdict",
|
|
8
|
-
"status",
|
|
9
|
-
"verified",
|
|
10
|
-
"confidence",
|
|
11
|
-
"reasons",
|
|
12
|
-
"signals",
|
|
13
|
-
"provider"
|
|
14
|
-
],
|
|
15
|
-
properties: {
|
|
16
|
-
verdict: oneOf([
|
|
17
|
-
"send",
|
|
18
|
-
"send_with_caution",
|
|
19
|
-
"verify_next",
|
|
20
|
-
"hold",
|
|
21
|
-
"drop"
|
|
22
|
-
]),
|
|
23
|
-
status: oneOf([
|
|
24
|
-
"valid",
|
|
25
|
-
"invalid",
|
|
26
|
-
"catch_all",
|
|
27
|
-
"valid_catch_all",
|
|
28
|
-
"unknown",
|
|
29
|
-
"do_not_mail",
|
|
30
|
-
"spamtrap",
|
|
31
|
-
"abuse",
|
|
32
|
-
"disposable"
|
|
33
|
-
]),
|
|
34
|
-
verified: { type: "boolean" },
|
|
35
|
-
confidence: nullable("number"),
|
|
36
|
-
reasons: { type: "array", items: { type: "string" } },
|
|
37
|
-
signals: {
|
|
38
|
-
type: "object",
|
|
39
|
-
required: [
|
|
40
|
-
"catch_all",
|
|
41
|
-
"deliverability",
|
|
42
|
-
"mx_class",
|
|
43
|
-
"mx_provider",
|
|
44
|
-
"mx_record",
|
|
45
|
-
"fraud_score",
|
|
46
|
-
"disposable",
|
|
47
|
-
"role_based",
|
|
48
|
-
"free_email",
|
|
49
|
-
"abuse",
|
|
50
|
-
"spamtrap",
|
|
51
|
-
"suspect",
|
|
52
|
-
"valid"
|
|
53
|
-
],
|
|
54
|
-
properties: {
|
|
55
|
-
catch_all: nullable("boolean"),
|
|
56
|
-
deliverability: oneOf([
|
|
57
|
-
"high",
|
|
58
|
-
"medium",
|
|
59
|
-
"low",
|
|
60
|
-
"unknown"
|
|
61
|
-
]),
|
|
62
|
-
mx_class: oneOf([
|
|
63
|
-
"consumer_mailbox",
|
|
64
|
-
"workspace_mailbox",
|
|
65
|
-
"security_gateway",
|
|
66
|
-
"on_prem",
|
|
67
|
-
"unknown"
|
|
68
|
-
]),
|
|
69
|
-
mx_provider: nullable("string"),
|
|
70
|
-
mx_record: nullable("string"),
|
|
71
|
-
fraud_score: nullable("number"),
|
|
72
|
-
disposable: nullable("boolean"),
|
|
73
|
-
role_based: nullable("boolean"),
|
|
74
|
-
free_email: nullable("boolean"),
|
|
75
|
-
abuse: nullable("boolean"),
|
|
76
|
-
spamtrap: nullable("boolean"),
|
|
77
|
-
suspect: nullable("boolean"),
|
|
78
|
-
valid: nullable("boolean")
|
|
79
|
-
}
|
|
80
|
-
},
|
|
81
|
-
provider: {
|
|
82
|
-
type: "object",
|
|
83
|
-
required: ["name", "raw_status", "raw_score"],
|
|
84
|
-
properties: {
|
|
85
|
-
name: { type: "string" },
|
|
86
|
-
raw_status: { type: ["string", "boolean", "number", "null"] },
|
|
87
|
-
raw_score: nullable("number")
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
};
|
|
92
|
-
function normalizeKey(value) {
|
|
93
|
-
if (value == null) return null;
|
|
94
|
-
if (typeof value === "boolean") return String(value);
|
|
95
|
-
const normalized = String(value).trim().toLowerCase().replace(/\s+/g, "_");
|
|
96
|
-
return normalized || null;
|
|
97
|
-
}
|
|
98
|
-
function boolish(value) {
|
|
99
|
-
if (typeof value === "boolean") return value;
|
|
100
|
-
if (typeof value === "number")
|
|
101
|
-
return value === 1 ? true : value === 0 ? false : null;
|
|
102
|
-
if (typeof value !== "string") return null;
|
|
103
|
-
const normalized = value.trim().toLowerCase();
|
|
104
|
-
if (["true", "yes", "y", "1"].includes(normalized)) return true;
|
|
105
|
-
if (["false", "no", "n", "0"].includes(normalized)) return false;
|
|
106
|
-
return null;
|
|
107
|
-
}
|
|
108
|
-
function numberish(value) {
|
|
109
|
-
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
110
|
-
if (typeof value !== "string" || value.trim() === "") return null;
|
|
111
|
-
const parsed = Number(value);
|
|
112
|
-
return Number.isFinite(parsed) ? parsed : null;
|
|
113
|
-
}
|
|
114
|
-
function stringish(value) {
|
|
115
|
-
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
116
|
-
}
|
|
117
|
-
function deliverability(value) {
|
|
118
|
-
const normalized = normalizeKey(value);
|
|
119
|
-
return normalized === "high" || normalized === "medium" || normalized === "low" ? normalized : "unknown";
|
|
120
|
-
}
|
|
121
|
-
function mxClass(mxProvider, mxRecord) {
|
|
122
|
-
const haystack = `${stringish(mxProvider) ?? ""} ${stringish(mxRecord) ?? ""}`.toLowerCase();
|
|
123
|
-
if (!haystack.trim()) return "unknown";
|
|
124
|
-
if (/proofpoint|pphosted|mimecast|barracuda|ess\.barracudanetworks|ironport|cisco|iphmx|messagelabs|symantec/.test(
|
|
125
|
-
haystack
|
|
126
|
-
)) {
|
|
127
|
-
return "security_gateway";
|
|
128
|
-
}
|
|
129
|
-
if (/aspmx\.l\.google|google|g-suite|google workspace/.test(haystack)) {
|
|
130
|
-
return "workspace_mailbox";
|
|
131
|
-
}
|
|
132
|
-
if (/protection\.outlook|office365|microsoft|outlook|exchange online/.test(
|
|
133
|
-
haystack
|
|
134
|
-
)) {
|
|
135
|
-
return "workspace_mailbox";
|
|
136
|
-
}
|
|
137
|
-
if (/gmail|yahoo|icloud|aol|hotmail/.test(haystack))
|
|
138
|
-
return "consumer_mailbox";
|
|
139
|
-
if (/postfix|exim|sendmail|zimbra|plesk|cpanel|mail\./.test(haystack))
|
|
140
|
-
return "on_prem";
|
|
141
|
-
return "unknown";
|
|
142
|
-
}
|
|
143
|
-
function entryForStatus(key, map) {
|
|
144
|
-
if (!key) return null;
|
|
145
|
-
return map?.[key] ?? null;
|
|
146
|
-
}
|
|
147
|
-
function read(values, name) {
|
|
148
|
-
return values[name];
|
|
149
|
-
}
|
|
150
|
-
function matchesRule(rule, values) {
|
|
151
|
-
return Object.entries(rule.when).every(([key, expected]) => {
|
|
152
|
-
const actual = read(values, key);
|
|
153
|
-
if (key.endsWith("Lt")) {
|
|
154
|
-
const source = numberish(read(values, key.slice(0, -2)));
|
|
155
|
-
return typeof expected === "number" && source != null && source < expected;
|
|
156
|
-
}
|
|
157
|
-
if (typeof expected === "boolean") return boolish(actual) === expected;
|
|
158
|
-
if (typeof expected === "number") return numberish(actual) === expected;
|
|
159
|
-
return normalizeKey(actual) === normalizeKey(expected);
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
function buildEmailStatus({
|
|
163
|
-
config,
|
|
164
|
-
values
|
|
165
|
-
}) {
|
|
166
|
-
const rawStatus = read(values, "rawStatus");
|
|
167
|
-
const rawScore = numberish(read(values, "rawScore"));
|
|
168
|
-
const valid = boolish(read(values, "valid"));
|
|
169
|
-
const catchAll = boolish(read(values, "catchAll"));
|
|
170
|
-
const disposable = boolish(read(values, "disposable"));
|
|
171
|
-
const abuse = boolish(read(values, "abuse"));
|
|
172
|
-
const spamtrap = boolish(read(values, "spamtrap"));
|
|
173
|
-
const suspect = boolish(read(values, "suspect"));
|
|
174
|
-
const rawKey = normalizeKey(rawStatus);
|
|
175
|
-
const mapped = config.rules?.find((rule) => matchesRule(rule, values)) ?? entryForStatus(rawKey, config.statusMap) ?? entryForStatus(valid == null ? null : String(valid), config.statusMap);
|
|
176
|
-
const status = mapped?.status ?? (disposable ? "disposable" : abuse ? "abuse" : spamtrap ? "spamtrap" : catchAll ? "catch_all" : valid === true ? "valid" : valid === false ? "invalid" : "unknown");
|
|
177
|
-
const defaultVerdict = status === "valid" ? "send" : status === "valid_catch_all" ? "send_with_caution" : status === "catch_all" ? "verify_next" : status === "unknown" ? "hold" : "drop";
|
|
178
|
-
const verdict = mapped?.verdict ?? defaultVerdict;
|
|
179
|
-
const verified = mapped?.verified ?? (status === "valid" || status === "valid_catch_all" || verdict === "send");
|
|
180
|
-
const reasons = [
|
|
181
|
-
mapped?.reason,
|
|
182
|
-
catchAll ? "catch_all_domain" : null,
|
|
183
|
-
mxClass(read(values, "mxProvider"), read(values, "mxRecord")) === "security_gateway" ? "security_gateway_mx" : null,
|
|
184
|
-
suspect ? "provider_marked_suspect" : null
|
|
185
|
-
].filter((reason) => typeof reason === "string");
|
|
186
|
-
return {
|
|
187
|
-
verdict,
|
|
188
|
-
status,
|
|
189
|
-
verified,
|
|
190
|
-
confidence: rawScore,
|
|
191
|
-
reasons,
|
|
192
|
-
signals: {
|
|
193
|
-
catch_all: catchAll,
|
|
194
|
-
deliverability: deliverability(read(values, "deliverability")),
|
|
195
|
-
mx_class: mxClass(read(values, "mxProvider"), read(values, "mxRecord")),
|
|
196
|
-
mx_provider: stringish(read(values, "mxProvider")),
|
|
197
|
-
mx_record: stringish(read(values, "mxRecord")),
|
|
198
|
-
fraud_score: numberish(read(values, "fraudScore")),
|
|
199
|
-
disposable,
|
|
200
|
-
role_based: boolish(read(values, "roleBased")),
|
|
201
|
-
free_email: boolish(read(values, "freeEmail")),
|
|
202
|
-
abuse,
|
|
203
|
-
spamtrap,
|
|
204
|
-
suspect,
|
|
205
|
-
valid
|
|
206
|
-
},
|
|
207
|
-
provider: {
|
|
208
|
-
name: config.provider,
|
|
209
|
-
raw_status: typeof rawStatus === "string" || typeof rawStatus === "boolean" || typeof rawStatus === "number" ? rawStatus : null,
|
|
210
|
-
raw_score: rawScore
|
|
211
|
-
}
|
|
212
|
-
};
|
|
213
|
-
}
|
|
214
|
-
|
|
215
1
|
// ../plays/extractor-targets.ts
|
|
216
2
|
var JOB_CHANGE_STATUS_VALUES = [
|
|
217
3
|
"moved",
|
|
@@ -477,6 +263,220 @@ function extractSummaryFields(payload) {
|
|
|
477
263
|
return {};
|
|
478
264
|
}
|
|
479
265
|
|
|
266
|
+
// ../plays/email-status.ts
|
|
267
|
+
var nullable = (type) => ({ type: [type, "null"] });
|
|
268
|
+
var oneOf = (values) => ({ type: "string", enum: values });
|
|
269
|
+
var EMAIL_STATUS_JSON_SCHEMA = {
|
|
270
|
+
type: "object",
|
|
271
|
+
required: [
|
|
272
|
+
"verdict",
|
|
273
|
+
"status",
|
|
274
|
+
"verified",
|
|
275
|
+
"confidence",
|
|
276
|
+
"reasons",
|
|
277
|
+
"signals",
|
|
278
|
+
"provider"
|
|
279
|
+
],
|
|
280
|
+
properties: {
|
|
281
|
+
verdict: oneOf([
|
|
282
|
+
"send",
|
|
283
|
+
"send_with_caution",
|
|
284
|
+
"verify_next",
|
|
285
|
+
"hold",
|
|
286
|
+
"drop"
|
|
287
|
+
]),
|
|
288
|
+
status: oneOf([
|
|
289
|
+
"valid",
|
|
290
|
+
"invalid",
|
|
291
|
+
"catch_all",
|
|
292
|
+
"valid_catch_all",
|
|
293
|
+
"unknown",
|
|
294
|
+
"do_not_mail",
|
|
295
|
+
"spamtrap",
|
|
296
|
+
"abuse",
|
|
297
|
+
"disposable"
|
|
298
|
+
]),
|
|
299
|
+
verified: { type: "boolean" },
|
|
300
|
+
confidence: nullable("number"),
|
|
301
|
+
reasons: { type: "array", items: { type: "string" } },
|
|
302
|
+
signals: {
|
|
303
|
+
type: "object",
|
|
304
|
+
required: [
|
|
305
|
+
"catch_all",
|
|
306
|
+
"deliverability",
|
|
307
|
+
"mx_class",
|
|
308
|
+
"mx_provider",
|
|
309
|
+
"mx_record",
|
|
310
|
+
"fraud_score",
|
|
311
|
+
"disposable",
|
|
312
|
+
"role_based",
|
|
313
|
+
"free_email",
|
|
314
|
+
"abuse",
|
|
315
|
+
"spamtrap",
|
|
316
|
+
"suspect",
|
|
317
|
+
"valid"
|
|
318
|
+
],
|
|
319
|
+
properties: {
|
|
320
|
+
catch_all: nullable("boolean"),
|
|
321
|
+
deliverability: oneOf([
|
|
322
|
+
"high",
|
|
323
|
+
"medium",
|
|
324
|
+
"low",
|
|
325
|
+
"unknown"
|
|
326
|
+
]),
|
|
327
|
+
mx_class: oneOf([
|
|
328
|
+
"consumer_mailbox",
|
|
329
|
+
"workspace_mailbox",
|
|
330
|
+
"security_gateway",
|
|
331
|
+
"on_prem",
|
|
332
|
+
"unknown"
|
|
333
|
+
]),
|
|
334
|
+
mx_provider: nullable("string"),
|
|
335
|
+
mx_record: nullable("string"),
|
|
336
|
+
fraud_score: nullable("number"),
|
|
337
|
+
disposable: nullable("boolean"),
|
|
338
|
+
role_based: nullable("boolean"),
|
|
339
|
+
free_email: nullable("boolean"),
|
|
340
|
+
abuse: nullable("boolean"),
|
|
341
|
+
spamtrap: nullable("boolean"),
|
|
342
|
+
suspect: nullable("boolean"),
|
|
343
|
+
valid: nullable("boolean")
|
|
344
|
+
}
|
|
345
|
+
},
|
|
346
|
+
provider: {
|
|
347
|
+
type: "object",
|
|
348
|
+
required: ["name", "raw_status", "raw_score"],
|
|
349
|
+
properties: {
|
|
350
|
+
name: { type: "string" },
|
|
351
|
+
raw_status: { type: ["string", "boolean", "number", "null"] },
|
|
352
|
+
raw_score: nullable("number")
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
};
|
|
357
|
+
function normalizeKey(value) {
|
|
358
|
+
if (value == null) return null;
|
|
359
|
+
if (typeof value === "boolean") return String(value);
|
|
360
|
+
const normalized = String(value).trim().toLowerCase().replace(/\s+/g, "_");
|
|
361
|
+
return normalized || null;
|
|
362
|
+
}
|
|
363
|
+
function boolish(value) {
|
|
364
|
+
if (typeof value === "boolean") return value;
|
|
365
|
+
if (typeof value === "number")
|
|
366
|
+
return value === 1 ? true : value === 0 ? false : null;
|
|
367
|
+
if (typeof value !== "string") return null;
|
|
368
|
+
const normalized = value.trim().toLowerCase();
|
|
369
|
+
if (["true", "yes", "y", "1"].includes(normalized)) return true;
|
|
370
|
+
if (["false", "no", "n", "0"].includes(normalized)) return false;
|
|
371
|
+
return null;
|
|
372
|
+
}
|
|
373
|
+
function numberish(value) {
|
|
374
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
375
|
+
if (typeof value !== "string" || value.trim() === "") return null;
|
|
376
|
+
const parsed = Number(value);
|
|
377
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
378
|
+
}
|
|
379
|
+
function stringish(value) {
|
|
380
|
+
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
381
|
+
}
|
|
382
|
+
function deliverability(value) {
|
|
383
|
+
const normalized = normalizeKey(value);
|
|
384
|
+
return normalized === "high" || normalized === "medium" || normalized === "low" ? normalized : "unknown";
|
|
385
|
+
}
|
|
386
|
+
function mxClass(mxProvider, mxRecord) {
|
|
387
|
+
const haystack = `${stringish(mxProvider) ?? ""} ${stringish(mxRecord) ?? ""}`.toLowerCase();
|
|
388
|
+
if (!haystack.trim()) return "unknown";
|
|
389
|
+
if (/proofpoint|pphosted|mimecast|barracuda|ess\.barracudanetworks|ironport|cisco|iphmx|messagelabs|symantec/.test(
|
|
390
|
+
haystack
|
|
391
|
+
)) {
|
|
392
|
+
return "security_gateway";
|
|
393
|
+
}
|
|
394
|
+
if (/aspmx\.l\.google|google|g-suite|google workspace/.test(haystack)) {
|
|
395
|
+
return "workspace_mailbox";
|
|
396
|
+
}
|
|
397
|
+
if (/protection\.outlook|office365|microsoft|outlook|exchange online/.test(
|
|
398
|
+
haystack
|
|
399
|
+
)) {
|
|
400
|
+
return "workspace_mailbox";
|
|
401
|
+
}
|
|
402
|
+
if (/gmail|yahoo|icloud|aol|hotmail/.test(haystack))
|
|
403
|
+
return "consumer_mailbox";
|
|
404
|
+
if (/postfix|exim|sendmail|zimbra|plesk|cpanel|mail\./.test(haystack))
|
|
405
|
+
return "on_prem";
|
|
406
|
+
return "unknown";
|
|
407
|
+
}
|
|
408
|
+
function entryForStatus(key, map) {
|
|
409
|
+
if (!key) return null;
|
|
410
|
+
return map?.[key] ?? null;
|
|
411
|
+
}
|
|
412
|
+
function read(values, name) {
|
|
413
|
+
return values[name];
|
|
414
|
+
}
|
|
415
|
+
function matchesRule(rule, values) {
|
|
416
|
+
return Object.entries(rule.when).every(([key, expected]) => {
|
|
417
|
+
const actual = read(values, key);
|
|
418
|
+
if (key.endsWith("Lt")) {
|
|
419
|
+
const source = numberish(read(values, key.slice(0, -2)));
|
|
420
|
+
return typeof expected === "number" && source != null && source < expected;
|
|
421
|
+
}
|
|
422
|
+
if (typeof expected === "boolean") return boolish(actual) === expected;
|
|
423
|
+
if (typeof expected === "number") return numberish(actual) === expected;
|
|
424
|
+
return normalizeKey(actual) === normalizeKey(expected);
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
function buildEmailStatus({
|
|
428
|
+
config,
|
|
429
|
+
values
|
|
430
|
+
}) {
|
|
431
|
+
const rawStatus = read(values, "rawStatus");
|
|
432
|
+
const rawScore = numberish(read(values, "rawScore"));
|
|
433
|
+
const valid = boolish(read(values, "valid"));
|
|
434
|
+
const catchAll = boolish(read(values, "catchAll"));
|
|
435
|
+
const disposable = boolish(read(values, "disposable"));
|
|
436
|
+
const abuse = boolish(read(values, "abuse"));
|
|
437
|
+
const spamtrap = boolish(read(values, "spamtrap"));
|
|
438
|
+
const suspect = boolish(read(values, "suspect"));
|
|
439
|
+
const rawKey = normalizeKey(rawStatus);
|
|
440
|
+
const mapped = config.rules?.find((rule) => matchesRule(rule, values)) ?? entryForStatus(rawKey, config.statusMap) ?? entryForStatus(valid == null ? null : String(valid), config.statusMap);
|
|
441
|
+
const status = mapped?.status ?? (disposable ? "disposable" : abuse ? "abuse" : spamtrap ? "spamtrap" : catchAll ? "catch_all" : valid === true ? "valid" : valid === false ? "invalid" : "unknown");
|
|
442
|
+
const defaultVerdict = status === "valid" ? "send" : status === "valid_catch_all" ? "send_with_caution" : status === "catch_all" ? "verify_next" : status === "unknown" ? "hold" : "drop";
|
|
443
|
+
const verdict = mapped?.verdict ?? defaultVerdict;
|
|
444
|
+
const verified = mapped?.verified ?? (status === "valid" || status === "valid_catch_all" || verdict === "send");
|
|
445
|
+
const reasons = [
|
|
446
|
+
mapped?.reason,
|
|
447
|
+
catchAll ? "catch_all_domain" : null,
|
|
448
|
+
mxClass(read(values, "mxProvider"), read(values, "mxRecord")) === "security_gateway" ? "security_gateway_mx" : null,
|
|
449
|
+
suspect ? "provider_marked_suspect" : null
|
|
450
|
+
].filter((reason) => typeof reason === "string");
|
|
451
|
+
return {
|
|
452
|
+
verdict,
|
|
453
|
+
status,
|
|
454
|
+
verified,
|
|
455
|
+
confidence: rawScore,
|
|
456
|
+
reasons,
|
|
457
|
+
signals: {
|
|
458
|
+
catch_all: catchAll,
|
|
459
|
+
deliverability: deliverability(read(values, "deliverability")),
|
|
460
|
+
mx_class: mxClass(read(values, "mxProvider"), read(values, "mxRecord")),
|
|
461
|
+
mx_provider: stringish(read(values, "mxProvider")),
|
|
462
|
+
mx_record: stringish(read(values, "mxRecord")),
|
|
463
|
+
fraud_score: numberish(read(values, "fraudScore")),
|
|
464
|
+
disposable,
|
|
465
|
+
role_based: boolish(read(values, "roleBased")),
|
|
466
|
+
free_email: boolish(read(values, "freeEmail")),
|
|
467
|
+
abuse,
|
|
468
|
+
spamtrap,
|
|
469
|
+
suspect,
|
|
470
|
+
valid
|
|
471
|
+
},
|
|
472
|
+
provider: {
|
|
473
|
+
name: config.provider,
|
|
474
|
+
raw_status: typeof rawStatus === "string" || typeof rawStatus === "boolean" || typeof rawStatus === "number" ? rawStatus : null,
|
|
475
|
+
raw_score: rawScore
|
|
476
|
+
}
|
|
477
|
+
};
|
|
478
|
+
}
|
|
479
|
+
|
|
480
480
|
export {
|
|
481
481
|
EMAIL_STATUS_JSON_SCHEMA,
|
|
482
482
|
buildEmailStatus,
|