@benclmnt/postmock 0.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 +251 -0
- package/dist/seeds/conformance/00-core.d.ts +4 -0
- package/dist/seeds/conformance/00-core.js +12 -0
- package/dist/seeds/conformance/20-bounces.d.ts +3 -0
- package/dist/seeds/conformance/20-bounces.js +108 -0
- package/dist/seeds/conformance/40-messages.d.ts +3 -0
- package/dist/seeds/conformance/40-messages.js +144 -0
- package/dist/seeds/conformance/50-server-color.d.ts +8 -0
- package/dist/seeds/conformance/50-server-color.js +13 -0
- package/dist/seeds/conformance/70-account.d.ts +9 -0
- package/dist/seeds/conformance/70-account.js +29 -0
- package/dist/seeds/conformance/80-templates.d.ts +4 -0
- package/dist/seeds/conformance/80-templates.js +23 -0
- package/dist/seeds/conformance.d.ts +2 -0
- package/dist/seeds/conformance.js +3 -0
- package/dist/seeds/empty.d.ts +4 -0
- package/dist/seeds/empty.js +3 -0
- package/dist/seeds/lib/conformance.d.ts +16 -0
- package/dist/seeds/lib/conformance.js +18 -0
- package/dist/seeds/lib/history.d.ts +27 -0
- package/dist/seeds/lib/history.js +129 -0
- package/dist/seeds/lib/read-server.d.ts +10 -0
- package/dist/seeds/lib/read-server.js +10 -0
- package/dist/seeds/lib/template-server.d.ts +13 -0
- package/dist/seeds/lib/template-server.js +13 -0
- package/dist/src/api/account/authentication.d.ts +39 -0
- package/dist/src/api/account/authentication.js +97 -0
- package/dist/src/api/account/domains.d.ts +59 -0
- package/dist/src/api/account/domains.js +78 -0
- package/dist/src/api/account/paging.d.ts +12 -0
- package/dist/src/api/account/paging.js +35 -0
- package/dist/src/api/account/push.d.ts +14 -0
- package/dist/src/api/account/push.js +84 -0
- package/dist/src/api/account/routes.d.ts +1 -0
- package/dist/src/api/account/routes.js +288 -0
- package/dist/src/api/account/senders.d.ts +54 -0
- package/dist/src/api/account/senders.js +87 -0
- package/dist/src/api/account/servers.d.ts +40 -0
- package/dist/src/api/account/servers.js +148 -0
- package/dist/src/api/bounces/json.d.ts +25 -0
- package/dist/src/api/bounces/json.js +27 -0
- package/dist/src/api/bounces/routes.d.ts +1 -0
- package/dist/src/api/bounces/routes.js +127 -0
- package/dist/src/api/bulk/bulk.d.ts +43 -0
- package/dist/src/api/bulk/bulk.js +81 -0
- package/dist/src/api/bulk/routes.d.ts +1 -0
- package/dist/src/api/bulk/routes.js +252 -0
- package/dist/src/api/data-removals/routes.d.ts +1 -0
- package/dist/src/api/data-removals/routes.js +59 -0
- package/dist/src/api/email/json.d.ts +11 -0
- package/dist/src/api/email/json.js +33 -0
- package/dist/src/api/email/routes.d.ts +1 -0
- package/dist/src/api/email/routes.js +64 -0
- package/dist/src/api/inbound/routes.d.ts +1 -0
- package/dist/src/api/inbound/routes.js +40 -0
- package/dist/src/api/index.d.ts +1 -0
- package/dist/src/api/index.js +3 -0
- package/dist/src/api/message-streams/routes.d.ts +1 -0
- package/dist/src/api/message-streams/routes.js +211 -0
- package/dist/src/api/message-streams/streams.d.ts +28 -0
- package/dist/src/api/message-streams/streams.js +50 -0
- package/dist/src/api/messages/json.d.ts +149 -0
- package/dist/src/api/messages/json.js +114 -0
- package/dist/src/api/messages/query.d.ts +19 -0
- package/dist/src/api/messages/query.js +64 -0
- package/dist/src/api/messages/routes.d.ts +1 -0
- package/dist/src/api/messages/routes.js +203 -0
- package/dist/src/api/server/json.d.ts +26 -0
- package/dist/src/api/server/json.js +25 -0
- package/dist/src/api/server/routes.d.ts +1 -0
- package/dist/src/api/server/routes.js +17 -0
- package/dist/src/api/stats/aggregate.d.ts +58 -0
- package/dist/src/api/stats/aggregate.js +66 -0
- package/dist/src/api/stats/routes.d.ts +1 -0
- package/dist/src/api/stats/routes.js +72 -0
- package/dist/src/api/suppressions/routes.d.ts +1 -0
- package/dist/src/api/suppressions/routes.js +98 -0
- package/dist/src/api/templates/content.d.ts +21 -0
- package/dist/src/api/templates/content.js +39 -0
- package/dist/src/api/templates/routes.d.ts +1 -0
- package/dist/src/api/templates/routes.js +164 -0
- package/dist/src/api/templates/send.d.ts +13 -0
- package/dist/src/api/templates/send.js +105 -0
- package/dist/src/api/templates/templates.d.ts +100 -0
- package/dist/src/api/templates/templates.js +218 -0
- package/dist/src/api/templates/validate.d.ts +15 -0
- package/dist/src/api/templates/validate.js +77 -0
- package/dist/src/api/triggers/routes.d.ts +1 -0
- package/dist/src/api/triggers/routes.js +62 -0
- package/dist/src/api/webhooks/routes.d.ts +14 -0
- package/dist/src/api/webhooks/routes.js +192 -0
- package/dist/src/config.d.ts +17 -0
- package/dist/src/config.js +95 -0
- package/dist/src/control/app.d.ts +5 -0
- package/dist/src/control/app.js +42 -0
- package/dist/src/control/endpoints/account.d.ts +1 -0
- package/dist/src/control/endpoints/account.js +68 -0
- package/dist/src/control/endpoints/bulk.d.ts +1 -0
- package/dist/src/control/endpoints/bulk.js +29 -0
- package/dist/src/control/endpoints/core.d.ts +1 -0
- package/dist/src/control/endpoints/core.js +104 -0
- package/dist/src/control/endpoints/inbound.d.ts +1 -0
- package/dist/src/control/endpoints/inbound.js +61 -0
- package/dist/src/control/endpoints/recipients.d.ts +1 -0
- package/dist/src/control/endpoints/recipients.js +136 -0
- package/dist/src/control/endpoints/smtp.d.ts +1 -0
- package/dist/src/control/endpoints/smtp.js +74 -0
- package/dist/src/control/endpoints/tracking.d.ts +1 -0
- package/dist/src/control/endpoints/tracking.js +95 -0
- package/dist/src/control/endpoints/webhooks.d.ts +1 -0
- package/dist/src/control/endpoints/webhooks.js +36 -0
- package/dist/src/control/index.d.ts +1 -0
- package/dist/src/control/index.js +3 -0
- package/dist/src/control/registry.d.ts +25 -0
- package/dist/src/control/registry.js +19 -0
- package/dist/src/control/seed.d.ts +11 -0
- package/dist/src/control/seed.js +32 -0
- package/dist/src/control/seeding.d.ts +10 -0
- package/dist/src/control/seeding.js +27 -0
- package/dist/src/discover.d.ts +16 -0
- package/dist/src/discover.js +49 -0
- package/dist/src/errors.d.ts +49 -0
- package/dist/src/errors.js +701 -0
- package/dist/src/events.d.ts +49 -0
- package/dist/src/events.js +19 -0
- package/dist/src/http/app.d.ts +8 -0
- package/dist/src/http/app.js +51 -0
- package/dist/src/http/auth.d.ts +7 -0
- package/dist/src/http/auth.js +32 -0
- package/dist/src/http/faults.d.ts +8 -0
- package/dist/src/http/faults.js +33 -0
- package/dist/src/http/normalize.d.ts +57 -0
- package/dist/src/http/normalize.js +225 -0
- package/dist/src/http/respond.d.ts +23 -0
- package/dist/src/http/respond.js +37 -0
- package/dist/src/http/routes.d.ts +60 -0
- package/dist/src/http/routes.js +64 -0
- package/dist/src/inbound/deliver.d.ts +9 -0
- package/dist/src/inbound/deliver.js +34 -0
- package/dist/src/inbound/parse.d.ts +21 -0
- package/dist/src/inbound/parse.js +71 -0
- package/dist/src/inbound/receive.d.ts +17 -0
- package/dist/src/inbound/receive.js +89 -0
- package/dist/src/main.d.ts +2 -0
- package/dist/src/main.js +14 -0
- package/dist/src/mime/compose.d.ts +33 -0
- package/dist/src/mime/compose.js +58 -0
- package/dist/src/pipeline/addresses.d.ts +6 -0
- package/dist/src/pipeline/addresses.js +38 -0
- package/dist/src/pipeline/inactive.d.ts +8 -0
- package/dist/src/pipeline/inactive.js +20 -0
- package/dist/src/pipeline/submit.d.ts +138 -0
- package/dist/src/pipeline/submit.js +415 -0
- package/dist/src/plugins/message-events.d.ts +7 -0
- package/dist/src/plugins/message-events.js +76 -0
- package/dist/src/plugins/smtp.d.ts +15 -0
- package/dist/src/plugins/smtp.js +42 -0
- package/dist/src/plugins/stats.d.ts +7 -0
- package/dist/src/plugins/stats.js +78 -0
- package/dist/src/plugins/webhooks.d.ts +4 -0
- package/dist/src/plugins/webhooks.js +80 -0
- package/dist/src/plugins.d.ts +20 -0
- package/dist/src/plugins.js +9 -0
- package/dist/src/recipients/test-bounces.d.ts +15 -0
- package/dist/src/recipients/test-bounces.js +31 -0
- package/dist/src/recipients/transitions.d.ts +57 -0
- package/dist/src/recipients/transitions.js +279 -0
- package/dist/src/render/mustachio.d.ts +60 -0
- package/dist/src/render/mustachio.js +265 -0
- package/dist/src/runtime.d.ts +12 -0
- package/dist/src/runtime.js +11 -0
- package/dist/src/server.d.ts +25 -0
- package/dist/src/server.js +49 -0
- package/dist/src/smtp/auth.d.ts +35 -0
- package/dist/src/smtp/auth.js +66 -0
- package/dist/src/smtp/listener.d.ts +16 -0
- package/dist/src/smtp/listener.js +121 -0
- package/dist/src/smtp/mime.d.ts +36 -0
- package/dist/src/smtp/mime.js +181 -0
- package/dist/src/smtp/receive.d.ts +21 -0
- package/dist/src/smtp/receive.js +89 -0
- package/dist/src/smtp/reply.d.ts +14 -0
- package/dist/src/smtp/reply.js +24 -0
- package/dist/src/state/clock.d.ts +35 -0
- package/dist/src/state/clock.js +107 -0
- package/dist/src/state/ids.d.ts +6 -0
- package/dist/src/state/ids.js +7 -0
- package/dist/src/state/servers.d.ts +27 -0
- package/dist/src/state/servers.js +101 -0
- package/dist/src/state/store.d.ts +57 -0
- package/dist/src/state/store.js +98 -0
- package/dist/src/state/suppressions.d.ts +9 -0
- package/dist/src/state/suppressions.js +8 -0
- package/dist/src/state/types.d.ts +530 -0
- package/dist/src/state/types.js +41 -0
- package/dist/src/time.d.ts +11 -0
- package/dist/src/time.js +48 -0
- package/dist/src/tracking.d.ts +53 -0
- package/dist/src/tracking.js +150 -0
- package/dist/src/webhooks/deliver.d.ts +60 -0
- package/dist/src/webhooks/deliver.js +172 -0
- package/dist/src/webhooks/egress.d.ts +19 -0
- package/dist/src/webhooks/egress.js +40 -0
- package/dist/src/webhooks/outbound.d.ts +26 -0
- package/dist/src/webhooks/outbound.js +47 -0
- package/dist/src/webhooks/payloads.d.ts +111 -0
- package/dist/src/webhooks/payloads.js +128 -0
- package/package.json +55 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { deliver, OUTBOUND } from "./deliver.js";
|
|
2
|
+
/**
|
|
3
|
+
* Sends an event to every verified `/webhooks` row of its stream with the trigger on, then to the
|
|
4
|
+
* server hook URL (docs/05 §1.5, §5). Server hook URLs apply to every stream (INFERRED, Q10).
|
|
5
|
+
*/
|
|
6
|
+
export async function emitOutbound(runtime, event) {
|
|
7
|
+
const server = runtime.store.state.servers.get(event.serverId);
|
|
8
|
+
if (server === undefined)
|
|
9
|
+
return;
|
|
10
|
+
const hooks = [];
|
|
11
|
+
for (const webhook of runtime.store.state.webhooks.values()) {
|
|
12
|
+
if (webhook.ServerID === server.ID &&
|
|
13
|
+
webhook.MessageStream === event.messageStream &&
|
|
14
|
+
webhook.Status === "verified" &&
|
|
15
|
+
webhook.Triggers[event.trigger].Enabled) {
|
|
16
|
+
hooks.push({
|
|
17
|
+
hook: { kind: "webhook", webhook },
|
|
18
|
+
target: {
|
|
19
|
+
serverId: server.ID,
|
|
20
|
+
hook: { kind: "webhook", webhookId: webhook.ID, trigger: event.trigger },
|
|
21
|
+
url: webhook.Url,
|
|
22
|
+
httpAuth: webhook.HttpAuth,
|
|
23
|
+
headers: webhook.HttpHeaders,
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
const field = event.serverHookField;
|
|
29
|
+
if (field !== null && server[field] !== "") {
|
|
30
|
+
hooks.push({
|
|
31
|
+
hook: { kind: "server", server },
|
|
32
|
+
target: {
|
|
33
|
+
serverId: server.ID,
|
|
34
|
+
hook: { kind: "server", field },
|
|
35
|
+
url: server[field],
|
|
36
|
+
httpAuth: null,
|
|
37
|
+
headers: [],
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
for (const { hook, target } of hooks) {
|
|
42
|
+
const payload = event.payload(hook);
|
|
43
|
+
if (payload !== null) {
|
|
44
|
+
await deliver(runtime, { target, recordType: event.recordType, payload, policy: OUTBOUND });
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import type { EventMap } from "../events.ts";
|
|
2
|
+
import { type Bounce, type ClickEvent, type InboundMessage, type OpenEvent, type SubscriptionChange } from "../state/types.ts";
|
|
3
|
+
/** docs/05 §2.1, §2.2, §2.8. `Content` only when the hook asks for it. */
|
|
4
|
+
export declare function bouncePayload(recordType: "Bounce" | "SpamComplaint", bounce: Bounce, includeContent: boolean): {
|
|
5
|
+
RecordType: "Bounce" | "SpamComplaint";
|
|
6
|
+
MessageStream: string;
|
|
7
|
+
ID: number;
|
|
8
|
+
Type: "AddressChange" | "AutoResponder" | "BadEmailAddress" | "Blocked" | "ChallengeVerification" | "DMARCPolicy" | "DnsError" | "HardBounce" | "InboundError" | "ManuallyDeactivated" | "OpenRelayTest" | "SMTPApiError" | "SoftBounce" | "SpamComplaint" | "SpamNotification" | "Subscribe" | "TemplateRenderingFailed" | "Transient" | "Unconfirmed" | "Unknown" | "Unsubscribe" | "VirusNotification";
|
|
9
|
+
TypeCode: 1 | 2 | 16 | 32 | 64 | 128 | 256 | 512 | 1024 | 2048 | 4096 | 8192 | 16384 | 100000 | 100001 | 100002 | 100003 | 100006 | 100007 | 100008 | 100009 | 100010;
|
|
10
|
+
Name: "Address change" | "Auto responder" | "DMARC Policy" | "DNS error" | "Hard bounce" | "ISP block" | "Invalid email address" | "Manually deactivated" | "Message delayed/Undeliverable" | "Open relay test" | "Processing failed" | "Registration not confirmed" | "SMTP API error" | "Soft bounce" | "Spam challenge verification" | "Spam complaint" | "Spam notification" | "Subscribe request" | "Template rendering failed" | "Unknown" | "Unsubscribe request" | "Virus notification";
|
|
11
|
+
Tag: string;
|
|
12
|
+
MessageID: string;
|
|
13
|
+
Metadata: Record<string, string>;
|
|
14
|
+
ServerID: number;
|
|
15
|
+
Description: string;
|
|
16
|
+
Details: string;
|
|
17
|
+
Email: string;
|
|
18
|
+
From: string | null;
|
|
19
|
+
BouncedAt: string;
|
|
20
|
+
DumpAvailable: boolean;
|
|
21
|
+
Inactive: boolean;
|
|
22
|
+
CanActivate: boolean;
|
|
23
|
+
Subject: string;
|
|
24
|
+
Content?: string;
|
|
25
|
+
};
|
|
26
|
+
/** docs/05 §2.3: one event per recipient. */
|
|
27
|
+
export declare function deliveryPayload({ message, recipient, deliveredAt, details, }: EventMap["delivered"]): {
|
|
28
|
+
RecordType: string;
|
|
29
|
+
MessageStream: string;
|
|
30
|
+
ServerID: number;
|
|
31
|
+
MessageID: string;
|
|
32
|
+
Recipient: string;
|
|
33
|
+
Tag: string;
|
|
34
|
+
DeliveredAt: string;
|
|
35
|
+
Details: string;
|
|
36
|
+
Metadata: Record<string, string>;
|
|
37
|
+
};
|
|
38
|
+
/** docs/05 §2.4. No `ServerID`. */
|
|
39
|
+
export declare function openPayload(open: OpenEvent): {
|
|
40
|
+
Client?: import("../state/types.ts").ClientInfo;
|
|
41
|
+
OS?: import("../state/types.ts").ClientInfo;
|
|
42
|
+
Platform?: "Desktop" | "Mobile" | "Unknown" | "WebMail";
|
|
43
|
+
UserAgent: string;
|
|
44
|
+
RecordType: string;
|
|
45
|
+
MessageStream: string;
|
|
46
|
+
FirstOpen: boolean;
|
|
47
|
+
ReadSeconds: number;
|
|
48
|
+
Geo?: import("../state/types.ts").Geo;
|
|
49
|
+
MessageID: string;
|
|
50
|
+
Metadata: Record<string, string>;
|
|
51
|
+
ReceivedAt: string;
|
|
52
|
+
Tag: string;
|
|
53
|
+
Recipient: string;
|
|
54
|
+
};
|
|
55
|
+
/** docs/05 §2.5. No `ServerID`. */
|
|
56
|
+
export declare function clickPayload(click: ClickEvent): {
|
|
57
|
+
Client?: import("../state/types.ts").ClientInfo;
|
|
58
|
+
OS?: import("../state/types.ts").ClientInfo;
|
|
59
|
+
Platform?: "Desktop" | "Mobile" | "Unknown" | "WebMail";
|
|
60
|
+
UserAgent: string;
|
|
61
|
+
RecordType: string;
|
|
62
|
+
MessageStream: string;
|
|
63
|
+
ClickLocation: "HTML" | "Text";
|
|
64
|
+
OriginalLink: string;
|
|
65
|
+
Geo?: import("../state/types.ts").Geo;
|
|
66
|
+
MessageID: string;
|
|
67
|
+
Metadata: Record<string, string>;
|
|
68
|
+
ReceivedAt: string;
|
|
69
|
+
Tag: string;
|
|
70
|
+
Recipient: string;
|
|
71
|
+
};
|
|
72
|
+
/** docs/05 §2.6. `MessageID`, `SuppressionReason` and `Tag` stay null where the change has none. */
|
|
73
|
+
export declare function subscriptionChangePayload(change: SubscriptionChange): {
|
|
74
|
+
RecordType: string;
|
|
75
|
+
MessageID: string | null;
|
|
76
|
+
ServerID: number;
|
|
77
|
+
MessageStream: string;
|
|
78
|
+
ChangedAt: string;
|
|
79
|
+
Recipient: string;
|
|
80
|
+
Origin: import("../state/types.ts").SuppressionOrigin;
|
|
81
|
+
SuppressSending: boolean;
|
|
82
|
+
SuppressionReason: import("../state/types.ts").SuppressionReason | null;
|
|
83
|
+
Tag: string | null;
|
|
84
|
+
Metadata: Record<string, string>;
|
|
85
|
+
};
|
|
86
|
+
/** docs/05 §2.7, §4.2. No `RecordType`. `RawEmail` only with the server's `RawEmailEnabled`. */
|
|
87
|
+
export declare function inboundPayload(message: InboundMessage, rawEmailEnabled: boolean): {
|
|
88
|
+
FromName: string;
|
|
89
|
+
MessageStream: string;
|
|
90
|
+
From: string;
|
|
91
|
+
FromFull: import("../state/types.ts").InboundAddress;
|
|
92
|
+
To: string;
|
|
93
|
+
ToFull: import("../state/types.ts").InboundAddress[];
|
|
94
|
+
Cc: string;
|
|
95
|
+
CcFull: import("../state/types.ts").InboundAddress[];
|
|
96
|
+
Bcc: string;
|
|
97
|
+
BccFull: import("../state/types.ts").InboundAddress[];
|
|
98
|
+
OriginalRecipient: string;
|
|
99
|
+
Subject: string;
|
|
100
|
+
MessageID: string;
|
|
101
|
+
ReplyTo: string;
|
|
102
|
+
MailboxHash: string;
|
|
103
|
+
Date: string;
|
|
104
|
+
TextBody: string;
|
|
105
|
+
HtmlBody: string;
|
|
106
|
+
StrippedTextReply: string;
|
|
107
|
+
Tag: string;
|
|
108
|
+
Headers: import("../state/types.ts").Header[];
|
|
109
|
+
Attachments: import("../state/types.ts").InboundAttachment[];
|
|
110
|
+
RawEmail?: string;
|
|
111
|
+
};
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { BOUNCE_TYPES, } from "../state/types.js";
|
|
2
|
+
import { formatTimestamp } from "../time.js";
|
|
3
|
+
// Webhook bodies per RecordType, keys in doc order (docs/05 §2). Dates use the `Z` form of the doc
|
|
4
|
+
// examples. A send without a tag gives `Tag: ""`, as inbound does (INFERRED).
|
|
5
|
+
const at = (instant) => formatTimestamp(instant, "utc");
|
|
6
|
+
const tag = (value) => value ?? "";
|
|
7
|
+
/** docs/05 §2.1, §2.2, §2.8. `Content` only when the hook asks for it. */
|
|
8
|
+
export function bouncePayload(recordType, bounce, includeContent) {
|
|
9
|
+
return {
|
|
10
|
+
RecordType: recordType,
|
|
11
|
+
MessageStream: bounce.MessageStream,
|
|
12
|
+
ID: bounce.ID,
|
|
13
|
+
Type: bounce.Type,
|
|
14
|
+
TypeCode: BOUNCE_TYPES[bounce.Type].TypeCode,
|
|
15
|
+
Name: BOUNCE_TYPES[bounce.Type].Name,
|
|
16
|
+
Tag: tag(bounce.Tag),
|
|
17
|
+
MessageID: bounce.MessageID,
|
|
18
|
+
Metadata: bounce.Metadata,
|
|
19
|
+
ServerID: bounce.ServerID,
|
|
20
|
+
Description: bounce.Description,
|
|
21
|
+
Details: bounce.Details,
|
|
22
|
+
Email: bounce.Email,
|
|
23
|
+
From: bounce.From,
|
|
24
|
+
BouncedAt: at(bounce.BouncedAt),
|
|
25
|
+
DumpAvailable: bounce.Content !== "",
|
|
26
|
+
Inactive: bounce.Inactive,
|
|
27
|
+
CanActivate: bounce.CanActivate,
|
|
28
|
+
Subject: bounce.Subject,
|
|
29
|
+
...(includeContent && { Content: bounce.Content }),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/** docs/05 §2.3: one event per recipient. */
|
|
33
|
+
export function deliveryPayload({ message, recipient, deliveredAt, details, }) {
|
|
34
|
+
return {
|
|
35
|
+
RecordType: "Delivery",
|
|
36
|
+
MessageStream: message.MessageStream,
|
|
37
|
+
ServerID: message.ServerID,
|
|
38
|
+
MessageID: message.MessageID,
|
|
39
|
+
Recipient: recipient,
|
|
40
|
+
Tag: tag(message.Tag),
|
|
41
|
+
DeliveredAt: at(deliveredAt),
|
|
42
|
+
Details: details,
|
|
43
|
+
Metadata: message.Metadata,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/** Client, OS, Platform and Geo are left out when unknown (docs/05 §2.4). */
|
|
47
|
+
const reader = (e) => ({
|
|
48
|
+
...(e.Client !== null && { Client: e.Client }),
|
|
49
|
+
...(e.OS !== null && { OS: e.OS }),
|
|
50
|
+
...(e.Platform !== null && { Platform: e.Platform }),
|
|
51
|
+
UserAgent: e.UserAgent,
|
|
52
|
+
});
|
|
53
|
+
/** docs/05 §2.4. No `ServerID`. */
|
|
54
|
+
export function openPayload(open) {
|
|
55
|
+
return {
|
|
56
|
+
RecordType: "Open",
|
|
57
|
+
MessageStream: open.MessageStream,
|
|
58
|
+
FirstOpen: open.FirstOpen,
|
|
59
|
+
...reader(open),
|
|
60
|
+
ReadSeconds: open.ReadSeconds,
|
|
61
|
+
...(open.Geo !== null && { Geo: open.Geo }),
|
|
62
|
+
MessageID: open.MessageID,
|
|
63
|
+
Metadata: open.Metadata,
|
|
64
|
+
ReceivedAt: at(open.ReceivedAt),
|
|
65
|
+
Tag: tag(open.Tag),
|
|
66
|
+
Recipient: open.Recipient,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/** docs/05 §2.5. No `ServerID`. */
|
|
70
|
+
export function clickPayload(click) {
|
|
71
|
+
return {
|
|
72
|
+
RecordType: "Click",
|
|
73
|
+
MessageStream: click.MessageStream,
|
|
74
|
+
ClickLocation: click.ClickLocation,
|
|
75
|
+
...reader(click),
|
|
76
|
+
OriginalLink: click.OriginalLink,
|
|
77
|
+
...(click.Geo !== null && { Geo: click.Geo }),
|
|
78
|
+
MessageID: click.MessageID,
|
|
79
|
+
Metadata: click.Metadata,
|
|
80
|
+
ReceivedAt: at(click.ReceivedAt),
|
|
81
|
+
Tag: tag(click.Tag),
|
|
82
|
+
Recipient: click.Recipient,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
/** docs/05 §2.6. `MessageID`, `SuppressionReason` and `Tag` stay null where the change has none. */
|
|
86
|
+
export function subscriptionChangePayload(change) {
|
|
87
|
+
return {
|
|
88
|
+
RecordType: "SubscriptionChange",
|
|
89
|
+
MessageID: change.MessageID,
|
|
90
|
+
ServerID: change.ServerID,
|
|
91
|
+
MessageStream: change.MessageStream,
|
|
92
|
+
ChangedAt: at(change.ChangedAt),
|
|
93
|
+
Recipient: change.Recipient,
|
|
94
|
+
Origin: change.Origin,
|
|
95
|
+
SuppressSending: change.SuppressSending,
|
|
96
|
+
SuppressionReason: change.SuppressionReason,
|
|
97
|
+
Tag: change.Tag,
|
|
98
|
+
Metadata: change.Metadata,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
/** docs/05 §2.7, §4.2. No `RecordType`. `RawEmail` only with the server's `RawEmailEnabled`. */
|
|
102
|
+
export function inboundPayload(message, rawEmailEnabled) {
|
|
103
|
+
return {
|
|
104
|
+
FromName: message.FromName,
|
|
105
|
+
MessageStream: message.MessageStream,
|
|
106
|
+
From: message.From,
|
|
107
|
+
FromFull: message.FromFull,
|
|
108
|
+
To: message.To,
|
|
109
|
+
ToFull: message.ToFull,
|
|
110
|
+
Cc: message.Cc,
|
|
111
|
+
CcFull: message.CcFull,
|
|
112
|
+
Bcc: message.Bcc,
|
|
113
|
+
BccFull: message.BccFull,
|
|
114
|
+
OriginalRecipient: message.OriginalRecipient,
|
|
115
|
+
Subject: message.Subject,
|
|
116
|
+
MessageID: message.MessageID,
|
|
117
|
+
ReplyTo: message.ReplyTo,
|
|
118
|
+
MailboxHash: message.MailboxHash,
|
|
119
|
+
Date: message.Date,
|
|
120
|
+
TextBody: message.TextBody,
|
|
121
|
+
HtmlBody: message.HtmlBody,
|
|
122
|
+
StrippedTextReply: message.StrippedTextReply,
|
|
123
|
+
Tag: message.Tag,
|
|
124
|
+
Headers: message.Headers,
|
|
125
|
+
Attachments: message.Attachments,
|
|
126
|
+
...(rawEmailEnabled && { RawEmail: message.rawEmail }),
|
|
127
|
+
};
|
|
128
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@benclmnt/postmock",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "A mock Postmark server for testing code that sends email through Postmark",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"publishConfig": {
|
|
8
|
+
"access": "public"
|
|
9
|
+
},
|
|
10
|
+
"bin": {
|
|
11
|
+
"postmock": "dist/src/main.js"
|
|
12
|
+
},
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"types": "./dist/src/server.d.ts",
|
|
16
|
+
"default": "./dist/src/server.js"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist"
|
|
21
|
+
],
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=24"
|
|
24
|
+
},
|
|
25
|
+
"packageManager": "pnpm@11.22.0",
|
|
26
|
+
"scripts": {
|
|
27
|
+
"start": "node src/main.ts",
|
|
28
|
+
"build": "rm -rf dist && tsc -p tsconfig.build.json",
|
|
29
|
+
"prepack": "npm run build",
|
|
30
|
+
"check": "biome check . && tsc --noEmit && vitest run",
|
|
31
|
+
"test": "vitest run",
|
|
32
|
+
"conformance": "node conformance/run.ts",
|
|
33
|
+
"conformance:check": "node conformance/check.ts",
|
|
34
|
+
"compat-table": "node tools/compat-table.ts"
|
|
35
|
+
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"@hono/node-server": "^2.1.1",
|
|
38
|
+
"hono": "^4.13.8",
|
|
39
|
+
"libmime": "5.4.4",
|
|
40
|
+
"mailparser": "^3.9.28",
|
|
41
|
+
"smtp-server": "^3.19.13",
|
|
42
|
+
"zod": "^4.6.5"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@biomejs/biome": "^2.5.13",
|
|
46
|
+
"@types/libmime": "^5.3.0",
|
|
47
|
+
"@types/mailparser": "^3.4.6",
|
|
48
|
+
"@types/node": "^24.13.4",
|
|
49
|
+
"@types/nodemailer": "^8.0.1",
|
|
50
|
+
"@types/smtp-server": "^3.5.13",
|
|
51
|
+
"nodemailer": "^9.1.1",
|
|
52
|
+
"typescript": "^7.0.2",
|
|
53
|
+
"vitest": "^5.0.1"
|
|
54
|
+
}
|
|
55
|
+
}
|