@into-cps-association/libms 0.4.5 → 0.5.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 (127) hide show
  1. package/DEVELOPER.md +80 -0
  2. package/DOCKER.md +295 -0
  3. package/README.md +8 -0
  4. package/compose.lib.dev.yml +9 -0
  5. package/compose.lib.yml +8 -0
  6. package/dist/src/app.module.d.ts +2 -1
  7. package/dist/src/app.module.js +14 -16
  8. package/dist/src/app.module.js.map +1 -1
  9. package/dist/src/bootstrap.d.ts +3 -3
  10. package/dist/src/bootstrap.js +13 -13
  11. package/dist/src/bootstrap.js.map +1 -1
  12. package/dist/src/cloudcmd/cloudcmd.d.ts +1 -5
  13. package/dist/src/cloudcmd/cloudcmd.js +15 -9
  14. package/dist/src/cloudcmd/cloudcmd.js.map +1 -1
  15. package/dist/src/enums/config-mode.enum.d.ts +4 -0
  16. package/dist/src/enums/config-mode.enum.js +6 -0
  17. package/dist/src/enums/config-mode.enum.js.map +1 -0
  18. package/dist/src/files/files-service.factory.d.ts +5 -0
  19. package/dist/src/files/files-service.factory.js +22 -0
  20. package/dist/src/files/files-service.factory.js.map +1 -0
  21. package/dist/src/files/files.module.d.ts +2 -1
  22. package/dist/src/files/files.module.js +23 -9
  23. package/dist/src/files/files.module.js.map +1 -1
  24. package/dist/src/files/files.resolver.d.ts +8 -0
  25. package/dist/src/files/{resolvers/files.resolver.js → files.resolver.js} +14 -14
  26. package/dist/src/files/files.resolver.js.map +1 -0
  27. package/dist/src/files/git/git-files.module.d.ts +2 -0
  28. package/dist/src/files/git/git-files.module.js +19 -0
  29. package/dist/src/files/git/git-files.module.js.map +1 -0
  30. package/dist/src/files/git/git-files.service.d.ts +14 -0
  31. package/dist/src/files/git/git-files.service.js +67 -0
  32. package/dist/src/files/git/git-files.service.js.map +1 -0
  33. package/dist/src/files/interfaces/files.service.interface.d.ts +6 -3
  34. package/dist/src/files/interfaces/files.service.interface.js +1 -2
  35. package/dist/src/files/interfaces/files.service.interface.js.map +1 -1
  36. package/dist/src/files/local/local-files.module.d.ts +2 -0
  37. package/dist/src/files/local/local-files.module.js +18 -0
  38. package/dist/src/files/local/local-files.module.js.map +1 -0
  39. package/dist/src/files/local/local-files.service.d.ts +14 -0
  40. package/dist/src/files/{services → local}/local-files.service.js +17 -15
  41. package/dist/src/files/local/local-files.service.js.map +1 -0
  42. package/dist/src/main.js +4 -6
  43. package/dist/src/main.js.map +1 -1
  44. package/dist/src/types.d.ts +19 -19
  45. package/dist/src/types.js +56 -59
  46. package/dist/src/types.js.map +1 -1
  47. package/dist/test/cloudcmd/cloudcmd.spec.js +14 -16
  48. package/dist/test/cloudcmd/cloudcmd.spec.js.map +1 -1
  49. package/dist/test/e2e/app.e2e.spec.js +18 -18
  50. package/dist/test/e2e/app.e2e.spec.js.map +1 -1
  51. package/dist/test/integration/files.service.integration.spec.js +28 -19
  52. package/dist/test/integration/files.service.integration.spec.js.map +1 -1
  53. package/dist/test/testUtil.d.ts +66 -68
  54. package/dist/test/testUtil.js +21 -23
  55. package/dist/test/testUtil.js.map +1 -1
  56. package/dist/test/unit/files-service.factory.unit.spec.js +22 -16
  57. package/dist/test/unit/files-service.factory.unit.spec.js.map +1 -1
  58. package/dist/test/unit/files.resolver.unit.spec.js +26 -24
  59. package/dist/test/unit/files.resolver.unit.spec.js.map +1 -1
  60. package/dist/test/unit/git-files.service.unit.spec.d.ts +1 -0
  61. package/dist/test/unit/git-files.service.unit.spec.js +55 -0
  62. package/dist/test/unit/git-files.service.unit.spec.js.map +1 -0
  63. package/dist/test/unit/local-files.service.unit.spec.js +23 -24
  64. package/dist/test/unit/local-files.service.unit.spec.js.map +1 -1
  65. package/dist/tsconfig.tsbuildinfo +1 -1
  66. package/eslint.config.js +60 -0
  67. package/jest.config.ts +47 -0
  68. package/package.json +55 -48
  69. package/src/app.module.ts +1 -1
  70. package/src/bootstrap.ts +7 -3
  71. package/src/cloudcmd/cloudcmd.ts +11 -3
  72. package/src/enums/config-mode.enum.ts +4 -0
  73. package/src/files/files-service.factory.ts +19 -0
  74. package/src/files/files.module.ts +24 -4
  75. package/src/files/{resolvers/files.resolver.ts → files.resolver.ts} +9 -8
  76. package/src/files/git/git-files.module.ts +9 -0
  77. package/src/files/git/git-files.service.ts +58 -0
  78. package/src/files/interfaces/files.service.interface.ts +4 -1
  79. package/src/files/local/local-files.module.ts +8 -0
  80. package/src/files/{services → local}/local-files.service.ts +15 -10
  81. package/src/main.ts +1 -1
  82. package/test/cloudcmd/cloudcmd.spec.ts +4 -6
  83. package/test/e2e/app.e2e.spec.ts +4 -3
  84. package/test/integration/files.service.integration.spec.ts +19 -4
  85. package/test/testUtil.ts +3 -0
  86. package/test/unit/files-service.factory.unit.spec.ts +24 -10
  87. package/test/unit/files.resolver.unit.spec.ts +19 -12
  88. package/test/unit/git-files.service.unit.spec.ts +81 -0
  89. package/test/unit/local-files.service.unit.spec.ts +4 -2
  90. package/tsconfig.json +10 -7
  91. package/.env +0 -6
  92. package/.eslintignore +0 -6
  93. package/.eslintrc +0 -53
  94. package/coverage/clover.xml +0 -162
  95. package/coverage/cobertura-coverage.xml +0 -306
  96. package/coverage/coverage-final.json +0 -8
  97. package/coverage/lcov-report/base.css +0 -224
  98. package/coverage/lcov-report/block-navigation.js +0 -87
  99. package/coverage/lcov-report/favicon.png +0 -0
  100. package/coverage/lcov-report/index.html +0 -176
  101. package/coverage/lcov-report/prettify.css +0 -1
  102. package/coverage/lcov-report/prettify.js +0 -2
  103. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  104. package/coverage/lcov-report/sorter.js +0 -196
  105. package/coverage/lcov-report/src/bootstrap.ts.html +0 -196
  106. package/coverage/lcov-report/src/cloudcmd/cloudcmd.ts.html +0 -181
  107. package/coverage/lcov-report/src/cloudcmd/index.html +0 -116
  108. package/coverage/lcov-report/src/files/files.module.ts.html +0 -112
  109. package/coverage/lcov-report/src/files/index.html +0 -116
  110. package/coverage/lcov-report/src/files/resolvers/files.resolver.ts.html +0 -154
  111. package/coverage/lcov-report/src/files/resolvers/index.html +0 -116
  112. package/coverage/lcov-report/src/files/services/files-service.factory.ts.html +0 -151
  113. package/coverage/lcov-report/src/files/services/index.html +0 -131
  114. package/coverage/lcov-report/src/files/services/local-files.service.ts.html +0 -313
  115. package/coverage/lcov-report/src/index.html +0 -131
  116. package/coverage/lcov-report/src/types.ts.html +0 -361
  117. package/coverage/lcov.info +0 -237
  118. package/dist/src/files/resolvers/files.resolver.d.ts +0 -8
  119. package/dist/src/files/resolvers/files.resolver.js.map +0 -1
  120. package/dist/src/files/services/files-service.factory.d.ts +0 -12
  121. package/dist/src/files/services/files-service.factory.js +0 -40
  122. package/dist/src/files/services/files-service.factory.js.map +0 -1
  123. package/dist/src/files/services/local-files.service.d.ts +0 -11
  124. package/dist/src/files/services/local-files.service.js.map +0 -1
  125. package/jest.config.json +0 -30
  126. package/src/files/services/files-service.factory.ts +0 -22
  127. /package/{pm2.config.js → pm2.config.cjs} +0 -0
@@ -0,0 +1,60 @@
1
+ import { fixupConfigRules } from '@eslint/compat';
2
+ import { FlatCompat } from '@eslint/eslintrc';
3
+ import globals from 'globals';
4
+ import jest from 'eslint-plugin-jest';
5
+ import js from '@eslint/js';
6
+ import prettier from 'eslint-config-prettier';
7
+ import ts from '@typescript-eslint/eslint-plugin';
8
+ import tsParser from '@typescript-eslint/parser';
9
+ import imprt from 'eslint-plugin-import'; // 'import' is ambiguous & prettier has trouble
10
+
11
+ const flatCompat = new FlatCompat();
12
+
13
+ export default [
14
+ {
15
+ ...js.configs.recommended,
16
+ files: ['src/**', 'test/**'],
17
+ },
18
+ {
19
+ ...fixupConfigRules(flatCompat.extends('airbnb-base')),
20
+ files: ['src/**', 'test/**'],
21
+ },
22
+ prettier,
23
+ {
24
+ languageOptions: {
25
+ globals: {
26
+ ...globals.jest,
27
+ ...globals.node,
28
+ Atomics: 'readonly',
29
+ SharedArrayBuffer: 'readonly',
30
+ },
31
+ parser: tsParser,
32
+ parserOptions: {
33
+ project: './tsconfig.json',
34
+ requireConfigFile: false,
35
+ ecmaVersion: 2022,
36
+ ecmaFeatures: { modules: true },
37
+ },
38
+ },
39
+ files: ['src/**', 'test/**'],
40
+ plugins: { jest, '@typescript-eslint': ts, import: imprt, ts },
41
+ rules: {
42
+ 'import/no-extraneous-dependencies': ['error', { devDependencies: true }],
43
+ 'no-console': 'error',
44
+ 'import/first': 'error',
45
+ 'linebreak-style': 0, // disable linter linebreak rule, to allow for both unix and windows developement
46
+ 'import/no-unresolved': 'off', // Whatever IDE will pass an error if if the module is not found, so no reason for this..
47
+ 'import/extensions': 'off', // That includes the production build.. We use linter for code checking / clean code optimization..
48
+ 'no-use-before-define': 'off',
49
+ },
50
+ ignores: [
51
+ 'api/*',
52
+ 'build/*',
53
+ 'coverage/*',
54
+ 'dist/*',
55
+ 'node_modules/*',
56
+ 'script/*',
57
+ 'src/types.ts',
58
+ ],
59
+ },
60
+ ];
package/jest.config.ts ADDED
@@ -0,0 +1,47 @@
1
+ import { createDefaultEsmPreset, type JestConfigWithTsJest } from 'ts-jest';
2
+
3
+ const jestConfig: JestConfigWithTsJest = {
4
+ testEnvironment: 'node',
5
+ transform: {
6
+ ...createDefaultEsmPreset().transform,
7
+ '\\.[jt]sx?$": "ts-jest': [
8
+ 'ts-jest',
9
+ {
10
+ useESM: true,
11
+ },
12
+ ],
13
+ },
14
+ collectCoverage: true,
15
+ coverageReporters: ['text', 'cobertura', 'clover', 'lcov', 'json'],
16
+ collectCoverageFrom: ['src/**/*.{ts,js}'],
17
+ coveragePathIgnorePatterns: [
18
+ 'node_modules',
19
+ './dist',
20
+ './src/app.module.ts',
21
+ './src/main.ts',
22
+ './src/bootstrap.ts',
23
+ ],
24
+ extensionsToTreatAsEsm: ['.ts'],
25
+ moduleFileExtensions: ['js', 'json', 'ts'],
26
+ modulePathIgnorePatterns: [],
27
+ coverageDirectory: '<rootDir>/coverage/',
28
+ coverageThreshold: {
29
+ global: {
30
+ branches: 20,
31
+ functions: 30,
32
+ lines: 50,
33
+ statements: 50,
34
+ },
35
+ },
36
+ verbose: true,
37
+ testRegex: './test/.*\\.spec.tsx?$',
38
+ modulePaths: ['<rootDir>', '<rootDir>/src/', '<rootDir>/test/'],
39
+ moduleDirectories: ['node_modules', 'src', 'test'],
40
+ rootDir: './',
41
+ roots: ['<rootDir>', 'src/', 'test/'],
42
+ moduleNameMapper: {
43
+ '^(\\.\\.?\\/.+)\\.jsx?$': '$1',
44
+ },
45
+ };
46
+
47
+ export default jestConfig;
package/package.json CHANGED
@@ -1,81 +1,88 @@
1
1
  {
2
2
  "name": "@into-cps-association/libms",
3
- "version": "0.4.5",
3
+ "version": "0.5.0",
4
4
  "description": "microservices that handles request by fetching and returning the file-names and folders of given directory",
5
5
  "author": "phillip.boe.jensen@gmail.com",
6
6
  "contributors": [
7
7
  "Prasad Talasila",
8
8
  "Mads Kelberg",
9
- "Linda Nguyen"
9
+ "Linda Nguyen",
10
+ "Nichlaes H. Sørensen"
10
11
  ],
11
12
  "private": false,
12
13
  "license": "SEE LICENSE IN <LICENSE.md>",
14
+ "type": "module",
15
+ "main": "dist/src/main.js",
13
16
  "scripts": {
14
- "build": "npx tsc",
17
+ "build": "tsc",
15
18
  "clean": "npx rimraf build node_modules coverage dist src.svg test.svg",
16
19
  "format": "prettier --ignore-path ../.gitignore --write \"**/*.{ts,tsx,css,scss}\"",
17
20
  "graph": "npx madge --image src.svg src && npx madge --image test.svg test",
18
- "start": "node dist/src/main.js",
19
- "start:pm2": "pm2 start pm2.config.js",
21
+ "start": "tsc & node dist/src/main.js",
22
+ "start:pm2": "pm2 start pm2.config.cjs",
20
23
  "stop:pm2": "pm2 delete libms",
21
- "syntax": "npx eslint . --fix",
24
+ "syntax": "eslint . --fix",
22
25
  "pretest": "npx shx cp test/data/user2/tools/README.md ../../files/user2/tools/README.md",
23
26
  "posttest": "npx rimraf ../../files/user2/tools/README.md",
24
- "test:all": "npx cross-env LOCAL_PATH=test/data jest --testPathIgnorePatterns=cloudcmd --coverage",
25
- "test:e2e": "npx cross-env LOCAL_PATH=test/data jest --config ./test/jest-e2e.json --coverage",
27
+ "test:all": "npx cross-env NODE_OPTIONS=--experimental-vm-modules LOCAL_PATH=test/data jest --testPathIgnorePatterns=cloudcmd --coverage",
28
+ "test:e2e": "npx cross-env NODE_OPTIONS=--experimental-vm-modules LOCAL_PATH=test/data jest --config ./test/jest-e2e.json --coverage",
26
29
  "test:http": "yarn build && pm2 start -f --name libms-test dist/src/main.js -- -c .env -H ./config/http.json && jest test/cloudcmd --coverage --coverageThreshold=\"{}\" && pm2 delete libms-test",
27
30
  "test:http-nocov": "yarn build && pm2 start -f --name libms-test dist/src/main.js -- -c .env -H ./config/http.json && jest test/cloudcmd --coverage=false && pm2 delete libms-test",
28
- "test:http-github": "yarn build && yarn start:pm2 && jest test/cloudcmd --coverage --coverageThreshold=\"{}\" && pm2 delete libms",
29
- "test:int": "npx cross-env LOCAL_PATH=test/data jest ../test/integration --coverage",
31
+ "test:http-github": "jest test/cloudcmd --coverage --coverageThreshold=\"{}\"",
32
+ "test:int": "npx cross-env NODE_OPTIONS=--experimental-vm-modules LOCAL_PATH=test/data jest ../test/integration --coverage",
30
33
  "test:nocov": "yarn test:http-nocov && npx cross-env LOCAL_PATH=test/data jest --testPathIgnorePatterns=cloudcmd --coverage=false",
31
- "test:unit": "npx cross-env LOCAL_PATH=test/data jest ../test/unit --coverage"
34
+ "test:unit": "npx cross-env NODE_OPTIONS=--experimental-vm-modules LOCAL_PATH=test/data jest ../test/unit --coverage"
32
35
  },
33
36
  "bin": "./dist/src/main.js",
34
37
  "dependencies": {
35
- "@apollo/client": "^3.8.9",
36
- "@apollo/server": "^4.10.0",
37
- "@nestjs/apollo": "^12.0.11",
38
- "@nestjs/common": "^10.3.7",
39
- "@nestjs/config": "^3.2.0",
40
- "@nestjs/core": "^10.3.3",
41
- "@nestjs/graphql": "^12.0.11",
42
- "@nestjs/platform-express": "^10.3.7",
43
- "axios": "^1.5.1",
44
- "cloudcmd": "^16.17.7",
45
- "commander": "^11.1.0",
46
- "dotenv": "^16.3.1",
47
- "graphql": "^16.8.1",
48
- "mock-fs": "^5.2.0",
49
- "reflect-metadata": "^0.2.1",
38
+ "@apollo/client": "^3.11.8",
39
+ "@apollo/server": "^4.11.0",
40
+ "@nestjs/apollo": "^12.2.0",
41
+ "@nestjs/common": "^10.4.4",
42
+ "@nestjs/config": "^3.2.3",
43
+ "@nestjs/core": "^10.4.4",
44
+ "@nestjs/graphql": "^12.2.0",
45
+ "@nestjs/platform-express": "^10.4.4",
46
+ "axios": "^1.7.7",
47
+ "cloudcmd": "^18.1.0",
48
+ "commander": "^12.1.0",
49
+ "dotenv": "^16.4.5",
50
+ "globals": "^15.11.0",
51
+ "graphql": "^16.9.0",
52
+ "isomorphic-git": "^1.27.1",
53
+ "mock-fs": "^5.3.0",
54
+ "reflect-metadata": "^0.2.2",
50
55
  "rxjs": "^7.8.1",
51
- "socket.io": "^4.7.2",
52
- "type-graphql": "^2.0.0-beta.3"
56
+ "socket.io": "^4.8.0",
57
+ "type-graphql": "^2.0.0-rc.2"
53
58
  },
54
59
  "devDependencies": {
55
- "@nestjs/cli": "^10.3.2",
56
- "@nestjs/schematics": "^10.1.1",
57
- "@nestjs/testing": "^10.3.3",
58
- "@types/express": "^4.17.21",
59
- "@types/jest": "^29.5.12",
60
- "@types/node": "20.12.5",
60
+ "@eslint/compat": "^1.2.2",
61
+ "@eslint/eslintrc": "^3.1.0",
62
+ "@nestjs/cli": "^10.4.5",
63
+ "@nestjs/schematics": "^10.1.4",
64
+ "@nestjs/testing": "^10.4.4",
65
+ "@types/express": "^5.0.0",
66
+ "@types/jest": "^29.5.13",
67
+ "@types/node": "22.7.0",
61
68
  "@types/supertest": "^6.0.2",
62
- "@typescript-eslint/eslint-plugin": "^6.19.0",
63
- "@typescript-eslint/parser": "^6.19.0",
69
+ "@typescript-eslint/eslint-plugin": "^8.12.2",
70
+ "@typescript-eslint/parser": "^8.12.2",
64
71
  "cross-fetch": "^4.0.0",
65
- "eslint": "^8.56.0",
72
+ "eslint": "^9.11.1",
66
73
  "eslint-config-airbnb-base": "^15.0.0",
67
74
  "eslint-config-prettier": "^9.1.0",
68
- "eslint-plugin-import": "^2.29.1",
69
- "eslint-plugin-jest": "^28.2.0",
70
- "eslint-plugin-prettier": "^5.1.3",
71
- "graphql-scalars": "^1.22.2",
72
- "jest": "29.7.0",
73
- "prettier": "^3.2.2",
74
- "react": "^18.2.0",
75
- "supertest": "^6.3.4",
76
- "ts-jest": "^29.1.1",
77
- "ts-node": "^10.9.1",
75
+ "eslint-plugin-import": "^2.31.0",
76
+ "eslint-plugin-jest": "^28.8.3",
77
+ "eslint-plugin-prettier": "^5.2.1",
78
+ "graphql-scalars": "^1.23.0",
79
+ "jest": "^29.7.0",
80
+ "prettier": "^3.3.3",
81
+ "react": "^18.3.1",
82
+ "supertest": "^7.0.0",
83
+ "ts-jest": "^29.2.5",
84
+ "ts-node": "^10.9.2",
78
85
  "tsconfig-paths": "4.2.0",
79
- "typescript": "^5.2.2"
86
+ "typescript": "^5.6.3"
80
87
  }
81
88
  }
package/src/app.module.ts CHANGED
@@ -3,7 +3,7 @@ import { Module } from '@nestjs/common';
3
3
  import { GraphQLModule } from '@nestjs/graphql';
4
4
  import { ApolloDriver } from '@nestjs/apollo';
5
5
  import { join } from 'path';
6
- import FilesModule from './files/files.module';
6
+ import FilesModule from './files/files.module.js';
7
7
 
8
8
  @Module({
9
9
  imports: [
package/src/bootstrap.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { NestFactory } from '@nestjs/core';
2
2
  import { ConfigService } from '@nestjs/config';
3
3
  import * as dotenv from 'dotenv';
4
- import AppModule from './app.module';
5
- import cloudCMD from './cloudcmd/cloudcmd';
4
+ import AppModule from './app.module.js';
5
+ import cloudCMD from './cloudcmd/cloudcmd.js';
6
6
 
7
7
  type BootstrapOptions = {
8
8
  config?: string;
@@ -15,7 +15,7 @@ export default async function bootstrap(options?: BootstrapOptions) {
15
15
  path: options?.config ?? '.env',
16
16
  override: true,
17
17
  });
18
- if (configFile.error) {
18
+ if (configFile.error && process.env.LOCAL_PATH === undefined) {
19
19
  // eslint-disable-next-line no-console
20
20
  console.error(configFile.error);
21
21
  if (options.runHelp) {
@@ -28,6 +28,10 @@ export default async function bootstrap(options?: BootstrapOptions) {
28
28
  const app = await NestFactory.create(AppModule);
29
29
  const configService = app.get(ConfigService);
30
30
  const port = configService.get<number>('PORT');
31
+ const localPath = configService.get<string>('LOCAL_PATH');
32
+ const mode = configService.get<string>('MODE');
33
+
34
+ console.log(`\x1b[32mStarting libms in \x1b[33m${mode} \x1b[32mmode, serving files from \x1b[34m${localPath} \x1b[32mon port \x1b[35m${port}\x1b[0m`);
31
35
 
32
36
  if (options.httpServer) {
33
37
  cloudCMD(app, options.httpServer, configService.get<string>('LOCAL_PATH'));
@@ -1,7 +1,9 @@
1
1
  import { INestApplication } from '@nestjs/common';
2
2
  import { Server } from 'socket.io';
3
- import * as cloudcmd from 'cloudcmd';
4
- import { join } from 'path';
3
+ import cloudcmd from 'cloudcmd';
4
+ import { join, relative } from 'path';
5
+
6
+ const isWindowsAbsolutePath = (filesPath: string) => filesPath.includes(':');
5
7
 
6
8
  const runCloudCMD = (
7
9
  app: INestApplication,
@@ -13,7 +15,13 @@ const runCloudCMD = (
13
15
  configPath: join(process.cwd(), optionsPath),
14
16
  });
15
17
 
16
- configManager('root', filesPath);
18
+ if (isWindowsAbsolutePath(filesPath)) {
19
+ const workDir = process.cwd();
20
+ const relativePath = relative(workDir, filesPath);
21
+ configManager('root', relativePath);
22
+ } else {
23
+ configManager('root', filesPath);
24
+ }
17
25
 
18
26
  const server = app.getHttpServer();
19
27
 
@@ -0,0 +1,4 @@
1
+ export enum CONFIG_MODE {
2
+ GIT = 'git',
3
+ LOCAL = 'local',
4
+ }
@@ -0,0 +1,19 @@
1
+ import { Injectable } from '@nestjs/common';
2
+ import { ConfigService } from '@nestjs/config';
3
+ import { IFilesService } from './interfaces/files.service.interface.js';
4
+
5
+ @Injectable()
6
+ export default class FilesServiceFactory {
7
+ static create(
8
+ configService: ConfigService,
9
+ fileServices: IFilesService[],
10
+ ): IFilesService {
11
+ const mode = configService.get<string>('MODE');
12
+ const service = fileServices.find((s) => s.getMode() == mode);
13
+
14
+ if (service == undefined) {
15
+ throw new Error(`Invalid MODE: ${mode}`);
16
+ }
17
+ return service;
18
+ }
19
+ }
@@ -1,9 +1,29 @@
1
1
  import { Module } from '@nestjs/common';
2
- import FilesResolver from './resolvers/files.resolver';
3
- import FilesServiceFactory from './services/files-service.factory';
4
- import LocalFilesService from './services/local-files.service';
2
+ import FilesResolver from './files.resolver.js';
3
+ import { GitFilesModule } from './git/git-files.module.js';
4
+ import { LocalFilesModule } from './local/local-files.module.js';
5
+ import LocalFilesService from './local/local-files.service.js';
6
+ import GitFilesService from './git/git-files.service.js';
7
+ import { FILE_SERVICE } from './interfaces/files.service.interface.js';
8
+ import FilesServiceFactory from './files-service.factory.js';
9
+ import { ConfigService } from '@nestjs/config';
5
10
 
6
11
  @Module({
7
- providers: [FilesResolver, LocalFilesService, FilesServiceFactory],
12
+ imports: [LocalFilesModule, GitFilesModule],
13
+ providers: [
14
+ FilesResolver,
15
+ {
16
+ provide: FILE_SERVICE,
17
+ useFactory: (
18
+ configService: ConfigService,
19
+ localFilesService: LocalFilesService,
20
+ gitFilesService: GitFilesService,
21
+ ) => {
22
+ const fileServices = [localFilesService, gitFilesService];
23
+ return FilesServiceFactory.create(configService, fileServices);
24
+ },
25
+ inject: [ConfigService, LocalFilesService, GitFilesService],
26
+ },
27
+ ],
8
28
  })
9
29
  export default class FilesModule {}
@@ -1,15 +1,16 @@
1
1
  import { Resolver, Query, Args } from '@nestjs/graphql';
2
- import { IFilesService } from '../interfaces/files.service.interface';
3
- import FilesServiceFactory from '../services/files-service.factory';
4
- import { Project } from '../../types';
2
+ import {
3
+ FILE_SERVICE,
4
+ IFilesService,
5
+ } from './interfaces/files.service.interface.js';
6
+ import { Project } from '../types.js';
7
+ import { Inject } from '@nestjs/common';
5
8
 
6
9
  @Resolver()
7
10
  export default class FilesResolver {
8
- private readonly filesService: IFilesService;
9
-
10
- constructor(filesServiceFactory: FilesServiceFactory) {
11
- this.filesService = filesServiceFactory.create();
12
- }
11
+ constructor(
12
+ @Inject(FILE_SERVICE) private readonly filesService: IFilesService,
13
+ ) {}
13
14
 
14
15
  @Query(() => Project)
15
16
  async listDirectory(@Args('path') path: string): Promise<Project> {
@@ -0,0 +1,9 @@
1
+ import { Module } from '@nestjs/common';
2
+ import GitFilesService from './git-files.service.js';
3
+ import LocalFilesService from '../local/local-files.service.js';
4
+
5
+ @Module({
6
+ providers: [GitFilesService, LocalFilesService],
7
+ exports: [GitFilesService],
8
+ })
9
+ export class GitFilesModule {}
@@ -0,0 +1,58 @@
1
+ import { Inject, Injectable } from '@nestjs/common';
2
+ import { Project } from 'src/types.js';
3
+ import { IFilesService } from '../interfaces/files.service.interface.js';
4
+ import { CONFIG_MODE } from '../../enums/config-mode.enum.js';
5
+ import { ConfigService } from '@nestjs/config';
6
+ import * as git from 'isomorphic-git';
7
+ import * as fs from 'fs';
8
+ import * as http from 'isomorphic-git/http/node/index.cjs';
9
+ import LocalFilesService from '../local/local-files.service.js';
10
+
11
+ @Injectable()
12
+ export default class GitFilesService implements IFilesService {
13
+ private readonly dataPath: string;
14
+ @Inject(LocalFilesService) private localFilesService: LocalFilesService;
15
+
16
+ constructor(private configService: ConfigService) {
17
+ this.dataPath = this.configService.get('LOCAL_PATH');
18
+ this.cloneRepositories();
19
+ }
20
+
21
+ private cloneRepositories() {
22
+ let userRepoUrl = '';
23
+ let userRepoUrls = [];
24
+ let userCounter = 1;
25
+ while ((userRepoUrl = this.configService.get(
26
+ `GIT_USER${userCounter}_REPO_URL`
27
+ )) !== undefined) {
28
+ userRepoUrls.push(userRepoUrl);
29
+ ++userCounter;
30
+ }
31
+
32
+ userRepoUrls.forEach((userRepoUrl, i) => {
33
+ git
34
+ .clone({
35
+ fs,
36
+ http,
37
+ dir: this.dataPath + `/user${i + 1}`,
38
+ url: userRepoUrl,
39
+ ref: 'main',
40
+ singleBranch: true,
41
+ })
42
+ .then(() => console.log('done cloning ' + userRepoUrl));
43
+ });
44
+ }
45
+
46
+ getMode(): CONFIG_MODE {
47
+ return CONFIG_MODE.GIT;
48
+ }
49
+
50
+ listDirectory(path: string): Promise<Project> {
51
+ console.log('listDirectory', path);
52
+ return this.localFilesService.listDirectory(path);
53
+ }
54
+
55
+ readFile(path: string): Promise<Project> {
56
+ return this.localFilesService.readFile(path);
57
+ }
58
+ }
@@ -1,7 +1,10 @@
1
- import { Project } from 'src/types';
1
+ import { CONFIG_MODE } from '../../enums/config-mode.enum.js';
2
+ import { Project } from 'src/types.js';
2
3
 
4
+ export const FILE_SERVICE = 'FILE_SERVICE';
3
5
  // FileService interface
4
6
  export interface IFilesService {
5
7
  listDirectory(path: string): Promise<Project>;
6
8
  readFile(path: string): Promise<Project>;
9
+ getMode(): CONFIG_MODE;
7
10
  }
@@ -0,0 +1,8 @@
1
+ import { Module } from '@nestjs/common';
2
+ import LocalFilesService from './local-files.service.js';
3
+
4
+ @Module({
5
+ providers: [LocalFilesService],
6
+ exports: [LocalFilesService],
7
+ })
8
+ export class LocalFilesModule {}
@@ -2,18 +2,24 @@ import { Injectable, InternalServerErrorException } from '@nestjs/common';
2
2
  import * as fs from 'fs';
3
3
  import { join } from 'path';
4
4
  import { ConfigService } from '@nestjs/config';
5
- import { Project } from 'src/types';
6
- import { IFilesService } from '../interfaces/files.service.interface';
5
+ import { Project } from 'src/types.js';
6
+ import { IFilesService } from '../interfaces/files.service.interface.js';
7
+ import { CONFIG_MODE } from '../../enums/config-mode.enum.js';
7
8
 
8
9
  @Injectable()
9
10
  export default class LocalFilesService implements IFilesService {
10
- // eslint-disable-next-line no-useless-constructor, no-empty-function
11
- constructor(private configService: ConfigService) {}
11
+ private readonly dataPath: string;
12
12
 
13
- async listDirectory(path: string): Promise<Project> {
14
- const dataPath = this.configService.get('LOCAL_PATH');
15
- const fullPath = join(dataPath, path);
13
+ constructor(private configService: ConfigService) {
14
+ this.dataPath = this.configService.get('LOCAL_PATH');
16
15
 
16
+ }
17
+ getMode(): CONFIG_MODE {
18
+ return CONFIG_MODE.LOCAL;
19
+ }
20
+
21
+ async listDirectory(path: string): Promise<Project> {
22
+ const fullPath = join(this.dataPath, path);
17
23
  const files = await fs.promises.readdir(fullPath);
18
24
 
19
25
  const edges = await Promise.all(
@@ -33,8 +39,7 @@ export default class LocalFilesService implements IFilesService {
33
39
  }
34
40
 
35
41
  async readFile(path: string): Promise<Project> {
36
- const dataPath = this.configService.get('LOCAL_PATH');
37
- const fullPath = join(dataPath, path);
42
+ const fullPath = join(this.dataPath, path);
38
43
 
39
44
  try {
40
45
  const content = await (
@@ -45,7 +50,7 @@ export default class LocalFilesService implements IFilesService {
45
50
 
46
51
  return LocalFilesService.formatResponse(name, content);
47
52
  } catch (error) {
48
- throw new InternalServerErrorException('Error reading file');
53
+ throw new InternalServerErrorException('Error reading file', error);
49
54
  }
50
55
  }
51
56
 
package/src/main.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { Command } from 'commander';
3
- import bootstrap from './bootstrap';
3
+ import bootstrap from './bootstrap.js';
4
4
 
5
5
  type ProgramOptions = {
6
6
  config?: string;
@@ -23,13 +23,11 @@ describe('cloudcmd test for the application', () => {
23
23
  responseType: 'json',
24
24
  },
25
25
  );
26
- /* eslint-disable no-console */
27
- console.log(response.data);
28
- /* eslint-enable no-console */
29
26
  expect(response.data.path).toEqual('/');
30
- expect(response.data.files[0].name).toEqual('common');
31
- expect(response.data.files[1].name).toEqual('user1');
32
- expect(response.data.files[2].name).toEqual('user2');
27
+ const fileNames = response.data.files.map((file) => file.name);
28
+ expect(fileNames).toContain('common');
29
+ expect(fileNames).toContain('user1');
30
+ expect(fileNames).toContain('user2');
33
31
  }, 10000);
34
32
 
35
33
  it('should return the content of a file that is uplaoded to cloudcmd ', async () => {
@@ -1,14 +1,15 @@
1
+ import { describe, it, expect } from '@jest/globals';
1
2
  import { Test, TestingModule } from '@nestjs/testing';
2
3
  import { INestApplication } from '@nestjs/common';
3
- import * as request from 'supertest';
4
+ import request from 'supertest';
4
5
  import fetch from 'cross-fetch';
5
6
  import {
6
7
  ApolloClient,
7
8
  DocumentNode,
8
- HttpLink,
9
9
  InMemoryCache,
10
10
  gql,
11
- } from '@apollo/client';
11
+ } from '@apollo/client/core/core.cjs';
12
+ import { HttpLink } from '@apollo/client/link/http/http.cjs';
12
13
  import AppModule from '../../src/app.module';
13
14
  import {
14
15
  e2eReadFile,
@@ -1,8 +1,8 @@
1
+ import { describe, it, expect, jest } from '@jest/globals';
1
2
  import { Test, TestingModule } from '@nestjs/testing';
2
3
  import { ConfigService } from '@nestjs/config';
3
- import FilesResolver from '../../src/files/resolvers/files.resolver';
4
- import FilesServiceFactory from '../../src/files/services/files-service.factory';
5
- import LocalFilesService from '../../src/files/services/local-files.service';
4
+ import FilesResolver from '../../src/files/files.resolver';
5
+ import LocalFilesService from '../../src/files/local/local-files.service';
6
6
  import {
7
7
  pathToTestDirectory,
8
8
  pathToTestFileContent,
@@ -10,6 +10,9 @@ import {
10
10
  testFileContent,
11
11
  MockConfigService,
12
12
  } from '../testUtil';
13
+ import GitFilesService from '../../src/files/git/git-files.service';
14
+ import { FILE_SERVICE } from '../../src/files/interfaces/files.service.interface';
15
+ import FilesServiceFactory from '../../src/files/files-service.factory';
13
16
 
14
17
  describe('Integration tests for FilesResolver', () => {
15
18
  let filesResolver: FilesResolver;
@@ -20,8 +23,20 @@ describe('Integration tests for FilesResolver', () => {
20
23
  const module: TestingModule = await Test.createTestingModule({
21
24
  providers: [
22
25
  FilesResolver,
23
- FilesServiceFactory,
26
+ {
27
+ provide: FILE_SERVICE,
28
+ useFactory: (
29
+ configService: ConfigService,
30
+ localFilesService: LocalFilesService,
31
+ gitFilesService: GitFilesService,
32
+ ) => {
33
+ const fileServices = [localFilesService, gitFilesService];
34
+ return FilesServiceFactory.create(configService, fileServices);
35
+ },
36
+ inject: [ConfigService, LocalFilesService, GitFilesService],
37
+ },
24
38
  LocalFilesService,
39
+ GitFilesService,
25
40
  { provide: ConfigService, useClass: MockConfigService },
26
41
  ],
27
42
  }).compile();
package/test/testUtil.ts CHANGED
@@ -63,6 +63,9 @@ export class MockConfigService {
63
63
  if (process.env.MODE === 'local') {
64
64
  return 'local';
65
65
  }
66
+ if (process.env.MODE === 'git') {
67
+ return 'git';
68
+ }
66
69
  return 'unknown';
67
70
 
68
71
  default: