@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,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,124 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -e
|
|
3
|
+
|
|
4
|
+
echo "Hostname: $(hostname)"
|
|
5
|
+
|
|
6
|
+
# Environment Variables with Defaults
|
|
7
|
+
MONGO_LOG=${MONGO_LOG:-"/var/log/mongodb/mongod.log"}
|
|
8
|
+
MONGO_INITDB_ROOT_USERNAME=${MONGO_INITDB_ROOT_USERNAME}
|
|
9
|
+
MONGO_INITDB_ROOT_PASSWORD=${MONGO_INITDB_ROOT_PASSWORD}
|
|
10
|
+
MONGO_REPLICA_SET_NAME=${MONGO_REPLICA_SET_NAME:-"rs0"}
|
|
11
|
+
MONGO_BIND_IP=${MONGO_BIND_IP:-"0.0.0.0"}
|
|
12
|
+
MONGO_PORT=${MONGO_PORT:-27017}
|
|
13
|
+
MONGO_KEYFILE=${MONGO_KEYFILE:-"/tmp/replica.key"}
|
|
14
|
+
MONGO_DB_PATH=${MONGO_DB_PATH:-"/data/db"}
|
|
15
|
+
MAX_ATTEMPTS=30
|
|
16
|
+
RETRY_INTERVAL=${RETRY_INTERVAL:-30}
|
|
17
|
+
SETUP_COMPLETE_FILE="/data/db/.setup_complete"
|
|
18
|
+
|
|
19
|
+
start_mongo_noauth() {
|
|
20
|
+
echo "Starting MongoDB without authentication..."
|
|
21
|
+
mongod --replSet "$MONGO_REPLICA_SET_NAME" --bind_ip_all --dbpath "$MONGO_DB_PATH" --logpath "$MONGO_LOG" \
|
|
22
|
+
--wiredTigerCacheSizeGB 0.5 \
|
|
23
|
+
--fork
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
wait_for_mongo() {
|
|
27
|
+
echo "Waiting for MongoDB to be ready..."
|
|
28
|
+
for i in $(seq 1 $MAX_ATTEMPTS); do
|
|
29
|
+
if mongosh --quiet --eval "db.runCommand({ ping: 1 })" &>/dev/null; then
|
|
30
|
+
echo "MongoDB is ready."
|
|
31
|
+
return 0
|
|
32
|
+
fi
|
|
33
|
+
echo "Attempt $i: MongoDB not ready yet, retrying in $RETRY_INTERVAL seconds..."
|
|
34
|
+
sleep $RETRY_INTERVAL
|
|
35
|
+
done
|
|
36
|
+
echo "Failed to connect to MongoDB after $MAX_ATTEMPTS attempts."
|
|
37
|
+
return 1
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
initialize_replica_set() {
|
|
41
|
+
echo "Initializing replica set with localhost..."
|
|
42
|
+
mongosh --quiet --eval "
|
|
43
|
+
rs.initiate({
|
|
44
|
+
_id: '$MONGO_REPLICA_SET_NAME',
|
|
45
|
+
members: [{ _id: 0, host: 'localhost:$MONGO_PORT' }]
|
|
46
|
+
})
|
|
47
|
+
"
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
wait_for_primary() {
|
|
51
|
+
echo "Waiting for replica set to become PRIMARY..."
|
|
52
|
+
for i in $(seq 1 $MAX_ATTEMPTS); do
|
|
53
|
+
if [ "$1" = "auth" ]; then
|
|
54
|
+
status=$(mongosh admin --quiet --eval "db.auth('$MONGO_INITDB_ROOT_USERNAME', '$MONGO_INITDB_ROOT_PASSWORD'); rs.status().myState")
|
|
55
|
+
else
|
|
56
|
+
status=$(mongosh --quiet --eval "rs.status().myState")
|
|
57
|
+
fi
|
|
58
|
+
if [ "$status" = "1" ]; then
|
|
59
|
+
echo "Replica set is now PRIMARY."
|
|
60
|
+
return 0
|
|
61
|
+
fi
|
|
62
|
+
echo "Attempt $i: Replica set is not PRIMARY yet, retrying in $RETRY_INTERVAL seconds..."
|
|
63
|
+
sleep $RETRY_INTERVAL
|
|
64
|
+
done
|
|
65
|
+
echo "Replica set did not become PRIMARY within the expected time."
|
|
66
|
+
return 1
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
create_root_user() {
|
|
70
|
+
echo "Creating root user..."
|
|
71
|
+
mongosh admin --quiet --eval "
|
|
72
|
+
db.createUser({
|
|
73
|
+
user: '$MONGO_INITDB_ROOT_USERNAME',
|
|
74
|
+
pwd: '$MONGO_INITDB_ROOT_PASSWORD',
|
|
75
|
+
roles: [{ role: 'root', db: 'admin' }]
|
|
76
|
+
});
|
|
77
|
+
"
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
start_mongo_auth() {
|
|
81
|
+
echo "Starting MongoDB with authentication..."
|
|
82
|
+
mongod --auth --replSet "$MONGO_REPLICA_SET_NAME" --bind_ip_all --dbpath "$MONGO_DB_PATH" --logpath "$MONGO_LOG" --keyFile "$MONGO_KEYFILE" \
|
|
83
|
+
--wiredTigerCacheSizeGB 0.5 \
|
|
84
|
+
--fork
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
start_mongo_auth_foreground() {
|
|
88
|
+
echo "Starting MongoDB with authentication in the foreground..."
|
|
89
|
+
exec mongod --auth --replSet "$MONGO_REPLICA_SET_NAME" --bind_ip_all --dbpath "$MONGO_DB_PATH" --keyFile "$MONGO_KEYFILE" \
|
|
90
|
+
--wiredTigerCacheSizeGB 0.5
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if [ -f "$SETUP_COMPLETE_FILE" ]; then
|
|
94
|
+
echo "Setup already completed. Starting MongoDB in foreground mode."
|
|
95
|
+
start_mongo_auth_foreground
|
|
96
|
+
exit 0
|
|
97
|
+
fi
|
|
98
|
+
|
|
99
|
+
# Main execution flow
|
|
100
|
+
echo "Starting MongoDB setup..."
|
|
101
|
+
|
|
102
|
+
start_mongo_noauth
|
|
103
|
+
wait_for_mongo || exit 1
|
|
104
|
+
|
|
105
|
+
echo "Initializing replica set..."
|
|
106
|
+
initialize_replica_set
|
|
107
|
+
wait_for_primary || exit 1
|
|
108
|
+
|
|
109
|
+
echo "Creating root user..."
|
|
110
|
+
create_root_user
|
|
111
|
+
|
|
112
|
+
echo "Shutting down MongoDB to restart with authentication..."
|
|
113
|
+
mongod --shutdown
|
|
114
|
+
|
|
115
|
+
echo "Starting MongoDB with authentication..."
|
|
116
|
+
start_mongo_auth
|
|
117
|
+
wait_for_mongo || exit 1
|
|
118
|
+
wait_for_primary "auth" || exit 1
|
|
119
|
+
|
|
120
|
+
# Mark setup as complete
|
|
121
|
+
touch "$SETUP_COMPLETE_FILE"
|
|
122
|
+
|
|
123
|
+
echo "MongoDB setup completed successfully. Starting MongoDB in foreground mode."
|
|
124
|
+
start_mongo_auth_foreground
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
MAX_ATTEMPTS=30
|
|
4
|
+
RETRY_INTERVAL=10
|
|
5
|
+
|
|
6
|
+
# Wait for MongoDB to start
|
|
7
|
+
for i in $(seq 1 $MAX_ATTEMPTS); do
|
|
8
|
+
if mongosh --quiet --eval 'db.runCommand({ ping: 1 })' >/dev/null 2>&1; then
|
|
9
|
+
echo "[HC] MongoDB is responsive."
|
|
10
|
+
break
|
|
11
|
+
fi
|
|
12
|
+
echo "[HC] Attempt $i/$MAX_ATTEMPTS: Waiting for MongoDB to start..."
|
|
13
|
+
sleep $RETRY_INTERVAL
|
|
14
|
+
if [ $i -eq $MAX_ATTEMPTS ]; then
|
|
15
|
+
echo "[HC] MongoDB failed to start after $MAX_ATTEMPTS attempts."
|
|
16
|
+
exit 1
|
|
17
|
+
fi
|
|
18
|
+
done
|
|
19
|
+
|
|
20
|
+
# Check if MongoDB replica set is ready
|
|
21
|
+
for i in $(seq 1 $MAX_ATTEMPTS); do
|
|
22
|
+
rs_status=$(mongosh --quiet --eval 'rs.status().ok' --authenticationDatabase admin -u "$MONGO_INITDB_ROOT_USERNAME" -p "$MONGO_INITDB_ROOT_PASSWORD" || echo "0")
|
|
23
|
+
if [ "$rs_status" = "1" ]; then
|
|
24
|
+
echo "[HC] MongoDB replica set is ready."
|
|
25
|
+
exit 0
|
|
26
|
+
fi
|
|
27
|
+
echo "[HC] Attempt $i/$MAX_ATTEMPTS: Waiting for MongoDB replica set to be ready..."
|
|
28
|
+
sleep $RETRY_INTERVAL
|
|
29
|
+
if [ $i -eq $MAX_ATTEMPTS ]; then
|
|
30
|
+
echo "[HC] MongoDB replica set failed to initialize after $MAX_ATTEMPTS attempts."
|
|
31
|
+
exit 1
|
|
32
|
+
fi
|
|
33
|
+
done
|
|
34
|
+
|
|
35
|
+
echo "[HC] MongoDB healthcheck failed."
|
|
36
|
+
exit 1
|
|
@@ -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,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{workspaceName}} - Node.js",
|
|
3
|
+
"image": "mcr.microsoft.com/devcontainers/javascript-node:20",
|
|
4
|
+
"customizations": {
|
|
5
|
+
"vscode": {
|
|
6
|
+
"extensions": [
|
|
7
|
+
"github.vscode-github-actions",
|
|
8
|
+
"ms-azuretools.vscode-docker",
|
|
9
|
+
"esbenp.prettier-vscode",
|
|
10
|
+
"ms-vscode-remote.remote-containers",
|
|
11
|
+
"firsttris.vscode-jest-runner",
|
|
12
|
+
"ms-playwright.playwright",
|
|
13
|
+
"nrwl.angular-console",
|
|
14
|
+
"GitHub.copilot",
|
|
15
|
+
"GitHub.copilot-chat",
|
|
16
|
+
"bruno-api-client.bruno"
|
|
17
|
+
]
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"hostRequirements": {
|
|
21
|
+
"memory": "16gb",
|
|
22
|
+
"cpus": 4
|
|
23
|
+
},
|
|
24
|
+
"runArgs": [
|
|
25
|
+
"--memory=16g",
|
|
26
|
+
"--memory-swap=16g",
|
|
27
|
+
"--cpus=4",
|
|
28
|
+
"--dns=1.1.1.1",
|
|
29
|
+
"--dns=8.8.8.8",
|
|
30
|
+
"--add-host=host.docker.internal:host-gateway",
|
|
31
|
+
"-p",
|
|
32
|
+
"3000:3000",
|
|
33
|
+
"-p",
|
|
34
|
+
"3443:3443",
|
|
35
|
+
"-p",
|
|
36
|
+
"4200:4200",
|
|
37
|
+
],
|
|
38
|
+
"mounts": [
|
|
39
|
+
"source=${localWorkspaceFolder}/.devcontainer/.env,target=/workspaces/${localWorkspaceFolderBasename}/.env,type=bind,consistency=cached"
|
|
40
|
+
],
|
|
41
|
+
"forwardPorts": [3000, 3443, 4200],
|
|
42
|
+
"portsAttributes": {
|
|
43
|
+
"3443": {
|
|
44
|
+
"label": "HTTPS Server",
|
|
45
|
+
"protocol": "https",
|
|
46
|
+
"onAutoForward": "notify"
|
|
47
|
+
},
|
|
48
|
+
"3000": {
|
|
49
|
+
"label": "HTTP Server",
|
|
50
|
+
"protocol": "http",
|
|
51
|
+
"onAutoForward": "notify"
|
|
52
|
+
},
|
|
53
|
+
"4200": {
|
|
54
|
+
"label": "React Dev Server",
|
|
55
|
+
"protocol": "http",
|
|
56
|
+
"onAutoForward": "notify"
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
"postCreateCommand": "set -a && [ -f .env ] && . ./.env && set +a && .devcontainer/post-create.sh"
|
|
60
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
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
|
+
# Basic git setup
|
|
9
|
+
git config --global --add safe.directory ${WORKSPACE} 2>/dev/null || true
|
|
10
|
+
|
|
11
|
+
cd ${WORKSPACE} && ./setup-nvm.sh
|
|
12
|
+
cd ${WORKSPACE} && ./ensure-git-globals.sh
|
|
13
|
+
cd ${WORKSPACE} && ./recover-yarn.sh
|
|
14
|
+
|
|
15
|
+
cd ${WORKSPACE} && export COREPACK_ENABLE_DOWNLOAD_PROMPT=0 && yes | corepack enable
|
|
16
|
+
|
|
17
|
+
# Setup Yarn Berry
|
|
18
|
+
echo "Setting up Yarn Berry..."
|
|
19
|
+
cd ${WORKSPACE} && corepack prepare yarn@${DEFAULT_YARN_VERSION} --activate && corepack yarn set version ${DEFAULT_YARN_VERSION} || echo "Yarn Berry setup failed"
|
|
20
|
+
|
|
21
|
+
# Install dependencies
|
|
22
|
+
echo "Installing dependencies..."
|
|
23
|
+
cd ${WORKSPACE} && corepack yarn config set nodeLinker node-modules
|
|
24
|
+
|
|
25
|
+
MAX_ATTEMPTS=5;
|
|
26
|
+
WAIT_TIME=2;
|
|
27
|
+
REGISTRY_URL=http://host.docker.internal:4873/;
|
|
28
|
+
ATTEMPTS=0;
|
|
29
|
+
echo 'Waiting for Verdaccio registry at $REGISTRY_URL (Max 10s total, 4s timeout per attempt)...';
|
|
30
|
+
while [ $ATTEMPTS -lt $MAX_ATTEMPTS ]; do
|
|
31
|
+
# Increased timeouts for cross-host networking stability: 2s connect, 4s total time.
|
|
32
|
+
if curl -sS -o /dev/null --fail --connect-timeout 2 --max-time 4 $REGISTRY_URL; then
|
|
33
|
+
echo 'Verdaccio detected. Configuring NPM and YARN.';
|
|
34
|
+
npm config set registry $REGISTRY_URL --location=project;
|
|
35
|
+
yarn config set npmRegistryServer $REGISTRY_URL;
|
|
36
|
+
VERDACCIO=1;
|
|
37
|
+
break;
|
|
38
|
+
fi;
|
|
39
|
+
sleep $WAIT_TIME;
|
|
40
|
+
ATTEMPTS=$((ATTEMPTS + 1));
|
|
41
|
+
done;
|
|
42
|
+
[ -z "$VERDACCIO" ] && echo 'Verdaccio not detected after 5 attempts. Using default public registry.';
|
|
43
|
+
|
|
44
|
+
cd ${WORKSPACE} && ./npm-install-globals.sh
|
|
45
|
+
cd ${WORKSPACE} && ./do-yarn.sh || echo "Dependency installation failed"
|
|
46
|
+
|
|
47
|
+
# Install mkcert if not already present
|
|
48
|
+
if ! command -v mkcert &> /dev/null; then
|
|
49
|
+
echo "Installing mkcert..."
|
|
50
|
+
sudo apt-get update -y && sudo apt-get install golang -y
|
|
51
|
+
|
|
52
|
+
# Clean up any existing mkcert directory from failed attempts
|
|
53
|
+
[ -d "${WORKSPACE}/mkcert" ] && rm -rf "${WORKSPACE}/mkcert"
|
|
54
|
+
|
|
55
|
+
cd ${WORKSPACE} && \
|
|
56
|
+
git clone https://github.com/FiloSottile/mkcert && \
|
|
57
|
+
cd mkcert && \
|
|
58
|
+
go build -ldflags "-X main.Version=$(git describe --tags)" && \
|
|
59
|
+
sudo cp mkcert /usr/local/bin/ && \
|
|
60
|
+
cd .. && \
|
|
61
|
+
rm -rf mkcert
|
|
62
|
+
|
|
63
|
+
/usr/local/bin/mkcert -install
|
|
64
|
+
else
|
|
65
|
+
echo "mkcert already installed"
|
|
66
|
+
fi
|
|
67
|
+
cd ${WORKSPACE} && /usr/local/bin/mkcert localhost 127.0.0.1 ::1 {{hostname}}
|
|
68
|
+
|
|
69
|
+
echo ""
|
|
70
|
+
cd ${WORKSPACE} && yarn playwright install --with-deps || echo "Playwright installation failed"
|
|
71
|
+
|
|
72
|
+
echo "Post-create setup complete"
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
MONGO_URI=mongodb://admin:{{password}}@db:27017/{{workspaceName}}?authSource=admin&directConnection=true
|
|
2
|
+
JWT_SECRET={{jwtSecret}}
|
|
3
|
+
API_DIST_DIR=/workspaces/{{workspaceName}}/dist/{{prefix}}-api
|
|
4
|
+
REACT_DIST_DIR=/workspaces/{{workspaceName}}/dist/{{prefix}}-react
|
|
5
|
+
DEBUG=true
|
|
6
|
+
DETAILED_DEBUG=true
|
|
7
|
+
MNEMONIC_ENCRYPTION_KEY={{mnemonicEncryptionKey}}
|
|
8
|
+
MNEMONIC_HMAC_SECRET={{mnemonicHmacSecret}}
|
|
9
|
+
MONGO_USE_TRANSACTIONS=false
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BaseApplication,
|
|
3
|
+
DatabaseInitializationService,
|
|
4
|
+
Environment,
|
|
5
|
+
IServerInitResult,
|
|
6
|
+
getSchemaMap,
|
|
7
|
+
} from '@digitaldefiance/node-express-suite';
|
|
8
|
+
|
|
9
|
+
// Simple debugLog implementation
|
|
10
|
+
function debugLog(debug: boolean, type: 'log' | 'warn' | 'error', ...args: any[]): void {
|
|
11
|
+
if (debug) {
|
|
12
|
+
console[type](...args);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
import { Constants as AppConstants } from '{{namespace}}/api-lib';
|
|
16
|
+
import { GlobalActiveContext, IActiveContext } from '@digitaldefiance/i18n-lib';
|
|
17
|
+
import { IECIESConfig } from '@digitaldefiance/ecies-lib';
|
|
18
|
+
import { ECIESService } from '@digitaldefiance/node-ecies-lib';
|
|
19
|
+
import {
|
|
20
|
+
CoreLanguageCode,
|
|
21
|
+
} from '@digitaldefiance/i18n-lib';
|
|
22
|
+
import { getSuiteCoreI18nEngine, getSuiteCoreTranslation, IFailableResult, SuiteCoreStringKey } from '@digitaldefiance/suite-core-lib';
|
|
23
|
+
import { randomBytes } from 'crypto';
|
|
24
|
+
import { join } from 'path';
|
|
25
|
+
|
|
26
|
+
async function main() {
|
|
27
|
+
const context = GlobalActiveContext.getInstance<CoreLanguageCode, IActiveContext<CoreLanguageCode>>();
|
|
28
|
+
context.languageContextSpace = 'admin';
|
|
29
|
+
|
|
30
|
+
const config: IECIESConfig = {
|
|
31
|
+
curveName: AppConstants.ECIES.CURVE_NAME,
|
|
32
|
+
primaryKeyDerivationPath: AppConstants.ECIES.PRIMARY_KEY_DERIVATION_PATH,
|
|
33
|
+
mnemonicStrength: AppConstants.ECIES.MNEMONIC_STRENGTH,
|
|
34
|
+
symmetricAlgorithm: AppConstants.ECIES.SYMMETRIC_ALGORITHM_CONFIGURATION,
|
|
35
|
+
symmetricKeyBits: AppConstants.ECIES.SYMMETRIC.KEY_BITS,
|
|
36
|
+
symmetricKeyMode: AppConstants.ECIES.SYMMETRIC.MODE,
|
|
37
|
+
};
|
|
38
|
+
const eciesService = new ECIESService(config);
|
|
39
|
+
if (process.argv.includes('--gen-system-user-mnemonic')) {
|
|
40
|
+
const mnemonic = eciesService.generateNewMnemonic();
|
|
41
|
+
process.env.ADMIN_MNEMONIC = mnemonic.value;
|
|
42
|
+
console.log(
|
|
43
|
+
`ADMIN_MNEMONIC="${mnemonic.value}"\n`,
|
|
44
|
+
getSuiteCoreTranslation(
|
|
45
|
+
SuiteCoreStringKey.Admin_MakeSureToSetItInEnv,
|
|
46
|
+
),
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
if (process.argv.includes('--gen-member-user-mnemonic')) {
|
|
50
|
+
const mnemonic = eciesService.generateNewMnemonic();
|
|
51
|
+
process.env.MEMBER_MNEMONIC = mnemonic.value;
|
|
52
|
+
console.log(
|
|
53
|
+
`MEMBER_MNEMONIC="${mnemonic.value}"\n`,
|
|
54
|
+
getSuiteCoreTranslation(
|
|
55
|
+
SuiteCoreStringKey.Admin_MakeSureToSetItInEnv,
|
|
56
|
+
),
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
if (process.argv.includes('--gen-mnemonic-hmac-secret')) {
|
|
60
|
+
const mnemonicHmacSecret = randomBytes(32).toString('hex');
|
|
61
|
+
process.env.MNEMONIC_HMAC_SECRET = mnemonicHmacSecret;
|
|
62
|
+
console.log(
|
|
63
|
+
`MNEMONIC_HMAC_SECRET="${mnemonicHmacSecret}"\n`,
|
|
64
|
+
getSuiteCoreTranslation(
|
|
65
|
+
SuiteCoreStringKey.Admin_MakeSureToSetItInEnv,
|
|
66
|
+
),
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
if (process.argv.includes('--gen-mnemonic-encryption-key')) {
|
|
70
|
+
const mnemonicEncryptionKey = randomBytes(32).toString('hex');
|
|
71
|
+
process.env.MNEMONIC_ENCRYPTION_KEY = mnemonicEncryptionKey;
|
|
72
|
+
console.log(
|
|
73
|
+
`MNEMONIC_ENCRYPTION_KEY="${mnemonicEncryptionKey}"\n`,
|
|
74
|
+
getSuiteCoreTranslation(
|
|
75
|
+
SuiteCoreStringKey.Admin_MakeSureToSetItInEnv,
|
|
76
|
+
),
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const envDir = join(
|
|
81
|
+
BaseApplication.distDir,
|
|
82
|
+
'{{prefix}}-inituserdb',
|
|
83
|
+
'.env',
|
|
84
|
+
);
|
|
85
|
+
const env: Environment = new Environment(envDir, true);
|
|
86
|
+
const app = new BaseApplication(env, getSchemaMap, DatabaseInitializationService.initUserDb, DatabaseInitializationService.serverInitResultHash, AppConstants);
|
|
87
|
+
context.languageContextSpace = 'admin';
|
|
88
|
+
const shouldDropDatabase = process.argv.includes('--drop');
|
|
89
|
+
debugLog(
|
|
90
|
+
app.environment.detailedDebug,
|
|
91
|
+
'log',
|
|
92
|
+
getSuiteCoreTranslation(SuiteCoreStringKey.Admin_TransactionsEnabledDisabledTemplate, {
|
|
93
|
+
STATE: getSuiteCoreTranslation(
|
|
94
|
+
app.environment.mongo.useTransactions
|
|
95
|
+
? SuiteCoreStringKey.Common_Enabled
|
|
96
|
+
: SuiteCoreStringKey.Common_Disabled,
|
|
97
|
+
),
|
|
98
|
+
}),
|
|
99
|
+
);
|
|
100
|
+
let exitCode = 1;
|
|
101
|
+
await app.start();
|
|
102
|
+
if (shouldDropDatabase) {
|
|
103
|
+
const result = await DatabaseInitializationService.dropDatabase(
|
|
104
|
+
app.db.connection,
|
|
105
|
+
);
|
|
106
|
+
if (result) {
|
|
107
|
+
debugLog(
|
|
108
|
+
app.environment.detailedDebug,
|
|
109
|
+
'log',
|
|
110
|
+
getSuiteCoreTranslation(SuiteCoreStringKey.Admin_DatabaseDropped),
|
|
111
|
+
);
|
|
112
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
113
|
+
debugLog(
|
|
114
|
+
app.environment.detailedDebug,
|
|
115
|
+
'log',
|
|
116
|
+
getSuiteCoreTranslation(SuiteCoreStringKey.Admin_ProceedingToDbInitialization),
|
|
117
|
+
);
|
|
118
|
+
} else {
|
|
119
|
+
debugLog(
|
|
120
|
+
app.environment.detailedDebug,
|
|
121
|
+
'error',
|
|
122
|
+
getSuiteCoreTranslation(SuiteCoreStringKey.Admin_Error_FailedToDropDatabase),
|
|
123
|
+
);
|
|
124
|
+
await app.stop();
|
|
125
|
+
process.exit(2);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
debugLog(
|
|
129
|
+
app.environment.detailedDebug,
|
|
130
|
+
'log',
|
|
131
|
+
getSuiteCoreTranslation(SuiteCoreStringKey.Admin_StartingDbInitialization),
|
|
132
|
+
);
|
|
133
|
+
const result: IFailableResult<IServerInitResult> =
|
|
134
|
+
await DatabaseInitializationService.initUserDb(app);
|
|
135
|
+
if (result.success && result.data) {
|
|
136
|
+
debugLog(
|
|
137
|
+
app.environment.debug,
|
|
138
|
+
'log',
|
|
139
|
+
getSuiteCoreTranslation(
|
|
140
|
+
SuiteCoreStringKey.Admin_UserDatabaseInitialized,
|
|
141
|
+
),
|
|
142
|
+
);
|
|
143
|
+
if (app.environment.detailedDebug) {
|
|
144
|
+
DatabaseInitializationService.printServerInitResults(result.data);
|
|
145
|
+
// DatabaseInitializationService.setEnvFromInitResults(result.data);
|
|
146
|
+
// app.reloadEnvironment(envDir, true);
|
|
147
|
+
const initHash = DatabaseInitializationService.serverInitResultHash(
|
|
148
|
+
result.data,
|
|
149
|
+
);
|
|
150
|
+
debugLog(
|
|
151
|
+
true,
|
|
152
|
+
'log',
|
|
153
|
+
`Database initialized with options hash: ${initHash}`,
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
exitCode = 0;
|
|
157
|
+
} else {
|
|
158
|
+
const engine = getSuiteCoreI18nEngine();
|
|
159
|
+
console.error(
|
|
160
|
+
engine.t(
|
|
161
|
+
'{{SuiteCoreStringKey.Admin_Error_FailedToInitializeUserDatabase}}:',
|
|
162
|
+
),
|
|
163
|
+
result.error,
|
|
164
|
+
);
|
|
165
|
+
exitCode++;
|
|
166
|
+
}
|
|
167
|
+
await app.stop();
|
|
168
|
+
process.exit(exitCode);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
main().catch((err) => {
|
|
172
|
+
const engine = getSuiteCoreI18nEngine();
|
|
173
|
+
console.error(
|
|
174
|
+
engine.t('{{SuiteCoreStringKey.Admin_Error_UnhandledErrorInMain}}:'),
|
|
175
|
+
err,
|
|
176
|
+
);
|
|
177
|
+
process.exit(1);
|
|
178
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { IConstants } from './interfaces/constants';
|
|
2
|
+
import { Constants } from '@digitaldefiance/suite-core-lib';
|
|
3
|
+
|
|
4
|
+
export const AppConstants: IConstants = {
|
|
5
|
+
...Constants,
|
|
6
|
+
Site: '{{siteTitle}}' as const,
|
|
7
|
+
SiteTagline: '{{siteTagline}}' as const,
|
|
8
|
+
SiteDescription: '{{siteDescription}}' as const,
|
|
9
|
+
SiteHostname: '{{hostname}}' as const,
|
|
10
|
+
PasswordRegex: /^(?=.*[A-Za-z])(?=.*\d)(?=.*[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?])[A-Za-z\d!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]{8,}$/,
|
|
11
|
+
UsernameMinLength: 3 as const,
|
|
12
|
+
UsernameMaxLength: 30 as const,
|
|
13
|
+
UsernameRegex: /^[A-Za-z0-9]{3,30}$/,
|
|
14
|
+
PasswordMinLength: 8 as const,
|
|
15
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { IECIESConfig, ECIES } from '@digitaldefiance/ecies-lib';
|
|
2
|
+
|
|
3
|
+
export const EciesConfig: IECIESConfig = {
|
|
4
|
+
curveName: ECIES.CURVE_NAME,
|
|
5
|
+
primaryKeyDerivationPath: ECIES.PRIMARY_KEY_DERIVATION_PATH,
|
|
6
|
+
mnemonicStrength: ECIES.MNEMONIC_STRENGTH,
|
|
7
|
+
symmetricAlgorithm: ECIES.SYMMETRIC_ALGORITHM_CONFIGURATION,
|
|
8
|
+
symmetricKeyBits: ECIES.SYMMETRIC.KEY_BITS,
|
|
9
|
+
symmetricKeyMode: ECIES.SYMMETRIC.MODE,
|
|
10
|
+
};
|