@tramvai/cli 3.11.0 → 3.13.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 (70) hide show
  1. package/lib/api/start/providers/application/shared.d.ts.map +1 -1
  2. package/lib/api/start/providers/application/shared.js +5 -3
  3. package/lib/api/start/providers/application/shared.js.map +1 -1
  4. package/lib/api/start/providers/child-app/shared.d.ts.map +1 -1
  5. package/lib/api/start/providers/child-app/shared.js +6 -4
  6. package/lib/api/start/providers/child-app/shared.js.map +1 -1
  7. package/lib/api/start/providers/module/shared.d.ts.map +1 -1
  8. package/lib/api/start/providers/module/shared.js +6 -4
  9. package/lib/api/start/providers/module/shared.js.map +1 -1
  10. package/lib/api/start/utils/stopServer.d.ts.map +1 -1
  11. package/lib/api/start/utils/stopServer.js.map +1 -1
  12. package/lib/api/start-prod/application.d.ts.map +1 -1
  13. package/lib/api/start-prod/application.js +0 -2
  14. package/lib/api/start-prod/application.js.map +1 -1
  15. package/lib/api/start-prod/providers/shared.d.ts.map +1 -1
  16. package/lib/api/start-prod/providers/shared.js +3 -1
  17. package/lib/api/start-prod/providers/shared.js.map +1 -1
  18. package/lib/commands/analyze/command.d.ts.map +1 -1
  19. package/lib/commands/analyze/command.js +2 -0
  20. package/lib/commands/analyze/command.js.map +1 -1
  21. package/lib/commands/build/command.d.ts.map +1 -1
  22. package/lib/commands/build/command.js +2 -0
  23. package/lib/commands/build/command.js.map +1 -1
  24. package/lib/commands/start/command.d.ts.map +1 -1
  25. package/lib/commands/start/command.js +2 -0
  26. package/lib/commands/start/command.js.map +1 -1
  27. package/lib/commands/start-prod/command.d.ts.map +1 -1
  28. package/lib/commands/start-prod/command.js +2 -0
  29. package/lib/commands/start-prod/command.js.map +1 -1
  30. package/lib/commands/static/application.d.ts.map +1 -1
  31. package/lib/commands/static/application.js +8 -3
  32. package/lib/commands/static/application.js.map +1 -1
  33. package/lib/di/providers/network.d.ts.map +1 -1
  34. package/lib/di/providers/network.js +6 -0
  35. package/lib/di/providers/network.js.map +1 -1
  36. package/lib/models/port-manager.d.ts +21 -7
  37. package/lib/models/port-manager.d.ts.map +1 -1
  38. package/lib/models/port-manager.js +140 -26
  39. package/lib/models/port-manager.js.map +1 -1
  40. package/lib/schema/autogeneratedSchema.json +18 -18
  41. package/lib/typings/application.d.ts +8 -4
  42. package/lib/typings/application.d.ts.map +1 -1
  43. package/lib/typings/configEntry/cli.d.ts +1 -1
  44. package/lib/validators/commands/checkSwcDependencies.d.ts +3 -0
  45. package/lib/validators/commands/checkSwcDependencies.d.ts.map +1 -0
  46. package/lib/validators/commands/checkSwcDependencies.js +40 -0
  47. package/lib/validators/commands/checkSwcDependencies.js.map +1 -0
  48. package/package.json +5 -2
  49. package/schema.json +18 -18
  50. package/src/api/benchmark/__integration__/start.test.ts +0 -2
  51. package/src/api/start/__integration__/start.test.ts +14 -95
  52. package/src/api/start/providers/application/shared.ts +4 -2
  53. package/src/api/start/providers/child-app/shared.ts +5 -2
  54. package/src/api/start/providers/module/shared.ts +5 -2
  55. package/src/api/start/utils/stopServer.ts +1 -0
  56. package/src/api/start-prod/application.ts +1 -4
  57. package/src/api/start-prod/providers/shared.ts +5 -2
  58. package/src/commands/analyze/command.ts +2 -0
  59. package/src/commands/build/command.ts +2 -0
  60. package/src/commands/start/command.ts +2 -0
  61. package/src/commands/start-prod/command.ts +2 -0
  62. package/src/commands/static/application.ts +10 -4
  63. package/src/di/providers/network.ts +6 -0
  64. package/src/library/swc/__integration__/swc.start.test.ts +0 -2
  65. package/src/models/port-manager.ts +154 -35
  66. package/src/schema/autogeneratedSchema.json +18 -18
  67. package/src/typings/application.ts +8 -4
  68. package/src/typings/configEntry/cli.ts +1 -1
  69. package/src/validators/commands/checkSwcDependencies.spec.ts +117 -0
  70. package/src/validators/commands/checkSwcDependencies.ts +40 -0
@@ -3,7 +3,6 @@ import supertest from 'supertest';
3
3
  import { outputFile } from 'fs-extra';
4
4
  import { start } from '@tramvai/cli';
5
5
  import type { PromiseType } from 'utility-types';
6
- import { getPort } from '@tramvai/internal-test-utils/utils/getPort';
7
6
  import { getServerUrl } from '@tramvai/test-integration';
8
7
  import { initPlaywright } from '@tramvai/test-pw';
9
8
  import { createServer } from '../utils/createServer';
@@ -49,16 +48,14 @@ describe('@tramvai/cli start command', () => {
49
48
  let startResult: PromiseType<ReturnType<typeof start>>;
50
49
 
51
50
  beforeAll(async () => {
52
- serverPort = await getPort();
53
- staticServerPort = await getPort();
54
-
55
51
  startResult = await start({
56
52
  rootDir: FIXTURES_DIR,
57
53
  target: 'app',
58
54
  resolveSymlinks: false,
59
- port: serverPort,
60
- staticPort: staticServerPort,
61
55
  });
56
+
57
+ serverPort = getListeningPort(startResult.server);
58
+ staticServerPort = getListeningPort(startResult.staticServer);
62
59
  });
63
60
 
64
61
  afterAll(() => {
@@ -66,15 +63,6 @@ describe('@tramvai/cli start command', () => {
66
63
  });
67
64
 
68
65
  it('should start application by target', async () => {
69
- const { server, staticServer } = startResult;
70
-
71
- expect(server?.address()).toMatchObject({
72
- port: serverPort,
73
- });
74
- expect(staticServer?.address()).toMatchObject({
75
- port: staticServerPort,
76
- });
77
-
78
66
  const responseServer = await supertestByPort(serverPort).get('/').expect(200);
79
67
 
80
68
  expect(responseServer.text)
@@ -162,15 +150,10 @@ describe('@tramvai/cli start command', () => {
162
150
  });
163
151
 
164
152
  it('should start application from config', async () => {
165
- const serverPort = await getPort();
166
- const staticServerPort = await getPort();
167
-
168
153
  const root = resolve(FIXTURES_DIR, 'app');
169
154
  const { server, staticServer, close } = await start({
170
155
  rootDir: root,
171
156
  resolveSymlinks: false,
172
- port: serverPort,
173
- staticPort: staticServerPort,
174
157
  config: {
175
158
  name: 'app',
176
159
  type: 'application',
@@ -178,12 +161,11 @@ describe('@tramvai/cli start command', () => {
178
161
  },
179
162
  });
180
163
 
181
- expect(server?.address()).toMatchObject({
182
- port: serverPort,
183
- });
184
- expect(staticServer?.address()).toMatchObject({
185
- port: staticServerPort,
186
- });
164
+ const serverPort = getListeningPort(server);
165
+ const staticServerPort = getListeningPort(staticServer);
166
+
167
+ expect(serverPort).toEqual(expect.any(Number));
168
+ expect(staticServerPort).toEqual(expect.any(Number));
187
169
 
188
170
  const responseServer = await supertestByPort(serverPort).get('/').expect(200);
189
171
 
@@ -201,39 +183,12 @@ describe('@tramvai/cli start command', () => {
201
183
  return close();
202
184
  });
203
185
 
204
- it('should start server on random ports', async () => {
205
- const { server, staticServer, close } = await start({
206
- rootDir: FIXTURES_DIR,
207
- target: 'app',
208
- port: 0,
209
- staticPort: 0,
210
- resolveSymlinks: false,
211
- });
212
-
213
- expect(server?.address()).toMatchObject({
214
- port: expect.any(Number),
215
- });
216
- expect(staticServer?.address()).toMatchObject({
217
- port: expect.any(Number),
218
- });
219
-
220
- await supertestByPort(getListeningPort(server)).get('/').expect(200);
221
-
222
- const testStatic = supertestByPort(getListeningPort(staticServer));
223
- await testStatic.get('/dist/client/platform.js').expect(200);
224
- await testStatic.get('/dist/server/server.js').expect(200);
225
-
226
- return close();
227
- });
228
-
229
186
  // eslint-disable-next-line jest/expect-expect
230
187
  it('should allow to exclude bundles from build', async () => {
231
188
  let { server, close } = await start({
232
189
  rootDir: FIXTURES_DIR,
233
190
  target: 'app',
234
191
  resolveSymlinks: false,
235
- port: 0,
236
- staticPort: 0,
237
192
  });
238
193
 
239
194
  let testServer = supertestByPort(getListeningPort(server));
@@ -250,8 +205,6 @@ describe('@tramvai/cli start command', () => {
250
205
  target: 'app',
251
206
  resolveSymlinks: false,
252
207
  onlyBundles: ['main', 'second'],
253
- port: 0,
254
- staticPort: 0,
255
208
  }));
256
209
 
257
210
  testServer = supertestByPort(getListeningPort(server));
@@ -264,14 +217,12 @@ describe('@tramvai/cli start command', () => {
264
217
  return close();
265
218
  });
266
219
 
267
- it('should NOT try to launch app on the next available port if it was provided via config', async () => {
220
+ it('should NOT try to launch app at the next available port if it was provided via config', async () => {
268
221
  const testServerStub = createServer();
269
222
  const testStaticServerStub = createServer();
270
223
 
271
- // To avoid situation when two subsequent calls
272
- // of the `detectPortSync` return the same free port.
273
- await listenServer(testServerStub, '0.0.0.0', getPort() + 50);
274
- await listenServer(testStaticServerStub, '0.0.0.0', getPort());
224
+ await listenServer(testServerStub, '0.0.0.0', 0);
225
+ await listenServer(testStaticServerStub, '0.0.0.0', 0);
275
226
 
276
227
  await expect(
277
228
  start({
@@ -285,35 +236,6 @@ describe('@tramvai/cli start command', () => {
285
236
 
286
237
  return Promise.all([stopServer(testServerStub), stopServer(testStaticServerStub)]);
287
238
  });
288
-
289
- it('should try to launch app on the next available port if it was NOT provided via config', async () => {
290
- const testServerStub = createServer();
291
- const testStaticServerStub = createServer();
292
-
293
- await listenServer(testServerStub, '0.0.0.0', PortManager.DEFAULT_PORT);
294
- await listenServer(testStaticServerStub, '0.0.0.0', PortManager.DEFAULT_STATIC_PORT);
295
-
296
- const { server, staticServer, close } = await start({
297
- rootDir: FIXTURES_DIR,
298
- target: 'app',
299
- resolveSymlinks: false,
300
- });
301
-
302
- const testServer = supertestByPort(getListeningPort(server));
303
- const testStatic = supertestByPort(getListeningPort(staticServer));
304
-
305
- expect(server?.address()).toMatchObject({
306
- port: expect.any(Number),
307
- });
308
- expect(staticServer?.address()).toMatchObject({
309
- port: expect.any(Number),
310
- });
311
-
312
- await testServer.get('/').expect(200);
313
- await testStatic.get('/').expect(404);
314
-
315
- return Promise.all([close(), stopServer(testServerStub), stopServer(testStaticServerStub)]);
316
- });
317
239
  });
318
240
 
319
241
  describe('module', () => {
@@ -323,7 +245,6 @@ describe('@tramvai/cli start command', () => {
323
245
  rootDir: FIXTURES_DIR,
324
246
  target: 'module',
325
247
  resolveSymlinks: false,
326
- port: 0,
327
248
  });
328
249
 
329
250
  const testStatic = supertestByPort(getListeningPort(staticServer));
@@ -335,22 +256,20 @@ describe('@tramvai/cli start command', () => {
335
256
  });
336
257
 
337
258
  it('should start module by specific config', async () => {
338
- const staticServerPort = getPort();
339
-
340
259
  const { staticServer, close } = await start({
341
260
  config: {
342
261
  type: 'module',
343
262
  name: 'module',
344
263
  root: resolve(FIXTURES_DIR, 'module'),
345
264
  },
346
- port: staticServerPort,
265
+ port: PortManager.DEFAULT_MODULE_STATIC_PORT,
347
266
  });
348
267
 
349
268
  expect(staticServer?.address()).toMatchObject({
350
- port: staticServerPort,
269
+ port: PortManager.DEFAULT_MODULE_STATIC_PORT,
351
270
  });
352
271
 
353
- const testStatic = supertestByPort(staticServerPort);
272
+ const testStatic = supertestByPort(PortManager.DEFAULT_MODULE_STATIC_PORT);
354
273
 
355
274
  await testStatic.get('/module/0.1.0/module_server.js').expect(200);
356
275
  await testStatic.get('/module/0.1.0/module_client.js').expect(200);
@@ -54,13 +54,15 @@ export const sharedProviders: readonly Provider[] = [
54
54
  provide({
55
55
  provide: CLOSE_HANDLER_TOKEN,
56
56
  multi: true,
57
- useFactory: ({ staticServer }) => {
58
- return () => {
57
+ useFactory: ({ staticServer, portManager }) => {
58
+ return async () => {
59
+ await portManager.cleanup();
59
60
  return stopServer(staticServer);
60
61
  };
61
62
  },
62
63
  deps: {
63
64
  staticServer: STATIC_SERVER_TOKEN,
65
+ portManager: PORT_MANAGER_TOKEN,
64
66
  },
65
67
  }),
66
68
  ] as const;
@@ -23,6 +23,7 @@ export const sharedProviders: readonly Provider[] = [
23
23
  appEnv: parameters.env,
24
24
  env: 'development',
25
25
  port: portManager.port,
26
+ staticPort: portManager.staticPort,
26
27
  }),
27
28
  deps: {
28
29
  configEntry: CONFIG_ENTRY_TOKEN,
@@ -52,13 +53,15 @@ export const sharedProviders: readonly Provider[] = [
52
53
  provide({
53
54
  provide: CLOSE_HANDLER_TOKEN,
54
55
  multi: true,
55
- useFactory: ({ staticServer }) => {
56
- return () => {
56
+ useFactory: ({ staticServer, portManager }) => {
57
+ return async () => {
58
+ await portManager.cleanup();
57
59
  return stopServer(staticServer);
58
60
  };
59
61
  },
60
62
  deps: {
61
63
  staticServer: STATIC_SERVER_TOKEN,
64
+ portManager: PORT_MANAGER_TOKEN,
62
65
  },
63
66
  }),
64
67
  ] as const;
@@ -23,6 +23,7 @@ export const sharedProviders: readonly Provider[] = [
23
23
  appEnv: parameters.env,
24
24
  env: 'development',
25
25
  port: portManager.port,
26
+ staticPort: portManager.staticPort,
26
27
  }),
27
28
  deps: {
28
29
  configEntry: CONFIG_ENTRY_TOKEN,
@@ -52,13 +53,15 @@ export const sharedProviders: readonly Provider[] = [
52
53
  provide({
53
54
  provide: CLOSE_HANDLER_TOKEN,
54
55
  multi: true,
55
- useFactory: ({ staticServer }) => {
56
- return () => {
56
+ useFactory: ({ staticServer, portManager }) => {
57
+ return async () => {
58
+ await portManager.cleanup();
57
59
  return stopServer(staticServer);
58
60
  };
59
61
  },
60
62
  deps: {
61
63
  staticServer: STATIC_SERVER_TOKEN,
64
+ portManager: PORT_MANAGER_TOKEN,
62
65
  },
63
66
  }),
64
67
  ] as const;
@@ -5,6 +5,7 @@ export const stopServer = async (server: StoppableServer) => {
5
5
  server.stop((err) => {
6
6
  if (err) {
7
7
  reject(err);
8
+
8
9
  return;
9
10
  }
10
11
 
@@ -1,6 +1,6 @@
1
1
  import type { Container } from '@tinkoff/dippy';
2
2
  import type { Params, Result } from './index';
3
- import { COMMAND_PARAMETERS_TOKEN, PORT_MANAGER_TOKEN, STATIC_SERVER_TOKEN } from '../../di/tokens';
3
+ import { COMMAND_PARAMETERS_TOKEN, STATIC_SERVER_TOKEN } from '../../di/tokens';
4
4
  import {
5
5
  INIT_HANDLER_TOKEN,
6
6
  CLOSE_HANDLER_TOKEN,
@@ -15,9 +15,6 @@ import { build } from '..';
15
15
 
16
16
  export const startProdApplication = async (di: Container): Result => {
17
17
  const parameters = di.get(COMMAND_PARAMETERS_TOKEN) as Params;
18
- const portManager = di.get(PORT_MANAGER_TOKEN);
19
-
20
- await portManager.computeAvailablePorts();
21
18
 
22
19
  registerProviders(di, [...sharedProviders, ...applicationsProviders]);
23
20
 
@@ -5,7 +5,7 @@ import fastifyCompress from '@fastify/compress';
5
5
  import fastifyStatic from '@fastify/static';
6
6
  import zlib from 'zlib';
7
7
  import { CLOSE_HANDLER_TOKEN, INIT_HANDLER_TOKEN, PROCESS_HANDLER_TOKEN } from '../tokens';
8
- import { CONFIG_MANAGER_TOKEN, STATIC_SERVER_TOKEN } from '../../../di/tokens';
8
+ import { CONFIG_MANAGER_TOKEN, PORT_MANAGER_TOKEN, STATIC_SERVER_TOKEN } from '../../../di/tokens';
9
9
  import { createServer } from '../../start/utils/createServer';
10
10
  import { stopServer } from '../../start/utils/stopServer';
11
11
  import { listenServer } from '../../start/utils/listenServer';
@@ -82,13 +82,16 @@ export const sharedProviders: readonly Provider[] = [
82
82
  provide({
83
83
  provide: CLOSE_HANDLER_TOKEN,
84
84
  multi: true,
85
- useFactory: ({ staticServer }) => {
85
+ useFactory: ({ staticServer, portManager }) => {
86
86
  return async () => {
87
+ await portManager.cleanup();
88
+
87
89
  return stopServer(staticServer);
88
90
  };
89
91
  },
90
92
  deps: {
91
93
  staticServer: STATIC_SERVER_TOKEN,
94
+ portManager: PORT_MANAGER_TOKEN,
92
95
  },
93
96
  }),
94
97
  ] as const;
@@ -3,6 +3,7 @@ import { checkApplication } from '../../validators/commands/checkBuild';
3
3
  import { checkConfigExists } from '../../validators/commands/checkConfigExists';
4
4
  import { checkPwaDependencies } from '../../validators/commands/checkPwaDependencies';
5
5
  import { runMigrationsAndCheckVersions } from '../../validators/commands/runMigrationsAndCheckVersions';
6
+ import { checkSwcDependencies } from '../../validators/commands/checkSwcDependencies';
6
7
 
7
8
  export type Params = {
8
9
  target: string;
@@ -49,6 +50,7 @@ class AnalyzeCommand extends CLICommand<Params> {
49
50
  checkApplication,
50
51
  runMigrationsAndCheckVersions,
51
52
  checkPwaDependencies,
53
+ checkSwcDependencies,
52
54
  ];
53
55
 
54
56
  action(parameters: Params) {
@@ -5,6 +5,7 @@ import { checkDependencies } from '../../validators/commands/checkDependencies';
5
5
  import { runMigrationsAndCheckVersions } from '../../validators/commands/runMigrationsAndCheckVersions';
6
6
  import type { BuildCommand as BuildCommandType } from '../../api/build';
7
7
  import { checkPwaDependencies } from '../../validators/commands/checkPwaDependencies';
8
+ import { checkSwcDependencies } from '../../validators/commands/checkSwcDependencies';
8
9
 
9
10
  export type Params = Parameters<BuildCommandType>[0] & {
10
11
  target: string;
@@ -83,6 +84,7 @@ class BuildCommand extends CLICommand<Params> {
83
84
  runMigrationsAndCheckVersions,
84
85
  checkDependencies,
85
86
  checkPwaDependencies,
87
+ checkSwcDependencies,
86
88
  ];
87
89
 
88
90
  action(parameters: Params) {
@@ -5,6 +5,7 @@ import { checkDependencies } from '../../validators/commands/checkDependencies';
5
5
  import { runMigrationsAndCheckVersions } from '../../validators/commands/runMigrationsAndCheckVersions';
6
6
  import type { StartCommand as StartCommandType } from '../../api/start';
7
7
  import { checkPwaDependencies } from '../../validators/commands/checkPwaDependencies';
8
+ import { checkSwcDependencies } from '../../validators/commands/checkSwcDependencies';
8
9
 
9
10
  export type Params = Parameters<StartCommandType>[0] & {
10
11
  target: string;
@@ -120,6 +121,7 @@ export class StartCommand extends CLICommand<Params> {
120
121
  runMigrationsAndCheckVersions,
121
122
  checkDependencies,
122
123
  checkPwaDependencies,
124
+ checkSwcDependencies,
123
125
  ];
124
126
 
125
127
  action(parameters) {
@@ -3,6 +3,7 @@ import { checkConfigExists } from '../../validators/commands/checkConfigExists';
3
3
  import { checkApplication } from '../../validators/commands/checkBuild';
4
4
  import { runMigrationsAndCheckVersions } from '../../validators/commands/runMigrationsAndCheckVersions';
5
5
  import { checkPwaDependencies } from '../../validators/commands/checkPwaDependencies';
6
+ import { checkSwcDependencies } from '../../validators/commands/checkSwcDependencies';
6
7
 
7
8
  export interface Params {
8
9
  target: string;
@@ -93,6 +94,7 @@ export class StartProdCommand extends CLICommand<Params> {
93
94
  checkApplication,
94
95
  runMigrationsAndCheckVersions,
95
96
  checkPwaDependencies,
97
+ checkSwcDependencies,
96
98
  ];
97
99
 
98
100
  action(parameters: Params) {
@@ -26,17 +26,21 @@ export const staticApp = async (
26
26
  configEntry: ApplicationConfigEntry,
27
27
  options: Params
28
28
  ): Promise<CommandResult> => {
29
- const network = new PortManager({ configEntry, commandParams: options });
29
+ const portManager = new PortManager({
30
+ configEntry,
31
+ commandParams: options,
32
+ logger: context.logger,
33
+ });
30
34
 
31
- await network.computeAvailablePorts();
35
+ await portManager.computeAvailablePorts();
32
36
 
33
37
  const clientConfigManager = createConfigManager<ApplicationConfigEntry>(configEntry, {
34
38
  env: 'production',
35
39
  ...options,
36
40
  buildType: 'client',
37
41
  modern: false,
38
- port: network.port,
39
- staticPort: network.staticPort,
42
+ port: portManager.port,
43
+ staticPort: portManager.staticPort,
40
44
  });
41
45
  const serverConfigManager = clientConfigManager.withSettings({ buildType: 'server' });
42
46
 
@@ -193,6 +197,8 @@ export const staticApp = async (
193
197
  staticServer.close();
194
198
  }
195
199
 
200
+ await portManager.cleanup();
201
+
196
202
  return {
197
203
  status: 'ok',
198
204
  message: 'application static generate success',
@@ -3,6 +3,7 @@ import type { Provider } from '@tinkoff/dippy';
3
3
 
4
4
  import { COMMAND_PARAMETERS_TOKEN, CONFIG_ENTRY_TOKEN, PORT_MANAGER_TOKEN } from '../tokens';
5
5
  import { PortManager } from '../../models/port-manager';
6
+ import { Logger } from '../../models/logger';
6
7
 
7
8
  export const networkProviders: readonly Provider[] = [
8
9
  provide({
@@ -11,6 +12,11 @@ export const networkProviders: readonly Provider[] = [
11
12
  deps: {
12
13
  configEntry: CONFIG_ENTRY_TOKEN,
13
14
  commandParams: COMMAND_PARAMETERS_TOKEN,
15
+ logger: 'network logger',
14
16
  },
15
17
  }),
18
+ provide({
19
+ provide: 'network logger',
20
+ useClass: Logger,
21
+ }),
16
22
  ] as const;
@@ -30,8 +30,6 @@ const getModuleCode = (code: string, name: string) => {
30
30
  beforeAll(async () => {
31
31
  app = await start({
32
32
  rootDir: __dirname,
33
- port: 0,
34
- staticPort: 0,
35
33
  strictErrorHandle: true,
36
34
  config: {
37
35
  name: 'swc-app',