@kernhq/module-mail 0.4.0 → 0.4.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/package.json +3 -6
- package/dist/service/env.d.ts +0 -10
- package/dist/service/env.d.ts.map +0 -1
- package/dist/service/env.js +0 -26
- package/dist/service/env.js.map +0 -1
- package/dist/service/main.d.ts +0 -2
- package/dist/service/main.d.ts.map +0 -1
- package/dist/service/main.js +0 -27
- package/dist/service/main.js.map +0 -1
- package/dist/service/manifest.d.ts +0 -2
- package/dist/service/manifest.d.ts.map +0 -1
- package/dist/service/manifest.js +0 -16
- package/dist/service/manifest.js.map +0 -1
- package/dist/service/principal.d.ts +0 -15
- package/dist/service/principal.d.ts.map +0 -1
- package/dist/service/principal.js +0 -48
- package/dist/service/principal.js.map +0 -1
- package/dist/service/service.d.ts +0 -22
- package/dist/service/service.d.ts.map +0 -1
- package/dist/service/service.js +0 -48
- package/dist/service/service.js.map +0 -1
- package/dist/service/webhooks.d.ts +0 -10
- package/dist/service/webhooks.d.ts.map +0 -1
- package/dist/service/webhooks.js +0 -138
- package/dist/service/webhooks.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kernhq/module-mail",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Kern mail module: outbound providers (SMTP/Mailgun/SES/Postmark/Resend), MJML templates, delivery queue, bounces & suppressions",
|
|
5
5
|
"homepage": "https://github.com/KernAIO/module-mail#readme",
|
|
6
6
|
"license": "AGPL-3.0-only",
|
|
@@ -50,10 +50,8 @@
|
|
|
50
50
|
"@kernhq/sdk": "^0.1.5",
|
|
51
51
|
"@orpc/contract": "^1.15.0",
|
|
52
52
|
"@orpc/server": "^1.15.0",
|
|
53
|
-
"dotenv": "^17.4.0",
|
|
54
53
|
"drizzle-orm": "^0.45.0",
|
|
55
54
|
"eta": "^4.6.0",
|
|
56
|
-
"fastify": "^5.6.0",
|
|
57
55
|
"imapflow": "^1.7.0",
|
|
58
56
|
"mjml": "^5.4.0",
|
|
59
57
|
"nodemailer": "^9.0.5",
|
|
@@ -104,13 +102,12 @@
|
|
|
104
102
|
},
|
|
105
103
|
"scripts": {
|
|
106
104
|
"build": "tsc -p tsconfig.json",
|
|
107
|
-
"dev": "
|
|
105
|
+
"dev": "tsc -p tsconfig.json --watch --preserveWatchOutput",
|
|
108
106
|
"typecheck": "tsc -p tsconfig.json --noEmit && svelte-check --tsconfig ./tsconfig.client.json --threshold error",
|
|
109
107
|
"test": "vitest run",
|
|
110
108
|
"db:generate": "drizzle-kit generate",
|
|
111
109
|
"lint": "biome check . && node scripts/check-ranges.mjs package.json",
|
|
112
110
|
"format": "biome check --write .",
|
|
113
|
-
"changeset": "changeset"
|
|
114
|
-
"start": "node dist/service/main.js"
|
|
111
|
+
"changeset": "changeset"
|
|
115
112
|
}
|
|
116
113
|
}
|
package/dist/service/env.d.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
export declare const MailEnv: z.ZodObject<{
|
|
3
|
-
SMTP_URL: z.ZodOptional<z.ZodString>;
|
|
4
|
-
MAIL_FROM: z.ZodDefault<z.ZodString>;
|
|
5
|
-
KERN_INSTANCE_NAME: z.ZodDefault<z.ZodString>;
|
|
6
|
-
MAIL_WEBHOOK_TOKEN: z.ZodOptional<z.ZodString>;
|
|
7
|
-
}, z.core.$strip>;
|
|
8
|
-
export type MailEnv = z.infer<typeof MailEnv>;
|
|
9
|
-
export declare function loadMailEnv(extra?: Record<string, string | undefined>): MailEnv;
|
|
10
|
-
//# sourceMappingURL=env.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../src/service/env.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAQvB,eAAO,MAAM,OAAO;;;;;iBAOlB,CAAA;AACF,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,OAAO,CAAC,CAAA;AAE7C,wBAAgB,WAAW,CAAC,KAAK,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAM,GAAG,OAAO,CAQnF"}
|
package/dist/service/env.js
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
/** Loads `.env` (repo-local, then the umbrella workspace) outside production and validates mail settings. */
|
|
2
|
-
import { dirname, resolve } from 'node:path';
|
|
3
|
-
import { fileURLToPath } from 'node:url';
|
|
4
|
-
import { config as loadDotenv } from 'dotenv';
|
|
5
|
-
import { z } from 'zod';
|
|
6
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
7
|
-
const here = dirname(fileURLToPath(import.meta.url));
|
|
8
|
-
loadDotenv({ path: resolve(here, '../.env'), quiet: true });
|
|
9
|
-
loadDotenv({ path: resolve(here, '../../../.env'), quiet: true });
|
|
10
|
-
}
|
|
11
|
-
export const MailEnv = z.object({
|
|
12
|
-
/** fallback provider when a workspace has not configured its own */
|
|
13
|
-
SMTP_URL: z.string().optional(),
|
|
14
|
-
MAIL_FROM: z.string().default('Kern <no-reply@localhost>'),
|
|
15
|
-
KERN_INSTANCE_NAME: z.string().default('Kern'),
|
|
16
|
-
/** shared secret provider webhooks must present (query `?token=` or `x-kern-webhook-token`) */
|
|
17
|
-
MAIL_WEBHOOK_TOKEN: z.string().optional(),
|
|
18
|
-
});
|
|
19
|
-
export function loadMailEnv(extra = {}) {
|
|
20
|
-
const parsed = MailEnv.safeParse({ ...process.env, ...extra });
|
|
21
|
-
if (!parsed.success) {
|
|
22
|
-
throw new Error(`Invalid mail environment:\n${parsed.error.issues.map((i) => ` ${i.path.join('.')}: ${i.message}`).join('\n')}`);
|
|
23
|
-
}
|
|
24
|
-
return parsed.data;
|
|
25
|
-
}
|
|
26
|
-
//# sourceMappingURL=env.js.map
|
package/dist/service/env.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"env.js","sourceRoot":"","sources":["../../src/service/env.ts"],"names":[],"mappings":"AAAA,6GAA6G;AAC7G,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,EAAE,CAAC;IAC1C,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;IACpD,UAAU,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;IAC3D,UAAU,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,eAAe,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;AACnE,CAAC;AAED,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9B,oEAAoE;IACpE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC/B,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,2BAA2B,CAAC;IAC1D,kBAAkB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC;IAC9C,+FAA+F;IAC/F,kBAAkB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC1C,CAAC,CAAA;AAGF,MAAM,UAAU,WAAW,CAAC,QAA4C,EAAE;IACxE,MAAM,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,KAAK,EAAE,CAAC,CAAA;IAC9D,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CACb,8BAA8B,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACjH,CAAA;IACH,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAA;AACpB,CAAC"}
|
package/dist/service/main.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/service/main.ts"],"names":[],"mappings":""}
|
package/dist/service/main.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { createMailService } from './service.js';
|
|
2
|
-
const svc = await createMailService({ role: 'both' });
|
|
3
|
-
const { kernel, app } = svc;
|
|
4
|
-
if (!app)
|
|
5
|
-
throw new Error('mail service started without an HTTP server');
|
|
6
|
-
await app.listen({ port: kernel.env.PORT, host: kernel.env.HOST });
|
|
7
|
-
kernel.log.info({ port: kernel.env.PORT }, 'mail service listening');
|
|
8
|
-
let stopping = false;
|
|
9
|
-
async function shutdown(signal) {
|
|
10
|
-
if (stopping)
|
|
11
|
-
return;
|
|
12
|
-
stopping = true;
|
|
13
|
-
kernel.log.info({ signal }, 'shutting down');
|
|
14
|
-
const timer = setTimeout(() => process.exit(1), 15_000);
|
|
15
|
-
timer.unref();
|
|
16
|
-
try {
|
|
17
|
-
await svc.stop();
|
|
18
|
-
process.exit(0);
|
|
19
|
-
}
|
|
20
|
-
catch (err) {
|
|
21
|
-
kernel.log.error({ err }, 'shutdown failed');
|
|
22
|
-
process.exit(1);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
process.on('SIGINT', () => void shutdown('SIGINT'));
|
|
26
|
-
process.on('SIGTERM', () => void shutdown('SIGTERM'));
|
|
27
|
-
//# sourceMappingURL=main.js.map
|
package/dist/service/main.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/service/main.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAEhD,MAAM,GAAG,GAAG,MAAM,iBAAiB,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAA;AACrD,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,CAAA;AAC3B,IAAI,CAAC,GAAG;IAAE,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAA;AAExE,MAAM,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAA;AAElE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,wBAAwB,CAAC,CAAA;AAEpE,IAAI,QAAQ,GAAG,KAAK,CAAA;AACpB,KAAK,UAAU,QAAQ,CAAC,MAAc;IACpC,IAAI,QAAQ;QAAE,OAAM;IACpB,QAAQ,GAAG,IAAI,CAAA;IACf,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,eAAe,CAAC,CAAA;IAC5C,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAA;IACvD,KAAK,CAAC,KAAK,EAAE,CAAA;IACb,IAAI,CAAC;QACH,MAAM,GAAG,CAAC,IAAI,EAAE,CAAA;QAChB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,EAAE,iBAAiB,CAAC,CAAA;QAC5C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;AACH,CAAC;AACD,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAA;AACnD,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,KAAK,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/service/manifest.ts"],"names":[],"mappings":""}
|
package/dist/service/manifest.js
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { mailModule } from '../server/index.js';
|
|
2
|
-
/**
|
|
3
|
-
* What this image contains, printed as JSON.
|
|
4
|
-
*
|
|
5
|
-
* node dist/manifest.js
|
|
6
|
-
*
|
|
7
|
-
* The release feed is generated by asking each published image this question, so what an admin is
|
|
8
|
-
* told a release changes comes from the artefact itself rather than from a list somebody remembered
|
|
9
|
-
* to edit. It touches no database and no network.
|
|
10
|
-
*/
|
|
11
|
-
console.log(JSON.stringify({
|
|
12
|
-
service: 'mail',
|
|
13
|
-
kernVersion: process.env.KERN_VERSION ?? '0.0.0-dev',
|
|
14
|
-
modules: { [mailModule.definition.id]: mailModule.definition.version },
|
|
15
|
-
}));
|
|
16
|
-
//# sourceMappingURL=manifest.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/service/manifest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAE/C;;;;;;;;GAQG;AACH,OAAO,CAAC,GAAG,CACT,IAAI,CAAC,SAAS,CAAC;IACb,OAAO,EAAE,MAAM;IACf,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,WAAW;IACpD,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC,EAAE,UAAU,CAAC,UAAU,CAAC,OAAO,EAAE;CACvE,CAAC,CACH,CAAA"}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { type Principal } from '@kernhq/contracts';
|
|
2
|
-
import type { Kernel } from '@kernhq/kernel';
|
|
3
|
-
import type { FastifyRequest } from 'fastify';
|
|
4
|
-
/**
|
|
5
|
-
* Resolves principals for a service that does not own the identity tables: the session token is handed
|
|
6
|
-
* to core (`core.users.principal`), and the answer is cached briefly so that a burst of requests or a
|
|
7
|
-
* WebSocket handshake storm does not amplify into core.
|
|
8
|
-
*/
|
|
9
|
-
export interface Principals {
|
|
10
|
-
fromToken(token: string): Promise<Principal>;
|
|
11
|
-
fromRequest(req: FastifyRequest): Promise<Principal>;
|
|
12
|
-
invalidate(token?: string): void;
|
|
13
|
-
}
|
|
14
|
-
export declare function createPrincipals(kernel: Kernel, ttlMs?: number): Principals;
|
|
15
|
-
//# sourceMappingURL=principal.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"principal.d.ts","sourceRoot":"","sources":["../../src/service/principal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,SAAS,EAAE,MAAM,mBAAmB,CAAA;AAC7D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAE7C;;;;GAIG;AACH,MAAM,WAAW,UAAU;IACzB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAAA;IAC5C,WAAW,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,SAAS,CAAC,CAAA;IACpD,UAAU,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACjC;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,SAAS,GAAG,UAAU,CAuC3E"}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { ANONYMOUS } from '@kernhq/contracts';
|
|
2
|
-
export function createPrincipals(kernel, ttlMs = 60_000) {
|
|
3
|
-
const cache = new Map();
|
|
4
|
-
const fromToken = async (token) => {
|
|
5
|
-
if (!token)
|
|
6
|
-
return ANONYMOUS;
|
|
7
|
-
const hit = cache.get(token);
|
|
8
|
-
if (hit && hit.expires > Date.now())
|
|
9
|
-
return hit.principal;
|
|
10
|
-
const principal = await kernel
|
|
11
|
-
.call('core.users.principal', { token })
|
|
12
|
-
.catch((err) => {
|
|
13
|
-
kernel.log.warn({ err }, 'principal lookup failed');
|
|
14
|
-
return ANONYMOUS;
|
|
15
|
-
});
|
|
16
|
-
if (principal.kind !== 'anonymous')
|
|
17
|
-
cache.set(token, { principal, expires: Date.now() + ttlMs });
|
|
18
|
-
return principal;
|
|
19
|
-
};
|
|
20
|
-
return {
|
|
21
|
-
fromToken,
|
|
22
|
-
async fromRequest(req) {
|
|
23
|
-
const service = req.headers['x-kern-service'];
|
|
24
|
-
if (typeof service === 'string') {
|
|
25
|
-
const name = await kernel.auth.verifyService(service);
|
|
26
|
-
if (name)
|
|
27
|
-
return { ...ANONYMOUS, kind: 'service', service: name, instanceAdmin: true };
|
|
28
|
-
}
|
|
29
|
-
const auth = req.headers.authorization;
|
|
30
|
-
if (auth?.startsWith('Bearer '))
|
|
31
|
-
return fromToken(auth.slice(7));
|
|
32
|
-
const cookie = req.headers.cookie;
|
|
33
|
-
if (cookie) {
|
|
34
|
-
const match = /(?:^|;\s*)(?:__Secure-)?kern\.session_token=([^;]+)/.exec(cookie);
|
|
35
|
-
if (match?.[1])
|
|
36
|
-
return fromToken(decodeURIComponent(match[1]));
|
|
37
|
-
}
|
|
38
|
-
return ANONYMOUS;
|
|
39
|
-
},
|
|
40
|
-
invalidate(token) {
|
|
41
|
-
if (token)
|
|
42
|
-
cache.delete(token);
|
|
43
|
-
else
|
|
44
|
-
cache.clear();
|
|
45
|
-
},
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
//# sourceMappingURL=principal.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"principal.js","sourceRoot":"","sources":["../../src/service/principal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAkB,MAAM,mBAAmB,CAAA;AAe7D,MAAM,UAAU,gBAAgB,CAAC,MAAc,EAAE,KAAK,GAAG,MAAM;IAC7D,MAAM,KAAK,GAAG,IAAI,GAAG,EAAqD,CAAA;IAE1E,MAAM,SAAS,GAAG,KAAK,EAAE,KAAa,EAAsB,EAAE;QAC5D,IAAI,CAAC,KAAK;YAAE,OAAO,SAAS,CAAA;QAC5B,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QAC5B,IAAI,GAAG,IAAI,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE;YAAE,OAAO,GAAG,CAAC,SAAS,CAAA;QACzD,MAAM,SAAS,GAAG,MAAM,MAAM;aAC3B,IAAI,CAAY,sBAAsB,EAAE,EAAE,KAAK,EAAE,CAAC;aAClD,KAAK,CAAC,CAAC,GAAG,EAAa,EAAE;YACxB,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,EAAE,yBAAyB,CAAC,CAAA;YACnD,OAAO,SAAS,CAAA;QAClB,CAAC,CAAC,CAAA;QACJ,IAAI,SAAS,CAAC,IAAI,KAAK,WAAW;YAAE,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,EAAE,CAAC,CAAA;QAChG,OAAO,SAAS,CAAA;IAClB,CAAC,CAAA;IAED,OAAO;QACL,SAAS;QACT,KAAK,CAAC,WAAW,CAAC,GAAG;YACnB,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAA;YAC7C,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;gBAChC,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAA;gBACrD,IAAI,IAAI;oBAAE,OAAO,EAAE,GAAG,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,CAAA;YACxF,CAAC;YACD,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,aAAa,CAAA;YACtC,IAAI,IAAI,EAAE,UAAU,CAAC,SAAS,CAAC;gBAAE,OAAO,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;YAChE,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,CAAA;YACjC,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,KAAK,GAAG,qDAAqD,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;gBAChF,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC;oBAAE,OAAO,SAAS,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;YAChE,CAAC;YACD,OAAO,SAAS,CAAA;QAClB,CAAC;QACD,UAAU,CAAC,KAAK;YACd,IAAI,KAAK;gBAAE,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;;gBACzB,KAAK,CAAC,KAAK,EAAE,CAAA;QACpB,CAAC;KACF,CAAA;AACH,CAAC"}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { type Kernel } from '@kernhq/kernel';
|
|
2
|
-
import type { FastifyInstance } from 'fastify';
|
|
3
|
-
import { type MailEnv } from './env.js';
|
|
4
|
-
import { type Principals } from './principal.js';
|
|
5
|
-
export interface MailServiceOptions {
|
|
6
|
-
role?: 'api' | 'worker' | 'both';
|
|
7
|
-
env?: Record<string, string | undefined>;
|
|
8
|
-
}
|
|
9
|
-
export interface MailService {
|
|
10
|
-
kernel: Kernel;
|
|
11
|
-
env: MailEnv;
|
|
12
|
-
app: FastifyInstance | null;
|
|
13
|
-
principals: Principals;
|
|
14
|
-
stop(): Promise<void>;
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Boots the mail service: the mail module (providers, templates, delivery log) plus the provider
|
|
18
|
-
* webhooks. Runs the `mail.send` worker in the same process by default, so a self-hosted install does
|
|
19
|
-
* not need a separate container for outgoing email.
|
|
20
|
-
*/
|
|
21
|
-
export declare function createMailService(opts?: MailServiceOptions): Promise<MailService>;
|
|
22
|
-
//# sourceMappingURL=service.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/service/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkC,KAAK,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAC5E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAE9C,OAAO,EAAe,KAAK,OAAO,EAAE,MAAM,UAAU,CAAA;AACpD,OAAO,EAAoB,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAGlE,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAA;IAChC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAA;CACzC;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,GAAG,EAAE,OAAO,CAAA;IACZ,GAAG,EAAE,eAAe,GAAG,IAAI,CAAA;IAC3B,UAAU,EAAE,UAAU,CAAA;IACtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACtB;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,GAAE,kBAAuB,GAAG,OAAO,CAAC,WAAW,CAAC,CA0C3F"}
|
package/dist/service/service.js
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { createHttpServer, createKernel } from '@kernhq/kernel';
|
|
2
|
-
import { mailModule } from '../server/index.js';
|
|
3
|
-
import { loadMailEnv } from './env.js';
|
|
4
|
-
import { createPrincipals } from './principal.js';
|
|
5
|
-
import { mountWebhooks } from './webhooks.js';
|
|
6
|
-
/**
|
|
7
|
-
* Boots the mail service: the mail module (providers, templates, delivery log) plus the provider
|
|
8
|
-
* webhooks. Runs the `mail.send` worker in the same process by default, so a self-hosted install does
|
|
9
|
-
* not need a separate container for outgoing email.
|
|
10
|
-
*/
|
|
11
|
-
export async function createMailService(opts = {}) {
|
|
12
|
-
const role = opts.role ?? 'both';
|
|
13
|
-
const env = loadMailEnv(opts.env ?? {});
|
|
14
|
-
const kernel = await createKernel({
|
|
15
|
-
service: 'mail',
|
|
16
|
-
modules: [mailModule],
|
|
17
|
-
role,
|
|
18
|
-
env: { PORT: process.env.PORT ?? '4200', ...opts.env },
|
|
19
|
-
});
|
|
20
|
-
await kernel.start();
|
|
21
|
-
const principals = createPrincipals(kernel);
|
|
22
|
-
let app = null;
|
|
23
|
-
if (role !== 'worker') {
|
|
24
|
-
const corsOrigins = [
|
|
25
|
-
...new Set([kernel.env.KERN_BASE_URL, ...(kernel.env.CORS_ORIGINS ?? '').split(',').map((s) => s.trim())].filter(Boolean)),
|
|
26
|
-
];
|
|
27
|
-
app = await createHttpServer({
|
|
28
|
-
kernel,
|
|
29
|
-
resolvePrincipal: (req) => principals.fromRequest(req),
|
|
30
|
-
corsOrigins,
|
|
31
|
-
openapi: { title: 'Kern', version: kernel.version },
|
|
32
|
-
extend: async (fastify) => {
|
|
33
|
-
mountWebhooks(fastify, kernel, env);
|
|
34
|
-
},
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
return {
|
|
38
|
-
kernel,
|
|
39
|
-
env,
|
|
40
|
-
app,
|
|
41
|
-
principals,
|
|
42
|
-
async stop() {
|
|
43
|
-
await app?.close();
|
|
44
|
-
await kernel.stop();
|
|
45
|
-
},
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
//# sourceMappingURL=service.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/service/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAe,MAAM,gBAAgB,CAAA;AAE5E,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAC/C,OAAO,EAAE,WAAW,EAAgB,MAAM,UAAU,CAAA;AACpD,OAAO,EAAE,gBAAgB,EAAmB,MAAM,gBAAgB,CAAA;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAe7C;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,OAA2B,EAAE;IACnE,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,MAAM,CAAA;IAChC,MAAM,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC,CAAA;IACvC,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC;QAChC,OAAO,EAAE,MAAM;QACf,OAAO,EAAE,CAAC,UAAU,CAAC;QACrB,IAAI;QACJ,GAAG,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE;KACvD,CAAC,CAAA;IACF,MAAM,MAAM,CAAC,KAAK,EAAE,CAAA;IAEpB,MAAM,UAAU,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAA;IAC3C,IAAI,GAAG,GAA2B,IAAI,CAAA;IACtC,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtB,MAAM,WAAW,GAAG;YAClB,GAAG,IAAI,GAAG,CACR,CAAC,MAAM,CAAC,GAAG,CAAC,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,CACnG,OAAO,CACR,CACF;SACF,CAAA;QACD,GAAG,GAAG,MAAM,gBAAgB,CAAC;YAC3B,MAAM;YACN,gBAAgB,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,GAAG,CAAC;YACtD,WAAW;YACX,OAAO,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE;YACnD,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;gBACxB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,CAAA;YACrC,CAAC;SACF,CAAC,CAAA;IACJ,CAAC;IAED,OAAO;QACL,MAAM;QACN,GAAG;QACH,GAAG;QACH,UAAU;QACV,KAAK,CAAC,IAAI;YACR,MAAM,GAAG,EAAE,KAAK,EAAE,CAAA;YAClB,MAAM,MAAM,CAAC,IAAI,EAAE,CAAA;QACrB,CAAC;KACF,CAAA;AACH,CAAC"}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Provider webhooks. Each provider reports deliveries, bounces and complaints in its own shape; they are
|
|
3
|
-
* normalised here into a delivery status update plus, for hard failures, a suppression entry so later
|
|
4
|
-
* sends skip the address.
|
|
5
|
-
*/
|
|
6
|
-
import type { Kernel } from '@kernhq/kernel';
|
|
7
|
-
import type { FastifyInstance } from 'fastify';
|
|
8
|
-
import type { MailEnv } from './env.js';
|
|
9
|
-
export declare function mountWebhooks(app: FastifyInstance, kernel: Kernel, env: MailEnv): void;
|
|
10
|
-
//# sourceMappingURL=webhooks.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"webhooks.d.ts","sourceRoot":"","sources":["../../src/service/webhooks.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAE5C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAE9C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAA;AAgGvC,wBAAgB,aAAa,CAAC,GAAG,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,GAAG,IAAI,CA8DtF"}
|
package/dist/service/webhooks.js
DELETED
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Provider webhooks. Each provider reports deliveries, bounces and complaints in its own shape; they are
|
|
3
|
-
* normalised here into a delivery status update plus, for hard failures, a suppression entry so later
|
|
4
|
-
* sends skip the address.
|
|
5
|
-
*/
|
|
6
|
-
import { eq } from 'drizzle-orm';
|
|
7
|
-
import { addSuppression, deliveries, emitDeliveryEvent, mailEvents } from '../server/index.js';
|
|
8
|
-
const asString = (v) => (typeof v === 'string' && v ? v : null);
|
|
9
|
-
function normalise(provider, body) {
|
|
10
|
-
switch (provider) {
|
|
11
|
-
case 'mailgun': {
|
|
12
|
-
const e = body['event-data'] ?? {};
|
|
13
|
-
const kind = asString(e.event);
|
|
14
|
-
return {
|
|
15
|
-
providerMessageId: asString(e.message?.headers?.['message-id']),
|
|
16
|
-
recipient: asString(e.recipient),
|
|
17
|
-
event: kind === 'delivered'
|
|
18
|
-
? 'delivered'
|
|
19
|
-
: kind === 'failed'
|
|
20
|
-
? e.severity === 'permanent'
|
|
21
|
-
? 'bounced'
|
|
22
|
-
: 'failed'
|
|
23
|
-
: kind === 'complained'
|
|
24
|
-
? 'complained'
|
|
25
|
-
: 'ignored',
|
|
26
|
-
reason: asString(e['delivery-status']?.message) ?? asString(e.reason),
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
case 'postmark': {
|
|
30
|
-
const type = asString(body.RecordType);
|
|
31
|
-
return {
|
|
32
|
-
providerMessageId: asString(body.MessageID),
|
|
33
|
-
recipient: asString(body.Email) ?? asString(body.Recipient),
|
|
34
|
-
event: type === 'Delivery'
|
|
35
|
-
? 'delivered'
|
|
36
|
-
: type === 'Bounce'
|
|
37
|
-
? body.Type === 'SoftBounce'
|
|
38
|
-
? 'failed'
|
|
39
|
-
: 'bounced'
|
|
40
|
-
: type === 'SpamComplaint'
|
|
41
|
-
? 'complained'
|
|
42
|
-
: 'ignored',
|
|
43
|
-
reason: asString(body.Description) ?? asString(body.Details),
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
case 'ses': {
|
|
47
|
-
const message = typeof body.Message === 'string' ? JSON.parse(body.Message) : (body.Message ?? body);
|
|
48
|
-
const type = asString(message.notificationType ?? message.eventType);
|
|
49
|
-
const recipient = asString(message.bounce?.bouncedRecipients?.[0]?.emailAddress) ??
|
|
50
|
-
asString(message.complaint?.complainedRecipients?.[0]?.emailAddress) ??
|
|
51
|
-
asString(message.mail?.destination?.[0]);
|
|
52
|
-
return {
|
|
53
|
-
providerMessageId: asString(message.mail?.messageId),
|
|
54
|
-
recipient,
|
|
55
|
-
event: type === 'Delivery'
|
|
56
|
-
? 'delivered'
|
|
57
|
-
: type === 'Bounce'
|
|
58
|
-
? message.bounce?.bounceType === 'Transient'
|
|
59
|
-
? 'failed'
|
|
60
|
-
: 'bounced'
|
|
61
|
-
: type === 'Complaint'
|
|
62
|
-
? 'complained'
|
|
63
|
-
: 'ignored',
|
|
64
|
-
reason: asString(message.bounce?.bouncedRecipients?.[0]?.diagnosticCode),
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
case 'resend': {
|
|
68
|
-
const type = asString(body.type);
|
|
69
|
-
return {
|
|
70
|
-
providerMessageId: asString(body.data?.email_id),
|
|
71
|
-
recipient: asString(body.data?.to?.[0]),
|
|
72
|
-
event: type === 'email.delivered'
|
|
73
|
-
? 'delivered'
|
|
74
|
-
: type === 'email.bounced'
|
|
75
|
-
? 'bounced'
|
|
76
|
-
: type === 'email.complained'
|
|
77
|
-
? 'complained'
|
|
78
|
-
: 'ignored',
|
|
79
|
-
reason: asString(body.data?.reason),
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
default:
|
|
83
|
-
return { providerMessageId: null, recipient: null, event: 'ignored', reason: null };
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
const PROVIDERS = ['mailgun', 'postmark', 'ses', 'resend'];
|
|
87
|
-
export function mountWebhooks(app, kernel, env) {
|
|
88
|
-
app.post('/api/mail/webhooks/:provider', async (req, reply) => {
|
|
89
|
-
const provider = req.params.provider;
|
|
90
|
-
if (!PROVIDERS.includes(provider)) {
|
|
91
|
-
return reply.status(404).send({ code: 'NOT_FOUND', message: 'Unknown provider' });
|
|
92
|
-
}
|
|
93
|
-
// Providers cannot present a Kern session, so webhook URLs carry a shared secret instead.
|
|
94
|
-
if (env.MAIL_WEBHOOK_TOKEN) {
|
|
95
|
-
const presented = req.query.token ?? req.headers['x-kern-webhook-token'];
|
|
96
|
-
if (presented !== env.MAIL_WEBHOOK_TOKEN) {
|
|
97
|
-
return reply.status(401).send({ code: 'UNAUTHORIZED', message: 'Invalid webhook token' });
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
const body = (req.body ?? {});
|
|
101
|
-
// SES subscription confirmation
|
|
102
|
-
if (body.Type === 'SubscriptionConfirmation' && typeof body.SubscribeURL === 'string') {
|
|
103
|
-
await fetch(body.SubscribeURL).catch(() => { });
|
|
104
|
-
return { ok: true, confirmed: true };
|
|
105
|
-
}
|
|
106
|
-
const n = normalise(provider, body);
|
|
107
|
-
if (n.event === 'ignored')
|
|
108
|
-
return { ok: true, ignored: true };
|
|
109
|
-
const row = n.providerMessageId
|
|
110
|
-
? (await kernel.database.db
|
|
111
|
-
.select()
|
|
112
|
-
.from(deliveries)
|
|
113
|
-
.where(eq(deliveries.providerMessageId, n.providerMessageId))
|
|
114
|
-
.limit(1))[0]
|
|
115
|
-
: undefined;
|
|
116
|
-
if (row) {
|
|
117
|
-
const status = n.event === 'delivered' ? 'sent' : n.event === 'bounced' ? 'bounced' : 'failed';
|
|
118
|
-
await kernel.database.db
|
|
119
|
-
.update(deliveries)
|
|
120
|
-
.set({ status, error: n.reason, updatedAt: new Date() })
|
|
121
|
-
.where(eq(deliveries.id, row.id));
|
|
122
|
-
if (n.event !== 'delivered') {
|
|
123
|
-
await emitDeliveryEvent(kernel, n.event === 'bounced' ? mailEvents.deliveryBounced : mailEvents.deliveryFailed, { id: row.id, workspaceId: row.workspaceId, to: row.to }, { error: n.reason ?? undefined });
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
if (n.recipient && (n.event === 'bounced' || n.event === 'complained')) {
|
|
127
|
-
await addSuppression(kernel, {
|
|
128
|
-
workspaceId: row?.workspaceId ?? null,
|
|
129
|
-
email: n.recipient,
|
|
130
|
-
reason: n.event === 'complained' ? 'complaint' : 'bounce',
|
|
131
|
-
source: provider,
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
kernel.log.info({ provider, event: n.event, recipient: n.recipient }, 'mail webhook');
|
|
135
|
-
return { ok: true };
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
//# sourceMappingURL=webhooks.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"webhooks.js","sourceRoot":"","sources":["../../src/service/webhooks.ts"],"names":[],"mappings":"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"}
|