underpost 2.8.876 → 2.8.878
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/.github/workflows/release.cd.yml +1 -2
- package/README.md +10 -2
- package/cli.md +4 -1
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/deployment/dd-test-development/deployment.yaml +6 -6
- package/package.json +1 -1
- package/src/api/file/file.controller.js +15 -1
- package/src/api/user/user.router.js +4 -3
- package/src/cli/deploy.js +2 -1
- package/src/cli/index.js +3 -0
- package/src/cli/repository.js +12 -4
- package/src/cli/run.js +26 -9
- package/src/client/Default.index.js +1 -5
- package/src/client/components/core/Auth.js +0 -1
- package/src/client/components/core/Content.js +11 -10
- package/src/client/services/core/core.service.js +4 -20
- package/src/client/services/default/default.service.js +4 -0
- package/src/client/services/test/test.service.js +3 -0
- package/src/client/services/user/user.service.js +4 -0
- package/src/index.js +1 -1
- package/src/server/auth.js +5 -4
- package/src/server/conf.js +37 -2
- package/src/server/runtime.js +80 -74
|
@@ -30,9 +30,8 @@ jobs:
|
|
|
30
30
|
echo "Starting remote release deploy"
|
|
31
31
|
cd /home/dd/engine
|
|
32
32
|
npm install -g underpost
|
|
33
|
-
underpost
|
|
33
|
+
underpost run secret
|
|
34
34
|
node bin run --dev pull
|
|
35
35
|
underpost run secret
|
|
36
36
|
underpost run underpost-config
|
|
37
|
-
node bin run --dev pull
|
|
38
37
|
underpost run ssh-deploy engine-test
|
package/README.md
CHANGED
|
@@ -51,6 +51,10 @@
|
|
|
51
51
|
|
|
52
52
|
|
|
53
53
|
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
|
|
54
58
|
|
|
55
59
|
|
|
56
60
|
|
|
@@ -59,7 +63,7 @@
|
|
|
59
63
|
<!-- badges -->
|
|
60
64
|
|
|
61
65
|
|
|
62
|
-
[](https://github.com/underpostnet/engine/actions/workflows/docker-image.yml) [](https://github.com/underpostnet/engine/actions/workflows/coverall.yml) [](https://www.npmjs.com/package/underpost) [](https://github.com/underpostnet/engine/actions/workflows/docker-image.yml) [](https://github.com/underpostnet/engine/actions/workflows/coverall.yml) [](https://www.npmjs.com/package/underpost) [](https://socket.dev/npm/package/underpost/overview/2.8.878) [](https://coveralls.io/github/underpostnet/engine?branch=master) [](https://www.npmjs.org/package/underpost) [](https://www.npmjs.com/package/underpost)
|
|
63
67
|
|
|
64
68
|
|
|
65
69
|
<!-- end-badges -->
|
|
@@ -99,6 +103,10 @@
|
|
|
99
103
|
|
|
100
104
|
|
|
101
105
|
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
|
|
102
110
|
|
|
103
111
|
|
|
104
112
|
|
|
@@ -148,7 +156,7 @@ Run dev client server
|
|
|
148
156
|
npm run dev
|
|
149
157
|
```
|
|
150
158
|
<!-- -->
|
|
151
|
-
## underpost ci/cd cli v2.8.
|
|
159
|
+
## underpost ci/cd cli v2.8.878
|
|
152
160
|
|
|
153
161
|
### Usage: `underpost [options] [command]`
|
|
154
162
|
```
|
package/cli.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
## underpost ci/cd cli v2.8.
|
|
1
|
+
## underpost ci/cd cli v2.8.878
|
|
2
2
|
|
|
3
3
|
### Usage: `underpost [options] [command]`
|
|
4
4
|
```
|
|
@@ -51,6 +51,7 @@ Arguments:
|
|
|
51
51
|
|
|
52
52
|
Options:
|
|
53
53
|
--deploy-id Crete deploy ID conf env files
|
|
54
|
+
--cluster Create deploy ID cluster files and sync to current cluster
|
|
54
55
|
--dev Sets the development cli context
|
|
55
56
|
-h, --help display help for command
|
|
56
57
|
|
|
@@ -609,6 +610,8 @@ Options:
|
|
|
609
610
|
--command <command-array> Array of commands to run.
|
|
610
611
|
--args <args-array> Array of arguments to pass to the command.
|
|
611
612
|
--dev Sets the development context environment for the script.
|
|
613
|
+
--build Set builder context runner
|
|
614
|
+
--replicas <replicas> Sets a custom number of replicas for deployment.
|
|
612
615
|
--pod-name <pod-name> Optional: Specifies the pod name for test execution.
|
|
613
616
|
--volume-host-path <volume-host-path> Optional: Specifies the volume host path for test execution.
|
|
614
617
|
--volume-mount-path <volume-mount-path> Optional: Specifies the volume mount path for test execution.
|
|
@@ -17,7 +17,7 @@ spec:
|
|
|
17
17
|
spec:
|
|
18
18
|
containers:
|
|
19
19
|
- name: dd-default-development-blue
|
|
20
|
-
image: localhost/rockylinux9-underpost:v2.8.
|
|
20
|
+
image: localhost/rockylinux9-underpost:v2.8.878
|
|
21
21
|
# resources:
|
|
22
22
|
# requests:
|
|
23
23
|
# memory: "124Ki"
|
|
@@ -100,7 +100,7 @@ spec:
|
|
|
100
100
|
spec:
|
|
101
101
|
containers:
|
|
102
102
|
- name: dd-default-development-green
|
|
103
|
-
image: localhost/rockylinux9-underpost:v2.8.
|
|
103
|
+
image: localhost/rockylinux9-underpost:v2.8.878
|
|
104
104
|
# resources:
|
|
105
105
|
# requests:
|
|
106
106
|
# memory: "124Ki"
|
|
@@ -17,13 +17,13 @@ spec:
|
|
|
17
17
|
spec:
|
|
18
18
|
containers:
|
|
19
19
|
- name: dd-test-development-blue
|
|
20
|
-
image: localhost/rockylinux9-underpost:v2.8.
|
|
20
|
+
image: localhost/rockylinux9-underpost:v2.8.878
|
|
21
21
|
# resources:
|
|
22
22
|
# requests:
|
|
23
|
-
# memory: "
|
|
23
|
+
# memory: "94Ki"
|
|
24
24
|
# cpu: "75m"
|
|
25
25
|
# limits:
|
|
26
|
-
# memory: "
|
|
26
|
+
# memory: "1504Ki"
|
|
27
27
|
# cpu: "1200m"
|
|
28
28
|
command:
|
|
29
29
|
- /bin/sh
|
|
@@ -104,13 +104,13 @@ spec:
|
|
|
104
104
|
spec:
|
|
105
105
|
containers:
|
|
106
106
|
- name: dd-test-development-green
|
|
107
|
-
image: localhost/rockylinux9-underpost:v2.8.
|
|
107
|
+
image: localhost/rockylinux9-underpost:v2.8.878
|
|
108
108
|
# resources:
|
|
109
109
|
# requests:
|
|
110
|
-
# memory: "
|
|
110
|
+
# memory: "94Ki"
|
|
111
111
|
# cpu: "75m"
|
|
112
112
|
# limits:
|
|
113
|
-
# memory: "
|
|
113
|
+
# memory: "1504Ki"
|
|
114
114
|
# cpu: "1200m"
|
|
115
115
|
command:
|
|
116
116
|
- /bin/sh
|
package/package.json
CHANGED
|
@@ -20,7 +20,21 @@ const FileController = {
|
|
|
20
20
|
get: async (req, res, options) => {
|
|
21
21
|
try {
|
|
22
22
|
const result = await FileService.get(req, res, options);
|
|
23
|
-
if (result instanceof Buffer)
|
|
23
|
+
if (result instanceof Buffer) {
|
|
24
|
+
if (
|
|
25
|
+
process.env.NODE_ENV === 'development' ||
|
|
26
|
+
req.hostname === options.host ||
|
|
27
|
+
(options.origins && options.origins.find((o) => o.match(req.hostname)))
|
|
28
|
+
) {
|
|
29
|
+
res.set('Cross-Origin-Resource-Policy', 'cross-origin');
|
|
30
|
+
return res.status(200).end(result);
|
|
31
|
+
}
|
|
32
|
+
return res.status(403).json({
|
|
33
|
+
status: 'error',
|
|
34
|
+
message: 'Forbidden',
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
24
38
|
return res.status(200).json({
|
|
25
39
|
status: 'success',
|
|
26
40
|
data: result,
|
|
@@ -48,9 +48,10 @@ const UserRouter = (options) => {
|
|
|
48
48
|
check: fs.readFileSync(`./src/client/public/default/assets/mailer/api-user-check.png`),
|
|
49
49
|
},
|
|
50
50
|
header: (res) => {
|
|
51
|
-
res.
|
|
52
|
-
res.
|
|
53
|
-
res.
|
|
51
|
+
res.set('Cross-Origin-Resource-Policy', 'cross-origin');
|
|
52
|
+
res.set('Access-Control-Allow-Origin', '*');
|
|
53
|
+
res.set('Access-Control-Allow-Headers', '*');
|
|
54
|
+
res.set('Content-Type', 'image/png');
|
|
54
55
|
},
|
|
55
56
|
};
|
|
56
57
|
|
package/src/cli/deploy.js
CHANGED
|
@@ -384,7 +384,8 @@ EOF`);
|
|
|
384
384
|
if (!options.remove === true) {
|
|
385
385
|
if (!options.disableUpdateDeployment) shellExec(`sudo kubectl apply -f ./${manifestsPath}/deployment.yaml`);
|
|
386
386
|
shellExec(`sudo kubectl apply -f ./${manifestsPath}/proxy.yaml`);
|
|
387
|
-
|
|
387
|
+
|
|
388
|
+
if (UnderpostDeploy.API.isValidTLSContext({ host: Object.keys(confServer)[0], env, options }))
|
|
388
389
|
shellExec(`sudo kubectl apply -f ./${manifestsPath}/secret.yaml`);
|
|
389
390
|
}
|
|
390
391
|
}
|
package/src/cli/index.js
CHANGED
|
@@ -24,6 +24,7 @@ program
|
|
|
24
24
|
.command('new')
|
|
25
25
|
.argument('<app-name>', 'The name or deploy-id of the application to create.')
|
|
26
26
|
.option('--deploy-id', 'Crete deploy ID conf env files')
|
|
27
|
+
.option('--cluster', 'Create deploy ID cluster files and sync to current cluster')
|
|
27
28
|
.option('--dev', 'Sets the development cli context')
|
|
28
29
|
.description('Initializes a new Underpost project with a predefined structure.')
|
|
29
30
|
.action(Underpost.repo.new);
|
|
@@ -350,6 +351,8 @@ program
|
|
|
350
351
|
.option('--command <command-array>', 'Array of commands to run.')
|
|
351
352
|
.option('--args <args-array>', 'Array of arguments to pass to the command.')
|
|
352
353
|
.option('--dev', 'Sets the development context environment for the script.')
|
|
354
|
+
.option('--build', 'Set builder context runner')
|
|
355
|
+
.option('--replicas <replicas>', 'Sets a custom number of replicas for deployment.')
|
|
353
356
|
.option('--pod-name <pod-name>', 'Optional: Specifies the pod name for test execution.')
|
|
354
357
|
.option('--volume-host-path <volume-host-path>', 'Optional: Specifies the volume host path for test execution.')
|
|
355
358
|
.option('--volume-mount-path <volume-mount-path>', 'Optional: Specifies the volume mount path for test execution.')
|
package/src/cli/repository.js
CHANGED
|
@@ -90,7 +90,7 @@ class UnderpostRepository {
|
|
|
90
90
|
);
|
|
91
91
|
},
|
|
92
92
|
|
|
93
|
-
new(repositoryName, options = { dev: false, deployId: false }) {
|
|
93
|
+
new(repositoryName, options = { dev: false, deployId: false, cluster: false }) {
|
|
94
94
|
return new Promise(async (resolve, reject) => {
|
|
95
95
|
try {
|
|
96
96
|
await logger.setUpInfo();
|
|
@@ -99,7 +99,7 @@ class UnderpostRepository {
|
|
|
99
99
|
return resolve(
|
|
100
100
|
await UnderpostStartUp.API.listenPortController(UnderpostStartUp.API.listenServerFactory(), ':'),
|
|
101
101
|
);
|
|
102
|
-
if (options.deployId === true) return Config.deployIdFactory(repositoryName);
|
|
102
|
+
if (options.deployId === true) return Config.deployIdFactory(repositoryName, options);
|
|
103
103
|
const npmRoot = getNpmRootPath();
|
|
104
104
|
const underpostRoot = options?.dev === true ? '.' : `${npmRoot}/underpost`;
|
|
105
105
|
const destFolder = `./${repositoryName}`;
|
|
@@ -160,10 +160,18 @@ class UnderpostRepository {
|
|
|
160
160
|
`Version mismatch: deploy-version:${packageJsonDeploy.version} !== engine-version:${packageJsonEngine.version},
|
|
161
161
|
Prevent build private config repo.`,
|
|
162
162
|
);
|
|
163
|
-
return {
|
|
163
|
+
return {
|
|
164
|
+
validVersion: false,
|
|
165
|
+
engineVersion: packageJsonEngine.version,
|
|
166
|
+
deployVersion: packageJsonDeploy.version,
|
|
167
|
+
};
|
|
164
168
|
}
|
|
165
169
|
shellExec(`node bin/build ${deployId} conf`);
|
|
166
|
-
return {
|
|
170
|
+
return {
|
|
171
|
+
validVersion: true,
|
|
172
|
+
engineVersion: packageJsonEngine.version,
|
|
173
|
+
deployVersion: packageJsonDeploy.version,
|
|
174
|
+
};
|
|
167
175
|
},
|
|
168
176
|
};
|
|
169
177
|
}
|
package/src/cli/run.js
CHANGED
|
@@ -8,6 +8,7 @@ import { range, setPad, timer } from '../client/components/core/CommonJs.js';
|
|
|
8
8
|
import UnderpostDeploy from './deploy.js';
|
|
9
9
|
import UnderpostRootEnv from './env.js';
|
|
10
10
|
import UnderpostRepository from './repository.js';
|
|
11
|
+
import os from 'os';
|
|
11
12
|
|
|
12
13
|
const logger = loggerFactory(import.meta);
|
|
13
14
|
|
|
@@ -20,6 +21,8 @@ class UnderpostRun {
|
|
|
20
21
|
imageName: '',
|
|
21
22
|
containerName: '',
|
|
22
23
|
namespace: '',
|
|
24
|
+
build: false,
|
|
25
|
+
replicas: 1,
|
|
23
26
|
};
|
|
24
27
|
static RUNNERS = {
|
|
25
28
|
'spark-template': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
@@ -104,6 +107,8 @@ class UnderpostRun {
|
|
|
104
107
|
},
|
|
105
108
|
'template-deploy': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
106
109
|
const baseCommand = options.dev || true ? 'node bin' : 'underpost';
|
|
110
|
+
shellExec(`${baseCommand} run clean`);
|
|
111
|
+
shellExec(`${baseCommand} push ./engine-private ${process.env.GITHUB_USERNAME}/engine-private`);
|
|
107
112
|
shellCd('/home/dd/engine');
|
|
108
113
|
shellExec(`git reset`);
|
|
109
114
|
shellExec(`${baseCommand} cmt . --empty ci package-pwa-microservices-template`);
|
|
@@ -154,17 +159,21 @@ class UnderpostRun {
|
|
|
154
159
|
const env = options.dev ? 'development' : 'production';
|
|
155
160
|
const baseCommand = options.dev || true ? 'node bin' : 'underpost';
|
|
156
161
|
shellExec(`${baseCommand} run clean`);
|
|
157
|
-
const
|
|
158
|
-
let [deployId, replicas, image, node] = path ? path.split(',') :
|
|
159
|
-
deployId = deployId ??
|
|
160
|
-
replicas = replicas ??
|
|
161
|
-
|
|
162
|
-
|
|
162
|
+
const defaultPath = ['dd-default', 1, ``, ``, 'kind-control-plane'];
|
|
163
|
+
let [deployId, replicas, versions, image, node] = path ? path.split(',') : defaultPath;
|
|
164
|
+
deployId = deployId ?? defaultPath[0];
|
|
165
|
+
replicas = replicas ?? defaultPath[1];
|
|
166
|
+
versions = versions ?? defaultPath[2];
|
|
167
|
+
image = image ?? defaultPath[3];
|
|
168
|
+
node = node ?? defaultPath[4];
|
|
163
169
|
shellExec(
|
|
164
170
|
`${baseCommand} deploy --kubeadm --build-manifest --sync --info-router --replicas ${
|
|
165
171
|
replicas ?? 1
|
|
166
|
-
} --node ${node}${image ? ` --image ${image}` : ''}
|
|
172
|
+
} --node ${node}${image ? ` --image ${image}` : ''}${
|
|
173
|
+
versions ? ` --versions ${versions.replaceAll('+', ',')}` : ''
|
|
174
|
+
} dd ${env}`,
|
|
167
175
|
);
|
|
176
|
+
if (!options.build) shellExec(`${baseCommand} deploy --kubeadm ${deployId} ${env}`);
|
|
168
177
|
},
|
|
169
178
|
'ls-deployments': async (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
170
179
|
console.table(await UnderpostDeploy.API.get(path, 'deployments'));
|
|
@@ -303,13 +312,21 @@ class UnderpostRun {
|
|
|
303
312
|
},
|
|
304
313
|
deploy: async (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
305
314
|
const deployId = path;
|
|
306
|
-
const { validVersion } = UnderpostRepository.API.privateConfUpdate(deployId);
|
|
315
|
+
const { validVersion, deployVersion } = UnderpostRepository.API.privateConfUpdate(deployId);
|
|
307
316
|
if (!validVersion) throw new Error('Version mismatch');
|
|
308
317
|
const currentTraffic = UnderpostDeploy.API.getCurrentTraffic(deployId);
|
|
309
318
|
const targetTraffic = currentTraffic === 'blue' ? 'green' : 'blue';
|
|
310
319
|
const env = 'production';
|
|
311
320
|
const ignorePods = UnderpostDeploy.API.get(`${deployId}-${env}-${targetTraffic}`).map((p) => p.NAME);
|
|
312
|
-
|
|
321
|
+
|
|
322
|
+
if (options.build === true) {
|
|
323
|
+
// deployId, replicas, versions, image, node
|
|
324
|
+
shellExec(
|
|
325
|
+
`node bin run sync ${deployId},${options.replicas ?? 1},${targetTraffic},${
|
|
326
|
+
options.imageName ?? `localhost/rockylinux9-underpost:${deployVersion}`
|
|
327
|
+
},${os.hostname()}`,
|
|
328
|
+
);
|
|
329
|
+
} else shellExec(`sudo kubectl rollout restart deployment/${deployId}-${env}-${targetTraffic}`);
|
|
313
330
|
|
|
314
331
|
let checkStatusIteration = 0;
|
|
315
332
|
const checkStatusIterationMsDelay = 1000;
|
|
@@ -17,10 +17,6 @@ import { SocketIoDefault } from './components/default/SocketIoDefault.js';
|
|
|
17
17
|
import { ElementsDefault } from './components/default/ElementsDefault.js';
|
|
18
18
|
import { CssDefaultDark, CssDefaultLight } from './components/default/CssDefault.js';
|
|
19
19
|
|
|
20
|
-
const htmlMainBody = async () => {
|
|
21
|
-
return html`<span>Hello World!!</span>`;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
20
|
window.onload = () =>
|
|
25
21
|
Worker.instance({
|
|
26
22
|
router: RouterDefault,
|
|
@@ -29,7 +25,7 @@ window.onload = () =>
|
|
|
29
25
|
await TranslateCore.Init();
|
|
30
26
|
await TranslateDefault.Init();
|
|
31
27
|
await Responsive.Init();
|
|
32
|
-
await MenuDefault.Render(
|
|
28
|
+
await MenuDefault.Render();
|
|
33
29
|
await SocketIo.Init({
|
|
34
30
|
channels: ElementsDefault.Data,
|
|
35
31
|
path: `/`,
|
|
@@ -4,7 +4,6 @@ import { loggerFactory } from './Logger.js';
|
|
|
4
4
|
import { LogIn } from './LogIn.js';
|
|
5
5
|
import { LogOut } from './LogOut.js';
|
|
6
6
|
import { NotificationManager } from './NotificationManager.js';
|
|
7
|
-
import { SignUp } from './SignUp.js';
|
|
8
7
|
import { Translate } from './Translate.js';
|
|
9
8
|
import { s } from './VanillaJs.js';
|
|
10
9
|
|
|
@@ -137,11 +137,7 @@ const Content = {
|
|
|
137
137
|
case 'svg':
|
|
138
138
|
case 'gif':
|
|
139
139
|
case 'png': {
|
|
140
|
-
const url = options
|
|
141
|
-
? options.url
|
|
142
|
-
: file._id
|
|
143
|
-
? getApiBaseUrl({ id: file._id, endpoint: 'file/blob' })
|
|
144
|
-
: URL.createObjectURL(getBlobFromUint8ArrayFile(file.data.data, file.mimetype));
|
|
140
|
+
const url = Content.urlFactory(options);
|
|
145
141
|
const imgRender = html`<img
|
|
146
142
|
class="in ${options.class}"
|
|
147
143
|
${styleFactory(options.style, `${renderChessPattern(50)}`)}
|
|
@@ -151,11 +147,7 @@ const Content = {
|
|
|
151
147
|
break;
|
|
152
148
|
}
|
|
153
149
|
case 'pdf': {
|
|
154
|
-
const url = options
|
|
155
|
-
? options.url
|
|
156
|
-
: file._id
|
|
157
|
-
? getApiBaseUrl({ id: file._id, endpoint: 'file/blob' })
|
|
158
|
-
: URL.createObjectURL(getBlobFromUint8ArrayFile(file.data.data, file.mimetype));
|
|
150
|
+
const url = Content.urlFactory(options);
|
|
159
151
|
render += html`<iframe
|
|
160
152
|
class="in ${options.class} iframe-${options.idModal}"
|
|
161
153
|
${styleFactory(options.style)}
|
|
@@ -189,6 +181,15 @@ const Content = {
|
|
|
189
181
|
if (options.raw) return render;
|
|
190
182
|
append(container, render);
|
|
191
183
|
},
|
|
184
|
+
urlFactory: function (options) {
|
|
185
|
+
return options.url
|
|
186
|
+
? options.url
|
|
187
|
+
: options.file?.data?.data
|
|
188
|
+
? URL.createObjectURL(getBlobFromUint8ArrayFile(options.file.data.data, options.file.mimetype))
|
|
189
|
+
: options.file._id
|
|
190
|
+
? getApiBaseUrl({ id: options.file._id, endpoint: 'file/blob' })
|
|
191
|
+
: null;
|
|
192
|
+
},
|
|
192
193
|
};
|
|
193
194
|
|
|
194
195
|
export { Content };
|
|
@@ -35,8 +35,6 @@ const getWsBaseUrl = (options = { id: '', endpoint: '', wsBasePath: '' }) =>
|
|
|
35
35
|
const headersFactory = (headerId = '') => {
|
|
36
36
|
const headers = {
|
|
37
37
|
Authorization: Auth.getJWT(),
|
|
38
|
-
withCredentials: true,
|
|
39
|
-
credentials: 'include', // no cors: 'same-origin'
|
|
40
38
|
};
|
|
41
39
|
switch (headerId) {
|
|
42
40
|
case 'file':
|
|
@@ -71,29 +69,12 @@ const CoreService = {
|
|
|
71
69
|
return reject(error);
|
|
72
70
|
}),
|
|
73
71
|
),
|
|
74
|
-
getRandomImage: (options = { category: ['city'], mimetype: 'image/jpg' }) => {
|
|
75
|
-
const src = `https://api.api-ninjas.com/v1/randomimage?category=${options.category[0]}`;
|
|
76
|
-
return new Promise((resolve) => {
|
|
77
|
-
fetch(src, {
|
|
78
|
-
headers: { 'X-Api-Key': 'FyITmcxRXkCaUehbX6K0/g==uxZcFKL0dZUUg48G', Accept: options.mimetype },
|
|
79
|
-
})
|
|
80
|
-
.then((res) => res.blob())
|
|
81
|
-
.then(async (blob) => {
|
|
82
|
-
return resolve({
|
|
83
|
-
file: {
|
|
84
|
-
mimetype: 'image/jpg',
|
|
85
|
-
name: 'image.jpg',
|
|
86
|
-
},
|
|
87
|
-
url: URL.createObjectURL(blob),
|
|
88
|
-
});
|
|
89
|
-
});
|
|
90
|
-
});
|
|
91
|
-
},
|
|
92
72
|
post: (options = { id: '', body: {} }) =>
|
|
93
73
|
new Promise((resolve, reject) =>
|
|
94
74
|
fetch(getApiBaseUrl({ id: options.id, endpoint }), {
|
|
95
75
|
method: 'POST',
|
|
96
76
|
headers: headersFactory(),
|
|
77
|
+
credentials: 'include',
|
|
97
78
|
body: payloadFactory(options.body),
|
|
98
79
|
})
|
|
99
80
|
.then(async (res) => {
|
|
@@ -113,6 +94,7 @@ const CoreService = {
|
|
|
113
94
|
fetch(getApiBaseUrl({ id: options.id, endpoint }), {
|
|
114
95
|
method: 'PUT',
|
|
115
96
|
headers: headersFactory(),
|
|
97
|
+
credentials: 'include',
|
|
116
98
|
body: payloadFactory(options.body),
|
|
117
99
|
})
|
|
118
100
|
.then(async (res) => {
|
|
@@ -132,6 +114,7 @@ const CoreService = {
|
|
|
132
114
|
fetch(getApiBaseUrl({ id: options.id, endpoint }), {
|
|
133
115
|
method: 'GET',
|
|
134
116
|
headers: headersFactory(),
|
|
117
|
+
credentials: 'include',
|
|
135
118
|
})
|
|
136
119
|
.then(async (res) => {
|
|
137
120
|
return await res.json();
|
|
@@ -150,6 +133,7 @@ const CoreService = {
|
|
|
150
133
|
fetch(getApiBaseUrl({ id: options.id, endpoint }), {
|
|
151
134
|
method: 'DELETE',
|
|
152
135
|
headers: headersFactory(),
|
|
136
|
+
credentials: 'include',
|
|
153
137
|
body: payloadFactory(options.body),
|
|
154
138
|
})
|
|
155
139
|
.then(async (res) => {
|
|
@@ -14,6 +14,7 @@ const DefaultService = {
|
|
|
14
14
|
fetch(getApiBaseUrl({ id: options.id, endpoint }), {
|
|
15
15
|
method: 'POST',
|
|
16
16
|
headers: headersFactory(),
|
|
17
|
+
credentials: 'include',
|
|
17
18
|
body: payloadFactory(options.body),
|
|
18
19
|
})
|
|
19
20
|
.then(async (res) => {
|
|
@@ -33,6 +34,7 @@ const DefaultService = {
|
|
|
33
34
|
fetch(getApiBaseUrl({ id: options.id, endpoint }), {
|
|
34
35
|
method: 'PUT',
|
|
35
36
|
headers: headersFactory(),
|
|
37
|
+
credentials: 'include',
|
|
36
38
|
body: payloadFactory(options.body),
|
|
37
39
|
})
|
|
38
40
|
.then(async (res) => {
|
|
@@ -56,6 +58,7 @@ const DefaultService = {
|
|
|
56
58
|
fetch(url.toString(), {
|
|
57
59
|
method: 'GET',
|
|
58
60
|
headers: headersFactory(),
|
|
61
|
+
credentials: 'include',
|
|
59
62
|
})
|
|
60
63
|
.then(async (res) => {
|
|
61
64
|
return await res.json();
|
|
@@ -75,6 +78,7 @@ const DefaultService = {
|
|
|
75
78
|
fetch(getApiBaseUrl({ id: options.id, endpoint }), {
|
|
76
79
|
method: 'DELETE',
|
|
77
80
|
headers: headersFactory(),
|
|
81
|
+
credentials: 'include',
|
|
78
82
|
body: payloadFactory(options.body),
|
|
79
83
|
})
|
|
80
84
|
.then(async (res) => {
|
|
@@ -14,6 +14,7 @@ const TestService = {
|
|
|
14
14
|
fetch(getApiBaseUrl({ id: options.id, endpoint }), {
|
|
15
15
|
method: 'POST',
|
|
16
16
|
headers: headersFactory(),
|
|
17
|
+
credentials: 'include',
|
|
17
18
|
body: payloadFactory(options.body),
|
|
18
19
|
})
|
|
19
20
|
.then(async (res) => {
|
|
@@ -33,6 +34,7 @@ const TestService = {
|
|
|
33
34
|
fetch(getApiBaseUrl({ id: options.id, endpoint }), {
|
|
34
35
|
method: 'GET',
|
|
35
36
|
headers: headersFactory(),
|
|
37
|
+
credentials: 'include',
|
|
36
38
|
})
|
|
37
39
|
.then(async (res) => {
|
|
38
40
|
return await res.json();
|
|
@@ -51,6 +53,7 @@ const TestService = {
|
|
|
51
53
|
fetch(getApiBaseUrl({ id: options.id, endpoint }), {
|
|
52
54
|
method: 'DELETE',
|
|
53
55
|
headers: headersFactory(),
|
|
56
|
+
credentials: 'include',
|
|
54
57
|
body: payloadFactory(options.body),
|
|
55
58
|
})
|
|
56
59
|
.then(async (res) => {
|
|
@@ -22,6 +22,7 @@ const UserService = {
|
|
|
22
22
|
fetch(getApiBaseUrl({ id: options.id, endpoint }), {
|
|
23
23
|
method: 'POST',
|
|
24
24
|
headers: headersFactory(),
|
|
25
|
+
credentials: 'include',
|
|
25
26
|
body: payloadFactory(options.body),
|
|
26
27
|
})
|
|
27
28
|
.then(async (res) => {
|
|
@@ -47,6 +48,7 @@ const UserService = {
|
|
|
47
48
|
fetch(url, {
|
|
48
49
|
method: 'GET',
|
|
49
50
|
headers: headersFactory(),
|
|
51
|
+
credentials: 'include',
|
|
50
52
|
})
|
|
51
53
|
.then(async (res) => {
|
|
52
54
|
return await res.json();
|
|
@@ -66,6 +68,7 @@ const UserService = {
|
|
|
66
68
|
fetch(getApiBaseUrl({ id: options.id, endpoint }), {
|
|
67
69
|
method: 'DELETE',
|
|
68
70
|
headers: headersFactory(),
|
|
71
|
+
credentials: 'include',
|
|
69
72
|
body: payloadFactory(options.body),
|
|
70
73
|
})
|
|
71
74
|
.then(async (res) => {
|
|
@@ -85,6 +88,7 @@ const UserService = {
|
|
|
85
88
|
fetch(getApiBaseUrl({ id: options.id, endpoint }), {
|
|
86
89
|
method: 'PUT',
|
|
87
90
|
headers: headersFactory(options.headerId),
|
|
91
|
+
credentials: 'include',
|
|
88
92
|
body: payloadFactory(options.body),
|
|
89
93
|
})
|
|
90
94
|
.then(async (res) => {
|
package/src/index.js
CHANGED
package/src/server/auth.js
CHANGED
|
@@ -523,6 +523,7 @@ function applySecurity(app, opts = {}) {
|
|
|
523
523
|
|
|
524
524
|
// Content-Security-Policy: include nonce from res.locals
|
|
525
525
|
// Note: We avoid 'unsafe-inline' on script/style. Use nonces or hashes.
|
|
526
|
+
const httpDirective = process.env.NODE_ENV === 'production' ? 'https:' : 'http:';
|
|
526
527
|
app.use(
|
|
527
528
|
helmet.contentSecurityPolicy({
|
|
528
529
|
useDefaults: true,
|
|
@@ -530,16 +531,16 @@ function applySecurity(app, opts = {}) {
|
|
|
530
531
|
defaultSrc: ["'self'"],
|
|
531
532
|
baseUri: ["'self'"],
|
|
532
533
|
blockAllMixedContent: [],
|
|
533
|
-
fontSrc: ["'self'",
|
|
534
|
+
fontSrc: ["'self'", httpDirective, 'data:'],
|
|
534
535
|
frameAncestors: frameAncestors,
|
|
535
|
-
imgSrc: ["'self'", 'data:',
|
|
536
|
+
imgSrc: ["'self'", 'data:', httpDirective],
|
|
536
537
|
objectSrc: ["'none'"],
|
|
537
538
|
// script-src and script-src-elem include dynamic nonce
|
|
538
539
|
scriptSrc: ["'self'", (req, res) => `'nonce-${res.locals.nonce}'`],
|
|
539
540
|
scriptSrcElem: ["'self'", (req, res) => `'nonce-${res.locals.nonce}'`],
|
|
540
541
|
// style-src: avoid 'unsafe-inline' when possible; if you must inline styles,
|
|
541
542
|
// use a nonce for them too (or hash).
|
|
542
|
-
styleSrc: ["'self'",
|
|
543
|
+
styleSrc: ["'self'", httpDirective, (req, res) => `'nonce-${res.locals.nonce}'`],
|
|
543
544
|
// deny plugins
|
|
544
545
|
objectSrc: ["'none'"],
|
|
545
546
|
},
|
|
@@ -552,7 +553,7 @@ function applySecurity(app, opts = {}) {
|
|
|
552
553
|
origin: origin || false,
|
|
553
554
|
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
|
554
555
|
credentials: true,
|
|
555
|
-
allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With', 'Accept', 'withcredentials'],
|
|
556
|
+
allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With', 'Accept', 'withcredentials', 'credentials'],
|
|
556
557
|
maxAge: 600,
|
|
557
558
|
}),
|
|
558
559
|
);
|
package/src/server/conf.js
CHANGED
|
@@ -33,12 +33,13 @@ const Config = {
|
|
|
33
33
|
else if (deployContext.startsWith('dd-')) return loadConf(deployContext, process.env.NODE_ENV, subConf);
|
|
34
34
|
if (deployContext === 'proxy') Config.buildProxy(deployContext, deployList, subConf);
|
|
35
35
|
},
|
|
36
|
-
deployIdFactory: function (deployId = 'dd-default') {
|
|
36
|
+
deployIdFactory: function (deployId = 'dd-default', options = { cluster: false }) {
|
|
37
37
|
if (!deployId.startsWith('dd-')) deployId = `dd-${deployId}`;
|
|
38
38
|
|
|
39
39
|
logger.info('Build deployId', deployId);
|
|
40
40
|
|
|
41
41
|
const folder = `./engine-private/conf/${deployId}`;
|
|
42
|
+
const repoName = `engine-${deployId.split('dd-')[1]}`;
|
|
42
43
|
|
|
43
44
|
if (!fs.existsSync(folder)) fs.mkdirSync(folder, { recursive: true });
|
|
44
45
|
fs.writeFileSync(
|
|
@@ -56,10 +57,44 @@ const Config = {
|
|
|
56
57
|
fs.readFileSync('./.env.test', 'utf8').replaceAll('dd-default', deployId),
|
|
57
58
|
'utf8',
|
|
58
59
|
);
|
|
59
|
-
fs.writeFileSync(
|
|
60
|
+
fs.writeFileSync(
|
|
61
|
+
`${folder}/package.json`,
|
|
62
|
+
fs.readFileSync('./package.json', 'utf8').replaceAll('dd-default', deployId),
|
|
63
|
+
'utf8',
|
|
64
|
+
);
|
|
60
65
|
|
|
61
66
|
this.buildTmpConf(folder);
|
|
62
67
|
|
|
68
|
+
if (options.cluster === true) {
|
|
69
|
+
fs.writeFileSync(
|
|
70
|
+
`./.github/workflows/${repoName}.cd.yml`,
|
|
71
|
+
fs.readFileSync(`./.github/workflows/engine-test.cd.yml`, 'utf8').replaceAll('test', deployId.split('dd-')[1]),
|
|
72
|
+
'utf8',
|
|
73
|
+
);
|
|
74
|
+
fs.writeFileSync(
|
|
75
|
+
`./.github/workflows/${repoName}.ci.yml`,
|
|
76
|
+
fs.readFileSync(`./.github/workflows/engine-test.ci.yml`, 'utf8').replaceAll('test', deployId.split('dd-')[1]),
|
|
77
|
+
'utf8',
|
|
78
|
+
);
|
|
79
|
+
shellExec(`node bin/deploy update-default-conf ${deployId}`);
|
|
80
|
+
fs.writeFileSync(
|
|
81
|
+
`./engine-private/deploy/dd.router`,
|
|
82
|
+
fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8').trim() + `,${deployId}`,
|
|
83
|
+
'utf8',
|
|
84
|
+
);
|
|
85
|
+
const updateRepo = (stage = 1) => {
|
|
86
|
+
shellExec(`git add . && git commit -m "Add base deployId ${deployId} cluster files stage:${stage}"`);
|
|
87
|
+
shellExec(
|
|
88
|
+
`cd engine-private && git add . && git commit -m "Add base deployId ${deployId} cluster files stage:${stage}"`,
|
|
89
|
+
);
|
|
90
|
+
};
|
|
91
|
+
updateRepo(1);
|
|
92
|
+
shellExec(`node bin run --build --dev sync`);
|
|
93
|
+
updateRepo(2);
|
|
94
|
+
shellExec(`node bin run --build sync`);
|
|
95
|
+
updateRepo(3);
|
|
96
|
+
}
|
|
97
|
+
|
|
63
98
|
return { deployIdFolder: folder, deployId };
|
|
64
99
|
},
|
|
65
100
|
buildTmpConf: function (folder = './conf') {
|
package/src/server/runtime.js
CHANGED
|
@@ -63,6 +63,7 @@ const buildRuntime = async () => {
|
|
|
63
63
|
singleReplica,
|
|
64
64
|
replicas,
|
|
65
65
|
valkey,
|
|
66
|
+
apiBaseHost,
|
|
66
67
|
} = confServer[host][path];
|
|
67
68
|
|
|
68
69
|
const { redirectTarget, singleReplicaHost } = await getInstanceContext({
|
|
@@ -116,9 +117,6 @@ const buildRuntime = async () => {
|
|
|
116
117
|
// set logger
|
|
117
118
|
app.use(loggerMiddleware(import.meta));
|
|
118
119
|
|
|
119
|
-
// instance public static
|
|
120
|
-
app.use('/', express.static(directory ? directory : `.${rootHostPath}`));
|
|
121
|
-
|
|
122
120
|
// js src compression
|
|
123
121
|
app.use(compression({ filter: shouldCompress }));
|
|
124
122
|
function shouldCompress(req, res) {
|
|
@@ -163,6 +161,9 @@ const buildRuntime = async () => {
|
|
|
163
161
|
return next();
|
|
164
162
|
});
|
|
165
163
|
|
|
164
|
+
// instance public static
|
|
165
|
+
app.use('/', express.static(directory ? directory : `.${rootHostPath}`));
|
|
166
|
+
|
|
166
167
|
// security
|
|
167
168
|
applySecurity(app, {
|
|
168
169
|
origin: origins.concat(
|
|
@@ -188,99 +189,104 @@ const buildRuntime = async () => {
|
|
|
188
189
|
await UnderpostStartUp.API.listenPortController(app, port, runningData);
|
|
189
190
|
break;
|
|
190
191
|
}
|
|
192
|
+
// instance server
|
|
193
|
+
const server = createServer({}, app);
|
|
194
|
+
if (peer) currentPort++;
|
|
191
195
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
196
|
+
if (!apiBaseHost) {
|
|
197
|
+
const swaggerJsonPath = `./public/${host}${path === '/' ? path : `${path}/`}swagger-output.json`;
|
|
198
|
+
if (fs.existsSync(swaggerJsonPath)) {
|
|
199
|
+
// logger.info('Build swagger serve', swaggerJsonPath);
|
|
195
200
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
201
|
+
const swaggerInstance =
|
|
202
|
+
(swaggerDoc) =>
|
|
203
|
+
(...args) =>
|
|
204
|
+
swaggerUi.setup(swaggerDoc)(...args);
|
|
200
205
|
|
|
201
|
-
|
|
206
|
+
const swaggerDoc = JSON.parse(fs.readFileSync(swaggerJsonPath, 'utf8'));
|
|
202
207
|
|
|
203
|
-
|
|
204
|
-
|
|
208
|
+
app.use(
|
|
209
|
+
`${path === '/' ? `/api-docs` : `${path}/api-docs`}`,
|
|
210
|
+
swaggerUi.serve,
|
|
211
|
+
swaggerInstance(swaggerDoc),
|
|
212
|
+
);
|
|
213
|
+
}
|
|
205
214
|
|
|
206
|
-
|
|
215
|
+
if (db && apis) await DataBaseProvider.load({ apis, host, path, db });
|
|
207
216
|
|
|
208
|
-
|
|
209
|
-
|
|
217
|
+
// valkey server
|
|
218
|
+
if (valkey) await createValkeyConnection({ host, path }, valkey);
|
|
210
219
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
220
|
+
if (mailer) {
|
|
221
|
+
const mailerSsrConf = confSSR[getCapVariableName(client)];
|
|
222
|
+
await MailerProvider.load({
|
|
223
|
+
id: `${host}${path}`,
|
|
224
|
+
meta: `mailer-${host}${path}`,
|
|
225
|
+
host,
|
|
226
|
+
path,
|
|
227
|
+
...mailer,
|
|
228
|
+
templates: mailerSsrConf ? mailerSsrConf.mailer : {},
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
if (apis) {
|
|
232
|
+
const authMiddleware = authMiddlewareFactory({ host, path });
|
|
233
|
+
|
|
234
|
+
const apiPath = `${path === '/' ? '' : path}/${process.env.BASE_API}`;
|
|
235
|
+
for (const api of apis)
|
|
236
|
+
await (async () => {
|
|
237
|
+
const { ApiRouter } = await import(`../api/${api}/${api}.router.js`);
|
|
238
|
+
const router = ApiRouter({ host, path, apiPath, mailer, db, authMiddleware, origins });
|
|
239
|
+
// router.use(cors({ origin: origins }));
|
|
240
|
+
// logger.info('Load api router', { host, path: apiPath, api });
|
|
241
|
+
app.use(`${apiPath}/${api}`, router);
|
|
242
|
+
})();
|
|
243
|
+
}
|
|
224
244
|
|
|
225
|
-
|
|
226
|
-
for (const api of apis)
|
|
245
|
+
if (ws)
|
|
227
246
|
await (async () => {
|
|
228
|
-
const {
|
|
229
|
-
|
|
230
|
-
//
|
|
231
|
-
|
|
232
|
-
|
|
247
|
+
const { createIoServer } = await import(`../ws/${ws}/${ws}.ws.server.js`);
|
|
248
|
+
// logger.info('Load socket.io ws router', { host, ws });
|
|
249
|
+
// start socket.io
|
|
250
|
+
const { options, meta } = await createIoServer(server, {
|
|
251
|
+
host,
|
|
252
|
+
path,
|
|
253
|
+
db,
|
|
254
|
+
port,
|
|
255
|
+
origins,
|
|
256
|
+
});
|
|
257
|
+
await UnderpostStartUp.API.listenPortController(UnderpostStartUp.API.listenServerFactory(), port, {
|
|
258
|
+
runtime: 'nodejs',
|
|
259
|
+
client: null,
|
|
260
|
+
host,
|
|
261
|
+
path: options.path,
|
|
262
|
+
meta,
|
|
263
|
+
});
|
|
233
264
|
})();
|
|
234
|
-
}
|
|
235
265
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
if (ws)
|
|
244
|
-
await (async () => {
|
|
245
|
-
const { createIoServer } = await import(`../ws/${ws}/${ws}.ws.server.js`);
|
|
246
|
-
// logger.info('Load socket.io ws router', { host, ws });
|
|
247
|
-
// start socket.io
|
|
248
|
-
const { options, meta } = await createIoServer(server, {
|
|
266
|
+
if (peer) {
|
|
267
|
+
const peerPort = newInstance(currentPort);
|
|
268
|
+
const { options, meta, peerServer } = await createPeerServer({
|
|
269
|
+
port: peerPort,
|
|
270
|
+
devPort: port,
|
|
271
|
+
origins,
|
|
249
272
|
host,
|
|
250
273
|
path,
|
|
251
|
-
db,
|
|
252
|
-
port,
|
|
253
|
-
origins,
|
|
254
274
|
});
|
|
255
|
-
|
|
275
|
+
|
|
276
|
+
await UnderpostStartUp.API.listenPortController(peerServer, peerPort, {
|
|
256
277
|
runtime: 'nodejs',
|
|
257
278
|
client: null,
|
|
258
279
|
host,
|
|
259
280
|
path: options.path,
|
|
260
281
|
meta,
|
|
261
282
|
});
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
if (peer) {
|
|
265
|
-
currentPort++;
|
|
266
|
-
const peerPort = newInstance(currentPort);
|
|
267
|
-
const { options, meta, peerServer } = await createPeerServer({
|
|
268
|
-
port: peerPort,
|
|
269
|
-
devPort: port,
|
|
270
|
-
origins,
|
|
271
|
-
host,
|
|
272
|
-
path,
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
await UnderpostStartUp.API.listenPortController(peerServer, peerPort, {
|
|
276
|
-
runtime: 'nodejs',
|
|
277
|
-
client: null,
|
|
278
|
-
host,
|
|
279
|
-
path: options.path,
|
|
280
|
-
meta,
|
|
281
|
-
});
|
|
283
|
+
}
|
|
282
284
|
}
|
|
283
285
|
|
|
286
|
+
// load ssr
|
|
287
|
+
const ssr = await ssrMiddlewareFactory({ app, directory, rootHostPath, path });
|
|
288
|
+
for (const [_, ssrMiddleware] of Object.entries(ssr)) app.use(ssrMiddleware);
|
|
289
|
+
|
|
284
290
|
await UnderpostStartUp.API.listenPortController(server, port, runningData);
|
|
285
291
|
|
|
286
292
|
break;
|