@digitaldefiance/express-suite-starter 2.3.5 → 2.3.6

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.
Files changed (95) hide show
  1. package/package.json +2 -1
  2. package/scaffolding/api/.env.example.mustache +52 -0
  3. package/scaffolding/api/src/assets/.gitkeep +0 -0
  4. package/scaffolding/api/src/main.ts.mustache +19 -0
  5. package/scaffolding/api/src/views/index.ejs +34 -0
  6. package/scaffolding/api-lib/src/index.ts +9 -0
  7. package/scaffolding/api-lib/src/lib/application.ts +35 -0
  8. package/scaffolding/api-lib/src/lib/constants.ts.mustache +10 -0
  9. package/scaffolding/api-lib/src/lib/documents/index.ts +1 -0
  10. package/scaffolding/api-lib/src/lib/documents/user.ts +17 -0
  11. package/scaffolding/api-lib/src/lib/environment.ts +52 -0
  12. package/scaffolding/api-lib/src/lib/interfaces/constants.ts +9 -0
  13. package/scaffolding/api-lib/src/lib/interfaces/environment-aws.ts +7 -0
  14. package/scaffolding/api-lib/src/lib/interfaces/environment.ts +9 -0
  15. package/scaffolding/api-lib/src/lib/middlewares.ts.mustache +113 -0
  16. package/scaffolding/api-lib/src/lib/models/email-token.ts +12 -0
  17. package/scaffolding/api-lib/src/lib/models/mnemonic.ts +12 -0
  18. package/scaffolding/api-lib/src/lib/models/role.ts +12 -0
  19. package/scaffolding/api-lib/src/lib/models/used-direct-login-token.ts +12 -0
  20. package/scaffolding/api-lib/src/lib/models/user-role.ts +12 -0
  21. package/scaffolding/api-lib/src/lib/models/user.ts +14 -0
  22. package/scaffolding/api-lib/src/lib/routers/api.ts +23 -0
  23. package/scaffolding/api-lib/src/lib/routers/app.ts +31 -0
  24. package/scaffolding/api-lib/src/lib/routers/index.ts +2 -0
  25. package/scaffolding/api-lib/src/lib/schemas/index.ts +2 -0
  26. package/scaffolding/api-lib/src/lib/schemas/schema.ts +53 -0
  27. package/scaffolding/api-lib/src/lib/schemas/user.ts +13 -0
  28. package/scaffolding/api-lib/src/lib/services/email.ts +109 -0
  29. package/scaffolding/api-lib/src/lib/services/index.ts +1 -0
  30. package/scaffolding/api-lib/src/lib/shared-types.ts +172 -0
  31. package/scaffolding/devcontainer-mongodb/.devcontainer/.env.example +3 -0
  32. package/scaffolding/devcontainer-mongodb/.devcontainer/Dockerfile +6 -0
  33. package/scaffolding/devcontainer-mongodb/.devcontainer/devcontainer.json.mustache +31 -0
  34. package/scaffolding/devcontainer-mongodb/.devcontainer/docker-compose.yml +31 -0
  35. package/scaffolding/devcontainer-mongodb/.devcontainer/load-env.sh +20 -0
  36. package/scaffolding/devcontainer-mongodb/.devcontainer/post-create.sh.hbs +54 -0
  37. package/scaffolding/devcontainer-mongodb-replicaset/.devcontainer/.env.example +14 -0
  38. package/scaffolding/devcontainer-mongodb-replicaset/.devcontainer/Dockerfile +38 -0
  39. package/scaffolding/devcontainer-mongodb-replicaset/.devcontainer/Mongo.Dockerfile +24 -0
  40. package/scaffolding/devcontainer-mongodb-replicaset/.devcontainer/devcontainer.json +69 -0
  41. package/scaffolding/devcontainer-mongodb-replicaset/.devcontainer/docker-compose.yml +66 -0
  42. package/scaffolding/devcontainer-mongodb-replicaset/.devcontainer/entrypoint.sh +29 -0
  43. package/scaffolding/devcontainer-mongodb-replicaset/.devcontainer/load-env.sh +20 -0
  44. package/scaffolding/devcontainer-mongodb-replicaset/.devcontainer/mongodb_entrypoint.sh +124 -0
  45. package/scaffolding/devcontainer-mongodb-replicaset/.devcontainer/mongodb_healthcheck.sh +36 -0
  46. package/scaffolding/devcontainer-mongodb-replicaset/.devcontainer/post-create.sh.hbs +54 -0
  47. package/scaffolding/devcontainer-simple/.devcontainer/.env.example +4 -0
  48. package/scaffolding/devcontainer-simple/.devcontainer/devcontainer.json.mustache +60 -0
  49. package/scaffolding/devcontainer-simple/.devcontainer/post-create.sh.hbs +72 -0
  50. package/scaffolding/inituserdb/.env.example.mustache +9 -0
  51. package/scaffolding/inituserdb/src/main.ts.mustache +178 -0
  52. package/scaffolding/lib/src/index.ts.mustache +6 -0
  53. package/scaffolding/lib/src/lib/constants.ts.mustache +15 -0
  54. package/scaffolding/lib/src/lib/ecies-config.ts +10 -0
  55. package/scaffolding/lib/src/lib/enumerations/{{workspaceName}}-string-key.ts.mustache +5 -0
  56. package/scaffolding/lib/src/lib/i18n-setup.ts.mustache +99 -0
  57. package/scaffolding/lib/src/lib/interfaces/constants.ts +13 -0
  58. package/scaffolding/lib/src/lib/strings-collection.ts.mustache +45 -0
  59. package/scaffolding/react/src/app/app.tsx.mustache +170 -0
  60. package/scaffolding/react/src/app/menus/extraMenu.tsx +20 -0
  61. package/scaffolding/react/src/app/menus/index.ts +5 -0
  62. package/scaffolding/react/src/app/pages/SplashPage.tsx +60 -0
  63. package/scaffolding/react/src/app/theme.tsx.mustache +91 -0
  64. package/scaffolding/react/src/assets/albatross.ico +0 -0
  65. package/scaffolding/react/src/assets/albatross.png +0 -0
  66. package/scaffolding/react/src/assets/albatross.svg +108 -0
  67. package/scaffolding/react/src/assets/fonts/allroundgothic-xlig.otf +0 -0
  68. package/scaffolding/react/src/assets/fonts/allroundgothic-xlig.ttf +0 -0
  69. package/scaffolding/react/src/assets/fonts/allroundgothic-xlig.woff +0 -0
  70. package/scaffolding/react/src/assets/fonts/allroundgothic-xlig.woff2 +0 -0
  71. package/scaffolding/react/src/assets/gen-by-albatross.png +0 -0
  72. package/scaffolding/react/src/assets/gen-by-albatross.svg +124 -0
  73. package/scaffolding/react/src/config/ecies.ts +10 -0
  74. package/scaffolding/react/src/config/runtime-config.ts +25 -0
  75. package/scaffolding/react/src/environments/environment.prod.ts.mustache +16 -0
  76. package/scaffolding/react/src/environments/environment.ts +15 -0
  77. package/scaffolding/react/src/interfaces/environment.ts +5 -0
  78. package/scaffolding/react/src/main.tsx +22 -0
  79. package/scaffolding/react/src/styles.scss +103 -0
  80. package/scaffolding/react/src/test-setup.ts +1 -0
  81. package/scaffolding/react-lib/src/index.ts +6 -0
  82. package/scaffolding/react-lib/src/theme/theme.tsx +67 -0
  83. package/scaffolding/root/.github/dependabot.yml +11 -0
  84. package/scaffolding/root/.github/workflows/ci.yml +44 -0
  85. package/scaffolding/root/.vscode/extensions.json +9 -0
  86. package/scaffolding/root/DEPLOYMENT.md +104 -0
  87. package/scaffolding/root/do-yarn.sh +148 -0
  88. package/scaffolding/root/ensure-git-globals.sh +30 -0
  89. package/scaffolding/root/eslint.config.mjs +70 -0
  90. package/scaffolding/root/list-scripts.sh +12 -0
  91. package/scaffolding/root/npm-install-globals.sh +5 -0
  92. package/scaffolding/root/nuke-node-modules.sh +23 -0
  93. package/scaffolding/root/recover-yarn.sh +37 -0
  94. package/scaffolding/root/reset.sh.mustache +25 -0
  95. 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,3 @@
1
+ MONGO_PASSWORD={{password}}
2
+ MONGO_INITDB_DATABASE={{workspaceName}}
3
+ COMPOSE_PROJECT_NAME={{prefix}}_devcontainer
@@ -0,0 +1,6 @@
1
+ FROM mcr.microsoft.com/devcontainers/javascript-node:20
2
+
3
+ # Install MongoDB tools
4
+ RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
5
+ && apt-get install -y mongodb-clients \
6
+ && apt-get clean -y && rm -rf /var/lib/apt/lists/*
@@ -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