@tramvai/cli 3.26.2 → 3.27.0

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 (109) hide show
  1. package/lib/api/shared/providers/selfSignedCertificateProvider.d.ts +3 -0
  2. package/lib/api/shared/providers/selfSignedCertificateProvider.d.ts.map +1 -0
  3. package/lib/api/shared/providers/selfSignedCertificateProvider.js +27 -0
  4. package/lib/api/shared/providers/selfSignedCertificateProvider.js.map +1 -0
  5. package/lib/api/shared/types/base.d.ts +4 -0
  6. package/lib/api/shared/types/base.d.ts.map +1 -1
  7. package/lib/api/shared/utils/selfSignedCertificate/certificatedHostsList.d.ts +4 -0
  8. package/lib/api/shared/utils/selfSignedCertificate/certificatedHostsList.d.ts.map +1 -0
  9. package/lib/api/shared/utils/selfSignedCertificate/certificatedHostsList.js +22 -0
  10. package/lib/api/shared/utils/selfSignedCertificate/certificatedHostsList.js.map +1 -0
  11. package/lib/api/shared/utils/selfSignedCertificate/common.d.ts +3 -0
  12. package/lib/api/shared/utils/selfSignedCertificate/common.d.ts.map +1 -0
  13. package/lib/api/shared/utils/selfSignedCertificate/common.js +8 -0
  14. package/lib/api/shared/utils/selfSignedCertificate/common.js.map +1 -0
  15. package/lib/api/shared/utils/selfSignedCertificate/createSelfSignedCertificate.d.ts +9 -0
  16. package/lib/api/shared/utils/selfSignedCertificate/createSelfSignedCertificate.d.ts.map +1 -0
  17. package/lib/api/shared/utils/selfSignedCertificate/createSelfSignedCertificate.js +64 -0
  18. package/lib/api/shared/utils/selfSignedCertificate/createSelfSignedCertificate.js.map +1 -0
  19. package/lib/api/shared/utils/selfSignedCertificate/getHosts.d.ts +3 -0
  20. package/lib/api/shared/utils/selfSignedCertificate/getHosts.d.ts.map +1 -0
  21. package/lib/api/shared/utils/selfSignedCertificate/getHosts.js +32 -0
  22. package/lib/api/shared/utils/selfSignedCertificate/getHosts.js.map +1 -0
  23. package/lib/api/start/index.d.ts +3 -0
  24. package/lib/api/start/index.d.ts.map +1 -1
  25. package/lib/api/start/index.js.map +1 -1
  26. package/lib/api/start/providers/application/server.d.ts.map +1 -1
  27. package/lib/api/start/providers/application/server.js +14 -3
  28. package/lib/api/start/providers/application/server.js.map +1 -1
  29. package/lib/api/start/providers/application/shared.d.ts.map +1 -1
  30. package/lib/api/start/providers/application/shared.js +11 -1
  31. package/lib/api/start/providers/application/shared.js.map +1 -1
  32. package/lib/api/start/utils/banner.d.ts.map +1 -1
  33. package/lib/api/start/utils/banner.js +8 -2
  34. package/lib/api/start/utils/banner.js.map +1 -1
  35. package/lib/api/start/utils/createServer.d.ts +3 -1
  36. package/lib/api/start/utils/createServer.d.ts.map +1 -1
  37. package/lib/api/start/utils/createServer.js +16 -1
  38. package/lib/api/start/utils/createServer.js.map +1 -1
  39. package/lib/api/start-prod/providers/application.d.ts.map +1 -1
  40. package/lib/api/start-prod/providers/application.js +24 -3
  41. package/lib/api/start-prod/providers/application.js.map +1 -1
  42. package/lib/api/start-prod/providers/child-app.d.ts.map +1 -1
  43. package/lib/api/start-prod/providers/child-app.js +5 -0
  44. package/lib/api/start-prod/providers/child-app.js.map +1 -1
  45. package/lib/api/start-prod/providers/shared.d.ts.map +1 -1
  46. package/lib/api/start-prod/providers/shared.js +0 -5
  47. package/lib/api/start-prod/providers/shared.js.map +1 -1
  48. package/lib/builder/webpack/devServer/server.d.ts.map +1 -1
  49. package/lib/builder/webpack/devServer/server.js +6 -1
  50. package/lib/builder/webpack/devServer/server.js.map +1 -1
  51. package/lib/builder/webpack/tokens.d.ts +3 -0
  52. package/lib/builder/webpack/tokens.d.ts.map +1 -1
  53. package/lib/commands/start/command.d.ts.map +1 -1
  54. package/lib/commands/start/command.js +16 -0
  55. package/lib/commands/start/command.js.map +1 -1
  56. package/lib/commands/start-prod/command.d.ts.map +1 -1
  57. package/lib/commands/start-prod/command.js +16 -0
  58. package/lib/commands/start-prod/command.js.map +1 -1
  59. package/lib/commands/static/application.d.ts.map +1 -1
  60. package/lib/commands/static/application.js +1 -1
  61. package/lib/commands/static/application.js.map +1 -1
  62. package/lib/config/configManager.d.ts +2 -0
  63. package/lib/config/configManager.d.ts.map +1 -1
  64. package/lib/config/configManager.js +2 -2
  65. package/lib/config/configManager.js.map +1 -1
  66. package/lib/di/tokens/config.d.ts +1 -0
  67. package/lib/di/tokens/config.d.ts.map +1 -1
  68. package/lib/di/tokens/server.d.ts +6 -0
  69. package/lib/di/tokens/server.d.ts.map +1 -1
  70. package/lib/di/tokens/server.js +2 -1
  71. package/lib/di/tokens/server.js.map +1 -1
  72. package/lib/library/webpack/application/client/dev.d.ts.map +1 -1
  73. package/lib/library/webpack/application/client/dev.js +6 -1
  74. package/lib/library/webpack/application/client/dev.js.map +1 -1
  75. package/lib/library/webpack/application/server/dev.d.ts.map +1 -1
  76. package/lib/library/webpack/application/server/dev.js +6 -1
  77. package/lib/library/webpack/application/server/dev.js.map +1 -1
  78. package/lib/schema/autogeneratedSchema.json +15 -15
  79. package/lib/utils/getApplicationUrl.d.ts +6 -0
  80. package/lib/utils/getApplicationUrl.d.ts.map +1 -0
  81. package/lib/utils/getApplicationUrl.js +8 -0
  82. package/lib/utils/getApplicationUrl.js.map +1 -0
  83. package/package.json +3 -3
  84. package/schema.json +15 -15
  85. package/src/api/shared/providers/selfSignedCertificateProvider.ts +29 -0
  86. package/src/api/shared/types/base.ts +5 -0
  87. package/src/api/shared/utils/selfSignedCertificate/certificatedHostsList.ts +22 -0
  88. package/src/api/shared/utils/selfSignedCertificate/common.ts +4 -0
  89. package/src/api/shared/utils/selfSignedCertificate/createSelfSignedCertificate.spec.ts +154 -0
  90. package/src/api/shared/utils/selfSignedCertificate/createSelfSignedCertificate.ts +99 -0
  91. package/src/api/shared/utils/selfSignedCertificate/getHosts.ts +31 -0
  92. package/src/api/start/index.ts +3 -0
  93. package/src/api/start/providers/application/server.ts +21 -5
  94. package/src/api/start/providers/application/shared.ts +12 -2
  95. package/src/api/start/utils/banner.ts +12 -4
  96. package/src/api/start/utils/createServer.ts +19 -1
  97. package/src/api/start-prod/providers/application.ts +27 -3
  98. package/src/api/start-prod/providers/child-app.ts +6 -0
  99. package/src/api/start-prod/providers/shared.ts +0 -5
  100. package/src/builder/webpack/devServer/server.ts +6 -1
  101. package/src/commands/start/command.ts +16 -0
  102. package/src/commands/start-prod/command.ts +16 -0
  103. package/src/commands/static/application.ts +3 -1
  104. package/src/config/configManager.ts +7 -4
  105. package/src/di/tokens/server.ts +5 -0
  106. package/src/library/webpack/application/client/dev.ts +6 -3
  107. package/src/library/webpack/application/server/dev.ts +6 -3
  108. package/src/schema/autogeneratedSchema.json +15 -15
  109. package/src/utils/getApplicationUrl.ts +11 -0
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getApplicationUrl = void 0;
4
+ const getApplicationUrl = ({ protocol, host, port, }) => {
5
+ return `${protocol}://${host}:${port}`;
6
+ };
7
+ exports.getApplicationUrl = getApplicationUrl;
8
+ //# sourceMappingURL=getApplicationUrl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getApplicationUrl.js","sourceRoot":"","sources":["../../src/utils/getApplicationUrl.ts"],"names":[],"mappings":";;;AAAO,MAAM,iBAAiB,GAAG,CAAC,EAChC,QAAQ,EACR,IAAI,EACJ,IAAI,GAKL,EAAE,EAAE;IACH,OAAO,GAAG,QAAQ,MAAM,IAAI,IAAI,IAAI,EAAE,CAAC;AACzC,CAAC,CAAC;AAVW,QAAA,iBAAiB,qBAU5B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tramvai/cli",
3
- "version": "3.26.2",
3
+ "version": "3.27.0",
4
4
  "description": "Cli инструмент для сборки и запуска приложений",
5
5
  "files": [
6
6
  "src",
@@ -70,8 +70,8 @@
70
70
  "@tinkoff/request-plugin-protocol-http": "^0.11.8",
71
71
  "@tinkoff/utils": "^2.1.3",
72
72
  "@tinkoff/webpack-dedupe-plugin": "2.0.2",
73
- "@tramvai/build": "4.1.0",
74
- "@tramvai/react": "3.26.2",
73
+ "@tramvai/build": "4.1.1",
74
+ "@tramvai/react": "3.27.0",
75
75
  "@tramvai/tools-check-versions": "0.5.3",
76
76
  "@tramvai/tools-migrate": "0.7.3",
77
77
  "ajv": "^8.12.0",
package/schema.json CHANGED
@@ -1166,23 +1166,23 @@
1166
1166
  "dotAll": {
1167
1167
  "type": "boolean"
1168
1168
  },
1169
- "__@match@6849": {
1169
+ "__@match@6855": {
1170
1170
  "type": "object",
1171
1171
  "additionalProperties": false
1172
1172
  },
1173
- "__@replace@6851": {
1173
+ "__@replace@6857": {
1174
1174
  "type": "object",
1175
1175
  "additionalProperties": false
1176
1176
  },
1177
- "__@search@6854": {
1177
+ "__@search@6860": {
1178
1178
  "type": "object",
1179
1179
  "additionalProperties": false
1180
1180
  },
1181
- "__@split@6856": {
1181
+ "__@split@6862": {
1182
1182
  "type": "object",
1183
1183
  "additionalProperties": false
1184
1184
  },
1185
- "__@matchAll@6858": {
1185
+ "__@matchAll@6864": {
1186
1186
  "type": "object",
1187
1187
  "additionalProperties": false
1188
1188
  }
@@ -1844,23 +1844,23 @@
1844
1844
  "dotAll": {
1845
1845
  "type": "boolean"
1846
1846
  },
1847
- "__@match@6849": {
1847
+ "__@match@6855": {
1848
1848
  "type": "object",
1849
1849
  "additionalProperties": false
1850
1850
  },
1851
- "__@replace@6851": {
1851
+ "__@replace@6857": {
1852
1852
  "type": "object",
1853
1853
  "additionalProperties": false
1854
1854
  },
1855
- "__@search@6854": {
1855
+ "__@search@6860": {
1856
1856
  "type": "object",
1857
1857
  "additionalProperties": false
1858
1858
  },
1859
- "__@split@6856": {
1859
+ "__@split@6862": {
1860
1860
  "type": "object",
1861
1861
  "additionalProperties": false
1862
1862
  },
1863
- "__@matchAll@6858": {
1863
+ "__@matchAll@6864": {
1864
1864
  "type": "object",
1865
1865
  "additionalProperties": false
1866
1866
  }
@@ -2522,23 +2522,23 @@
2522
2522
  "dotAll": {
2523
2523
  "type": "boolean"
2524
2524
  },
2525
- "__@match@6849": {
2525
+ "__@match@6855": {
2526
2526
  "type": "object",
2527
2527
  "additionalProperties": false
2528
2528
  },
2529
- "__@replace@6851": {
2529
+ "__@replace@6857": {
2530
2530
  "type": "object",
2531
2531
  "additionalProperties": false
2532
2532
  },
2533
- "__@search@6854": {
2533
+ "__@search@6860": {
2534
2534
  "type": "object",
2535
2535
  "additionalProperties": false
2536
2536
  },
2537
- "__@split@6856": {
2537
+ "__@split@6862": {
2538
2538
  "type": "object",
2539
2539
  "additionalProperties": false
2540
2540
  },
2541
- "__@matchAll@6858": {
2541
+ "__@matchAll@6864": {
2542
2542
  "type": "object",
2543
2543
  "additionalProperties": false
2544
2544
  }
@@ -0,0 +1,29 @@
1
+ import type { Provider } from '@tinkoff/dippy';
2
+ import { provide } from '@tinkoff/dippy';
3
+ import {
4
+ COMMAND_PARAMETERS_TOKEN,
5
+ CONFIG_MANAGER_TOKEN,
6
+ SELF_SIGNED_CERTIFICATE_TOKEN,
7
+ } from '../../../di/tokens';
8
+ import { createSelfSignedCertificate } from '../utils/selfSignedCertificate/createSelfSignedCertificate';
9
+
10
+ export const selfSignedCertificateProvider: Provider[] = [
11
+ provide({
12
+ provide: SELF_SIGNED_CERTIFICATE_TOKEN,
13
+ useFactory: ({ configManager, parameters }) => {
14
+ const { host } = configManager;
15
+ if (configManager.httpProtocol === 'https') {
16
+ return createSelfSignedCertificate({
17
+ host,
18
+ certificatePath: parameters?.httpsCert,
19
+ keyPath: parameters?.httpsKey,
20
+ });
21
+ }
22
+ return null;
23
+ },
24
+ deps: {
25
+ configManager: CONFIG_MANAGER_TOKEN,
26
+ parameters: COMMAND_PARAMETERS_TOKEN,
27
+ },
28
+ }),
29
+ ];
@@ -2,3 +2,8 @@ export interface BaseParams {
2
2
  stdout?: NodeJS.WritableStream;
3
3
  stderr?: NodeJS.WritableStream;
4
4
  }
5
+
6
+ export interface Certificate {
7
+ keyPath: string;
8
+ certificatePath: string;
9
+ }
@@ -0,0 +1,22 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { certificateDirectoryPath } from './common';
4
+
5
+ export const certificatedHostsListFilePath = path.resolve(
6
+ certificateDirectoryPath,
7
+ 'certificatedHostsList'
8
+ );
9
+ const separator = ',';
10
+
11
+ export const createCertificatedHostsListFile = (data: string[]) => {
12
+ fs.writeFileSync(certificatedHostsListFilePath, data.join(separator), 'utf-8');
13
+ };
14
+
15
+ export const readCertificatedHostsListFile = (): Set<string> | null => {
16
+ if (!fs.existsSync(certificatedHostsListFilePath)) {
17
+ return null;
18
+ }
19
+
20
+ const data = fs.readFileSync(certificatedHostsListFilePath, 'utf-8');
21
+ return new Set(data.split(separator));
22
+ };
@@ -0,0 +1,4 @@
1
+ import path from 'path';
2
+
3
+ export const certificateDirectory = 'certificates';
4
+ export const certificateDirectoryPath = path.resolve(process.cwd(), certificateDirectory);
@@ -0,0 +1,154 @@
1
+ import os from 'os';
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+ import child_process from 'child_process';
5
+
6
+ import { createSelfSignedCertificate } from './createSelfSignedCertificate';
7
+ import { certificatedHostsListFilePath } from './certificatedHostsList';
8
+ import { certificateDirectoryPath } from './common';
9
+
10
+ const defaultKeyPath = path.resolve(certificateDirectoryPath, 'localhost-key.pem');
11
+ const defaultCertificatePath = path.resolve(certificateDirectoryPath, 'localhost.pem');
12
+ const gitignorePath = path.resolve(process.cwd(), '.gitignore');
13
+ const customHost = 'localhost.domain.com';
14
+
15
+ jest.mock('os', () => {
16
+ return {
17
+ networkInterfaces: (param: string) => {
18
+ return [];
19
+ },
20
+ };
21
+ });
22
+
23
+ const existsSyncSpy = jest.spyOn(fs, 'existsSync');
24
+ const mkdirSyncSpy = jest.spyOn(fs, 'mkdirSync');
25
+ const writeFileSyncSpy = jest.spyOn(fs, 'writeFileSync');
26
+ const readFileSyncSpy = jest.spyOn(fs, 'readFileSync');
27
+ const execSyncSpy = jest.spyOn(child_process, 'execSync');
28
+ const appendFileSyncSpy = jest.spyOn(fs, 'appendFileSync');
29
+
30
+ describe('shared/utils/selfSignedCertificate', () => {
31
+ beforeEach(() => {
32
+ writeFileSyncSpy.mockImplementation(() => undefined);
33
+ mkdirSyncSpy.mockImplementation(() => {
34
+ return undefined;
35
+ });
36
+ execSyncSpy.mockImplementation((command) => {
37
+ if (command === 'mkcert -CAROOT') return '/location';
38
+ return '';
39
+ });
40
+
41
+ readFileSyncSpy.mockImplementation((path) => {
42
+ if (path === gitignorePath) return '';
43
+ return `localhost,${customHost}`;
44
+ });
45
+ });
46
+ afterEach(() => {
47
+ jest.clearAllMocks();
48
+ existsSyncSpy.mockReset();
49
+ mkdirSyncSpy.mockReset();
50
+ writeFileSyncSpy.mockReset();
51
+ execSyncSpy.mockReset();
52
+ });
53
+ it('should generate certificate', async () => {
54
+ existsSyncSpy.mockImplementation((path) => {
55
+ if (path === certificatedHostsListFilePath || path === gitignorePath) {
56
+ return false;
57
+ }
58
+ return true;
59
+ });
60
+
61
+ const result = createSelfSignedCertificate({});
62
+
63
+ expect(execSyncSpy).toHaveBeenNthCalledWith(
64
+ 1,
65
+ `mkcert -install -key-file "${defaultKeyPath}" -cert-file "${defaultCertificatePath}" localhost`
66
+ );
67
+
68
+ expect(result).toEqual({
69
+ keyPath: defaultKeyPath,
70
+ certificatePath: defaultCertificatePath,
71
+ });
72
+ });
73
+ it('should generate certificate for provided host', async () => {
74
+ existsSyncSpy.mockImplementation((path) => {
75
+ if (path === certificatedHostsListFilePath || path === gitignorePath) {
76
+ return false;
77
+ }
78
+ return true;
79
+ });
80
+ const result = createSelfSignedCertificate({ host: customHost });
81
+ expect(execSyncSpy).toHaveBeenNthCalledWith(
82
+ 1,
83
+ `mkcert -install -key-file "${defaultKeyPath}" -cert-file "${defaultCertificatePath}" localhost ${customHost}`
84
+ );
85
+ expect(result).toEqual({
86
+ keyPath: defaultKeyPath,
87
+ certificatePath: defaultCertificatePath,
88
+ });
89
+ });
90
+
91
+ it('should return already existed certificate if it was generated previously', async () => {
92
+ existsSyncSpy.mockImplementation((path) => {
93
+ if (path === gitignorePath) {
94
+ return false;
95
+ }
96
+ return true;
97
+ });
98
+ const result = createSelfSignedCertificate({ host: customHost });
99
+ expect(execSyncSpy).toHaveBeenCalledTimes(0);
100
+
101
+ expect(result).toEqual({
102
+ keyPath: defaultKeyPath,
103
+ certificatePath: defaultCertificatePath,
104
+ });
105
+ });
106
+
107
+ it('should use custom certificate if provided', () => {
108
+ const customCertificate = {
109
+ certificatePath: path.resolve('path-to-custom-certificate/cert.pem'),
110
+ keyPath: path.resolve('path-to-custom-certificate/key.pem'),
111
+ };
112
+ const result = createSelfSignedCertificate({
113
+ host: customHost,
114
+ ...customCertificate,
115
+ });
116
+
117
+ expect(execSyncSpy).toHaveBeenCalledTimes(0);
118
+
119
+ expect(result).toEqual({
120
+ keyPath: customCertificate.keyPath,
121
+ certificatePath: customCertificate.certificatePath,
122
+ });
123
+ });
124
+ it('if a new host be provided, a new certificate should be generated even if a certificate already exists.', () => {
125
+ existsSyncSpy.mockImplementation((path) => {
126
+ if (path === gitignorePath) {
127
+ return false;
128
+ }
129
+ return true;
130
+ });
131
+ const result = createSelfSignedCertificate({ host: 'new.localhost.domain' });
132
+ expect(execSyncSpy).toHaveBeenNthCalledWith(
133
+ 1,
134
+ `mkcert -install -key-file "${defaultKeyPath}" -cert-file "${defaultCertificatePath}" localhost new.localhost.domain`
135
+ );
136
+
137
+ expect(result).toEqual({
138
+ keyPath: defaultKeyPath,
139
+ certificatePath: defaultCertificatePath,
140
+ });
141
+ });
142
+ it('should add certificates folder to .gitignore if .gitignore file exist', () => {
143
+ existsSyncSpy.mockImplementation((path) => {
144
+ return true;
145
+ });
146
+ const result = createSelfSignedCertificate({ host: 'new.localhost.domain' });
147
+ expect(appendFileSyncSpy).toBeCalledTimes(1);
148
+
149
+ expect(result).toEqual({
150
+ keyPath: defaultKeyPath,
151
+ certificatePath: defaultCertificatePath,
152
+ });
153
+ });
154
+ });
@@ -0,0 +1,99 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { execSync } from 'child_process';
4
+ import chalk from 'chalk';
5
+ import type { Certificate } from '../../types/base';
6
+ import { getHosts } from './getHosts';
7
+ import { certificateDirectoryPath, certificateDirectory } from './common';
8
+ import {
9
+ createCertificatedHostsListFile,
10
+ readCertificatedHostsListFile,
11
+ } from './certificatedHostsList';
12
+
13
+ interface CreateSelfSignedCertificateOptions {
14
+ host?: string;
15
+ keyPath?: string;
16
+ certificatePath?: string;
17
+ }
18
+
19
+ // eslint-disable-next-line max-statements
20
+ export const createSelfSignedCertificate = (
21
+ options: CreateSelfSignedCertificateOptions
22
+ ): Certificate => {
23
+ try {
24
+ const { host } = options;
25
+ const hosts = getHosts(host === '0.0.0.0' ? null : host);
26
+ const hostsFile = readCertificatedHostsListFile();
27
+
28
+ const defaultKeyPath = path.resolve(certificateDirectoryPath, 'localhost-key.pem');
29
+ const defaultCertificatePath = path.resolve(certificateDirectoryPath, 'localhost.pem');
30
+
31
+ const keyPath = options.keyPath ? path.resolve(options.keyPath) : defaultKeyPath;
32
+ const certificatePath = options.certificatePath
33
+ ? path.resolve(options.certificatePath)
34
+ : defaultCertificatePath;
35
+
36
+ // check if certificates are already generated, in this case we simply skip step
37
+
38
+ const isExternalCertificateProvided = options.certificatePath && options.keyPath;
39
+
40
+ const isCertificateAlreadyExist =
41
+ !isExternalCertificateProvided &&
42
+ fs.existsSync(keyPath) &&
43
+ fs.existsSync(certificatePath) &&
44
+ hostsFile &&
45
+ hosts.every((h) => hostsFile.has(h));
46
+
47
+ const gitignorePath = path.resolve(process.cwd(), '.gitignore');
48
+ if (
49
+ fs.existsSync(gitignorePath) &&
50
+ !fs.readFileSync(gitignorePath, 'utf-8').includes(certificateDirectory)
51
+ ) {
52
+ fs.appendFileSync(gitignorePath, `\n${certificateDirectory}`);
53
+ }
54
+
55
+ if (isExternalCertificateProvided || isCertificateAlreadyExist) {
56
+ console.log(
57
+ chalk.blue(
58
+ 'Certificates for https environment are already exist, skipping step with certificate generation'
59
+ )
60
+ );
61
+
62
+ return {
63
+ keyPath,
64
+ certificatePath,
65
+ };
66
+ }
67
+
68
+ fs.mkdirSync(certificateDirectoryPath, { recursive: true });
69
+ createCertificatedHostsListFile(hosts);
70
+
71
+ // TODO: maybe it is better to install mkcert for users for better dx
72
+ // check https://github.com/liuweiGL/vite-plugin-mkcert/blob/main/plugin/index.ts and https://github.com/vercel/next.js/blob/28fdc367b1f6d41245ea036bc40d1035a8a4d0e4/packages/next/src/lib/mkcert.ts#L68
73
+ execSync(
74
+ `mkcert -install -key-file "${keyPath}" -cert-file "${certificatePath}" ${hosts.join(' ')}`
75
+ );
76
+
77
+ if (!fs.existsSync(keyPath) || !fs.existsSync(certificatePath)) {
78
+ throw new Error(
79
+ 'Error occured while certificate creation. Generated certificate files not found'
80
+ );
81
+ }
82
+
83
+ const CAROOTFileLocation = execSync('mkcert -CAROOT').toString().trim();
84
+
85
+ console.log(chalk.green(`Root certificate located in ${chalk.blue(CAROOTFileLocation)}`));
86
+
87
+ return {
88
+ keyPath,
89
+ certificatePath,
90
+ };
91
+ } catch (error) {
92
+ console.error(
93
+ chalk.red(
94
+ `Error while generating the certificate. The mkcert tool may not be installed please check and install it if that is the case.`
95
+ )
96
+ );
97
+ throw new Error(error);
98
+ }
99
+ };
@@ -0,0 +1,31 @@
1
+ import os from 'os';
2
+
3
+ export const getDefaultHosts = () => {
4
+ const defaultHosts = ['localhost'];
5
+ const networkInterfaces = os.networkInterfaces();
6
+
7
+ for (const networkInterfaceKey in networkInterfaces) {
8
+ const networkInterfacesInfo = networkInterfaces[networkInterfaceKey];
9
+
10
+ if (networkInterfacesInfo) {
11
+ for (const info of networkInterfacesInfo) {
12
+ // https://github.com/nodejs/node/issues/42787
13
+ //@ts-expect-error
14
+ if (info.family === 'IPv4' || info.family === '4') {
15
+ defaultHosts.push(info.address);
16
+ }
17
+ }
18
+ }
19
+ }
20
+
21
+ return defaultHosts;
22
+ };
23
+
24
+ export const getHosts = (host?: string) => {
25
+ const hosts = new Set([...getDefaultHosts()]);
26
+
27
+ if (host && !hosts.has(host)) {
28
+ hosts.add(host);
29
+ }
30
+ return Array.from(hosts);
31
+ };
@@ -11,6 +11,9 @@ import type { Builder } from '../../typings/build/Builder';
11
11
 
12
12
  export type Params = WithConfig<{
13
13
  buildType?: 'server' | 'client' | 'all';
14
+ https?: boolean;
15
+ httpsKey?: string;
16
+ httpsCert?: string;
14
17
  host?: string;
15
18
  port?: number;
16
19
  staticPort?: number;
@@ -1,8 +1,13 @@
1
1
  import type { Provider } from '@tinkoff/dippy';
2
2
  import { provide } from '@tinkoff/dippy';
3
-
3
+ import { readFileSync } from 'fs';
4
+ import { createProxyServer } from 'http-proxy';
4
5
  import { INIT_HANDLER_TOKEN, CLOSE_HANDLER_TOKEN } from '../../tokens';
5
- import { CONFIG_MANAGER_TOKEN, SERVER_TOKEN } from '../../../../di/tokens';
6
+ import {
7
+ CONFIG_MANAGER_TOKEN,
8
+ SELF_SIGNED_CERTIFICATE_TOKEN,
9
+ SERVER_TOKEN,
10
+ } from '../../../../di/tokens';
6
11
  import { stopServer } from '../../utils/stopServer';
7
12
  import { createServer } from '../../utils/createServer';
8
13
  import { listenServer } from '../../utils/listenServer';
@@ -10,14 +15,24 @@ import { listenServer } from '../../utils/listenServer';
10
15
  export const serverProviders: readonly Provider[] = [
11
16
  provide({
12
17
  provide: SERVER_TOKEN,
13
- useFactory: createServer,
18
+ useFactory: ({ selfSignedCertificate }) => {
19
+ return createServer(selfSignedCertificate);
20
+ },
21
+ deps: {
22
+ selfSignedCertificate: {
23
+ token: SELF_SIGNED_CERTIFICATE_TOKEN,
24
+ optional: true,
25
+ },
26
+ },
14
27
  }),
15
28
  provide({
16
29
  provide: INIT_HANDLER_TOKEN,
17
30
  multi: true,
18
- useFactory: ({ server, configManager }) => {
31
+ useFactory: ({ server, configManager, selfSignedCertificate }) => {
19
32
  return async function staticServerListen() {
20
- const { host, port } = configManager;
33
+ const { https } = configManager;
34
+ const port = https && configManager.host !== '0.0.0.0' ? 443 : configManager.port;
35
+ const host = https ? '0.0.0.0' : configManager.host;
21
36
 
22
37
  await listenServer(server, host, port);
23
38
  };
@@ -25,6 +40,7 @@ export const serverProviders: readonly Provider[] = [
25
40
  deps: {
26
41
  server: SERVER_TOKEN,
27
42
  configManager: CONFIG_MANAGER_TOKEN,
43
+ selfSignedCertificate: SELF_SIGNED_CERTIFICATE_TOKEN,
28
44
  },
29
45
  }),
30
46
  provide({
@@ -1,6 +1,5 @@
1
1
  import type { Provider } from '@tinkoff/dippy';
2
2
  import { provide } from '@tinkoff/dippy';
3
-
4
3
  import { CLOSE_HANDLER_TOKEN, INIT_HANDLER_TOKEN } from '../../tokens';
5
4
  import {
6
5
  CONFIG_MANAGER_TOKEN,
@@ -8,14 +7,17 @@ import {
8
7
  COMMAND_PARAMETERS_TOKEN,
9
8
  STATIC_SERVER_TOKEN,
10
9
  PORT_MANAGER_TOKEN,
10
+ SELF_SIGNED_CERTIFICATE_TOKEN,
11
11
  } from '../../../../di/tokens';
12
12
  import { stopServer } from '../../utils/stopServer';
13
13
  import type { ApplicationConfigEntry } from '../../../../typings/configEntry/application';
14
14
  import { createConfigManager } from '../../../../config/configManager';
15
15
  import { createServer } from '../../utils/createServer';
16
16
  import { listenServer } from '../../utils/listenServer';
17
+ import { selfSignedCertificateProvider } from '../../../shared/providers/selfSignedCertificateProvider';
17
18
 
18
19
  export const sharedProviders: readonly Provider[] = [
20
+ ...selfSignedCertificateProvider,
19
21
  provide({
20
22
  provide: CONFIG_MANAGER_TOKEN,
21
23
  useFactory: ({ configEntry, parameters, portManager }) =>
@@ -34,7 +36,15 @@ export const sharedProviders: readonly Provider[] = [
34
36
  }),
35
37
  provide({
36
38
  provide: STATIC_SERVER_TOKEN,
37
- useFactory: createServer,
39
+ useFactory: ({ selfSignedCertificate }) => {
40
+ return createServer(selfSignedCertificate);
41
+ },
42
+ deps: {
43
+ selfSignedCertificate: {
44
+ token: SELF_SIGNED_CERTIFICATE_TOKEN,
45
+ optional: true,
46
+ },
47
+ },
38
48
  }),
39
49
  provide({
40
50
  provide: INIT_HANDLER_TOKEN,
@@ -8,6 +8,7 @@ import { isApplication } from '../../../config/validate';
8
8
  const label = (name) => chalk.bold.cyan(`▸ ${name}:`);
9
9
  const link = (url) => chalk.underline.blue(url);
10
10
 
11
+ // eslint-disable-next-line max-statements
11
12
  export function showBanner(di: Container) {
12
13
  if (!di.get({ token: UI_SHOW_BANNER_TOKEN, optional: true })) {
13
14
  return;
@@ -31,14 +32,21 @@ export function showBanner(di: Container) {
31
32
  titleLines.push(`${label('FileSystemPages')} true`);
32
33
  }
33
34
 
34
- const server = `http://${config.host.replace('0.0.0.0', 'localhost')}:${config.port}`;
35
- const staticServer = `http://${config.staticHost.replace('0.0.0.0', 'localhost')}:${
36
- config.staticPort
37
- }`;
35
+ // TODO: add information about hosted url !
36
+ const baseServerUrl = `${config.httpProtocol}://${config.host.replace('0.0.0.0', 'localhost')}`;
37
+ const server = `${baseServerUrl}:${config.port}`;
38
+
39
+ const staticServer = `${config.httpProtocol}://${config.staticHost.replace(
40
+ '0.0.0.0',
41
+ 'localhost'
42
+ )}:${config.staticPort}`;
38
43
 
39
44
  if (config.type === 'application') {
40
45
  // Listeners
41
46
  messageLines.push(chalk.bold('Static: ') + link(staticServer));
47
+ if (config.host !== '0.0.0.0' && config.https) {
48
+ messageLines.push(chalk.bold('App: ') + link(baseServerUrl));
49
+ }
42
50
  messageLines.push(chalk.bold('App: ') + link(server));
43
51
  }
44
52
 
@@ -1,8 +1,26 @@
1
1
  import { createServer as httpCreateServer } from 'http';
2
+ import { createServer as httpsCreateServer } from 'https';
3
+ import { readFileSync } from 'fs';
2
4
  import stoppable from 'stoppable';
5
+ import type { Certificate } from '../../shared/types/base';
3
6
 
4
- export const createServer = () => {
7
+ const createHttpsServer = ({ keyPath, certificatePath }: Certificate) => {
8
+ const options = {
9
+ key: readFileSync(keyPath),
10
+ cert: readFileSync(certificatePath),
11
+ };
12
+ const httpsServer = httpsCreateServer(options);
13
+ return stoppable(httpsServer, 0);
14
+ };
15
+
16
+ const createHttpServer = () => {
5
17
  const server = httpCreateServer();
6
18
 
7
19
  return stoppable(server, 0);
8
20
  };
21
+
22
+ export const createServer = (certificate?: Certificate) => {
23
+ return certificate && certificate?.certificatePath && certificate?.keyPath
24
+ ? createHttpsServer(certificate)
25
+ : createHttpServer();
26
+ };