@mettlecast/domain-runtime 0.2.75 → 0.2.77
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/ctx/context.d.ts +3 -0
- package/dist/ctx/index.d.ts +1 -0
- package/dist/ctx/ses.d.ts +33 -0
- package/dist/ctx/ses.js +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3 -0
- package/dist/runtime/hydrate.d.ts +3 -0
- package/dist/runtime/hydrate.js +3 -0
- package/dist/runtime/index.d.ts +2 -0
- package/dist/runtime/index.js +1 -0
- package/dist/runtime/ses.d.ts +29 -0
- package/dist/runtime/ses.js +58 -0
- package/package.json +2 -1
package/dist/ctx/context.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ import type { AuditContext } from '../runtime/audit.js';
|
|
|
7
7
|
import type { DomainStoreContext } from './store.js';
|
|
8
8
|
import type { DomainFilesContext } from './files.js';
|
|
9
9
|
import type { CognitoContext } from './cognito.js';
|
|
10
|
+
import type { SesContext } from './ses.js';
|
|
10
11
|
/**
|
|
11
12
|
* The unified domain context injected into every handler.
|
|
12
13
|
* All fields are always populated by the runtime; no field is ever null.
|
|
@@ -50,6 +51,8 @@ export interface DomainContext {
|
|
|
50
51
|
files: DomainFilesContext;
|
|
51
52
|
/** Cognito control-plane client (Admin* operations). Noop when no user pool is configured. */
|
|
52
53
|
cognito: CognitoContext;
|
|
54
|
+
/** SES email-sending client. Noop when SES_FROM_EMAIL is not set. */
|
|
55
|
+
ses: SesContext;
|
|
53
56
|
/** URL path parameters from the incoming request, excluding tenantId (e.g. { tableName: 'users' }). */
|
|
54
57
|
pathParams: Record<string, string>;
|
|
55
58
|
}
|
package/dist/ctx/index.d.ts
CHANGED
|
@@ -5,3 +5,4 @@ export type { DomainContext } from './context.js';
|
|
|
5
5
|
export type { DomainStoreContext, StoreQueryOptions, StoreQueryResult } from './store.js';
|
|
6
6
|
export type { DomainFilesContext, FilesPutOptions, FilesListResult } from './files.js';
|
|
7
7
|
export type { CognitoContext } from './cognito.js';
|
|
8
|
+
export type { SesContext } from './ses.js';
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SES email-sending context. Automatically scoped to the configured
|
|
3
|
+
* sending identity — domain code never passes `Source`, region, or
|
|
4
|
+
* the SES client configuration.
|
|
5
|
+
*
|
|
6
|
+
* The runtime creates this when `SES_FROM_EMAIL` is set in the
|
|
7
|
+
* Lambda environment. Domain code accesses it via `ctx.ses`.
|
|
8
|
+
*/
|
|
9
|
+
export interface SesContext {
|
|
10
|
+
/**
|
|
11
|
+
* Send an email via SES. The runtime manages the SES client,
|
|
12
|
+
* region, and sending identity — domain code only provides
|
|
13
|
+
* the email content.
|
|
14
|
+
*
|
|
15
|
+
* @param params.to - Recipient email address(es).
|
|
16
|
+
* @param params.subject - Email subject line.
|
|
17
|
+
* @param params.htmlBody - HTML body content.
|
|
18
|
+
* @param params.textBody - Plain-text fallback body.
|
|
19
|
+
* @param params.from - Optional sender override (defaults to env SES_FROM_EMAIL).
|
|
20
|
+
* @param params.replyTo - Optional reply-to address(es).
|
|
21
|
+
* @returns The SES MessageId for the sent email.
|
|
22
|
+
*/
|
|
23
|
+
sendEmail(params: {
|
|
24
|
+
to: string | string[];
|
|
25
|
+
subject: string;
|
|
26
|
+
htmlBody?: string;
|
|
27
|
+
textBody?: string;
|
|
28
|
+
from?: string;
|
|
29
|
+
replyTo?: string | string[];
|
|
30
|
+
}): Promise<{
|
|
31
|
+
messageId: string;
|
|
32
|
+
}>;
|
|
33
|
+
}
|
package/dist/ctx/ses.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -4,3 +4,6 @@ export * from './primitives/index.js';
|
|
|
4
4
|
export * from './schema/index.js';
|
|
5
5
|
// Runtime implementations
|
|
6
6
|
export * from './runtime/index.js';
|
|
7
|
+
// Explicit re-export — `export *` wildcard doesn't reliably surface this
|
|
8
|
+
// for TS module resolution in all configurations.
|
|
9
|
+
export { initOtel } from './runtime/tracer.js';
|
|
@@ -7,6 +7,7 @@ import type { IntegrationDefinition } from '../primitives/integration.js';
|
|
|
7
7
|
import type { DomainStoreContext } from '../ctx/store.js';
|
|
8
8
|
import type { DomainFilesContext } from '../ctx/files.js';
|
|
9
9
|
import type { CognitoContext } from '../ctx/cognito.js';
|
|
10
|
+
import type { SesContext } from '../ctx/ses.js';
|
|
10
11
|
import type { ActionRegistry } from './actions.js';
|
|
11
12
|
/**
|
|
12
13
|
* Full options for hydrateCtx. All fields are optional — defaults are used for
|
|
@@ -113,6 +114,8 @@ export interface HydrateOptions {
|
|
|
113
114
|
pathParams?: Record<string, string>;
|
|
114
115
|
/** Override the Cognito context. If omitted, createCognito() is used (reads COGNITO_USER_POOL_ID from env). */
|
|
115
116
|
cognito?: CognitoContext;
|
|
117
|
+
/** Override the SES context. If omitted, createSes() is used (reads SES_FROM_EMAIL from env). */
|
|
118
|
+
ses?: SesContext;
|
|
116
119
|
}
|
|
117
120
|
/**
|
|
118
121
|
* Hydrates a fully populated DomainContext from a Lambda invocation event and options bag.
|
package/dist/runtime/hydrate.js
CHANGED
|
@@ -16,6 +16,7 @@ import { extractObservabilityBindings } from './observability-bindings.js';
|
|
|
16
16
|
import { createStore, createNoopStore } from './store.js';
|
|
17
17
|
import { createFiles, createNoopFiles } from './files.js';
|
|
18
18
|
import { createCognito } from './cognito.js';
|
|
19
|
+
import { createSes } from './ses.js';
|
|
19
20
|
/**
|
|
20
21
|
* Hydrates a fully populated DomainContext from a Lambda invocation event and options bag.
|
|
21
22
|
* All 14 DomainContext fields are populated. Fields with AWS dependencies fall back to
|
|
@@ -172,6 +173,7 @@ export async function hydrateCtx(_event, options = {}) {
|
|
|
172
173
|
? createFiles({ bucketName: options.domainBucketName ?? process.env['DOMAIN_BUCKET_NAME'], tenantId: tenant.id, tenantRoleArn: process.env['DOMAIN_TENANT_ROLE_ARN'] })
|
|
173
174
|
: createNoopFiles());
|
|
174
175
|
const cognito = options.cognito ?? createCognito();
|
|
176
|
+
const ses = options.ses ?? createSes();
|
|
175
177
|
ctx = {
|
|
176
178
|
db,
|
|
177
179
|
publish,
|
|
@@ -192,6 +194,7 @@ export async function hydrateCtx(_event, options = {}) {
|
|
|
192
194
|
store,
|
|
193
195
|
files,
|
|
194
196
|
cognito,
|
|
197
|
+
ses,
|
|
195
198
|
pathParams: options.pathParams ?? {},
|
|
196
199
|
};
|
|
197
200
|
return ctx;
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -62,3 +62,5 @@ export { createStore, createNoopStore } from './store.js';
|
|
|
62
62
|
export { createFiles, createNoopFiles } from './files.js';
|
|
63
63
|
export { createCognito, createNoopCognito } from './cognito.js';
|
|
64
64
|
export type { CognitoOptions } from './cognito.js';
|
|
65
|
+
export { createSes, createNoopSes } from './ses.js';
|
|
66
|
+
export type { SesOptions } from './ses.js';
|
package/dist/runtime/index.js
CHANGED
|
@@ -64,3 +64,4 @@ export { healthHandler, readinessHandler } from './health-handler.js';
|
|
|
64
64
|
export { createStore, createNoopStore } from './store.js';
|
|
65
65
|
export { createFiles, createNoopFiles } from './files.js';
|
|
66
66
|
export { createCognito, createNoopCognito } from './cognito.js';
|
|
67
|
+
export { createSes, createNoopSes } from './ses.js';
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { SesContext } from '../ctx/ses.js';
|
|
2
|
+
/** Options for the SES context factory. */
|
|
3
|
+
export interface SesOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Default from address for outgoing emails. Defaults to process.env.SES_FROM_EMAIL.
|
|
6
|
+
* If not set, the factory returns a noop context that throws on any call.
|
|
7
|
+
*/
|
|
8
|
+
fromAddress?: string;
|
|
9
|
+
/**
|
|
10
|
+
* AWS region. Defaults to process.env.SES_AWS_REGION or process.env.AWS_REGION.
|
|
11
|
+
*/
|
|
12
|
+
region?: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Create a SES-backed SesContext.
|
|
16
|
+
*
|
|
17
|
+
* The SDK client is created lazily on first use. The `fromAddress` is
|
|
18
|
+
* captured at construction time from `SES_FROM_EMAIL` — domain code
|
|
19
|
+
* never needs to pass it.
|
|
20
|
+
*
|
|
21
|
+
* @param options - SesOptions. If fromAddress is not resolved, returns a noop.
|
|
22
|
+
* @returns A SesContext backed by the AWS SDK, or a noop that throws.
|
|
23
|
+
*/
|
|
24
|
+
export declare function createSes(options?: SesOptions): SesContext;
|
|
25
|
+
/**
|
|
26
|
+
* Create a noop SesContext for tests or environments without SES.
|
|
27
|
+
* Every method throws with a clear message.
|
|
28
|
+
*/
|
|
29
|
+
export declare function createNoopSes(): SesContext;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Create a SES-backed SesContext.
|
|
3
|
+
*
|
|
4
|
+
* The SDK client is created lazily on first use. The `fromAddress` is
|
|
5
|
+
* captured at construction time from `SES_FROM_EMAIL` — domain code
|
|
6
|
+
* never needs to pass it.
|
|
7
|
+
*
|
|
8
|
+
* @param options - SesOptions. If fromAddress is not resolved, returns a noop.
|
|
9
|
+
* @returns A SesContext backed by the AWS SDK, or a noop that throws.
|
|
10
|
+
*/
|
|
11
|
+
export function createSes(options = {}) {
|
|
12
|
+
const fromAddress = options.fromAddress ?? process.env['SES_FROM_EMAIL'];
|
|
13
|
+
if (!fromAddress) {
|
|
14
|
+
return createNoopSes();
|
|
15
|
+
}
|
|
16
|
+
const region = options.region ?? process.env['SES_AWS_REGION'] ?? process.env['AWS_REGION'] ?? 'eu-north-1';
|
|
17
|
+
let client;
|
|
18
|
+
async function getClient() {
|
|
19
|
+
if (!client) {
|
|
20
|
+
const sdk = await import('@aws-sdk/client-ses');
|
|
21
|
+
client = new sdk.SESClient({ region });
|
|
22
|
+
}
|
|
23
|
+
return client;
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
async sendEmail(params) {
|
|
27
|
+
const sdk = await import('@aws-sdk/client-ses');
|
|
28
|
+
const c = await getClient();
|
|
29
|
+
const result = await c.send(new sdk.SendEmailCommand({
|
|
30
|
+
Source: params.from ?? fromAddress,
|
|
31
|
+
Destination: {
|
|
32
|
+
ToAddresses: Array.isArray(params.to) ? params.to : [params.to],
|
|
33
|
+
},
|
|
34
|
+
Message: {
|
|
35
|
+
Subject: { Data: params.subject, Charset: 'UTF-8' },
|
|
36
|
+
Body: {
|
|
37
|
+
...(params.htmlBody ? { Html: { Data: params.htmlBody, Charset: 'UTF-8' } } : {}),
|
|
38
|
+
...(params.textBody ? { Text: { Data: params.textBody, Charset: 'UTF-8' } } : {}),
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
...(params.replyTo ? {
|
|
42
|
+
ReplyToAddresses: Array.isArray(params.replyTo) ? params.replyTo : [params.replyTo],
|
|
43
|
+
} : {}),
|
|
44
|
+
}));
|
|
45
|
+
return { messageId: result.MessageId };
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Create a noop SesContext for tests or environments without SES.
|
|
51
|
+
* Every method throws with a clear message.
|
|
52
|
+
*/
|
|
53
|
+
export function createNoopSes() {
|
|
54
|
+
const msg = 'ctx.ses: SES_FROM_EMAIL is not set. Configure the email stack to enable SES operations.';
|
|
55
|
+
return {
|
|
56
|
+
async sendEmail() { throw new Error(msg); },
|
|
57
|
+
};
|
|
58
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mettlecast/domain-runtime",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.77",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"registry": "https://registry.npmjs.org",
|
|
@@ -48,6 +48,7 @@
|
|
|
48
48
|
"@aws-sdk/client-eventbridge": "^3.0.0",
|
|
49
49
|
"@aws-sdk/client-lambda": "^3.0.0",
|
|
50
50
|
"@aws-sdk/client-s3": "^3.0.0",
|
|
51
|
+
"@aws-sdk/client-ses": "^3.0.0",
|
|
51
52
|
"@aws-sdk/client-secrets-manager": "^3.0.0",
|
|
52
53
|
"@aws-sdk/client-sfn": "^3.0.0",
|
|
53
54
|
"@aws-sdk/client-sqs": "^3.0.0",
|