wirejs-deploy-amplify-basic 0.1.171 → 0.1.173
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.
|
@@ -16,6 +16,7 @@ import { Table, AttributeType, BillingMode } from 'aws-cdk-lib/aws-dynamodb';
|
|
|
16
16
|
import { AnyPrincipal, PolicyStatement } from 'aws-cdk-lib/aws-iam';
|
|
17
17
|
import { Rule, RuleTargetInput, Schedule } from 'aws-cdk-lib/aws-events';
|
|
18
18
|
import { LambdaFunction as LambdaFunctionTarget } from 'aws-cdk-lib/aws-events-targets';
|
|
19
|
+
import { SESClient, VerifyEmailIdentityCommand, GetIdentityVerificationAttributesCommand } from '@aws-sdk/client-ses';
|
|
19
20
|
|
|
20
21
|
import { TableDefinition, indexName, DeploymentConfig } from 'wirejs-resources';
|
|
21
22
|
import { TableIndexes } from './constructs/table-indexes';
|
|
@@ -236,11 +237,15 @@ for (const resource of generated) {
|
|
|
236
237
|
*/
|
|
237
238
|
function cronExpressionToSchedule(expression: string): Schedule {
|
|
238
239
|
const [minute, hour, dayOfMonth, month, dayOfWeek] = expression.trim().split(/\s+/);
|
|
239
|
-
//
|
|
240
|
-
// If
|
|
241
|
-
const
|
|
242
|
-
|
|
243
|
-
|
|
240
|
+
// CDK's Schedule.cron() does not accept both `day` and `weekDay` simultaneously.
|
|
241
|
+
// If dayOfWeek is specified (not '*' or '?'), use it; otherwise use dayOfMonth.
|
|
242
|
+
const useWeekDay = dayOfWeek !== '*' && dayOfWeek !== '?';
|
|
243
|
+
return Schedule.cron({
|
|
244
|
+
minute,
|
|
245
|
+
hour,
|
|
246
|
+
month,
|
|
247
|
+
...(useWeekDay ? { weekDay: dayOfWeek } : { day: dayOfMonth }),
|
|
248
|
+
});
|
|
244
249
|
}
|
|
245
250
|
|
|
246
251
|
/**
|
|
@@ -305,4 +310,75 @@ api.addToRolePolicy(new PolicyStatement({
|
|
|
305
310
|
}));
|
|
306
311
|
|
|
307
312
|
|
|
313
|
+
/**
|
|
314
|
+
* SES permissions for EmailSender resources
|
|
315
|
+
*/
|
|
316
|
+
function isEmailSender(resource: any): resource is {
|
|
317
|
+
type: 'EmailSender';
|
|
318
|
+
options: { absoluteId: string; from: string };
|
|
319
|
+
} {
|
|
320
|
+
return resource.type === 'EmailSender';
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
const emailSenderResources = generated.filter(isEmailSender);
|
|
324
|
+
if (emailSenderResources.length > 0) {
|
|
325
|
+
const senderAddresses = emailSenderResources.map(r => r.options.from);
|
|
326
|
+
api.addToRolePolicy(new PolicyStatement({
|
|
327
|
+
actions: [
|
|
328
|
+
'ses:SendEmail',
|
|
329
|
+
'ses:SendRawEmail',
|
|
330
|
+
],
|
|
331
|
+
resources: [
|
|
332
|
+
`arn:${backend.stack.partition}:ses:${backend.stack.region}:${backend.stack.account}:identity/*`,
|
|
333
|
+
],
|
|
334
|
+
}));
|
|
335
|
+
|
|
336
|
+
// Initiate SES email verification for each sender address during deployment.
|
|
337
|
+
// This sends a verification email to each address automatically so customers
|
|
338
|
+
// don't need to manually trigger it from the AWS console.
|
|
339
|
+
const sesClient = new SESClient();
|
|
340
|
+
const verificationResults: { address: string; status: string }[] = [];
|
|
341
|
+
|
|
342
|
+
for (const address of senderAddresses) {
|
|
343
|
+
try {
|
|
344
|
+
// Check current verification status first
|
|
345
|
+
const statusResult = await sesClient.send(
|
|
346
|
+
new GetIdentityVerificationAttributesCommand({ Identities: [address] })
|
|
347
|
+
);
|
|
348
|
+
const currentStatus = statusResult.VerificationAttributes?.[address]?.VerificationStatus;
|
|
349
|
+
|
|
350
|
+
if (currentStatus === 'Success') {
|
|
351
|
+
verificationResults.push({ address, status: 'already verified ✅' });
|
|
352
|
+
} else {
|
|
353
|
+
// Trigger a (new) verification email
|
|
354
|
+
await sesClient.send(new VerifyEmailIdentityCommand({ EmailAddress: address }));
|
|
355
|
+
verificationResults.push({ address, status: 'verification email sent 📧' });
|
|
356
|
+
}
|
|
357
|
+
} catch (err: any) {
|
|
358
|
+
verificationResults.push({ address, status: `could not initiate automatically — ${err?.message ?? err}` });
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
console.log(`
|
|
363
|
+
⚠️ AWS SES Email Verification
|
|
364
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
365
|
+
Your app uses EmailSender with the following sender address(es):
|
|
366
|
+
|
|
367
|
+
${verificationResults.map(r => ` • ${r.address} — ${r.status}`).join('\n')}
|
|
368
|
+
|
|
369
|
+
${verificationResults.some(r => r.status.includes('sent'))
|
|
370
|
+
? 'Check your inbox and click the verification link in each email from AWS SES.'
|
|
371
|
+
: ''}
|
|
372
|
+
AWS SES starts in "sandbox" mode — you must also verify recipient addresses
|
|
373
|
+
or request production access to send to arbitrary recipients.
|
|
374
|
+
|
|
375
|
+
To request production (sandbox removal) access:
|
|
376
|
+
https://docs.aws.amazon.com/ses/latest/dg/request-production-access.html
|
|
377
|
+
|
|
378
|
+
See docs/amplify.md in your project for more details.
|
|
379
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
380
|
+
`);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
|
|
308
384
|
backend.addOutput({ custom: { api: apiUrl.url } });
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export * from 'wirejs-resources';
|
|
2
2
|
export { FileService } from './services/file.js';
|
|
3
3
|
export { AuthenticationService } from './services/authentication.js';
|
|
4
|
+
export { EmailSender } from './services/email-sender.js';
|
|
4
5
|
export { LLM } from './services/llm.js';
|
|
5
6
|
export { DistributedTable } from './resources/distributed-table.js';
|
|
6
7
|
export { RealtimeService } from './services/realtime.js';
|
package/dist/index.js
CHANGED
|
@@ -6,6 +6,8 @@ import { FileService } from './services/file.js';
|
|
|
6
6
|
export { FileService } from './services/file.js';
|
|
7
7
|
import { AuthenticationService } from './services/authentication.js';
|
|
8
8
|
export { AuthenticationService } from './services/authentication.js';
|
|
9
|
+
import { EmailSender } from './services/email-sender.js';
|
|
10
|
+
export { EmailSender } from './services/email-sender.js';
|
|
9
11
|
import { LLM } from './services/llm.js';
|
|
10
12
|
export { LLM } from './services/llm.js';
|
|
11
13
|
import { DistributedTable } from './resources/distributed-table.js';
|
|
@@ -23,6 +25,7 @@ overrides.AuthenticationService = AuthenticationService;
|
|
|
23
25
|
overrides.BackgroundJob = BackgroundJob;
|
|
24
26
|
overrides.CronJob = CronJob;
|
|
25
27
|
overrides.DistributedTable = DistributedTable;
|
|
28
|
+
overrides.EmailSender = EmailSender;
|
|
26
29
|
overrides.Endpoint = Endpoint;
|
|
27
30
|
overrides.FileService = FileService;
|
|
28
31
|
overrides.LLM = LLM;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Resource, EmailSender as BaseEmailSender, EmailMessage } from 'wirejs-resources';
|
|
2
|
+
export declare class EmailSender extends BaseEmailSender {
|
|
3
|
+
constructor(scope: Resource | string, id: string, options: {
|
|
4
|
+
from: string;
|
|
5
|
+
});
|
|
6
|
+
send(message: EmailMessage): Promise<void>;
|
|
7
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { SESClient, SendEmailCommand, } from '@aws-sdk/client-ses';
|
|
2
|
+
import { EmailSender as BaseEmailSender, } from 'wirejs-resources';
|
|
3
|
+
import { addResource } from '../resource-collector.js';
|
|
4
|
+
const ses = new SESClient();
|
|
5
|
+
export class EmailSender extends BaseEmailSender {
|
|
6
|
+
constructor(scope, id, options) {
|
|
7
|
+
super(scope, id, options);
|
|
8
|
+
addResource('EmailSender', { absoluteId: this.absoluteId, from: options.from });
|
|
9
|
+
}
|
|
10
|
+
async send(message) {
|
|
11
|
+
const toAddresses = Array.isArray(message.to) ? message.to : [message.to];
|
|
12
|
+
await ses.send(new SendEmailCommand({
|
|
13
|
+
Source: this.from,
|
|
14
|
+
Destination: { ToAddresses: toAddresses },
|
|
15
|
+
Message: {
|
|
16
|
+
Subject: { Data: message.subject },
|
|
17
|
+
Body: {
|
|
18
|
+
Text: { Data: message.body },
|
|
19
|
+
...(message.html !== undefined ? { Html: { Data: message.html } } : {}),
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
}));
|
|
23
|
+
}
|
|
24
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wirejs-deploy-amplify-basic",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.173",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
"@aws-sdk/client-cognito-identity-provider": "^3.741.0",
|
|
33
33
|
"@aws-sdk/client-dynamodb": "^3.774.0",
|
|
34
34
|
"@aws-sdk/client-s3": "^3.738.0",
|
|
35
|
+
"@aws-sdk/client-ses": "^3.738.0",
|
|
35
36
|
"@aws-sdk/credential-provider-node": "^3.806.0",
|
|
36
37
|
"@aws-sdk/client-lambda": "3.821.0",
|
|
37
38
|
"@aws-sdk/lib-dynamodb": "^3.778.0",
|
|
@@ -44,7 +45,7 @@
|
|
|
44
45
|
"recursive-copy": "^2.0.14",
|
|
45
46
|
"rimraf": "^6.0.1",
|
|
46
47
|
"wirejs-dom": "^1.0.44",
|
|
47
|
-
"wirejs-resources": "^0.1.
|
|
48
|
+
"wirejs-resources": "^0.1.173"
|
|
48
49
|
},
|
|
49
50
|
"devDependencies": {
|
|
50
51
|
"@aws-amplify/backend": "^1.14.0",
|