@diskd-ai/email-client-mcp 0.1.34 → 0.1.39
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/config/schema.d.ts +535 -5
- package/dist/config/schema.js +71 -6
- package/dist/config/schema.js.map +1 -1
- package/dist/delivery/application/decideTransportOutcome.d.ts +15 -0
- package/dist/delivery/application/decideTransportOutcome.js +14 -0
- package/dist/delivery/application/decideTransportOutcome.js.map +1 -0
- package/dist/delivery/application/outboxRepository.d.ts +83 -0
- package/dist/delivery/application/outboxRepository.js +2 -0
- package/dist/delivery/application/outboxRepository.js.map +1 -0
- package/dist/delivery/domain/deliveryProgress.d.ts +17 -0
- package/dist/delivery/domain/deliveryProgress.js +34 -0
- package/dist/delivery/domain/deliveryProgress.js.map +1 -0
- package/dist/delivery/domain/deliveryState.d.ts +21 -0
- package/dist/delivery/domain/deliveryState.js +7 -0
- package/dist/delivery/domain/deliveryState.js.map +1 -0
- package/dist/delivery/domain/identity.d.ts +28 -0
- package/dist/delivery/domain/identity.js +28 -0
- package/dist/delivery/domain/identity.js.map +1 -0
- package/dist/delivery/domain/json.d.ts +5 -0
- package/dist/delivery/domain/json.js +2 -0
- package/dist/delivery/domain/json.js.map +1 -0
- package/dist/delivery/domain/transportOutcome.d.ts +31 -0
- package/dist/delivery/domain/transportOutcome.js +2 -0
- package/dist/delivery/domain/transportOutcome.js.map +1 -0
- package/dist/delivery/infrastructure/deliveryProcessor.d.ts +42 -0
- package/dist/delivery/infrastructure/deliveryProcessor.js +179 -0
- package/dist/delivery/infrastructure/deliveryProcessor.js.map +1 -0
- package/dist/delivery/infrastructure/deliveryRuntime.d.ts +17 -0
- package/dist/delivery/infrastructure/deliveryRuntime.js +186 -0
- package/dist/delivery/infrastructure/deliveryRuntime.js.map +1 -0
- package/dist/delivery/infrastructure/emailOutboxPayload.d.ts +7 -0
- package/dist/delivery/infrastructure/emailOutboxPayload.js +42 -0
- package/dist/delivery/infrastructure/emailOutboxPayload.js.map +1 -0
- package/dist/delivery/infrastructure/outboxEvent.d.ts +30 -0
- package/dist/delivery/infrastructure/outboxEvent.js +72 -0
- package/dist/delivery/infrastructure/outboxEvent.js.map +1 -0
- package/dist/delivery/infrastructure/outboxSdkAdapter.d.ts +7 -0
- package/dist/delivery/infrastructure/outboxSdkAdapter.js +164 -0
- package/dist/delivery/infrastructure/outboxSdkAdapter.js.map +1 -0
- package/dist/delivery/infrastructure/perAccountRateLimiter.d.ts +9 -0
- package/dist/delivery/infrastructure/perAccountRateLimiter.js +27 -0
- package/dist/delivery/infrastructure/perAccountRateLimiter.js.map +1 -0
- package/dist/delivery/infrastructure/smtpTransport.d.ts +43 -0
- package/dist/delivery/infrastructure/smtpTransport.js +142 -0
- package/dist/delivery/infrastructure/smtpTransport.js.map +1 -0
- package/dist/sdk/diskdClient.d.ts +1 -1
- package/dist/sdk/diskdClient.js +1 -1
- package/dist/server.js +87 -14
- package/dist/server.js.map +1 -1
- package/dist/store/driveStore.d.ts +3 -3
- package/dist/store/driveStore.js +24 -8
- package/dist/store/driveStore.js.map +1 -1
- package/dist/store/payloadTypes.d.ts +4 -0
- package/dist/sync/sync.d.ts +5 -4
- package/dist/sync/sync.js +21 -10
- package/dist/sync/sync.js.map +1 -1
- package/dist/tools/findMailboxFolder.d.ts +2 -2
- package/dist/tools/getEmail.d.ts +4 -4
- package/dist/tools/getEmails.d.ts +4 -4
- package/dist/tools/listEmails.d.ts +22 -9
- package/dist/tools/listEmails.js +37 -26
- package/dist/tools/listEmails.js.map +1 -1
- package/dist/tools/setEmailAttributes.d.ts +2 -2
- package/dist/tools/systemHydrateEmailAttachment.d.ts +4 -4
- package/dist/tools/systemHydrateEmailBodies.d.ts +8 -8
- package/package.json +5 -2
package/dist/config/schema.js
CHANGED
|
@@ -3,17 +3,25 @@
|
|
|
3
3
|
* `/home/mcp/.config/email-client-mcp/config.toml` by the assembler
|
|
4
4
|
* (or wherever `EMAIL_CLIENT_MCP_CONFIG` points).
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* vault accounts can serve both servers; adds [sdk] and [watcher]
|
|
6
|
+
* Uses the canonical email vault account shape and adds [sdk] and [watcher]
|
|
8
7
|
* sections specific to this server.
|
|
9
8
|
*/
|
|
10
9
|
import { z } from "zod";
|
|
10
|
+
import { sanitizeMailboxId } from "../store/conventions.js";
|
|
11
|
+
const DEFAULT_WATCHER_INTERVAL_MS = 300_000;
|
|
11
12
|
const imapSchema = z.object({
|
|
12
13
|
host: z.string().min(1),
|
|
13
14
|
port: z.number().int().min(1).max(65535),
|
|
14
15
|
tls: z.boolean().default(true),
|
|
15
16
|
verify_ssl: z.boolean().default(false),
|
|
16
17
|
});
|
|
18
|
+
const smtpSchema = z.object({
|
|
19
|
+
host: z.string().min(1),
|
|
20
|
+
port: z.number().int().min(1).max(65535),
|
|
21
|
+
tls: z.boolean().default(true),
|
|
22
|
+
starttls: z.boolean().default(false),
|
|
23
|
+
verify_ssl: z.boolean().default(true),
|
|
24
|
+
});
|
|
17
25
|
const passwordAccountSchema = z.object({
|
|
18
26
|
name: z.string().min(1),
|
|
19
27
|
email: z.string().min(1),
|
|
@@ -21,6 +29,7 @@ const passwordAccountSchema = z.object({
|
|
|
21
29
|
full_name: z.string().optional(),
|
|
22
30
|
password: z.string().min(1),
|
|
23
31
|
imap: imapSchema,
|
|
32
|
+
smtp: smtpSchema.optional(),
|
|
24
33
|
});
|
|
25
34
|
const oauth2Schema = z.object({
|
|
26
35
|
provider: z.string().min(1),
|
|
@@ -35,6 +44,7 @@ const oauthAccountSchema = z.object({
|
|
|
35
44
|
full_name: z.string().optional(),
|
|
36
45
|
oauth2: oauth2Schema,
|
|
37
46
|
imap: imapSchema,
|
|
47
|
+
smtp: smtpSchema.optional(),
|
|
38
48
|
});
|
|
39
49
|
export const accountSchema = z.union([passwordAccountSchema, oauthAccountSchema]);
|
|
40
50
|
export const isOAuthAccount = (a) => "oauth2" in a;
|
|
@@ -50,7 +60,7 @@ const recentFirstSchema = z.object({
|
|
|
50
60
|
});
|
|
51
61
|
const watcherSchema = z.object({
|
|
52
62
|
enabled: z.boolean().default(true),
|
|
53
|
-
interval_ms: z.number().int().min(60_000).default(
|
|
63
|
+
interval_ms: z.number().int().min(60_000).default(DEFAULT_WATCHER_INTERVAL_MS),
|
|
54
64
|
folders: z.array(z.string()).optional(),
|
|
55
65
|
flag_reconcile_window: z.number().int().min(0).default(500),
|
|
56
66
|
body_hydration: bodyHydrationSchema.default({
|
|
@@ -75,12 +85,54 @@ const sdkSchema = z.object({
|
|
|
75
85
|
base_url: z.string().url().optional(),
|
|
76
86
|
workspace_id: z.string().optional(),
|
|
77
87
|
});
|
|
78
|
-
|
|
79
|
-
|
|
88
|
+
const deliverSchema = z.discriminatedUnion("enabled", [
|
|
89
|
+
z.object({ enabled: z.literal(false) }),
|
|
90
|
+
z.object({
|
|
91
|
+
enabled: z.literal(true),
|
|
92
|
+
nats_url: z.string().regex(/^nats:\/\/\S+$/, "expected a nats:// URL"),
|
|
93
|
+
rate_limit_per_account_per_minute: z.number().int().min(1),
|
|
94
|
+
}),
|
|
95
|
+
]);
|
|
96
|
+
const accountsSchema = z
|
|
97
|
+
.array(accountSchema)
|
|
98
|
+
.min(1)
|
|
99
|
+
.superRefine((accounts, context) => {
|
|
100
|
+
const duplicateName = accounts.find((account, index) => accounts.findIndex((candidate) => candidate.name === account.name) !== index);
|
|
101
|
+
if (duplicateName !== undefined) {
|
|
102
|
+
context.addIssue({
|
|
103
|
+
code: z.ZodIssueCode.custom,
|
|
104
|
+
message: `duplicate account name: ${duplicateName.name}`,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
const duplicateEmail = accounts.find((account, index) => {
|
|
108
|
+
const email = account.email.trim().toLowerCase();
|
|
109
|
+
return (accounts.findIndex((candidate) => candidate.email.trim().toLowerCase() === email) !== index);
|
|
110
|
+
});
|
|
111
|
+
if (duplicateEmail !== undefined) {
|
|
112
|
+
context.addIssue({
|
|
113
|
+
code: z.ZodIssueCode.custom,
|
|
114
|
+
message: `duplicate account email: ${duplicateEmail.email.trim().toLowerCase()}`,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
const duplicateMailboxId = accounts.find((account, index) => {
|
|
118
|
+
const mailboxId = sanitizeMailboxId(account.name);
|
|
119
|
+
return (accounts.findIndex((candidate) => sanitizeMailboxId(candidate.name) === mailboxId) !== index);
|
|
120
|
+
});
|
|
121
|
+
if (duplicateMailboxId !== undefined) {
|
|
122
|
+
context.addIssue({
|
|
123
|
+
code: z.ZodIssueCode.custom,
|
|
124
|
+
message: `account name maps to duplicate mailbox id: ${sanitizeMailboxId(duplicateMailboxId.name)}`,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
export const configSchema = z
|
|
129
|
+
.object({
|
|
130
|
+
accounts: accountsSchema,
|
|
80
131
|
sdk: sdkSchema.optional(),
|
|
132
|
+
deliver: deliverSchema.default({ enabled: false }),
|
|
81
133
|
watcher: watcherSchema.default({
|
|
82
134
|
enabled: true,
|
|
83
|
-
interval_ms:
|
|
135
|
+
interval_ms: DEFAULT_WATCHER_INTERVAL_MS,
|
|
84
136
|
flag_reconcile_window: 500,
|
|
85
137
|
body_hydration: {
|
|
86
138
|
enabled: true,
|
|
@@ -93,6 +145,19 @@ export const configSchema = z.object({
|
|
|
93
145
|
backfill_window_per_tick: 500,
|
|
94
146
|
},
|
|
95
147
|
}),
|
|
148
|
+
})
|
|
149
|
+
.superRefine((config, context) => {
|
|
150
|
+
if (!config.deliver.enabled)
|
|
151
|
+
return;
|
|
152
|
+
for (const [index, configuredAccount] of config.accounts.entries()) {
|
|
153
|
+
if (configuredAccount.smtp !== undefined)
|
|
154
|
+
continue;
|
|
155
|
+
context.addIssue({
|
|
156
|
+
code: z.ZodIssueCode.custom,
|
|
157
|
+
path: ["accounts", index, "smtp"],
|
|
158
|
+
message: `SMTP settings are required for delivery account: ${configuredAccount.name}`,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
96
161
|
});
|
|
97
162
|
/**
|
|
98
163
|
* Default config search path. Overridden by `EMAIL_CLIENT_MCP_CONFIG`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/config/schema.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/config/schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { TransportOutcome } from "../domain/transportOutcome.js";
|
|
2
|
+
export type DeliveryOutcomeDecision = {
|
|
3
|
+
readonly kind: "RecordSent";
|
|
4
|
+
} | {
|
|
5
|
+
readonly kind: "ScheduleRetry";
|
|
6
|
+
readonly reason: string;
|
|
7
|
+
} | {
|
|
8
|
+
readonly kind: "RecordFailedPermanent";
|
|
9
|
+
readonly reason: string;
|
|
10
|
+
} | {
|
|
11
|
+
readonly kind: "RecordFailedUnknown";
|
|
12
|
+
readonly reason: string;
|
|
13
|
+
};
|
|
14
|
+
/** Convert a normalized transport outcome into one canonical lifecycle effect. */
|
|
15
|
+
export declare const decideTransportOutcome: (outcome: TransportOutcome) => DeliveryOutcomeDecision;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** Convert a normalized transport outcome into one canonical lifecycle effect. */
|
|
2
|
+
export const decideTransportOutcome = (outcome) => {
|
|
3
|
+
switch (outcome.kind) {
|
|
4
|
+
case "Accepted":
|
|
5
|
+
return { kind: "RecordSent" };
|
|
6
|
+
case "UnknownOutcome":
|
|
7
|
+
return { kind: "RecordFailedUnknown", reason: outcome.failure.reason };
|
|
8
|
+
case "RejectedBeforeAcceptance":
|
|
9
|
+
return outcome.rejection.kind === "Transient"
|
|
10
|
+
? { kind: "ScheduleRetry", reason: outcome.rejection.failure.reason }
|
|
11
|
+
: { kind: "RecordFailedPermanent", reason: outcome.rejection.failure.reason };
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=decideTransportOutcome.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decideTransportOutcome.js","sourceRoot":"","sources":["../../../src/delivery/application/decideTransportOutcome.ts"],"names":[],"mappings":"AAQA,kFAAkF;AAClF,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,OAAyB,EAA2B,EAAE;IAC3F,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;QACrB,KAAK,UAAU;YACb,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;QAChC,KAAK,gBAAgB;YACnB,OAAO,EAAE,IAAI,EAAE,qBAAqB,EAAE,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;QACzE,KAAK,0BAA0B;YAC7B,OAAO,OAAO,CAAC,SAAS,CAAC,IAAI,KAAK,WAAW;gBAC3C,CAAC,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,EAAE,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,EAAE;gBACrE,CAAC,CAAC,EAAE,IAAI,EAAE,uBAAuB,EAAE,MAAM,EAAE,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;IACpF,CAAC;AACH,CAAC,CAAC"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { Option, Result } from "../../domain/result.js";
|
|
2
|
+
import type { DeliveryProgress } from "../domain/deliveryProgress.js";
|
|
3
|
+
import type { JsonObject } from "../domain/json.js";
|
|
4
|
+
export type ExchangeState = "review" | "outbox" | "sent" | "failed" | "reconciliation_required";
|
|
5
|
+
export type OutboxLease = {
|
|
6
|
+
readonly kind: "Available";
|
|
7
|
+
} | {
|
|
8
|
+
readonly kind: "Leased";
|
|
9
|
+
readonly owner: string;
|
|
10
|
+
readonly expiresAt: string;
|
|
11
|
+
};
|
|
12
|
+
export type OutboxItem = {
|
|
13
|
+
readonly externalId: string;
|
|
14
|
+
readonly account: string;
|
|
15
|
+
readonly mailboxId: string;
|
|
16
|
+
readonly state: ExchangeState;
|
|
17
|
+
readonly payload: JsonObject;
|
|
18
|
+
readonly result: Option<JsonObject>;
|
|
19
|
+
readonly revision: string;
|
|
20
|
+
readonly deliveryAttempts: number;
|
|
21
|
+
readonly lease: OutboxLease;
|
|
22
|
+
readonly failureReason: Option<string>;
|
|
23
|
+
readonly createdAt: string;
|
|
24
|
+
readonly updatedAt: string;
|
|
25
|
+
};
|
|
26
|
+
export type OutboxRepositoryOperation = "Get" | "ListPending" | "Claim" | "RenewLease" | "WriteProgress" | "WriteTerminal";
|
|
27
|
+
export type OutboxRepositoryError = {
|
|
28
|
+
readonly kind: "NotFound";
|
|
29
|
+
readonly operation: OutboxRepositoryOperation;
|
|
30
|
+
} | {
|
|
31
|
+
readonly kind: "RevisionConflict";
|
|
32
|
+
readonly operation: OutboxRepositoryOperation;
|
|
33
|
+
} | {
|
|
34
|
+
readonly kind: "LeaseConflict";
|
|
35
|
+
readonly operation: OutboxRepositoryOperation;
|
|
36
|
+
} | {
|
|
37
|
+
readonly kind: "LeaseExpired";
|
|
38
|
+
readonly operation: OutboxRepositoryOperation;
|
|
39
|
+
} | {
|
|
40
|
+
readonly kind: "InvalidResponse";
|
|
41
|
+
readonly operation: OutboxRepositoryOperation;
|
|
42
|
+
readonly message: string;
|
|
43
|
+
} | {
|
|
44
|
+
readonly kind: "SdkFailure";
|
|
45
|
+
readonly operation: OutboxRepositoryOperation;
|
|
46
|
+
readonly message: string;
|
|
47
|
+
};
|
|
48
|
+
export type OutboxLeaseInput = {
|
|
49
|
+
readonly externalId: string;
|
|
50
|
+
readonly expectedRevision: string;
|
|
51
|
+
readonly leaseOwner: string;
|
|
52
|
+
readonly leaseSeconds: number;
|
|
53
|
+
};
|
|
54
|
+
export type OutboxTerminalOutcome = {
|
|
55
|
+
readonly kind: "Sent";
|
|
56
|
+
readonly providerResponse: JsonObject;
|
|
57
|
+
} | {
|
|
58
|
+
readonly kind: "Failed";
|
|
59
|
+
readonly reason: string;
|
|
60
|
+
};
|
|
61
|
+
export type OutboxRepository = {
|
|
62
|
+
readonly get: (externalId: string) => Promise<Result<OutboxRepositoryError, OutboxItem>>;
|
|
63
|
+
readonly listPending: (input: {
|
|
64
|
+
readonly limit: number;
|
|
65
|
+
readonly cursor: Option<string>;
|
|
66
|
+
}) => Promise<Result<OutboxRepositoryError, {
|
|
67
|
+
readonly items: readonly OutboxItem[];
|
|
68
|
+
readonly nextCursor: Option<string>;
|
|
69
|
+
}>>;
|
|
70
|
+
readonly claim: (input: OutboxLeaseInput) => Promise<Result<OutboxRepositoryError, OutboxItem>>;
|
|
71
|
+
readonly renewLease: (input: OutboxLeaseInput) => Promise<Result<OutboxRepositoryError, OutboxItem>>;
|
|
72
|
+
readonly writeProgress: (input: {
|
|
73
|
+
readonly externalId: string;
|
|
74
|
+
readonly expectedRevision: string;
|
|
75
|
+
readonly progress: DeliveryProgress;
|
|
76
|
+
}) => Promise<Result<OutboxRepositoryError, OutboxItem>>;
|
|
77
|
+
readonly writeTerminal: (input: {
|
|
78
|
+
readonly externalId: string;
|
|
79
|
+
readonly expectedRevision: string;
|
|
80
|
+
readonly leaseOwner: string;
|
|
81
|
+
readonly outcome: OutboxTerminalOutcome;
|
|
82
|
+
}) => Promise<Result<OutboxRepositoryError, OutboxItem>>;
|
|
83
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outboxRepository.js","sourceRoot":"","sources":["../../../src/delivery/application/outboxRepository.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type Result } from "../../domain/result.js";
|
|
2
|
+
import type { JsonObject } from "./json.js";
|
|
3
|
+
export type DeliveryProgress = {
|
|
4
|
+
readonly kind: "DeliveryStarted";
|
|
5
|
+
readonly messageId: string;
|
|
6
|
+
readonly recordedAt: string;
|
|
7
|
+
} | {
|
|
8
|
+
readonly kind: "RetrySafe";
|
|
9
|
+
readonly reason: string;
|
|
10
|
+
readonly recordedAt: string;
|
|
11
|
+
};
|
|
12
|
+
export type DeliveryProgressError = {
|
|
13
|
+
readonly kind: "InvalidDeliveryProgress";
|
|
14
|
+
readonly reason: string;
|
|
15
|
+
};
|
|
16
|
+
export declare const encodeDeliveryProgress: (progress: DeliveryProgress) => JsonObject;
|
|
17
|
+
export declare const decodeDeliveryProgress: (value: JsonObject) => Result<DeliveryProgressError, DeliveryProgress>;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Err, Ok } from "../../domain/result.js";
|
|
2
|
+
export const encodeDeliveryProgress = (progress) => progress.kind === "DeliveryStarted"
|
|
3
|
+
? {
|
|
4
|
+
deliveryProgress: "started",
|
|
5
|
+
messageId: progress.messageId,
|
|
6
|
+
recordedAt: progress.recordedAt,
|
|
7
|
+
}
|
|
8
|
+
: {
|
|
9
|
+
deliveryProgress: "retry_safe",
|
|
10
|
+
reason: progress.reason,
|
|
11
|
+
recordedAt: progress.recordedAt,
|
|
12
|
+
};
|
|
13
|
+
const readNonEmptyString = (value) => typeof value === "string" && value.length > 0 ? value : undefined;
|
|
14
|
+
export const decodeDeliveryProgress = (value) => {
|
|
15
|
+
const discriminator = value.deliveryProgress;
|
|
16
|
+
const recordedAt = readNonEmptyString(value.recordedAt);
|
|
17
|
+
if (discriminator === "started") {
|
|
18
|
+
const messageId = readNonEmptyString(value.messageId);
|
|
19
|
+
if (messageId !== undefined && recordedAt !== undefined) {
|
|
20
|
+
return Ok({ kind: "DeliveryStarted", messageId, recordedAt });
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
if (discriminator === "retry_safe") {
|
|
24
|
+
const reason = readNonEmptyString(value.reason);
|
|
25
|
+
if (reason !== undefined && recordedAt !== undefined) {
|
|
26
|
+
return Ok({ kind: "RetrySafe", reason, recordedAt });
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return Err({
|
|
30
|
+
kind: "InvalidDeliveryProgress",
|
|
31
|
+
reason: "Outbox result is not a recognized delivery progress marker",
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
//# sourceMappingURL=deliveryProgress.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deliveryProgress.js","sourceRoot":"","sources":["../../../src/delivery/domain/deliveryProgress.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,EAAE,EAAe,MAAM,wBAAwB,CAAC;AAoB9D,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,QAA0B,EAAc,EAAE,CAC/E,QAAQ,CAAC,IAAI,KAAK,iBAAiB;IACjC,CAAC,CAAC;QACE,gBAAgB,EAAE,SAAS;QAC3B,SAAS,EAAE,QAAQ,CAAC,SAAS;QAC7B,UAAU,EAAE,QAAQ,CAAC,UAAU;KAChC;IACH,CAAC,CAAC;QACE,gBAAgB,EAAE,YAAY;QAC9B,MAAM,EAAE,QAAQ,CAAC,MAAM;QACvB,UAAU,EAAE,QAAQ,CAAC,UAAU;KAChC,CAAC;AAER,MAAM,kBAAkB,GAAG,CAAC,KAAc,EAAsB,EAAE,CAChE,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AAEpE,MAAM,CAAC,MAAM,sBAAsB,GAAG,CACpC,KAAiB,EACgC,EAAE;IACnD,MAAM,aAAa,GAAG,KAAK,CAAC,gBAAgB,CAAC;IAC7C,MAAM,UAAU,GAAG,kBAAkB,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACxD,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;QAChC,MAAM,SAAS,GAAG,kBAAkB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QACtD,IAAI,SAAS,KAAK,SAAS,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;YACxD,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC,CAAC;QAChE,CAAC;IACH,CAAC;IACD,IAAI,aAAa,KAAK,YAAY,EAAE,CAAC;QACnC,MAAM,MAAM,GAAG,kBAAkB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAChD,IAAI,MAAM,KAAK,SAAS,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;YACrD,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;QACT,IAAI,EAAE,yBAAyB;QAC/B,MAAM,EAAE,4DAA4D;KACrE,CAAC,CAAC;AACL,CAAC,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical delivery lifecycle variants understood by the delivery feature.
|
|
3
|
+
* Drive owns persistence and revision rules; this module only models the
|
|
4
|
+
* locally observable states without importing an SDK DTO.
|
|
5
|
+
*/
|
|
6
|
+
export type DeliveryState = {
|
|
7
|
+
readonly kind: "Pending";
|
|
8
|
+
} | {
|
|
9
|
+
readonly kind: "Claimed";
|
|
10
|
+
} | {
|
|
11
|
+
readonly kind: "Sending";
|
|
12
|
+
} | {
|
|
13
|
+
readonly kind: "RetryScheduled";
|
|
14
|
+
} | {
|
|
15
|
+
readonly kind: "Sent";
|
|
16
|
+
} | {
|
|
17
|
+
readonly kind: "FailedPermanent";
|
|
18
|
+
} | {
|
|
19
|
+
readonly kind: "FailedUnknown";
|
|
20
|
+
};
|
|
21
|
+
export declare const isTerminalDeliveryState: (state: DeliveryState) => boolean;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical delivery lifecycle variants understood by the delivery feature.
|
|
3
|
+
* Drive owns persistence and revision rules; this module only models the
|
|
4
|
+
* locally observable states without importing an SDK DTO.
|
|
5
|
+
*/
|
|
6
|
+
export const isTerminalDeliveryState = (state) => state.kind === "Sent" || state.kind === "FailedPermanent" || state.kind === "FailedUnknown";
|
|
7
|
+
//# sourceMappingURL=deliveryState.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deliveryState.js","sourceRoot":"","sources":["../../../src/delivery/domain/deliveryState.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAWH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,KAAoB,EAAW,EAAE,CACvE,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,KAAK,CAAC,IAAI,KAAK,iBAAiB,IAAI,KAAK,CAAC,IAAI,KAAK,eAAe,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type Result } from "../../domain/result.js";
|
|
2
|
+
export type DeliveryAccountIdentity = {
|
|
3
|
+
readonly accountId: string;
|
|
4
|
+
readonly allowedFromAddresses: readonly string[];
|
|
5
|
+
};
|
|
6
|
+
export type ResolvedDeliveryIdentity = {
|
|
7
|
+
readonly accountId: string;
|
|
8
|
+
readonly fromAddress: string;
|
|
9
|
+
};
|
|
10
|
+
export type DeliveryIdentityError = {
|
|
11
|
+
readonly kind: "AccountNotFound";
|
|
12
|
+
readonly accountId: string;
|
|
13
|
+
} | {
|
|
14
|
+
readonly kind: "AmbiguousAccount";
|
|
15
|
+
readonly accountId: string;
|
|
16
|
+
} | {
|
|
17
|
+
readonly kind: "InvalidFromIdentity";
|
|
18
|
+
} | {
|
|
19
|
+
readonly kind: "UnauthorizedFromIdentity";
|
|
20
|
+
readonly accountId: string;
|
|
21
|
+
readonly fromAddress: string;
|
|
22
|
+
} | {
|
|
23
|
+
readonly kind: "AmbiguousFromIdentity";
|
|
24
|
+
readonly fromAddress: string;
|
|
25
|
+
};
|
|
26
|
+
export declare const normalizeEmailAddress: (address: string) => string;
|
|
27
|
+
/** Resolve one configured connector and authorize its sender identity. */
|
|
28
|
+
export declare const resolveDeliveryIdentity: (accounts: readonly DeliveryAccountIdentity[], accountId: string, fromAddress: string) => Result<DeliveryIdentityError, ResolvedDeliveryIdentity>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Err, Ok } from "../../domain/result.js";
|
|
2
|
+
export const normalizeEmailAddress = (address) => address.trim().toLowerCase();
|
|
3
|
+
const hasFromAddress = (account, fromAddress) => account.allowedFromAddresses.some((allowedAddress) => normalizeEmailAddress(allowedAddress) === fromAddress);
|
|
4
|
+
/** Resolve one configured connector and authorize its sender identity. */
|
|
5
|
+
export const resolveDeliveryIdentity = (accounts, accountId, fromAddress) => {
|
|
6
|
+
const matchingAccounts = accounts.filter((account) => account.accountId === accountId);
|
|
7
|
+
if (matchingAccounts.length === 0)
|
|
8
|
+
return Err({ kind: "AccountNotFound", accountId });
|
|
9
|
+
if (matchingAccounts.length > 1)
|
|
10
|
+
return Err({ kind: "AmbiguousAccount", accountId });
|
|
11
|
+
const normalizedFromAddress = normalizeEmailAddress(fromAddress);
|
|
12
|
+
if (normalizedFromAddress.length === 0)
|
|
13
|
+
return Err({ kind: "InvalidFromIdentity" });
|
|
14
|
+
const selectedAccount = matchingAccounts[0];
|
|
15
|
+
if (selectedAccount === undefined || !hasFromAddress(selectedAccount, normalizedFromAddress)) {
|
|
16
|
+
return Err({
|
|
17
|
+
kind: "UnauthorizedFromIdentity",
|
|
18
|
+
accountId,
|
|
19
|
+
fromAddress: normalizedFromAddress,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
const addressOwners = accounts.filter((account) => hasFromAddress(account, normalizedFromAddress));
|
|
23
|
+
if (addressOwners.length > 1) {
|
|
24
|
+
return Err({ kind: "AmbiguousFromIdentity", fromAddress: normalizedFromAddress });
|
|
25
|
+
}
|
|
26
|
+
return Ok({ accountId, fromAddress: normalizedFromAddress });
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=identity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity.js","sourceRoot":"","sources":["../../../src/delivery/domain/identity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,EAAE,EAAe,MAAM,wBAAwB,CAAC;AAuB9D,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,OAAe,EAAU,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AAE/F,MAAM,cAAc,GAAG,CAAC,OAAgC,EAAE,WAAmB,EAAW,EAAE,CACxF,OAAO,CAAC,oBAAoB,CAAC,IAAI,CAC/B,CAAC,cAAc,EAAE,EAAE,CAAC,qBAAqB,CAAC,cAAc,CAAC,KAAK,WAAW,CAC1E,CAAC;AAEJ,0EAA0E;AAC1E,MAAM,CAAC,MAAM,uBAAuB,GAAG,CACrC,QAA4C,EAC5C,SAAiB,EACjB,WAAmB,EACsC,EAAE;IAC3D,MAAM,gBAAgB,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC;IACvF,IAAI,gBAAgB,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,GAAG,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,SAAS,EAAE,CAAC,CAAC;IACtF,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,GAAG,CAAC,EAAE,IAAI,EAAE,kBAAkB,EAAE,SAAS,EAAE,CAAC,CAAC;IAErF,MAAM,qBAAqB,GAAG,qBAAqB,CAAC,WAAW,CAAC,CAAC;IACjE,IAAI,qBAAqB,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,GAAG,CAAC,EAAE,IAAI,EAAE,qBAAqB,EAAE,CAAC,CAAC;IAEpF,MAAM,eAAe,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAAC;IAC5C,IAAI,eAAe,KAAK,SAAS,IAAI,CAAC,cAAc,CAAC,eAAe,EAAE,qBAAqB,CAAC,EAAE,CAAC;QAC7F,OAAO,GAAG,CAAC;YACT,IAAI,EAAE,0BAA0B;YAChC,SAAS;YACT,WAAW,EAAE,qBAAqB;SACnC,CAAC,CAAC;IACL,CAAC;IAED,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAChD,cAAc,CAAC,OAAO,EAAE,qBAAqB,CAAC,CAC/C,CAAC;IACF,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,OAAO,GAAG,CAAC,EAAE,IAAI,EAAE,uBAAuB,EAAE,WAAW,EAAE,qBAAqB,EAAE,CAAC,CAAC;IACpF,CAAC;IAED,OAAO,EAAE,CAAC,EAAE,SAAS,EAAE,WAAW,EAAE,qBAAqB,EAAE,CAAC,CAAC;AAC/D,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json.js","sourceRoot":"","sources":["../../../src/delivery/domain/json.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/** Normalized SMTP failure details. Provider-specific objects stay in adapters. */
|
|
2
|
+
export type TransportFailure = {
|
|
3
|
+
readonly reason: string;
|
|
4
|
+
};
|
|
5
|
+
export type TransportReceipt = {
|
|
6
|
+
readonly messageId: string;
|
|
7
|
+
readonly accepted: readonly string[];
|
|
8
|
+
readonly rejected: readonly string[];
|
|
9
|
+
readonly response: string;
|
|
10
|
+
};
|
|
11
|
+
export type PreAcceptanceFailure = {
|
|
12
|
+
readonly kind: "Transient";
|
|
13
|
+
readonly failure: TransportFailure;
|
|
14
|
+
} | {
|
|
15
|
+
readonly kind: "Permanent";
|
|
16
|
+
readonly failure: TransportFailure;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* SMTP outcome at the only boundary that controls automatic retry safety.
|
|
20
|
+
* Unknown outcomes are intentionally distinct from definitive rejection.
|
|
21
|
+
*/
|
|
22
|
+
export type TransportOutcome = {
|
|
23
|
+
readonly kind: "Accepted";
|
|
24
|
+
readonly receipt: TransportReceipt;
|
|
25
|
+
} | {
|
|
26
|
+
readonly kind: "RejectedBeforeAcceptance";
|
|
27
|
+
readonly rejection: PreAcceptanceFailure;
|
|
28
|
+
} | {
|
|
29
|
+
readonly kind: "UnknownOutcome";
|
|
30
|
+
readonly failure: TransportFailure;
|
|
31
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transportOutcome.js","sourceRoot":"","sources":["../../../src/delivery/domain/transportOutcome.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { Account } from "../../config/schema.js";
|
|
2
|
+
import type { OutboxRepository } from "../application/outboxRepository.js";
|
|
3
|
+
import type { PerAccountRateLimiter } from "./perAccountRateLimiter.js";
|
|
4
|
+
import type { SmtpSender } from "./smtpTransport.js";
|
|
5
|
+
export type DeliveryDisposition = {
|
|
6
|
+
readonly kind: "Ack";
|
|
7
|
+
readonly reason: string;
|
|
8
|
+
} | {
|
|
9
|
+
readonly kind: "Reject";
|
|
10
|
+
readonly reason: string;
|
|
11
|
+
} | {
|
|
12
|
+
readonly kind: "Retry";
|
|
13
|
+
readonly reason: string;
|
|
14
|
+
readonly delayMs: number;
|
|
15
|
+
};
|
|
16
|
+
export type DeliveryTarget = {
|
|
17
|
+
readonly kind: "EventLocator";
|
|
18
|
+
readonly externalId: string;
|
|
19
|
+
readonly account: string;
|
|
20
|
+
readonly mailboxId: string;
|
|
21
|
+
} | {
|
|
22
|
+
readonly kind: "Reconciliation";
|
|
23
|
+
readonly externalId: string;
|
|
24
|
+
};
|
|
25
|
+
export type DeliveryLog = (message: string, extra?: Readonly<Record<string, unknown>>) => void;
|
|
26
|
+
export type ConfiguredDeliveryAccount = {
|
|
27
|
+
readonly config: Account;
|
|
28
|
+
readonly sender: SmtpSender;
|
|
29
|
+
};
|
|
30
|
+
export type DeliveryProcessor = {
|
|
31
|
+
readonly process: (target: DeliveryTarget) => Promise<DeliveryDisposition>;
|
|
32
|
+
};
|
|
33
|
+
type DeliveryProcessorDependencies = {
|
|
34
|
+
readonly repository: OutboxRepository;
|
|
35
|
+
readonly accounts: readonly ConfiguredDeliveryAccount[];
|
|
36
|
+
readonly rateLimiter: PerAccountRateLimiter;
|
|
37
|
+
readonly leaseOwner: string;
|
|
38
|
+
readonly now: () => Date;
|
|
39
|
+
readonly log: DeliveryLog;
|
|
40
|
+
};
|
|
41
|
+
export declare const buildDeliveryProcessor: (dependencies: DeliveryProcessorDependencies) => DeliveryProcessor;
|
|
42
|
+
export {};
|