nebula-starter-kit 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/README.md +107 -0
- package/dist/index.js +8 -0
- package/dist/run.js +112 -0
- package/dist/utils/addService.js +204 -0
- package/dist/utils/appName.js +75 -0
- package/dist/utils/deployNow.js +18 -0
- package/dist/utils/generateFiles.js +326 -0
- package/dist/utils/generateSchemas.js +58 -0
- package/dist/utils/listServices.js +24 -0
- package/dist/utils/replaceServiceNames.js +42 -0
- package/dist/utils/telemetryAddon.js +91 -0
- package/package.json +31 -0
- package/templates/core/audit/audit.controller.ts +125 -0
- package/templates/core/audit/audit.module.ts +10 -0
- package/templates/core/audit/audit.schema.ts +14 -0
- package/templates/core/audit/audit.service.ts +47 -0
- package/templates/core/auth/auth.controller.ts +207 -0
- package/templates/core/auth/auth.dto.ts +50 -0
- package/templates/core/auth/auth.module.ts +10 -0
- package/templates/core/auth/auth.service.ts +178 -0
- package/templates/core/auth/utils.ts +160 -0
- package/templates/core/constants/environment.db.ts +27 -0
- package/templates/core/constants/environment.module.ts +9 -0
- package/templates/core/constants/environment.service.ts +69 -0
- package/templates/core/core.controller.ts +35 -0
- package/templates/core/core.module.ts +22 -0
- package/templates/core/database/database.module.ts +20 -0
- package/templates/core/database/database.provider.ts +32 -0
- package/templates/core/database/database.service.ts +168 -0
- package/templates/core/database/database.types.ts +13 -0
- package/templates/core/filters/audit.decorator.ts +5 -0
- package/templates/core/filters/audit.interceptor.ts +74 -0
- package/templates/core/filters/http-exception.filter.ts +43 -0
- package/templates/core/filters/success-message.decorator.ts +5 -0
- package/templates/core/filters/success-response.interceptor.ts +35 -0
- package/templates/core/summarize/summarize.controller.ts +74 -0
- package/templates/core/summarize/summarize.dto.ts +13 -0
- package/templates/core/summarize/summarize.module.ts +9 -0
- package/templates/core/summarize/summarize.service.ts +54 -0
- package/templates/nest-cli.json +8 -0
- package/templates/package.json +52 -0
- package/templates/service/src/__name__.controller.ts +15 -0
- package/templates/service/src/__name__.module.ts +11 -0
- package/templates/service/src/__name__.schema.ts +15 -0
- package/templates/service/src/__name__.service.ts +12 -0
- package/templates/service/src/lambda.ts +60 -0
- package/templates/tsconfig.json +28 -0
- package/templates/ui/README.md +36 -0
- package/templates/ui/eslint.config.mjs +18 -0
- package/templates/ui/next.config.ts +8 -0
- package/templates/ui/package.json +33 -0
- package/templates/ui/postcss.config.mjs +7 -0
- package/templates/ui/public/file.svg +1 -0
- package/templates/ui/public/globe.svg +1 -0
- package/templates/ui/public/next.svg +1 -0
- package/templates/ui/public/vercel.svg +1 -0
- package/templates/ui/public/window.svg +1 -0
- package/templates/ui/src/app/LandingPage.tsx +98 -0
- package/templates/ui/src/app/ai/summarize/page.tsx +115 -0
- package/templates/ui/src/app/context/AuthContext.tsx +48 -0
- package/templates/ui/src/app/favicon.ico +0 -0
- package/templates/ui/src/app/globals.css +26 -0
- package/templates/ui/src/app/layout.tsx +37 -0
- package/templates/ui/src/app/page.tsx +7 -0
- package/templates/ui/src/app/services/page.tsx +99 -0
- package/templates/ui/src/components/Auth.css +252 -0
- package/templates/ui/src/components/Auth.tsx +455 -0
- package/templates/ui/src/components/Error.tsx +32 -0
- package/templates/ui/src/components/FormInput.tsx +77 -0
- package/templates/ui/src/components/Loading.tsx +10 -0
- package/templates/ui/src/components/Login.tsx +171 -0
- package/templates/ui/src/components/Popup.css +90 -0
- package/templates/ui/src/components/Signup.tsx +155 -0
- package/templates/ui/src/utils/axiosInstance.ts +37 -0
- package/templates/ui/src/utils/axiosRawInstance.ts +33 -0
- package/templates/ui/src/utils/util.constant.ts +0 -0
- package/templates/ui/src/utils/util.function.ts +165 -0
- package/templates/ui/src/utils/util.type.ts +64 -0
- package/templates/ui/src/utils/variables.ts +6 -0
- package/templates/ui/tailwind.config.js +8 -0
- package/templates/ui/tsconfig.json +43 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Module } from '@nestjs/common';
|
|
2
|
+
import { AuditController } from './audit.controller';
|
|
3
|
+
import { AuditService } from './audit.service';
|
|
4
|
+
|
|
5
|
+
@Module({
|
|
6
|
+
imports: [],
|
|
7
|
+
controllers: [AuditController],
|
|
8
|
+
providers: [AuditService],
|
|
9
|
+
})
|
|
10
|
+
export class AuditModule {}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const AUDIT_TABLE = process.env.AUDIT_TABLE || 'lifeline-audit';
|
|
2
|
+
|
|
3
|
+
export const AUDIT_TABLE_SCHEMA = {
|
|
4
|
+
tableName: AUDIT_TABLE,
|
|
5
|
+
hashKey: 'userId',
|
|
6
|
+
rangeKey: 'createdAt',
|
|
7
|
+
gsis: [
|
|
8
|
+
{
|
|
9
|
+
indexName: 'userId-auditId-index',
|
|
10
|
+
partitionKey: 'userId',
|
|
11
|
+
sortKey: 'auditId',
|
|
12
|
+
},
|
|
13
|
+
],
|
|
14
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Injectable } from '@nestjs/common';
|
|
2
|
+
import { PutCommand } from '@aws-sdk/lib-dynamodb';
|
|
3
|
+
import { EnvironmentService } from '@core/constants/environment.service';
|
|
4
|
+
import { AUDIT_TABLE } from './audit.schema';
|
|
5
|
+
import { createDynamoClient } from '@core/constants/environment.db';
|
|
6
|
+
|
|
7
|
+
let cached: { db: any } | undefined;
|
|
8
|
+
|
|
9
|
+
@Injectable()
|
|
10
|
+
export class AuditService {
|
|
11
|
+
private readonly auditTable = AUDIT_TABLE;
|
|
12
|
+
constructor(private readonly config: EnvironmentService) {}
|
|
13
|
+
|
|
14
|
+
public repository(): { db: any } {
|
|
15
|
+
try {
|
|
16
|
+
if (!cached) {
|
|
17
|
+
const db = createDynamoClient(this.config);
|
|
18
|
+
|
|
19
|
+
cached = { db };
|
|
20
|
+
}
|
|
21
|
+
return cached!;
|
|
22
|
+
} catch (error) {
|
|
23
|
+
throw error;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async log(data: any) {
|
|
28
|
+
const timestamp = new Date().toISOString();
|
|
29
|
+
|
|
30
|
+
const { db } = this.repository();
|
|
31
|
+
try {
|
|
32
|
+
await db.send(
|
|
33
|
+
new PutCommand({
|
|
34
|
+
TableName: this.auditTable,
|
|
35
|
+
Item: {
|
|
36
|
+
pk: `USER#${data.userId || 'anonymous'}`,
|
|
37
|
+
sk: `TIME#${timestamp}`,
|
|
38
|
+
...data,
|
|
39
|
+
createdAt: timestamp,
|
|
40
|
+
},
|
|
41
|
+
}),
|
|
42
|
+
);
|
|
43
|
+
} catch (error) {
|
|
44
|
+
console.error('Error logging audit data:', error);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Controller,
|
|
3
|
+
Get,
|
|
4
|
+
Post,
|
|
5
|
+
Body,
|
|
6
|
+
Req,
|
|
7
|
+
Res,
|
|
8
|
+
NotFoundException,
|
|
9
|
+
BadRequestException,
|
|
10
|
+
} from '@nestjs/common';
|
|
11
|
+
import { AuthService } from './auth.service';
|
|
12
|
+
import {
|
|
13
|
+
ConfirmUserDto,
|
|
14
|
+
ForgotPasswordDto,
|
|
15
|
+
LoginDto,
|
|
16
|
+
RegisterDTO,
|
|
17
|
+
ResetPasswordDto,
|
|
18
|
+
} from './auth.dto';
|
|
19
|
+
import {
|
|
20
|
+
CognitoIdentityProviderClient,
|
|
21
|
+
ListUsersCommandOutput,
|
|
22
|
+
} from '@aws-sdk/client-cognito-identity-provider';
|
|
23
|
+
import { EnvironmentService } from '@core/constants/environment.service';
|
|
24
|
+
import {
|
|
25
|
+
confirmUserBySelf,
|
|
26
|
+
forgotPassword,
|
|
27
|
+
initiateLogin,
|
|
28
|
+
listUsersInPool,
|
|
29
|
+
resetPassword,
|
|
30
|
+
signUpUser,
|
|
31
|
+
} from './utils';
|
|
32
|
+
|
|
33
|
+
import * as dotenv from 'dotenv';
|
|
34
|
+
dotenv.config();
|
|
35
|
+
|
|
36
|
+
@Controller('auth')
|
|
37
|
+
export class AuthController {
|
|
38
|
+
private client: CognitoIdentityProviderClient;
|
|
39
|
+
private CLIENT_ID: any;
|
|
40
|
+
private USER_POOL_ID: any;
|
|
41
|
+
constructor(
|
|
42
|
+
// private readonly authService: AuthService,
|
|
43
|
+
private readonly environment: EnvironmentService,
|
|
44
|
+
) {
|
|
45
|
+
this.client = new CognitoIdentityProviderClient({
|
|
46
|
+
region: this.environment?.region() || process.env.REGION,
|
|
47
|
+
});
|
|
48
|
+
this.CLIENT_ID =
|
|
49
|
+
this.environment?.COGNITO_CLIENT_ID() || process.env.COGNITO_CLIENT_ID;
|
|
50
|
+
this.USER_POOL_ID =
|
|
51
|
+
this.environment?.COGNITO_USER_POOL_ID() ||
|
|
52
|
+
process.env.COGNITO_USER_POOL_ID;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
@Post('register')
|
|
56
|
+
async register(@Body() body: RegisterDTO): Promise<any> {
|
|
57
|
+
try {
|
|
58
|
+
console.log('body', body);
|
|
59
|
+
if (!body) {
|
|
60
|
+
throw new BadRequestException('Request body missing');
|
|
61
|
+
}
|
|
62
|
+
const { email, password, name } = body;
|
|
63
|
+
let username = email;
|
|
64
|
+
let preferred_username = name;
|
|
65
|
+
|
|
66
|
+
if (!username || !password || !name) {
|
|
67
|
+
throw new NotFoundException('username, password and name are required');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const result = await signUpUser({
|
|
71
|
+
username,
|
|
72
|
+
password,
|
|
73
|
+
email,
|
|
74
|
+
name,
|
|
75
|
+
preferred_username,
|
|
76
|
+
client: this.client,
|
|
77
|
+
clientId: this.CLIENT_ID,
|
|
78
|
+
});
|
|
79
|
+
if (result?.$metadata?.httpStatusCode || 200) {
|
|
80
|
+
return result;
|
|
81
|
+
}
|
|
82
|
+
} catch (err: any) {
|
|
83
|
+
console.error(err.message);
|
|
84
|
+
const msg = err?.message || JSON.stringify(err);
|
|
85
|
+
throw err;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
@Post('login')
|
|
90
|
+
async login(@Body() body: LoginDto): Promise<any> {
|
|
91
|
+
try {
|
|
92
|
+
if (!body) {
|
|
93
|
+
throw new BadRequestException('Request body missing');
|
|
94
|
+
}
|
|
95
|
+
const { email, password } = body;
|
|
96
|
+
|
|
97
|
+
if (!email || !password) {
|
|
98
|
+
throw new NotFoundException('email and password are required');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const result = await initiateLogin({
|
|
102
|
+
email,
|
|
103
|
+
password,
|
|
104
|
+
client: this.client,
|
|
105
|
+
clientId: this.CLIENT_ID,
|
|
106
|
+
});
|
|
107
|
+
if (result?.$metadata?.httpStatusCode === 200) {
|
|
108
|
+
return { token: result.AuthenticationResult?.AccessToken };
|
|
109
|
+
}
|
|
110
|
+
} catch (err: any) {
|
|
111
|
+
console.error(err.message);
|
|
112
|
+
const msg = err?.message || JSON.stringify(err);
|
|
113
|
+
throw err;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
@Post('confirm')
|
|
118
|
+
async confirmUser(@Body() body: ConfirmUserDto): Promise<any> {
|
|
119
|
+
try {
|
|
120
|
+
if (!body) {
|
|
121
|
+
throw new BadRequestException('Request body missing');
|
|
122
|
+
}
|
|
123
|
+
const { email, code } = body;
|
|
124
|
+
if (!email || !code) {
|
|
125
|
+
throw new NotFoundException('email and code are required');
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
await confirmUserBySelf(email, code, this.client, this.CLIENT_ID);
|
|
129
|
+
return { success: true, message: `✅ User ${email} confirmed` };
|
|
130
|
+
} catch (err: any) {
|
|
131
|
+
console.error('Error confirming user:', err.message);
|
|
132
|
+
throw err;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
@Post('forgot-password')
|
|
137
|
+
async forgotPassword(@Body() body: ForgotPasswordDto): Promise<any> {
|
|
138
|
+
try {
|
|
139
|
+
if (!body) {
|
|
140
|
+
throw new BadRequestException('Request body missing');
|
|
141
|
+
}
|
|
142
|
+
const { email } = body;
|
|
143
|
+
if (!email) {
|
|
144
|
+
throw new NotFoundException('email is required');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
await forgotPassword(email, this.client, this.CLIENT_ID);
|
|
148
|
+
return {
|
|
149
|
+
success: true,
|
|
150
|
+
message: `✅ Password reset link sent to ${email}`,
|
|
151
|
+
};
|
|
152
|
+
} catch (err: any) {
|
|
153
|
+
console.error('Error sending forgot password email:', err.message);
|
|
154
|
+
throw err;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
@Post('reset-password')
|
|
159
|
+
async resetPassword(@Body() body: ResetPasswordDto): Promise<any> {
|
|
160
|
+
try {
|
|
161
|
+
if (!body) {
|
|
162
|
+
throw new BadRequestException('Request body missing');
|
|
163
|
+
}
|
|
164
|
+
const { email, code, newPassword } = body;
|
|
165
|
+
if (!email || !code || !newPassword) {
|
|
166
|
+
throw new NotFoundException('email, code and newPassword are required');
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
await resetPassword(
|
|
170
|
+
email,
|
|
171
|
+
code,
|
|
172
|
+
newPassword,
|
|
173
|
+
this.client,
|
|
174
|
+
this.CLIENT_ID,
|
|
175
|
+
);
|
|
176
|
+
return {
|
|
177
|
+
success: true,
|
|
178
|
+
message: `✅ Password for ${email} has been reset`,
|
|
179
|
+
};
|
|
180
|
+
} catch (err: any) {
|
|
181
|
+
console.error('Error resetting password:', err.message);
|
|
182
|
+
throw err;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
@Get()
|
|
187
|
+
async listUsers(): Promise<any> {
|
|
188
|
+
try {
|
|
189
|
+
const result: ListUsersCommandOutput = await listUsersInPool(
|
|
190
|
+
this.USER_POOL_ID,
|
|
191
|
+
this.client,
|
|
192
|
+
);
|
|
193
|
+
const users = (result.Users || []).map((user) => {
|
|
194
|
+
const attributes = user.Attributes || [];
|
|
195
|
+
return {
|
|
196
|
+
email: attributes.find((attr) => attr.Name === 'email')?.Value,
|
|
197
|
+
name: attributes.find((attr) => attr.Name === 'name')?.Value,
|
|
198
|
+
};
|
|
199
|
+
});
|
|
200
|
+
console.log('Users in pool:', users.length);
|
|
201
|
+
return { users };
|
|
202
|
+
} catch (err: any) {
|
|
203
|
+
console.error('Error listing users in pool:', err.message);
|
|
204
|
+
throw err;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { ApiProperty } from '@nestjs/swagger';
|
|
2
|
+
import { IsEmail, IsNotEmpty, IsString } from 'class-validator';
|
|
3
|
+
|
|
4
|
+
export class ForgotPasswordDto {
|
|
5
|
+
@ApiProperty({
|
|
6
|
+
example: 'consultoba@gmail.com',
|
|
7
|
+
description: 'Email address',
|
|
8
|
+
})
|
|
9
|
+
@IsNotEmpty()
|
|
10
|
+
@IsEmail()
|
|
11
|
+
email!: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export class LoginDto extends ForgotPasswordDto {
|
|
15
|
+
@ApiProperty({ example: 'Password123@', description: 'Password' })
|
|
16
|
+
@IsNotEmpty()
|
|
17
|
+
@IsString()
|
|
18
|
+
password!: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export class RegisterDTO extends LoginDto {
|
|
22
|
+
@ApiProperty({ example: 'John', description: 'Name' })
|
|
23
|
+
@IsNotEmpty()
|
|
24
|
+
name!: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export class ConfirmUserDto {
|
|
28
|
+
@ApiProperty({
|
|
29
|
+
example: 'consultoba@gmail.com',
|
|
30
|
+
description: 'Email address',
|
|
31
|
+
})
|
|
32
|
+
@IsNotEmpty()
|
|
33
|
+
@IsEmail()
|
|
34
|
+
email!: string;
|
|
35
|
+
|
|
36
|
+
@ApiProperty({ example: '123123', description: 'Confirmation code' })
|
|
37
|
+
@IsNotEmpty()
|
|
38
|
+
@IsString()
|
|
39
|
+
code!: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export class ResetPasswordDto extends ConfirmUserDto {
|
|
43
|
+
@ApiProperty({
|
|
44
|
+
example: 'newPassword123@',
|
|
45
|
+
description: 'New password',
|
|
46
|
+
})
|
|
47
|
+
@IsNotEmpty()
|
|
48
|
+
@IsString()
|
|
49
|
+
newPassword!: string;
|
|
50
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Module } from '@nestjs/common';
|
|
2
|
+
import { AuthController } from './auth.controller';
|
|
3
|
+
import { AuthService } from './auth.service';
|
|
4
|
+
|
|
5
|
+
@Module({
|
|
6
|
+
imports: [],
|
|
7
|
+
controllers: [AuthController],
|
|
8
|
+
// providers: [AuthService],
|
|
9
|
+
})
|
|
10
|
+
export class AuthModule {}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { Injectable, NotFoundException } from '@nestjs/common';
|
|
2
|
+
import {
|
|
3
|
+
confirmUserBySelf,
|
|
4
|
+
forgotPassword,
|
|
5
|
+
getUserPools,
|
|
6
|
+
initiateLogin,
|
|
7
|
+
listUsersInPool,
|
|
8
|
+
resetPassword,
|
|
9
|
+
signUpUser,
|
|
10
|
+
} from './utils';
|
|
11
|
+
import {
|
|
12
|
+
CognitoIdentityProviderClient,
|
|
13
|
+
ListUsersCommandOutput,
|
|
14
|
+
} from '@aws-sdk/client-cognito-identity-provider';
|
|
15
|
+
import { EnvironmentService } from '../constants/environment.service';
|
|
16
|
+
import {
|
|
17
|
+
ConfirmUserDto,
|
|
18
|
+
ForgotPasswordDto,
|
|
19
|
+
LoginDto,
|
|
20
|
+
RegisterDTO,
|
|
21
|
+
ResetPasswordDto,
|
|
22
|
+
} from './auth.dto';
|
|
23
|
+
|
|
24
|
+
@Injectable()
|
|
25
|
+
export class AuthService {
|
|
26
|
+
private client: CognitoIdentityProviderClient;
|
|
27
|
+
private CLIENT_ID: string;
|
|
28
|
+
private USER_POOL_ID: string;
|
|
29
|
+
|
|
30
|
+
constructor(private readonly environment: EnvironmentService) {
|
|
31
|
+
this.client = new CognitoIdentityProviderClient({
|
|
32
|
+
region: this.environment?.region(),
|
|
33
|
+
});
|
|
34
|
+
this.CLIENT_ID = this.environment?.COGNITO_CLIENT_ID();
|
|
35
|
+
this.USER_POOL_ID = this.environment?.COGNITO_USER_POOL_ID();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
public async register(payload: RegisterDTO): Promise<any> {
|
|
39
|
+
try {
|
|
40
|
+
const { email, password, name } = payload;
|
|
41
|
+
let username = email;
|
|
42
|
+
let preferred_username = name;
|
|
43
|
+
|
|
44
|
+
if (!username || !password || !name) {
|
|
45
|
+
throw new NotFoundException('username, password and name are required');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const result = await signUpUser({
|
|
49
|
+
username,
|
|
50
|
+
password,
|
|
51
|
+
email,
|
|
52
|
+
name,
|
|
53
|
+
preferred_username,
|
|
54
|
+
client: this.client,
|
|
55
|
+
clientId: this.CLIENT_ID,
|
|
56
|
+
});
|
|
57
|
+
if (result?.$metadata?.httpStatusCode || 200) {
|
|
58
|
+
return result;
|
|
59
|
+
}
|
|
60
|
+
} catch (err: any) {
|
|
61
|
+
console.error(err.message);
|
|
62
|
+
const msg = err?.message || JSON.stringify(err);
|
|
63
|
+
throw err;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
public async login(payload: LoginDto): Promise<any> {
|
|
68
|
+
try {
|
|
69
|
+
const { email, password } = payload;
|
|
70
|
+
|
|
71
|
+
if (!email || !password) {
|
|
72
|
+
throw new NotFoundException('email and password are required');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const result = await initiateLogin({
|
|
76
|
+
email,
|
|
77
|
+
password,
|
|
78
|
+
client: this.client,
|
|
79
|
+
clientId: this.CLIENT_ID,
|
|
80
|
+
});
|
|
81
|
+
if (result?.$metadata?.httpStatusCode === 200) {
|
|
82
|
+
return { token: result.AuthenticationResult?.AccessToken };
|
|
83
|
+
}
|
|
84
|
+
} catch (err: any) {
|
|
85
|
+
console.error(err.message);
|
|
86
|
+
const msg = err?.message || JSON.stringify(err);
|
|
87
|
+
throw err;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
public async confirmUser(payload: ConfirmUserDto): Promise<any> {
|
|
92
|
+
try {
|
|
93
|
+
const { email, code } = payload;
|
|
94
|
+
if (!email || !code) {
|
|
95
|
+
throw new NotFoundException('email and code are required');
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
await confirmUserBySelf(email, code, this.client, this.CLIENT_ID);
|
|
99
|
+
return { success: true, message: `✅ User ${email} confirmed` };
|
|
100
|
+
} catch (err: any) {
|
|
101
|
+
console.error('Error confirming user:', err.message);
|
|
102
|
+
throw err;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
public async forgotPassword(payload: ForgotPasswordDto): Promise<any> {
|
|
107
|
+
try {
|
|
108
|
+
const { email } = payload;
|
|
109
|
+
if (!email) {
|
|
110
|
+
throw new NotFoundException('email is required');
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
await forgotPassword(email, this.client, this.CLIENT_ID);
|
|
114
|
+
return {
|
|
115
|
+
success: true,
|
|
116
|
+
message: `✅ Password reset link sent to ${email}`,
|
|
117
|
+
};
|
|
118
|
+
} catch (err: any) {
|
|
119
|
+
console.error('Error sending forgot password email:', err.message);
|
|
120
|
+
throw err;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
public async resetPassword(payload: ResetPasswordDto): Promise<any> {
|
|
125
|
+
try {
|
|
126
|
+
const { email, code, newPassword } = payload;
|
|
127
|
+
if (!email || !code || !newPassword) {
|
|
128
|
+
throw new NotFoundException('email, code and newPassword are required');
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
await resetPassword(
|
|
132
|
+
email,
|
|
133
|
+
code,
|
|
134
|
+
newPassword,
|
|
135
|
+
this.client,
|
|
136
|
+
this.CLIENT_ID,
|
|
137
|
+
);
|
|
138
|
+
return {
|
|
139
|
+
success: true,
|
|
140
|
+
message: `✅ Password for ${email} has been reset`,
|
|
141
|
+
};
|
|
142
|
+
} catch (err: any) {
|
|
143
|
+
console.error('Error resetting password:', err.message);
|
|
144
|
+
throw err;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
public async listUserPools(): Promise<any> {
|
|
149
|
+
try {
|
|
150
|
+
const result = await getUserPools(this.client);
|
|
151
|
+
return result;
|
|
152
|
+
} catch (err: any) {
|
|
153
|
+
console.error('Error listing user pools:', err.message);
|
|
154
|
+
throw err;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
public async listUsersInPool(): Promise<any> {
|
|
159
|
+
try {
|
|
160
|
+
const result: ListUsersCommandOutput = await listUsersInPool(
|
|
161
|
+
this.USER_POOL_ID,
|
|
162
|
+
this.client,
|
|
163
|
+
);
|
|
164
|
+
const users = (result.Users || []).map((user) => {
|
|
165
|
+
const attributes = user.Attributes || [];
|
|
166
|
+
return {
|
|
167
|
+
email: attributes.find((attr) => attr.Name === 'email')?.Value,
|
|
168
|
+
name: attributes.find((attr) => attr.Name === 'name')?.Value,
|
|
169
|
+
};
|
|
170
|
+
});
|
|
171
|
+
console.log('Users in pool:', users.length);
|
|
172
|
+
return users;
|
|
173
|
+
} catch (err: any) {
|
|
174
|
+
console.error('Error listing users in pool:', err.message);
|
|
175
|
+
throw err;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AdminConfirmSignUpCommand,
|
|
3
|
+
CognitoIdentityProviderClient,
|
|
4
|
+
ConfirmSignUpCommand,
|
|
5
|
+
InitiateAuthCommand,
|
|
6
|
+
ListUserPoolsCommand,
|
|
7
|
+
SignUpCommand,
|
|
8
|
+
ListUsersCommand,
|
|
9
|
+
ForgotPasswordCommand,
|
|
10
|
+
ConfirmForgotPasswordCommand,
|
|
11
|
+
} from '@aws-sdk/client-cognito-identity-provider';
|
|
12
|
+
|
|
13
|
+
export async function signUpUser({
|
|
14
|
+
username,
|
|
15
|
+
password,
|
|
16
|
+
email,
|
|
17
|
+
name,
|
|
18
|
+
preferred_username,
|
|
19
|
+
client,
|
|
20
|
+
clientId,
|
|
21
|
+
}: {
|
|
22
|
+
username: string;
|
|
23
|
+
password: string;
|
|
24
|
+
email: string;
|
|
25
|
+
name: string;
|
|
26
|
+
preferred_username: string;
|
|
27
|
+
client: CognitoIdentityProviderClient;
|
|
28
|
+
clientId: string;
|
|
29
|
+
}) {
|
|
30
|
+
const input = {
|
|
31
|
+
ClientId: clientId,
|
|
32
|
+
Username: username,
|
|
33
|
+
Password: password,
|
|
34
|
+
UserAttributes: [
|
|
35
|
+
{ Name: 'email', Value: email },
|
|
36
|
+
{ Name: 'name', Value: name },
|
|
37
|
+
{ Name: 'preferred_username', Value: preferred_username },
|
|
38
|
+
] as any,
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const cmd = new SignUpCommand(input);
|
|
42
|
+
return await client.send(cmd);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export async function initiateLogin({
|
|
46
|
+
email,
|
|
47
|
+
password,
|
|
48
|
+
client,
|
|
49
|
+
clientId,
|
|
50
|
+
}: {
|
|
51
|
+
email: string;
|
|
52
|
+
password: string;
|
|
53
|
+
client: CognitoIdentityProviderClient;
|
|
54
|
+
clientId: string;
|
|
55
|
+
}) {
|
|
56
|
+
const input = {
|
|
57
|
+
AuthFlow: 'USER_PASSWORD_AUTH',
|
|
58
|
+
ClientId: clientId,
|
|
59
|
+
AuthParameters: {
|
|
60
|
+
USERNAME: email,
|
|
61
|
+
PASSWORD: password,
|
|
62
|
+
},
|
|
63
|
+
} as any;
|
|
64
|
+
|
|
65
|
+
const cmd = new InitiateAuthCommand(input);
|
|
66
|
+
return await client.send(cmd);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Optional: admin confirm (if you want to auto-confirm users via admin privileges)
|
|
70
|
+
export async function adminConfirm(
|
|
71
|
+
username: string,
|
|
72
|
+
client: CognitoIdentityProviderClient,
|
|
73
|
+
UserPoolId: string,
|
|
74
|
+
) {
|
|
75
|
+
const cmd = new AdminConfirmSignUpCommand({
|
|
76
|
+
UserPoolId,
|
|
77
|
+
Username: username,
|
|
78
|
+
});
|
|
79
|
+
return await client.send(cmd);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export async function confirmUserBySelf(
|
|
83
|
+
username: string,
|
|
84
|
+
code: number | string,
|
|
85
|
+
client: CognitoIdentityProviderClient,
|
|
86
|
+
clientId: string,
|
|
87
|
+
) {
|
|
88
|
+
const confirmCommand = new ConfirmSignUpCommand({
|
|
89
|
+
ClientId: clientId,
|
|
90
|
+
Username: username,
|
|
91
|
+
ConfirmationCode: code.toString(),
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
console.log('✅ User confirmed successfully');
|
|
95
|
+
return await client.send(confirmCommand);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export async function confirmUser(
|
|
99
|
+
username: string,
|
|
100
|
+
UserPoolId: string,
|
|
101
|
+
client: CognitoIdentityProviderClient,
|
|
102
|
+
) {
|
|
103
|
+
const command = new AdminConfirmSignUpCommand({
|
|
104
|
+
UserPoolId,
|
|
105
|
+
Username: username,
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
console.log(`✅ User ${username} confirmed`);
|
|
109
|
+
return await client.send(command);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export async function forgotPassword(
|
|
113
|
+
email: string,
|
|
114
|
+
client: CognitoIdentityProviderClient,
|
|
115
|
+
clientId: string,
|
|
116
|
+
) {
|
|
117
|
+
const command = new ForgotPasswordCommand({
|
|
118
|
+
ClientId: clientId,
|
|
119
|
+
Username: email,
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
console.log(`✅ Forgot password initiated for ${email}`);
|
|
123
|
+
return await client.send(command);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export async function resetPassword(
|
|
127
|
+
email: string,
|
|
128
|
+
code: string,
|
|
129
|
+
newPassword: string,
|
|
130
|
+
client: CognitoIdentityProviderClient,
|
|
131
|
+
clientId: string,
|
|
132
|
+
) {
|
|
133
|
+
const command = new ConfirmForgotPasswordCommand({
|
|
134
|
+
ClientId: clientId,
|
|
135
|
+
Username: email,
|
|
136
|
+
ConfirmationCode: code,
|
|
137
|
+
Password: newPassword,
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
console.log(`✅ Password reset initiated for ${email}`);
|
|
141
|
+
return await client.send(command);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export async function getUserPools(client: CognitoIdentityProviderClient) {
|
|
145
|
+
const command = new ListUserPoolsCommand({ MaxResults: 10 });
|
|
146
|
+
const response = await client.send(command);
|
|
147
|
+
console.log(response.UserPools);
|
|
148
|
+
return response.UserPools;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export async function listUsersInPool(
|
|
152
|
+
userPoolId: string,
|
|
153
|
+
client: CognitoIdentityProviderClient,
|
|
154
|
+
) {
|
|
155
|
+
const command = new ListUsersCommand({
|
|
156
|
+
UserPoolId: userPoolId,
|
|
157
|
+
});
|
|
158
|
+
const response = await client.send(command);
|
|
159
|
+
return response;
|
|
160
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
|
|
2
|
+
import { DynamoDBDocumentClient } from '@aws-sdk/lib-dynamodb';
|
|
3
|
+
import { EnvironmentService } from './environment.service';
|
|
4
|
+
|
|
5
|
+
let cached: DynamoDBDocumentClient;
|
|
6
|
+
|
|
7
|
+
export const createDynamoClient = (env?: EnvironmentService) => {
|
|
8
|
+
if (cached) return cached;
|
|
9
|
+
|
|
10
|
+
const raw = new DynamoDBClient({
|
|
11
|
+
region: env?.region() || process.env.REGION,
|
|
12
|
+
...(env &&
|
|
13
|
+
!env.isLambda() && {
|
|
14
|
+
endpoint: env.dynamoEndpoint(),
|
|
15
|
+
credentials: {
|
|
16
|
+
accessKeyId: env.accessKeyId(),
|
|
17
|
+
secretAccessKey: env.secretAccessKey(),
|
|
18
|
+
},
|
|
19
|
+
}),
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
cached = DynamoDBDocumentClient.from(raw, {
|
|
23
|
+
marshallOptions: { removeUndefinedValues: true },
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
return cached;
|
|
27
|
+
};
|