@digitaldefiance/express-suite-starter 2.3.5 → 2.3.7
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 -2
- package/scaffolding/api/.env.example.mustache +52 -0
- package/scaffolding/api/src/assets/.gitkeep +0 -0
- package/scaffolding/api/src/main.ts.mustache +19 -0
- package/scaffolding/api/src/views/index.ejs +34 -0
- package/scaffolding/api-lib/src/index.ts +9 -0
- package/scaffolding/api-lib/src/lib/application.ts +35 -0
- package/scaffolding/api-lib/src/lib/constants.ts.mustache +10 -0
- package/scaffolding/api-lib/src/lib/documents/index.ts +1 -0
- package/scaffolding/api-lib/src/lib/documents/user.ts +17 -0
- package/scaffolding/api-lib/src/lib/environment.ts +52 -0
- package/scaffolding/api-lib/src/lib/interfaces/constants.ts +9 -0
- package/scaffolding/api-lib/src/lib/interfaces/environment-aws.ts +7 -0
- package/scaffolding/api-lib/src/lib/interfaces/environment.ts +9 -0
- package/scaffolding/api-lib/src/lib/middlewares.ts.mustache +113 -0
- package/scaffolding/api-lib/src/lib/models/email-token.ts +12 -0
- package/scaffolding/api-lib/src/lib/models/mnemonic.ts +12 -0
- package/scaffolding/api-lib/src/lib/models/role.ts +12 -0
- package/scaffolding/api-lib/src/lib/models/used-direct-login-token.ts +12 -0
- package/scaffolding/api-lib/src/lib/models/user-role.ts +12 -0
- package/scaffolding/api-lib/src/lib/models/user.ts +14 -0
- package/scaffolding/api-lib/src/lib/routers/api.ts +23 -0
- package/scaffolding/api-lib/src/lib/routers/app.ts +31 -0
- package/scaffolding/api-lib/src/lib/routers/index.ts +2 -0
- package/scaffolding/api-lib/src/lib/schemas/index.ts +2 -0
- package/scaffolding/api-lib/src/lib/schemas/schema.ts +53 -0
- package/scaffolding/api-lib/src/lib/schemas/user.ts +13 -0
- package/scaffolding/api-lib/src/lib/services/email.ts +109 -0
- package/scaffolding/api-lib/src/lib/services/index.ts +1 -0
- package/scaffolding/api-lib/src/lib/shared-types.ts +172 -0
- package/scaffolding/devcontainer-mongodb/.devcontainer/.env.example +3 -0
- package/scaffolding/devcontainer-mongodb/.devcontainer/Dockerfile +6 -0
- package/scaffolding/devcontainer-mongodb/.devcontainer/devcontainer.json.mustache +31 -0
- package/scaffolding/devcontainer-mongodb/.devcontainer/docker-compose.yml +31 -0
- package/scaffolding/devcontainer-mongodb/.devcontainer/load-env.sh +20 -0
- package/scaffolding/devcontainer-mongodb/.devcontainer/post-create.sh.hbs +54 -0
- package/scaffolding/devcontainer-mongodb-replicaset/.devcontainer/.env.example +14 -0
- package/scaffolding/devcontainer-mongodb-replicaset/.devcontainer/Dockerfile +38 -0
- package/scaffolding/devcontainer-mongodb-replicaset/.devcontainer/Mongo.Dockerfile +24 -0
- package/scaffolding/devcontainer-mongodb-replicaset/.devcontainer/devcontainer.json +69 -0
- package/scaffolding/devcontainer-mongodb-replicaset/.devcontainer/docker-compose.yml +66 -0
- package/scaffolding/devcontainer-mongodb-replicaset/.devcontainer/entrypoint.sh +29 -0
- package/scaffolding/devcontainer-mongodb-replicaset/.devcontainer/load-env.sh +20 -0
- package/scaffolding/devcontainer-mongodb-replicaset/.devcontainer/mongodb_entrypoint.sh +124 -0
- package/scaffolding/devcontainer-mongodb-replicaset/.devcontainer/mongodb_healthcheck.sh +36 -0
- package/scaffolding/devcontainer-mongodb-replicaset/.devcontainer/post-create.sh.hbs +54 -0
- package/scaffolding/devcontainer-simple/.devcontainer/.env.example +4 -0
- package/scaffolding/devcontainer-simple/.devcontainer/devcontainer.json.mustache +60 -0
- package/scaffolding/devcontainer-simple/.devcontainer/post-create.sh.hbs +72 -0
- package/scaffolding/inituserdb/.env.example.mustache +9 -0
- package/scaffolding/inituserdb/src/main.ts.mustache +178 -0
- package/scaffolding/lib/src/index.ts.mustache +6 -0
- package/scaffolding/lib/src/lib/constants.ts.mustache +15 -0
- package/scaffolding/lib/src/lib/ecies-config.ts +10 -0
- package/scaffolding/lib/src/lib/enumerations/{{workspaceName}}-string-key.ts.mustache +5 -0
- package/scaffolding/lib/src/lib/i18n-setup.ts.mustache +99 -0
- package/scaffolding/lib/src/lib/interfaces/constants.ts +13 -0
- package/scaffolding/lib/src/lib/strings-collection.ts.mustache +45 -0
- package/scaffolding/react/src/app/app.tsx.mustache +170 -0
- package/scaffolding/react/src/app/menus/extraMenu.tsx +20 -0
- package/scaffolding/react/src/app/menus/index.ts +5 -0
- package/scaffolding/react/src/app/pages/SplashPage.tsx +60 -0
- package/scaffolding/react/src/app/theme.tsx.mustache +91 -0
- package/scaffolding/react/src/assets/albatross.ico +0 -0
- package/scaffolding/react/src/assets/albatross.png +0 -0
- package/scaffolding/react/src/assets/albatross.svg +108 -0
- package/scaffolding/react/src/assets/fonts/allroundgothic-xlig.otf +0 -0
- package/scaffolding/react/src/assets/fonts/allroundgothic-xlig.ttf +0 -0
- package/scaffolding/react/src/assets/fonts/allroundgothic-xlig.woff +0 -0
- package/scaffolding/react/src/assets/fonts/allroundgothic-xlig.woff2 +0 -0
- package/scaffolding/react/src/assets/gen-by-albatross.png +0 -0
- package/scaffolding/react/src/assets/gen-by-albatross.svg +124 -0
- package/scaffolding/react/src/config/ecies.ts +10 -0
- package/scaffolding/react/src/config/runtime-config.ts +25 -0
- package/scaffolding/react/src/environments/environment.prod.ts.mustache +16 -0
- package/scaffolding/react/src/environments/environment.ts +15 -0
- package/scaffolding/react/src/interfaces/environment.ts +5 -0
- package/scaffolding/react/src/main.tsx +22 -0
- package/scaffolding/react/src/styles.scss +103 -0
- package/scaffolding/react/src/test-setup.ts +1 -0
- package/scaffolding/react-lib/src/index.ts +6 -0
- package/scaffolding/react-lib/src/theme/theme.tsx +67 -0
- package/scaffolding/root/.github/dependabot.yml +11 -0
- package/scaffolding/root/.github/workflows/ci.yml +44 -0
- package/scaffolding/root/.vscode/extensions.json +9 -0
- package/scaffolding/root/DEPLOYMENT.md +104 -0
- package/scaffolding/root/do-yarn.sh +148 -0
- package/scaffolding/root/ensure-git-globals.sh +30 -0
- package/scaffolding/root/eslint.config.mjs +70 -0
- package/scaffolding/root/list-scripts.sh +12 -0
- package/scaffolding/root/npm-install-globals.sh +5 -0
- package/scaffolding/root/nuke-node-modules.sh +23 -0
- package/scaffolding/root/recover-yarn.sh +37 -0
- package/scaffolding/root/reset.sh.mustache +25 -0
- package/scaffolding/root/setup-nvm.sh +15 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { SESClient, SendEmailCommand } from '@aws-sdk/client-ses';
|
|
2
|
+
import { IApplication, IBaseDocument } from '@digitaldefiance/node-express-suite';
|
|
3
|
+
|
|
4
|
+
// Simple debugLog implementation
|
|
5
|
+
function debugLog(debug: boolean, type: 'log' | 'warn' | 'error', ...args: any[]): void {
|
|
6
|
+
if (debug) {
|
|
7
|
+
console[type](...args);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
import { Types } from '@digitaldefiance/mongoose-types';
|
|
11
|
+
import { Environment } from '../environment';
|
|
12
|
+
import { IConstants } from '../interfaces/constants';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* A generic service for sending emails using Amazon SES.
|
|
16
|
+
*/
|
|
17
|
+
export class EmailService {
|
|
18
|
+
private readonly sesClient: SESClient;
|
|
19
|
+
private readonly emailSender: string;
|
|
20
|
+
private readonly disableEmailSend: boolean;
|
|
21
|
+
private readonly debug: boolean;
|
|
22
|
+
private readonly application: IApplication;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Constructs an instance of EmailService.
|
|
26
|
+
* @param config Configuration object containing AWS credentials, region, sender email, and debug/disable flags.
|
|
27
|
+
*/
|
|
28
|
+
constructor(application: IApplication) {
|
|
29
|
+
this.application = application;
|
|
30
|
+
const environment = application.environment as Environment;
|
|
31
|
+
this.emailSender = environment.emailSender;
|
|
32
|
+
this.disableEmailSend = environment.disableEmailSend;
|
|
33
|
+
this.debug = environment.debug;
|
|
34
|
+
|
|
35
|
+
// Initialize the SES client with provided AWS credentials and region.
|
|
36
|
+
this.sesClient = new SESClient({
|
|
37
|
+
region: environment.aws.region,
|
|
38
|
+
credentials: {
|
|
39
|
+
accessKeyId: environment.aws.accessKeyId.value ?? '',
|
|
40
|
+
secretAccessKey:
|
|
41
|
+
environment.aws.secretAccessKey.value ?? '',
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Sends an email using Amazon SES.
|
|
48
|
+
* @param to The recipient's email address.
|
|
49
|
+
* @param subject The subject line of the email.
|
|
50
|
+
* @param text The plain text body of the email.
|
|
51
|
+
* @param html The HTML body of the email.
|
|
52
|
+
* @returns A Promise that resolves when the email is sent successfully, or rejects on failure.
|
|
53
|
+
* @throws Error if email sending is disabled or if SES encounters an error.
|
|
54
|
+
*/
|
|
55
|
+
public async sendEmail(
|
|
56
|
+
to: string,
|
|
57
|
+
subject: string,
|
|
58
|
+
text: string,
|
|
59
|
+
html: string,
|
|
60
|
+
): Promise<void> {
|
|
61
|
+
if (this.disableEmailSend) {
|
|
62
|
+
debugLog(
|
|
63
|
+
this.debug,
|
|
64
|
+
'log',
|
|
65
|
+
`Email sending disabled for: ${to} - Subject: ${subject}`,
|
|
66
|
+
);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const sendCommand = new SendEmailCommand({
|
|
71
|
+
Destination: {
|
|
72
|
+
ToAddresses: [to], // Recipient email address
|
|
73
|
+
},
|
|
74
|
+
Message: {
|
|
75
|
+
Body: {
|
|
76
|
+
Html: {
|
|
77
|
+
Charset: 'UTF-8',
|
|
78
|
+
Data: html, // HTML content of the email
|
|
79
|
+
},
|
|
80
|
+
Text: {
|
|
81
|
+
Charset: 'UTF-8',
|
|
82
|
+
Data: text, // Plain text content of the email
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
Subject: {
|
|
86
|
+
Charset: 'UTF-8',
|
|
87
|
+
Data: subject, // Subject of the email
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
Source: this.emailSender, // Sender email address (must be verified in SES)
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
await this.sesClient.send(sendCommand);
|
|
95
|
+
debugLog(
|
|
96
|
+
this.debug,
|
|
97
|
+
'log',
|
|
98
|
+
`Email sent successfully to ${to} with subject: ${subject}`,
|
|
99
|
+
);
|
|
100
|
+
} catch (error) {
|
|
101
|
+
console.error(`Failed to send email to ${to}:`, error);
|
|
102
|
+
throw new Error(
|
|
103
|
+
`Failed to send email: ${
|
|
104
|
+
error instanceof Error ? error.message : String(error)
|
|
105
|
+
}`,
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './email';
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { NextFunction, Request, RequestHandler, Response } from 'express';
|
|
2
|
+
import { ValidationChain } from 'express-validator';
|
|
3
|
+
import { ClientSession, Document, Model, Types } from '@digitaldefiance/mongoose-types';
|
|
4
|
+
import { Brand } from 'ts-brand';
|
|
5
|
+
import type { IUserDocument } from './documents/user';
|
|
6
|
+
import { CoreLanguageCode } from '@digitaldefiance/i18n-lib';
|
|
7
|
+
import { IKeyPairBufferWithUnEncryptedPrivateKey, ISigningKeyPrivateKeyInfo, ISimplePublicKeyOnly, ISimpleKeyPairBuffer, ISimplePublicKeyOnlyBuffer } from '@digitaldefiance/node-ecies-lib'
|
|
8
|
+
import {IApiErrorResponse, IApiMessageResponse, ISchema, IStatusCodeResponse, IApiExpressValidationErrorResponse, IApiMongoValidationErrorResponse, IUserRoleDocument, IUsedDirectLoginTokenDocument, IRoleDocument, IMnemonicDocument, IEmailTokenDocument } from '@digitaldefiance/node-express-suite';
|
|
9
|
+
|
|
10
|
+
export type DefaultBackendIdType = Types.ObjectId;
|
|
11
|
+
|
|
12
|
+
export type MongooseDocument = Document;
|
|
13
|
+
export type MongooseModel<
|
|
14
|
+
TRawDocType,
|
|
15
|
+
TQueryHelpers = {},
|
|
16
|
+
TInstanceMethods = {},
|
|
17
|
+
TVirtuals = {},
|
|
18
|
+
> = Model<TRawDocType, TQueryHelpers, TInstanceMethods, TVirtuals>;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Transaction callback type for withTransaction
|
|
22
|
+
*/
|
|
23
|
+
export type TransactionCallback<T> = (
|
|
24
|
+
session: ClientSession | undefined,
|
|
25
|
+
...args: Array<unknown>
|
|
26
|
+
) => Promise<T>;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Validated body for express-validator
|
|
30
|
+
*/
|
|
31
|
+
export type ValidatedBody<T extends string> = {
|
|
32
|
+
[K in T]: unknown;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Schema map interface
|
|
37
|
+
*/
|
|
38
|
+
export type ModelDocMap = {
|
|
39
|
+
EmailToken: IEmailTokenDocument;
|
|
40
|
+
Mnemonic: IMnemonicDocument;
|
|
41
|
+
Role: IRoleDocument;
|
|
42
|
+
UsedDirectLoginToken: IUsedDirectLoginTokenDocument;
|
|
43
|
+
User: IUserDocument;
|
|
44
|
+
UserRole: IUserRoleDocument;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export type SchemaMap = {
|
|
48
|
+
/**
|
|
49
|
+
* For each model name, contains the corresponding schema and model
|
|
50
|
+
*/
|
|
51
|
+
[K in keyof ModelDocMap]: ISchema<ModelDocMap[K]>;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export type ApiRequestHandler<T extends ApiResponse> = (
|
|
55
|
+
req: Request,
|
|
56
|
+
res: Response,
|
|
57
|
+
next: NextFunction,
|
|
58
|
+
) => Promise<IStatusCodeResponse<T>>;
|
|
59
|
+
|
|
60
|
+
export type TypedHandlers = {
|
|
61
|
+
[key: string]: ApiRequestHandler<ApiResponse>;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export interface IRouteDefinition<T extends TypedHandlers> {
|
|
65
|
+
method: 'get' | 'post' | 'put' | 'delete' | 'patch';
|
|
66
|
+
path: string;
|
|
67
|
+
options: {
|
|
68
|
+
handlerKey: keyof T;
|
|
69
|
+
validation?: (validationLanguage: CoreLanguageCode) => ValidationChain[];
|
|
70
|
+
useAuthentication: boolean;
|
|
71
|
+
useCryptoAuthentication: boolean;
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export type RouteHandlers = Record<string, ApiRequestHandler<ApiResponse>>;
|
|
76
|
+
|
|
77
|
+
export type HttpMethod = 'get' | 'post' | 'put' | 'delete' | 'patch';
|
|
78
|
+
|
|
79
|
+
export interface RouteConfig<H extends object> {
|
|
80
|
+
method: HttpMethod;
|
|
81
|
+
path: string;
|
|
82
|
+
handlerKey: keyof H;
|
|
83
|
+
handlerArgs?: Array<unknown>;
|
|
84
|
+
useAuthentication: boolean;
|
|
85
|
+
useCryptoAuthentication: boolean;
|
|
86
|
+
middleware?: RequestHandler[];
|
|
87
|
+
validation?: FlexibleValidationChain;
|
|
88
|
+
rawJsonHandler?: boolean;
|
|
89
|
+
authFailureStatusCode?: number;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function routeConfig<T extends object>(
|
|
93
|
+
method: 'get' | 'post' | 'put' | 'delete' | 'patch',
|
|
94
|
+
path: string,
|
|
95
|
+
options: {
|
|
96
|
+
handlerKey: keyof T;
|
|
97
|
+
validation?: (validationLanguage: CoreLanguageCode) => ValidationChain[];
|
|
98
|
+
useAuthentication: boolean;
|
|
99
|
+
useCryptoAuthentication: boolean;
|
|
100
|
+
},
|
|
101
|
+
): RouteConfig<T> {
|
|
102
|
+
return {
|
|
103
|
+
method,
|
|
104
|
+
path,
|
|
105
|
+
handlerKey: options.handlerKey,
|
|
106
|
+
validation: options.validation,
|
|
107
|
+
useAuthentication: options.useAuthentication,
|
|
108
|
+
useCryptoAuthentication: options.useCryptoAuthentication,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export type THandlerArgs<T extends Array<unknown>> = T;
|
|
113
|
+
|
|
114
|
+
export type FlexibleValidationChain =
|
|
115
|
+
| ValidationChain[]
|
|
116
|
+
| ((lang: CoreLanguageCode) => ValidationChain[]);
|
|
117
|
+
|
|
118
|
+
export type JsonPrimitive = string | number | boolean | null | undefined;
|
|
119
|
+
|
|
120
|
+
export type JsonResponse =
|
|
121
|
+
| JsonPrimitive
|
|
122
|
+
| { [key: string]: JsonResponse }
|
|
123
|
+
| JsonResponse[];
|
|
124
|
+
|
|
125
|
+
export type ApiErrorResponse =
|
|
126
|
+
| IApiErrorResponse
|
|
127
|
+
| IApiExpressValidationErrorResponse
|
|
128
|
+
| IApiMongoValidationErrorResponse;
|
|
129
|
+
|
|
130
|
+
export type ApiResponse = IApiMessageResponse | ApiErrorResponse | JsonResponse;
|
|
131
|
+
|
|
132
|
+
export type SendFunction<T extends ApiResponse> = (
|
|
133
|
+
statusCode: number,
|
|
134
|
+
data: T,
|
|
135
|
+
res: Response<T>,
|
|
136
|
+
) => void;
|
|
137
|
+
|
|
138
|
+
export type KeyPairBufferWithUnEncryptedPrivateKey = Brand<
|
|
139
|
+
IKeyPairBufferWithUnEncryptedPrivateKey,
|
|
140
|
+
'KeyPairBufferWithUnEncryptedPrivateKey'
|
|
141
|
+
>;
|
|
142
|
+
export type SigningKeyPrivateKeyInfo = Brand<
|
|
143
|
+
ISigningKeyPrivateKeyInfo,
|
|
144
|
+
'SigningKeyPrivateKeyInfo'
|
|
145
|
+
>;
|
|
146
|
+
export type SimpleKeyPair = Brand<SimplePublicKeyOnly, 'SimpleKeyPair'>;
|
|
147
|
+
export type SimplePublicKeyOnly = Brand<
|
|
148
|
+
ISimplePublicKeyOnly,
|
|
149
|
+
'SimplePublicKeyOnly'
|
|
150
|
+
>;
|
|
151
|
+
export type SimpleKeyPairBuffer = Brand<
|
|
152
|
+
ISimpleKeyPairBuffer,
|
|
153
|
+
'SimpleKeyPairBuffer'
|
|
154
|
+
>;
|
|
155
|
+
export type SimplePublicKeyOnlyBuffer = Brand<
|
|
156
|
+
ISimplePublicKeyOnlyBuffer,
|
|
157
|
+
'SimplePublicKeyOnlyBuffer'
|
|
158
|
+
>;
|
|
159
|
+
export type HexString = Brand<string, 'HexString'>;
|
|
160
|
+
export type SignatureString = Brand<HexString, 'SignatureString'>;
|
|
161
|
+
export type SignatureBuffer = Buffer & Brand<Buffer, 'SignatureBuffer'>;
|
|
162
|
+
export type ChecksumBuffer = Buffer &
|
|
163
|
+
Brand<Buffer, 'Sha3Checksum', 'ChecksumBuffer'>;
|
|
164
|
+
export type ChecksumString = Brand<HexString, 'Sha3Checksum', 'ChecksumString'>;
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Extended Buffer type for data
|
|
168
|
+
*/
|
|
169
|
+
export type DataBuffer = Buffer & {
|
|
170
|
+
toBuffer(): Buffer;
|
|
171
|
+
toHex(): string;
|
|
172
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{workspaceName}} - Node.js & MongoDB",
|
|
3
|
+
"dockerComposeFile": "docker-compose.yml",
|
|
4
|
+
"service": "app",
|
|
5
|
+
"workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
|
|
6
|
+
"customizations": {
|
|
7
|
+
"vscode": {
|
|
8
|
+
"extensions": [
|
|
9
|
+
"mongodb.mongodb-vscode",
|
|
10
|
+
"dbaeumer.vscode-eslint",
|
|
11
|
+
"esbenp.prettier-vscode",
|
|
12
|
+
"firsttris.vscode-jest-runner",
|
|
13
|
+
"nrwl.angular-console"
|
|
14
|
+
]
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"hostRequirements": {
|
|
18
|
+
"memory": "16gb",
|
|
19
|
+
"cpus": 4
|
|
20
|
+
},
|
|
21
|
+
"runArgs": [
|
|
22
|
+
"--memory=12g",
|
|
23
|
+
"--memory-swap=16g",
|
|
24
|
+
"--cpus=4",
|
|
25
|
+
"--dns=1.1.1.1",
|
|
26
|
+
"--dns=8.8.8.8",
|
|
27
|
+
"--add-host=host.docker.internal:host-gateway"
|
|
28
|
+
],
|
|
29
|
+
"forwardPorts": [3000, 3443, 4200, 27017],
|
|
30
|
+
"postCreateCommand": "yarn install"
|
|
31
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
services:
|
|
2
|
+
app:
|
|
3
|
+
build:
|
|
4
|
+
context: .
|
|
5
|
+
dockerfile: Dockerfile
|
|
6
|
+
volumes:
|
|
7
|
+
- ../..:/workspaces:cached
|
|
8
|
+
command: sleep infinity
|
|
9
|
+
network_mode: service:db
|
|
10
|
+
dns:
|
|
11
|
+
- 1.1.1.1
|
|
12
|
+
- 8.8.8.8
|
|
13
|
+
extra_hosts:
|
|
14
|
+
- "host.docker.internal:host-gateway"
|
|
15
|
+
# Add memory limits to prevent OOM kills
|
|
16
|
+
mem_limit: 16g
|
|
17
|
+
memswap_limit: 16g
|
|
18
|
+
cpus: 4
|
|
19
|
+
|
|
20
|
+
db:
|
|
21
|
+
image: mongo:8
|
|
22
|
+
restart: unless-stopped
|
|
23
|
+
volumes:
|
|
24
|
+
- mongodb-data:/data/db
|
|
25
|
+
environment:
|
|
26
|
+
MONGO_INITDB_ROOT_USERNAME: admin
|
|
27
|
+
MONGO_INITDB_ROOT_PASSWORD: ${MONGO_PASSWORD}
|
|
28
|
+
MONGO_INITDB_DATABASE: ${MONGO_INITDB_DATABASE}
|
|
29
|
+
|
|
30
|
+
volumes:
|
|
31
|
+
mongodb-data:
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
|
3
|
+
|
|
4
|
+
# Check if we're in a /workspaces or /workspace path
|
|
5
|
+
if [[ "${PWD}" =~ ^/workspaces?/ ]]; then
|
|
6
|
+
WORKSPACE=$(echo "${PWD}" | grep -oP '^/workspaces?/[^/]+')
|
|
7
|
+
elif [ "$(basename "${PWD}")" = ".devcontainer" ]; then
|
|
8
|
+
WORKSPACE=$(realpath "${PWD}/..")
|
|
9
|
+
else
|
|
10
|
+
WORKSPACE=$(realpath "${SCRIPT_DIR}/..")
|
|
11
|
+
fi
|
|
12
|
+
|
|
13
|
+
DEVCONTAINER_DIR="${WORKSPACE}/.devcontainer"
|
|
14
|
+
|
|
15
|
+
if [ -f "${DEVCONTAINER_DIR}/.env" ]; then
|
|
16
|
+
echo "Loading environment variables from ${DEVCONTAINER_DIR}/.env"
|
|
17
|
+
set -a
|
|
18
|
+
source "${DEVCONTAINER_DIR}/.env"
|
|
19
|
+
set +a
|
|
20
|
+
fi
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -e
|
|
3
|
+
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
|
4
|
+
WORKSPACE=$(realpath "${SCRIPT_DIR}/..")
|
|
5
|
+
|
|
6
|
+
echo "Post-create setup starting..."
|
|
7
|
+
|
|
8
|
+
cd ${WORKSPACE} && source .devcontainer/load-env.sh
|
|
9
|
+
|
|
10
|
+
# Basic git setup
|
|
11
|
+
git config --global --add safe.directory ${WORKSPACE} 2>/dev/null || true
|
|
12
|
+
|
|
13
|
+
cd ${WORKSPACE} && ./setup-nvm.sh
|
|
14
|
+
cd ${WORKSPACE} && ./ensure-git-globals.sh
|
|
15
|
+
cd ${WORKSPACE} && ./recover-yarn.sh
|
|
16
|
+
|
|
17
|
+
cd ${WORKSPACE} && export COREPACK_ENABLE_DOWNLOAD_PROMPT=0 && yes | corepack enable
|
|
18
|
+
|
|
19
|
+
# Setup Yarn Berry
|
|
20
|
+
echo "Setting up Yarn Berry..."
|
|
21
|
+
cd ${WORKSPACE} && corepack prepare yarn@${DEFAULT_YARN_VERSION} --activate && corepack yarn set version ${DEFAULT_YARN_VERSION} || echo "Yarn Berry setup failed"
|
|
22
|
+
|
|
23
|
+
# Install dependencies
|
|
24
|
+
echo "Installing dependencies..."
|
|
25
|
+
cd ${WORKSPACE} && corepack yarn config set nodeLinker node-modules
|
|
26
|
+
|
|
27
|
+
MAX_ATTEMPTS=5;
|
|
28
|
+
WAIT_TIME=2;
|
|
29
|
+
REGISTRY_URL=http://host.docker.internal:4873/;
|
|
30
|
+
ATTEMPTS=0;
|
|
31
|
+
echo 'Waiting for Verdaccio registry at $REGISTRY_URL (Max 10s total, 4s timeout per attempt)...';
|
|
32
|
+
while [ $ATTEMPTS -lt $MAX_ATTEMPTS ]; do
|
|
33
|
+
# Increased timeouts for cross-host networking stability: 2s connect, 4s total time.
|
|
34
|
+
if curl -sS -o /dev/null --fail --connect-timeout 2 --max-time 4 $REGISTRY_URL; then
|
|
35
|
+
echo 'Verdaccio detected. Configuring NPM and YARN.';
|
|
36
|
+
npm config set registry $REGISTRY_URL --location=project;
|
|
37
|
+
yarn config set npmRegistryServer $REGISTRY_URL;
|
|
38
|
+
VERDACCIO=1;
|
|
39
|
+
break;
|
|
40
|
+
fi;
|
|
41
|
+
sleep $WAIT_TIME;
|
|
42
|
+
ATTEMPTS=$((ATTEMPTS + 1));
|
|
43
|
+
done;
|
|
44
|
+
[ -z "$VERDACCIO" ] && echo 'Verdaccio not detected after 5 attempts. Using default public registry.';
|
|
45
|
+
|
|
46
|
+
cd ${WORKSPACE} && ./npm-install-globals.sh
|
|
47
|
+
cd ${WORKSPACE} && ./do-yarn.sh || echo "Dependency installation failed"
|
|
48
|
+
|
|
49
|
+
cd ${WORKSPACE} && /usr/local/bin/mkcert localhost 127.0.0.1 ::1 {{hostname}}
|
|
50
|
+
|
|
51
|
+
echo ""
|
|
52
|
+
cd ${WORKSPACE} && yarn playwright install --with-deps || echo "Playwright installation failed"
|
|
53
|
+
|
|
54
|
+
echo "Post-create setup complete"
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
MONGO_INITDB_ROOT_USERNAME=admin
|
|
2
|
+
MONGO_INITDB_ROOT_PASSWORD={{password}}
|
|
3
|
+
MONGO_INITDB_DATABASE={{workspaceName}}
|
|
4
|
+
MONGO_REPLICA_SET_NAME=rs0
|
|
5
|
+
MONGO_PORT=27017
|
|
6
|
+
MONGO_KEYFILE=/tmp/replica.key
|
|
7
|
+
MONGO_DB_PATH=/data/db
|
|
8
|
+
DEFAULT_YARN_VERSION=4.11.0
|
|
9
|
+
DEFAULT_NVM_VERSION=22
|
|
10
|
+
GIT_EMAIL=your@email.com
|
|
11
|
+
GIT_NAME="Your Name"
|
|
12
|
+
DEBUG="false"
|
|
13
|
+
|
|
14
|
+
COMPOSE_PROJECT_NAME={{prefix}}_devcontainer
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
FROM mcr.microsoft.com/devcontainers/javascript-node:1-22-bookworm
|
|
2
|
+
|
|
3
|
+
# Install MongoDB command line tools - though mongo-database-tools not available on arm64
|
|
4
|
+
ARG MONGO_TOOLS_VERSION=6.0
|
|
5
|
+
RUN . /etc/os-release \
|
|
6
|
+
&& curl -sSL "https://www.mongodb.org/static/pgp/server-${MONGO_TOOLS_VERSION}.asc" | gpg --dearmor > /usr/share/keyrings/mongodb-archive-keyring.gpg \
|
|
7
|
+
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/mongodb-archive-keyring.gpg] http://repo.mongodb.org/apt/debian ${VERSION_CODENAME}/mongodb-org/${MONGO_TOOLS_VERSION} main" | tee /etc/apt/sources.list.d/mongodb-org-${MONGO_TOOLS_VERSION}.list \
|
|
8
|
+
&& apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
|
9
|
+
&& apt-get install -y mongodb-mongosh libnss3-tools golang \
|
|
10
|
+
&& if [ "$(dpkg --print-architecture)" = "amd64" ]; then apt-get install -y mongodb-database-tools; fi \
|
|
11
|
+
&& apt-get clean -y && rm -rf /var/lib/apt/lists/*
|
|
12
|
+
|
|
13
|
+
# [Optional] Uncomment this section to install additional OS packages.
|
|
14
|
+
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
|
15
|
+
# && apt-get -y install --no-install-recommends <your-package-list-here>
|
|
16
|
+
|
|
17
|
+
# [Optional] Uncomment if you want to install an additional version of node using nvm
|
|
18
|
+
# ARG EXTRA_NODE_VERSION=10
|
|
19
|
+
# RUN su node -c "source /usr/local/share/nvm/nvm.sh && nvm install ${EXTRA_NODE_VERSION}"
|
|
20
|
+
|
|
21
|
+
# [Optional] Uncomment if you want to install more global node modules
|
|
22
|
+
# RUN su node -c "npm install -g <your-package-list-here>"
|
|
23
|
+
|
|
24
|
+
RUN git clone https://github.com/FiloSottile/mkcert && cd mkcert && go build -ldflags "-X main.Version=$(git describe --tags)" && cp mkcert /usr/local/bin && cd .. && rm -rf mkcert && /usr/local/bin/mkcert -install
|
|
25
|
+
|
|
26
|
+
# Install global npm packages and setup corepack
|
|
27
|
+
RUN npm install -g nx @angular/cli typescript ts-node nodemon && \
|
|
28
|
+
corepack enable && \
|
|
29
|
+
corepack prepare yarn@4.9.2 --activate
|
|
30
|
+
|
|
31
|
+
# Copy and set up custom entrypoint for better signal handling
|
|
32
|
+
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
|
|
33
|
+
RUN chmod +x /usr/local/bin/entrypoint.sh
|
|
34
|
+
|
|
35
|
+
RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" && unzip awscliv2.zip && sudo ./aws/install && rm -rf awscliv2.zip aws
|
|
36
|
+
|
|
37
|
+
# Set the entrypoint
|
|
38
|
+
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# db/Mongo.Dockerfile
|
|
2
|
+
|
|
3
|
+
FROM mongo:latest
|
|
4
|
+
|
|
5
|
+
# Generate a secure key for the replica set
|
|
6
|
+
RUN openssl rand -base64 756 > "/tmp/replica.key" \
|
|
7
|
+
&& chmod 600 /tmp/replica.key \
|
|
8
|
+
&& chown mongodb:mongodb /tmp/replica.key
|
|
9
|
+
|
|
10
|
+
# Remove any existing init scripts to prevent conflicts
|
|
11
|
+
RUN rm -rf /docker-entrypoint-initdb.d/*
|
|
12
|
+
|
|
13
|
+
# Copy the updated entrypoint script
|
|
14
|
+
COPY mongodb_entrypoint.sh /usr/local/bin/mongodb_entrypoint.sh
|
|
15
|
+
RUN chmod +x /usr/local/bin/mongodb_entrypoint.sh
|
|
16
|
+
|
|
17
|
+
COPY mongodb_healthcheck.sh /usr/local/bin/mongodb_healthcheck.sh
|
|
18
|
+
RUN chmod +x /usr/local/bin/mongodb_healthcheck.sh
|
|
19
|
+
|
|
20
|
+
# Override the default entrypoint
|
|
21
|
+
ENTRYPOINT ["/usr/local/bin/mongodb_entrypoint.sh"]
|
|
22
|
+
|
|
23
|
+
# Expose MongoDB port
|
|
24
|
+
EXPOSE 27017
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
|
2
|
+
// README at: https://github.com/devcontainers/templates/tree/main/src/javascript-node-mongo
|
|
3
|
+
{
|
|
4
|
+
"name": "Node.js & Mongo DB",
|
|
5
|
+
"dockerComposeFile": "docker-compose.yml",
|
|
6
|
+
"service": "app",
|
|
7
|
+
"workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
|
|
8
|
+
// Features to add to the dev container. More info: https://containers.dev/features.
|
|
9
|
+
"features": {
|
|
10
|
+
"ghcr.io/devcontainers/features/docker-outside-of-docker:1": {}
|
|
11
|
+
},
|
|
12
|
+
// Add container environment variables to help with stability
|
|
13
|
+
"containerEnv": {
|
|
14
|
+
"COREPACK_ENABLE_DOWNLOAD_PROMPT": "0",
|
|
15
|
+
"VSCODE_REMOTE_CONTAINERS_SESSION": "${containerSessionId}"
|
|
16
|
+
},
|
|
17
|
+
// You can also add hostRequirements to check if the host has enough memory
|
|
18
|
+
"hostRequirements": {
|
|
19
|
+
"memory": "16gb",
|
|
20
|
+
"cpus": 4
|
|
21
|
+
},
|
|
22
|
+
"runArgs": [
|
|
23
|
+
"--memory=12g",
|
|
24
|
+
"--memory-swap=16g",
|
|
25
|
+
"--cpus=4",
|
|
26
|
+
"--dns=1.1.1.1",
|
|
27
|
+
"--dns=8.8.8.8",
|
|
28
|
+
"--add-host=host.docker.internal:host-gateway"
|
|
29
|
+
],
|
|
30
|
+
// Configure tool-specific properties.
|
|
31
|
+
"customizations": {
|
|
32
|
+
// Configure properties specific to VS Code.
|
|
33
|
+
"vscode": {
|
|
34
|
+
// Add the IDs of extensions you want installed when the container is created.
|
|
35
|
+
"extensions": [
|
|
36
|
+
"mongodb.mongodb-vscode",
|
|
37
|
+
"github.vscode-github-actions",
|
|
38
|
+
"ms-azuretools.vscode-docker",
|
|
39
|
+
"esbenp.prettier-vscode",
|
|
40
|
+
"ms-vscode-remote.remote-containers",
|
|
41
|
+
"firsttris.vscode-jest-runner",
|
|
42
|
+
"ms-playwright.playwright",
|
|
43
|
+
"nrwl.angular-console",
|
|
44
|
+
"GitHub.copilot",
|
|
45
|
+
"GitHub.copilot-chat",
|
|
46
|
+
"bruno-api-client.bruno"
|
|
47
|
+
]
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
|
51
|
+
"forwardPorts": [
|
|
52
|
+
3000,
|
|
53
|
+
3443,
|
|
54
|
+
4200,
|
|
55
|
+
27017
|
|
56
|
+
],
|
|
57
|
+
// Use 'postCreateCommand' to run commands after the container is created.
|
|
58
|
+
"postCreateCommand": "./.devcontainer/post-create.sh",
|
|
59
|
+
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
|
|
60
|
+
"remoteUser": "node",
|
|
61
|
+
// Add connection timeout and retry settings
|
|
62
|
+
"shutdownAction": "none",
|
|
63
|
+
"userEnvProbe": "none",
|
|
64
|
+
"updateRemoteUserUID": false,
|
|
65
|
+
"remoteEnv": {
|
|
66
|
+
"SHELL": "/bin/bash"
|
|
67
|
+
},
|
|
68
|
+
"overrideCommand": false,
|
|
69
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
services:
|
|
2
|
+
app:
|
|
3
|
+
build:
|
|
4
|
+
context: .
|
|
5
|
+
dockerfile: Dockerfile
|
|
6
|
+
volumes:
|
|
7
|
+
- ../..:/workspaces:cached
|
|
8
|
+
command: ["sleep", "infinity"]
|
|
9
|
+
dns:
|
|
10
|
+
- 1.1.1.1
|
|
11
|
+
- 8.8.8.8
|
|
12
|
+
extra_hosts:
|
|
13
|
+
- "host.docker.internal:host-gateway"
|
|
14
|
+
# Add init system for better signal handling
|
|
15
|
+
init: true
|
|
16
|
+
# Add restart policy
|
|
17
|
+
restart: unless-stopped
|
|
18
|
+
# Add memory limits to prevent OOM kills
|
|
19
|
+
mem_limit: 16g
|
|
20
|
+
memswap_limit: 16g
|
|
21
|
+
cpus: 4
|
|
22
|
+
# Add environment variables for debugging
|
|
23
|
+
environment:
|
|
24
|
+
- DB_HOST=db:27017
|
|
25
|
+
- DEBUG=1
|
|
26
|
+
- CONTAINER_ROLE=app
|
|
27
|
+
env_file:
|
|
28
|
+
- .env
|
|
29
|
+
depends_on:
|
|
30
|
+
- db
|
|
31
|
+
ports:
|
|
32
|
+
- "3000:3000"
|
|
33
|
+
|
|
34
|
+
db:
|
|
35
|
+
build:
|
|
36
|
+
context: .
|
|
37
|
+
dockerfile: ./Mongo.Dockerfile
|
|
38
|
+
container_name: db # Ensures the container name is 'db'
|
|
39
|
+
hostname: db # Sets the internal hostname to 'db'
|
|
40
|
+
restart: unless-stopped
|
|
41
|
+
# Add memory limits to prevent OOM kills
|
|
42
|
+
mem_limit: 2g
|
|
43
|
+
memswap_limit: 2g
|
|
44
|
+
healthcheck:
|
|
45
|
+
test: ["CMD", "bash", "/usr/local/bin/mongodb_healthcheck.sh"]
|
|
46
|
+
interval: 30s
|
|
47
|
+
timeout: 10s
|
|
48
|
+
retries: 5
|
|
49
|
+
start_period: 40s
|
|
50
|
+
ports:
|
|
51
|
+
- "27017:27017"
|
|
52
|
+
volumes:
|
|
53
|
+
- mongodb-data:/data/db
|
|
54
|
+
environment:
|
|
55
|
+
- MONGO_INITDB_ROOT_USERNAME=${MONGO_INITDB_ROOT_USERNAME}
|
|
56
|
+
- MONGO_INITDB_ROOT_PASSWORD=${MONGO_INITDB_ROOT_PASSWORD}
|
|
57
|
+
- MONGO_INITDB_DATABASE=${MONGO_INITDB_DATABASE}
|
|
58
|
+
- MONGO_REPLICA_SET_NAME=${MONGO_REPLICA_SET_NAME}
|
|
59
|
+
- MONGO_PORT=${MONGO_PORT}
|
|
60
|
+
- MONGO_KEYFILE=${MONGO_KEYFILE}
|
|
61
|
+
- MONGO_DB_PATH=${MONGO_DB_PATH}
|
|
62
|
+
- DB_HOST=127.0.0.1:27017
|
|
63
|
+
- EDITOR=vim
|
|
64
|
+
|
|
65
|
+
volumes:
|
|
66
|
+
mongodb-data:
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -e
|
|
3
|
+
|
|
4
|
+
# Print debug info
|
|
5
|
+
echo "Container started. PID: $$"
|
|
6
|
+
echo "Arguments: $@"
|
|
7
|
+
echo "Environment:"
|
|
8
|
+
env | grep -E "(VSCODE|REMOTE)" || true
|
|
9
|
+
|
|
10
|
+
# Set up signal handlers for graceful shutdown
|
|
11
|
+
trap 'echo "Received SIGTERM, shutting down gracefully..."; exit 0' TERM
|
|
12
|
+
trap 'echo "Received SIGINT, shutting down gracefully..."; exit 0' INT
|
|
13
|
+
|
|
14
|
+
# Start the original command in background
|
|
15
|
+
if [ $# -gt 0 ]; then
|
|
16
|
+
echo "Executing: $@"
|
|
17
|
+
"$@" &
|
|
18
|
+
CHILD_PID=$!
|
|
19
|
+
echo "Child process started with PID: $CHILD_PID"
|
|
20
|
+
|
|
21
|
+
# Wait for child process and handle signals
|
|
22
|
+
wait $CHILD_PID
|
|
23
|
+
EXIT_CODE=$?
|
|
24
|
+
echo "Child process exited with code: $EXIT_CODE"
|
|
25
|
+
exit $EXIT_CODE
|
|
26
|
+
else
|
|
27
|
+
echo "No command provided, running sleep infinity"
|
|
28
|
+
exec sleep infinity
|
|
29
|
+
fi
|