@alacard-project/config-sdk 1.0.3 → 1.0.5
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/README.md +14 -68
- package/eslint.config.mjs +27 -0
- package/package.json +38 -8
- package/test/config.client.spec.ts +34 -0
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# @alacard/config-sdk
|
|
1
|
+
# @alacard-project/config-sdk
|
|
2
2
|
|
|
3
3
|
**Alacard Config SDK** — это клиентская библиотека для взаимодействия с централизованным микросервисом конфигураций (CCS) через gRPC. SDK обеспечивает строго типизированный доступ к настройкам, поддерживает горячую перезагрузку через Kafka и имеет встроенный fallback на `.env` файлы.
|
|
4
4
|
|
|
@@ -8,14 +8,12 @@
|
|
|
8
8
|
- 🛡️ **Строгая типизация**: Автоматическая генерация TypeScript-интерфейсов из Protocol Buffers (`ts-proto`).
|
|
9
9
|
- ⚡ **Hot-Reloading**: Мгновенное обновление параметров в памяти приложения при изменении в базе (через Kafka).
|
|
10
10
|
- 📂 **.env Fallback**: Поддержка локальных `.env.<environment>` файлов для разработки и как резервный вариант.
|
|
11
|
-
- 🏗️ **Instance-based**: Поддержка нескольких экземпляров клиента в одном
|
|
11
|
+
- 🏗️ **Instance-based**: Поддержка нескольких экземпляров клиента в одном процессе.
|
|
12
12
|
|
|
13
13
|
## Установка
|
|
14
14
|
|
|
15
|
-
Так как пакет является приватным, убедитесь, что ваш `.npmrc` настроен для доступа к соответствующему реестру.
|
|
16
|
-
|
|
17
15
|
```bash
|
|
18
|
-
npm install @alacard/config-sdk
|
|
16
|
+
npm install @alacard-project/config-sdk
|
|
19
17
|
```
|
|
20
18
|
|
|
21
19
|
## Быстрый старт
|
|
@@ -25,83 +23,31 @@ npm install @alacard/config-sdk
|
|
|
25
23
|
Инициализируйте клиент при запуске вашего приложения (например, в `main.ts` или `bootstrap.ts`):
|
|
26
24
|
|
|
27
25
|
```typescript
|
|
28
|
-
import { ConfigClient } from '@alacard/config-sdk';
|
|
26
|
+
import { ConfigClient } from '@alacard-project/config-sdk';
|
|
29
27
|
|
|
30
28
|
async function bootstrap() {
|
|
31
29
|
const config = await ConfigClient.initialize({
|
|
32
30
|
serviceName: 'auth-service',
|
|
33
31
|
environment: process.env.NODE_ENV || 'development',
|
|
34
|
-
grpcUrl: process.env.GRPC_CONFIG_URL || '
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
// Опционально: Интеграция с Vault (KV + PKI)
|
|
38
|
-
vault: {
|
|
39
|
-
address: 'https://vault.prod.alacard.local:8200',
|
|
40
|
-
roleId: process.env.VAULT_ROLE_ID!,
|
|
41
|
-
secretId: process.env.VAULT_SECRET_ID!,
|
|
42
|
-
pkiPath: 'pki/issue/config-service', // Путь для динамических сертификатов
|
|
43
|
-
},
|
|
44
|
-
|
|
45
|
-
// Опционально: Ручная настройка mTLS (если не используется Vault PKI)
|
|
46
|
-
/*
|
|
47
|
-
tls: {
|
|
48
|
-
rootCert: fs.readFileSync('./certs/ca.crt'),
|
|
49
|
-
clientCert: fs.readFileSync('./certs/client.crt'),
|
|
50
|
-
clientKey: fs.readFileSync('./certs/client.key'),
|
|
51
|
-
},
|
|
52
|
-
*/
|
|
53
|
-
|
|
54
|
-
kafkaBrokers: ['localhost:9092'],
|
|
55
|
-
useDotenvFallback: true,
|
|
32
|
+
grpcUrl: process.env.GRPC_CONFIG_URL || 'config-microservice:50055',
|
|
33
|
+
kafkaBrokers: ['kafka:9092'],
|
|
34
|
+
useDotenvFallback: true, // Использовать .env если gRPC недоступен
|
|
56
35
|
});
|
|
57
36
|
|
|
58
37
|
const dbUrl = config.get('DATABASE_URL');
|
|
38
|
+
console.log('Config loaded!');
|
|
59
39
|
}
|
|
60
40
|
```
|
|
61
41
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
1. **.env Fallback**: SDK пробует прочитать локальный `.env.<env>` файл (если `useDotenvFallback: true`).
|
|
65
|
-
2. **Vault KV**: Если настроен `vault`, SDK логинится через AppRole и забирает секреты из `secret/data/config-service/<serviceName>`.
|
|
66
|
-
3. **Vault PKI (mTLS)**: Если в `vault` указан `pkiPath`, SDK получает динамические сертификаты для защиты gRPC соединения.
|
|
67
|
-
4. **gRPC Config Service**: SDK запрашивает финальный конфиг через зашифрованное соединение с микросервиса конфигураций.
|
|
68
|
-
5. **Kafka Watch**: Запускается подписка на изменения для обновления параметров "на лету".
|
|
42
|
+
### Использование в NestJS
|
|
69
43
|
|
|
70
|
-
|
|
71
|
-
const port = config.getInt('PORT', 3000);
|
|
72
|
-
const dbUrl = config.get('DATABASE_URL');
|
|
44
|
+
Рекомендуется создать `ConfigService` обертку или использовать `ConfigModule` (если он реализован в вашем проекте), который внутри вызывает `ConfigClient.initialize`.
|
|
73
45
|
|
|
74
|
-
|
|
75
|
-
}
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
### Использование в других частях кода
|
|
79
|
-
|
|
80
|
-
После инициализации вы можете получить доступ к инстансу в любом месте приложения:
|
|
81
|
-
|
|
82
|
-
```typescript
|
|
83
|
-
import { ConfigClient } from '@alacard/config-sdk';
|
|
84
|
-
|
|
85
|
-
const config = ConfigClient.getInstance();
|
|
86
|
-
const apiKey = config.get('EXTERNAL_API_KEY');
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
## Доступные методы
|
|
90
|
-
|
|
91
|
-
- `get(key: string, defaultValue?: string): string` — получить строковое значение.
|
|
92
|
-
- `getInt(key: string, defaultValue?: number): number` — получить целое число.
|
|
93
|
-
- `getAll(): Record<string, string>` — получить все загруженные настройки.
|
|
94
|
-
|
|
95
|
-
## Команды для разработки
|
|
96
|
-
|
|
97
|
-
Если вы вносите правки в сам SDK:
|
|
98
|
-
|
|
99
|
-
- `npm run gen:proto` — перегенерировать TypeScript-код из `.proto` файлов.
|
|
100
|
-
- `npm run build` — скомпилировать TypeScript в JavaScript для публикации.
|
|
101
|
-
|
|
102
|
-
## Структура конфигурации (gRPC)
|
|
46
|
+
## Как это работает (Порядок загрузки)
|
|
103
47
|
|
|
104
|
-
|
|
48
|
+
1. **.env Fallback**: SDK пробует прочитать локальный `.env.<env>` файл (если `useDotenvFallback: true`).
|
|
49
|
+
2. **gRPC Config Service**: SDK запрашивает финальный конфиг через gRPC.
|
|
50
|
+
3. **Kafka Watch**: Запускается подписка на изменения для обновления параметров "на лету".
|
|
105
51
|
|
|
106
52
|
---
|
|
107
53
|
© 2026 Alacard Team
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
import eslint from '@eslint/js';
|
|
3
|
+
import tseslint from 'typescript-eslint';
|
|
4
|
+
import globals from 'globals';
|
|
5
|
+
|
|
6
|
+
export default tseslint.config(
|
|
7
|
+
{
|
|
8
|
+
ignores: ['dist/**'],
|
|
9
|
+
},
|
|
10
|
+
eslint.configs.recommended,
|
|
11
|
+
...tseslint.configs.recommended,
|
|
12
|
+
{
|
|
13
|
+
languageOptions: {
|
|
14
|
+
globals: {
|
|
15
|
+
...globals.node,
|
|
16
|
+
...globals.jest,
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
rules: {
|
|
20
|
+
'@typescript-eslint/interface-name-prefix': 'off',
|
|
21
|
+
'@typescript-eslint/explicit-function-return-type': 'off',
|
|
22
|
+
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
|
23
|
+
'@typescript-eslint/no-explicit-any': 'off', // Relaxed for SDK flexibility
|
|
24
|
+
'@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alacard-project/config-sdk",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"engines": {
|
|
5
5
|
"node": ">=24.0.0"
|
|
6
6
|
},
|
|
@@ -8,23 +8,53 @@
|
|
|
8
8
|
"description": "Standalone gRPC-based Configuration SDK for Alacard microservices",
|
|
9
9
|
"main": "dist/index.js",
|
|
10
10
|
"types": "dist/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": "./dist/index.js"
|
|
13
|
+
},
|
|
11
14
|
"scripts": {
|
|
12
15
|
"build": "tsc",
|
|
13
16
|
"gen:proto": "protoc --plugin=./node_modules/.bin/protoc-gen-ts_proto --ts_proto_out=src/proto --proto_path=proto proto/config.proto --ts_proto_opt=outputServices=grpc-js,env=node,useOptionals=messages,exportCommonSymbols=false,esModuleInterop=true",
|
|
17
|
+
"lint": "eslint \"src/**/*.ts\" --fix",
|
|
18
|
+
"test": "jest",
|
|
19
|
+
"test:cov": "jest --coverage",
|
|
14
20
|
"prepublishOnly": "npm run build"
|
|
15
21
|
},
|
|
16
22
|
"dependencies": {
|
|
17
23
|
"@alacard-project/shared": "^1.0.4",
|
|
18
|
-
"@bufbuild/protobuf": "^2.
|
|
19
|
-
"@grpc/grpc-js": "^1.
|
|
20
|
-
"@grpc/proto-loader": "^0.
|
|
24
|
+
"@bufbuild/protobuf": "^2.2.3",
|
|
25
|
+
"@grpc/grpc-js": "^1.12.5",
|
|
26
|
+
"@grpc/proto-loader": "^0.7.13",
|
|
21
27
|
"axios": "^1.7.9",
|
|
22
|
-
"dotenv": "^16.4.
|
|
28
|
+
"dotenv": "^16.4.7",
|
|
23
29
|
"kafkajs": "^2.2.4"
|
|
24
30
|
},
|
|
25
31
|
"devDependencies": {
|
|
26
|
-
"@
|
|
32
|
+
"@eslint/js": "^9.18.0",
|
|
33
|
+
"@types/jest": "^29.5.14",
|
|
34
|
+
"@types/node": "^22.10.7",
|
|
35
|
+
"eslint": "^9.18.0",
|
|
36
|
+
"globals": "^15.14.0",
|
|
37
|
+
"jest": "^29.7.0",
|
|
38
|
+
"ts-jest": "^29.2.5",
|
|
27
39
|
"ts-proto": "^2.6.1",
|
|
28
|
-
"typescript": "^5.
|
|
40
|
+
"typescript": "^5.7.3",
|
|
41
|
+
"typescript-eslint": "^8.20.0"
|
|
42
|
+
},
|
|
43
|
+
"jest": {
|
|
44
|
+
"moduleFileExtensions": [
|
|
45
|
+
"js",
|
|
46
|
+
"json",
|
|
47
|
+
"ts"
|
|
48
|
+
],
|
|
49
|
+
"rootDir": "src",
|
|
50
|
+
"testRegex": ".*\\.spec\\.ts$",
|
|
51
|
+
"transform": {
|
|
52
|
+
"^.+\\.(t|j)s$": "ts-jest"
|
|
53
|
+
},
|
|
54
|
+
"collectCoverageFrom": [
|
|
55
|
+
"**/*.(t|j)s"
|
|
56
|
+
],
|
|
57
|
+
"coverageDirectory": "../coverage",
|
|
58
|
+
"testEnvironment": "node"
|
|
29
59
|
}
|
|
30
|
-
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { ConfigClient } from '../src/config-client';
|
|
2
|
+
|
|
3
|
+
// Mock gRPC and Kafka dependencies
|
|
4
|
+
jest.mock('@grpc/grpc-js', () => ({
|
|
5
|
+
credentials: { createInsecure: jest.fn() },
|
|
6
|
+
ServiceClient: jest.fn(),
|
|
7
|
+
loadPackageDefinition: jest.fn(),
|
|
8
|
+
}));
|
|
9
|
+
jest.mock('@grpc/proto-loader', () => ({
|
|
10
|
+
loadSync: jest.fn(),
|
|
11
|
+
}));
|
|
12
|
+
|
|
13
|
+
describe('ConfigClient', () => {
|
|
14
|
+
let client: ConfigClient;
|
|
15
|
+
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
// Reset mocks if needed
|
|
18
|
+
jest.clearAllMocks();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should be defined', () => {
|
|
22
|
+
expect(ConfigClient).toBeDefined();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// Add more tests for initialization and fetching
|
|
26
|
+
it('should handle environment variables gracefully if remote fails', async () => {
|
|
27
|
+
// Simulation of fallback
|
|
28
|
+
process.env.TEST_VAR = 'fallback_value';
|
|
29
|
+
|
|
30
|
+
// This test would ideally mock the static initialize logic
|
|
31
|
+
// But for now we just verify structural integrity
|
|
32
|
+
expect(process.env.TEST_VAR).toBe('fallback_value');
|
|
33
|
+
});
|
|
34
|
+
});
|