@rsdk/cli.cmd.kafka 4.3.0-next.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.
- package/CHANGELOG.md +10 -0
- package/dist/config.schema.d.ts +34 -0
- package/dist/config.schema.js +26 -0
- package/dist/config.schema.js.map +1 -0
- package/dist/extract/kafka-config.extractor.d.ts +6 -0
- package/dist/extract/kafka-config.extractor.js +39 -0
- package/dist/extract/kafka-config.extractor.js.map +1 -0
- package/dist/extract/types.d.ts +85 -0
- package/dist/extract/types.js +3 -0
- package/dist/extract/types.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/schema/print-schema.d.ts +5 -0
- package/dist/schema/print-schema.js +11 -0
- package/dist/schema/print-schema.js.map +1 -0
- package/dist/schema/schema.command.d.ts +2 -0
- package/dist/schema/schema.command.js +12 -0
- package/dist/schema/schema.command.js.map +1 -0
- package/dist/schemas/string-enum.d.ts +2 -0
- package/dist/schemas/string-enum.js +14 -0
- package/dist/schemas/string-enum.js.map +1 -0
- package/dist/sync/check-exist.d.ts +7 -0
- package/dist/sync/check-exist.js +56 -0
- package/dist/sync/check-exist.js.map +1 -0
- package/dist/sync/context.d.ts +3 -0
- package/dist/sync/context.js +3 -0
- package/dist/sync/context.js.map +1 -0
- package/dist/sync/create-topic.task.d.ts +5 -0
- package/dist/sync/create-topic.task.js +28 -0
- package/dist/sync/create-topic.task.js.map +1 -0
- package/dist/sync/get-config.d.ts +5 -0
- package/dist/sync/get-config.js +27 -0
- package/dist/sync/get-config.js.map +1 -0
- package/dist/sync/kafka.cmd.d.ts +5 -0
- package/dist/sync/kafka.cmd.js +88 -0
- package/dist/sync/kafka.cmd.js.map +1 -0
- package/dist/sync/kafka.creds-provider.d.ts +4 -0
- package/dist/sync/kafka.creds-provider.js +21 -0
- package/dist/sync/kafka.creds-provider.js.map +1 -0
- package/package.json +34 -0
- package/src/config.schema.ts +31 -0
- package/src/extract/kafka-config.extractor.ts +46 -0
- package/src/extract/types.ts +101 -0
- package/src/index.ts +13 -0
- package/src/schema/print-schema.ts +15 -0
- package/src/schema/schema.command.ts +10 -0
- package/src/schemas/string-enum.ts +15 -0
- package/src/sync/check-exist.ts +67 -0
- package/src/sync/context.ts +3 -0
- package/src/sync/create-topic.task.ts +35 -0
- package/src/sync/get-config.ts +24 -0
- package/src/sync/kafka.cmd.ts +82 -0
- package/src/sync/kafka.creds-provider.ts +15 -0
- package/tsconfig.build.json +12 -0
- package/tsconfig.json +7 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Change Log
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
|
+
|
|
6
|
+
## [4.3.0-next.0](https://github.com/R-Vision/rsdk/compare/v4.2.5-next.0...v4.3.0-next.0) (2024-03-19)
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* reworked cli system ([745ebf5](https://github.com/R-Vision/rsdk/commit/745ebf53635de135a4a9083f47ce833efe2d4411))
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export declare const TopicSchema: import("@sinclair/typebox").TObject<{
|
|
2
|
+
name: import("@sinclair/typebox").TString;
|
|
3
|
+
spec: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
|
|
4
|
+
partitions: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TInteger>;
|
|
5
|
+
replicationFactor: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TInteger>;
|
|
6
|
+
settings: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
|
|
7
|
+
'cleanup.policy': import("@sinclair/typebox").TUnsafe<"delete" | "compact">;
|
|
8
|
+
}>>;
|
|
9
|
+
}>>;
|
|
10
|
+
}>;
|
|
11
|
+
export declare const CliKafkaConfigSchema: import("@sinclair/typebox").TObject<{
|
|
12
|
+
topics: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
|
|
13
|
+
name: import("@sinclair/typebox").TString;
|
|
14
|
+
spec: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
|
|
15
|
+
partitions: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TInteger>;
|
|
16
|
+
replicationFactor: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TInteger>;
|
|
17
|
+
settings: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
|
|
18
|
+
'cleanup.policy': import("@sinclair/typebox").TUnsafe<"delete" | "compact">;
|
|
19
|
+
}>>;
|
|
20
|
+
}>>;
|
|
21
|
+
}>>;
|
|
22
|
+
}>;
|
|
23
|
+
export declare const CliKafkaConfigSchemaChecker: import("@sinclair/typebox/compiler").TypeCheck<import("@sinclair/typebox").TObject<{
|
|
24
|
+
topics: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
|
|
25
|
+
name: import("@sinclair/typebox").TString;
|
|
26
|
+
spec: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
|
|
27
|
+
partitions: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TInteger>;
|
|
28
|
+
replicationFactor: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TInteger>;
|
|
29
|
+
settings: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
|
|
30
|
+
'cleanup.policy': import("@sinclair/typebox").TUnsafe<"delete" | "compact">;
|
|
31
|
+
}>>;
|
|
32
|
+
}>>;
|
|
33
|
+
}>>;
|
|
34
|
+
}>>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CliKafkaConfigSchemaChecker = exports.CliKafkaConfigSchema = exports.TopicSchema = void 0;
|
|
4
|
+
const typebox_1 = require("@sinclair/typebox");
|
|
5
|
+
const compiler_1 = require("@sinclair/typebox/compiler");
|
|
6
|
+
const string_enum_1 = require("./schemas/string-enum");
|
|
7
|
+
const specSchema = typebox_1.Type.Optional(typebox_1.Type.Partial(typebox_1.Type.Object({
|
|
8
|
+
partitions: typebox_1.Type.Integer({
|
|
9
|
+
default: 2,
|
|
10
|
+
}),
|
|
11
|
+
replicationFactor: typebox_1.Type.Integer({
|
|
12
|
+
default: 1,
|
|
13
|
+
}),
|
|
14
|
+
settings: typebox_1.Type.Object({
|
|
15
|
+
'cleanup.policy': (0, string_enum_1.StringEnum)(['delete', 'compact']),
|
|
16
|
+
}),
|
|
17
|
+
})));
|
|
18
|
+
exports.TopicSchema = typebox_1.Type.Object({
|
|
19
|
+
name: typebox_1.Type.String(),
|
|
20
|
+
spec: typebox_1.Type.Optional(specSchema),
|
|
21
|
+
});
|
|
22
|
+
exports.CliKafkaConfigSchema = typebox_1.Type.Object({
|
|
23
|
+
topics: typebox_1.Type.Array(exports.TopicSchema),
|
|
24
|
+
});
|
|
25
|
+
exports.CliKafkaConfigSchemaChecker = compiler_1.TypeCompiler.Compile(exports.CliKafkaConfigSchema);
|
|
26
|
+
//# sourceMappingURL=config.schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.schema.js","sourceRoot":"","sources":["../src/config.schema.ts"],"names":[],"mappings":";;;AAAA,+CAAyC;AACzC,yDAA0D;AAE1D,uDAAmD;AAEnD,MAAM,UAAU,GAAG,cAAI,CAAC,QAAQ,CAC9B,cAAI,CAAC,OAAO,CACV,cAAI,CAAC,MAAM,CAAC;IACV,UAAU,EAAE,cAAI,CAAC,OAAO,CAAC;QACvB,OAAO,EAAE,CAAC;KACX,CAAC;IACF,iBAAiB,EAAE,cAAI,CAAC,OAAO,CAAC;QAC9B,OAAO,EAAE,CAAC;KACX,CAAC;IACF,QAAQ,EAAE,cAAI,CAAC,MAAM,CAAC;QACpB,gBAAgB,EAAE,IAAA,wBAAU,EAAC,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;KACpD,CAAC;CACH,CAAC,CACH,CACF,CAAC;AAEW,QAAA,WAAW,GAAG,cAAI,CAAC,MAAM,CAAC;IACrC,IAAI,EAAE,cAAI,CAAC,MAAM,EAAE;IACnB,IAAI,EAAE,cAAI,CAAC,QAAQ,CAAC,UAAU,CAAC;CAChC,CAAC,CAAC;AAEU,QAAA,oBAAoB,GAAG,cAAI,CAAC,MAAM,CAAC;IAC9C,MAAM,EAAE,cAAI,CAAC,KAAK,CAAC,mBAAW,CAAC;CAChC,CAAC,CAAC;AACU,QAAA,2BAA2B,GACtC,uBAAY,CAAC,OAAO,CAAC,4BAAoB,CAAC,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Static } from '@sinclair/typebox';
|
|
2
|
+
import type { CliKafkaConfigSchema } from '../config.schema';
|
|
3
|
+
export declare class KafkaConfigExtractor {
|
|
4
|
+
static extractCommand(includeSchema?: string): Promise<void>;
|
|
5
|
+
static extract(): Promise<Static<typeof CliKafkaConfigSchema>>;
|
|
6
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.KafkaConfigExtractor = void 0;
|
|
7
|
+
const promises_1 = require("node:fs/promises");
|
|
8
|
+
const node_path_1 = require("node:path");
|
|
9
|
+
const yaml_1 = __importDefault(require("yaml"));
|
|
10
|
+
class KafkaConfigExtractor {
|
|
11
|
+
static async extractCommand(includeSchema) {
|
|
12
|
+
const resultKafkaConfig = await this.extract();
|
|
13
|
+
await (0, promises_1.writeFile)((0, node_path_1.resolve)('kafka.yml'), yaml_1.default.stringify({
|
|
14
|
+
...(includeSchema && { $schema: includeSchema }),
|
|
15
|
+
...resultKafkaConfig,
|
|
16
|
+
}));
|
|
17
|
+
}
|
|
18
|
+
static async extract() {
|
|
19
|
+
const pathToRsdkJson = (0, node_path_1.resolve)('autodoc/rsdk.json');
|
|
20
|
+
const rsdkJson = JSON.parse(await (0, promises_1.readFile)(pathToRsdkJson, 'utf8'));
|
|
21
|
+
const kafkaMetadata = rsdkJson.rsdkMetadata
|
|
22
|
+
.filter(({ scope }) => scope === 'kafka-topic')
|
|
23
|
+
.map(({ value }) => value);
|
|
24
|
+
const topics = kafkaMetadata.map((meta) => {
|
|
25
|
+
const topicName = meta.topicName;
|
|
26
|
+
if (!topicName) {
|
|
27
|
+
throw new Error('topicName must be provided', {
|
|
28
|
+
cause: meta,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
name: topicName,
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
return { topics };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
exports.KafkaConfigExtractor = KafkaConfigExtractor;
|
|
39
|
+
//# sourceMappingURL=kafka-config.extractor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kafka-config.extractor.js","sourceRoot":"","sources":["../../src/extract/kafka-config.extractor.ts"],"names":[],"mappings":";;;;;;AACA,+CAAuD;AACvD,yCAAoC;AACpC,gDAAwB;AAMxB,MAAa,oBAAoB;IAC/B,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,aAAsB;QAChD,MAAM,iBAAiB,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QAE/C,MAAM,IAAA,oBAAS,EACb,IAAA,mBAAO,EAAC,WAAW,CAAC,EACpB,cAAI,CAAC,SAAS,CAAC;YACb,GAAG,CAAC,aAAa,IAAI,EAAE,OAAO,EAAE,aAAa,EAAE,CAAC;YAChD,GAAG,iBAAiB;SACrB,CAAC,CACH,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,OAAO;QAClB,MAAM,cAAc,GAAG,IAAA,mBAAO,EAAC,mBAAmB,CAAC,CAAC;QACpD,MAAM,QAAQ,GAAS,IAAI,CAAC,KAAK,CAAC,MAAM,IAAA,mBAAQ,EAAC,cAAc,EAAE,MAAM,CAAC,CAAC,CAAC;QAE1E,MAAM,aAAa,GAAG,QAAQ,CAAC,YAAY;aACxC,MAAM,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,KAAK,aAAa,CAAC;aAC9C,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC;QAE7B,MAAM,MAAM,GACV,aAAa,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;YACzB,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;YACjC,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,MAAM,IAAI,KAAK,CAAC,4BAA4B,EAAE;oBAC5C,KAAK,EAAE,IAAI;iBACZ,CAAC,CAAC;YACL,CAAC;YACD,OAAO;gBACL,IAAI,EAAE,SAAS;aAChB,CAAC;QACJ,CAAC,CAAC,CAAC;QAEL,OAAO,EAAE,MAAM,EAAE,CAAC;IACpB,CAAC;CACF;AApCD,oDAoCC"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
export interface Root {
|
|
2
|
+
metadata: Metadata;
|
|
3
|
+
rsdkMetadata: RsdkMetadaum[];
|
|
4
|
+
}
|
|
5
|
+
export interface Metadata {
|
|
6
|
+
name: string;
|
|
7
|
+
version: string;
|
|
8
|
+
description: string;
|
|
9
|
+
protocols: string[];
|
|
10
|
+
config: Config;
|
|
11
|
+
}
|
|
12
|
+
export interface Config {
|
|
13
|
+
prefix: string;
|
|
14
|
+
sections: Section[];
|
|
15
|
+
sources: any[];
|
|
16
|
+
properties: any[];
|
|
17
|
+
}
|
|
18
|
+
export interface Section {
|
|
19
|
+
tags?: string[];
|
|
20
|
+
constructorName: string;
|
|
21
|
+
properties: Property[];
|
|
22
|
+
name?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface Property {
|
|
25
|
+
expectedInEnv: boolean;
|
|
26
|
+
key: string;
|
|
27
|
+
description: string;
|
|
28
|
+
parser: Parser;
|
|
29
|
+
defaultValue: any;
|
|
30
|
+
}
|
|
31
|
+
export interface Parser {
|
|
32
|
+
type: string;
|
|
33
|
+
description: string;
|
|
34
|
+
}
|
|
35
|
+
export interface RsdkMetadaum {
|
|
36
|
+
scope: string;
|
|
37
|
+
value: Value;
|
|
38
|
+
}
|
|
39
|
+
export interface Value {
|
|
40
|
+
global?: boolean;
|
|
41
|
+
imports?: Import[];
|
|
42
|
+
providers?: Provider2[];
|
|
43
|
+
exports?: string[];
|
|
44
|
+
token?: string;
|
|
45
|
+
partitionKeyField: any;
|
|
46
|
+
topicName?: string;
|
|
47
|
+
group?: string;
|
|
48
|
+
type?: number;
|
|
49
|
+
eventType?: EventType;
|
|
50
|
+
options?: Options3;
|
|
51
|
+
constructorName?: string;
|
|
52
|
+
}
|
|
53
|
+
export interface Import {
|
|
54
|
+
providers: Provider[];
|
|
55
|
+
exports: Export[];
|
|
56
|
+
}
|
|
57
|
+
export interface Provider {
|
|
58
|
+
inject: Inject | undefined[];
|
|
59
|
+
}
|
|
60
|
+
export interface Inject {
|
|
61
|
+
optional: boolean;
|
|
62
|
+
}
|
|
63
|
+
export interface Export {
|
|
64
|
+
inject: Inject2 | undefined[];
|
|
65
|
+
}
|
|
66
|
+
export interface Inject2 {
|
|
67
|
+
optional: boolean;
|
|
68
|
+
}
|
|
69
|
+
export interface Provider2 {
|
|
70
|
+
provide: string;
|
|
71
|
+
useValue: UseValue;
|
|
72
|
+
}
|
|
73
|
+
export interface UseValue {
|
|
74
|
+
context: string;
|
|
75
|
+
}
|
|
76
|
+
export interface EventType {
|
|
77
|
+
$group: string;
|
|
78
|
+
$partitionKeyField: any;
|
|
79
|
+
$type: string;
|
|
80
|
+
}
|
|
81
|
+
export interface Options3 {
|
|
82
|
+
key: string;
|
|
83
|
+
scope: string;
|
|
84
|
+
description: string;
|
|
85
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/extract/types.ts"],"names":[],"mappings":""}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Cmd = void 0;
|
|
4
|
+
const cli_common_1 = require("@rsdk/cli.common");
|
|
5
|
+
const kafka_cmd_1 = require("./sync/kafka.cmd");
|
|
6
|
+
class KafkaRsdkCmd {
|
|
7
|
+
getCommands() {
|
|
8
|
+
return [...(0, cli_common_1.getCommanderCommand)(kafka_cmd_1.KafkaCmd)];
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
exports.Cmd = new KafkaRsdkCmd();
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AACA,iDAAuD;AAGvD,gDAA4C;AAE5C,MAAM,YAAY;IAChB,WAAW;QACT,OAAO,CAAC,GAAG,IAAA,gCAAmB,EAAC,oBAAQ,CAAC,CAAC,CAAC;IAC5C,CAAC;CACF;AAEY,QAAA,GAAG,GAAG,IAAI,YAAY,EAAE,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.printSchema = exports.printDefaultOutFile = void 0;
|
|
4
|
+
const promises_1 = require("node:fs/promises");
|
|
5
|
+
const config_schema_1 = require("../config.schema");
|
|
6
|
+
exports.printDefaultOutFile = './kafka.schema.json';
|
|
7
|
+
async function printSchema(options) {
|
|
8
|
+
await (0, promises_1.writeFile)(options?.outFile ?? exports.printDefaultOutFile, JSON.stringify(config_schema_1.CliKafkaConfigSchema, null, options?.pretty ? 2 : 0));
|
|
9
|
+
}
|
|
10
|
+
exports.printSchema = printSchema;
|
|
11
|
+
//# sourceMappingURL=print-schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"print-schema.js","sourceRoot":"","sources":["../../src/schema/print-schema.ts"],"names":[],"mappings":";;;AAAA,+CAA6C;AAE7C,oDAAwD;AAE3C,QAAA,mBAAmB,GAAG,qBAAqB,CAAC;AAElD,KAAK,UAAU,WAAW,CAAC,OAGjC;IACC,MAAM,IAAA,oBAAS,EACb,OAAO,EAAE,OAAO,IAAI,2BAAmB,EACvC,IAAI,CAAC,SAAS,CAAC,oCAAoB,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CACpE,CAAC;AACJ,CAAC;AARD,kCAQC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SchemaCommand = void 0;
|
|
4
|
+
const commander_1 = require("commander");
|
|
5
|
+
const print_schema_1 = require("./print-schema");
|
|
6
|
+
exports.SchemaCommand = new commander_1.Command('schema')
|
|
7
|
+
.description('print json schema for kafka.yml')
|
|
8
|
+
.option('-o, --out-file', 'output file name', 'kafka.schema.json')
|
|
9
|
+
.action(async (_, cmd) => {
|
|
10
|
+
await (0, print_schema_1.printSchema)(cmd.opts().outFile);
|
|
11
|
+
});
|
|
12
|
+
//# sourceMappingURL=schema.command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.command.js","sourceRoot":"","sources":["../../src/schema/schema.command.ts"],"names":[],"mappings":";;;AAAA,yCAAoC;AAEpC,iDAA6C;AAEhC,QAAA,aAAa,GAAG,IAAI,mBAAO,CAAC,QAAQ,CAAC;KAC/C,WAAW,CAAC,iCAAiC,CAAC;KAC9C,MAAM,CAAC,gBAAgB,EAAE,kBAAkB,EAAE,mBAAmB,CAAC;KACjE,MAAM,CAAC,KAAK,EAAE,CAAC,EAAE,GAAY,EAAE,EAAE;IAChC,MAAM,IAAA,0BAAW,EAAC,GAAG,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,CAAC;AACxC,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StringEnum = void 0;
|
|
4
|
+
const typebox_1 = require("@sinclair/typebox");
|
|
5
|
+
typebox_1.TypeRegistry.Set('StringEnum', (schema, value) => {
|
|
6
|
+
return schema.enum.includes(value);
|
|
7
|
+
});
|
|
8
|
+
const StringEnum = (values) => typebox_1.Type.Unsafe({
|
|
9
|
+
[typebox_1.Kind]: 'StringEnum',
|
|
10
|
+
type: 'string',
|
|
11
|
+
enum: values,
|
|
12
|
+
});
|
|
13
|
+
exports.StringEnum = StringEnum;
|
|
14
|
+
//# sourceMappingURL=string-enum.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"string-enum.js","sourceRoot":"","sources":["../../src/schemas/string-enum.ts"],"names":[],"mappings":";;;AACA,+CAA6D;AAE7D,sBAAY,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC,MAAW,EAAE,KAAU,EAAE,EAAE;IACzD,OAAO,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACrC,CAAC,CAAC,CAAC;AAEI,MAAM,UAAU,GAAG,CACxB,MAAc,EACM,EAAE,CACtB,cAAI,CAAC,MAAM,CAAY;IACrB,CAAC,cAAI,CAAC,EAAE,YAAY;IACpB,IAAI,EAAE,QAAQ;IACd,IAAI,EAAE,MAAM;CACb,CAAC,CAAC;AAPQ,QAAA,UAAU,cAOlB"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Static } from '@sinclair/typebox';
|
|
2
|
+
import type { Admin } from 'kafkajs';
|
|
3
|
+
import type { Listr, ListrRendererFactory, ListrTaskWrapper } from 'listr2';
|
|
4
|
+
import type { TopicSchema } from '../config.schema';
|
|
5
|
+
export declare class KafkaTopicConfigurator {
|
|
6
|
+
static configure(topic: Static<typeof TopicSchema>, admin: Admin, parentTask: ListrTaskWrapper<unknown, ListrRendererFactory>): Promise<Listr | void>;
|
|
7
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.KafkaTopicConfigurator = void 0;
|
|
4
|
+
const kafkajs_1 = require("kafkajs");
|
|
5
|
+
const listr2_1 = require("listr2");
|
|
6
|
+
class KafkaTopicConfigurator {
|
|
7
|
+
static async configure(topic, admin, parentTask) {
|
|
8
|
+
const metadata = await admin.fetchTopicMetadata({
|
|
9
|
+
topics: [topic.name],
|
|
10
|
+
});
|
|
11
|
+
const partitions = metadata.topics[0].partitions.length;
|
|
12
|
+
if (topic.spec?.partitions && partitions !== topic.spec.partitions) {
|
|
13
|
+
throw new Error(`partitoins for ${topic.name} settled to ${partitions}, but expected ${topic.spec.partitions}`);
|
|
14
|
+
}
|
|
15
|
+
const topicConfig = await admin.describeConfigs({
|
|
16
|
+
resources: [
|
|
17
|
+
{
|
|
18
|
+
type: kafkajs_1.ConfigResourceTypes.TOPIC,
|
|
19
|
+
configNames: ['cleanup.policy'],
|
|
20
|
+
name: topic.name,
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
includeSynonyms: true,
|
|
24
|
+
});
|
|
25
|
+
const cleanupPolicy = topicConfig.resources.find(({ resourceName }) => resourceName === topic.name);
|
|
26
|
+
if (!cleanupPolicy) {
|
|
27
|
+
throw new Error('cleanupPolicy not found');
|
|
28
|
+
}
|
|
29
|
+
const currentValue = cleanupPolicy?.configEntries[0].configValue;
|
|
30
|
+
const configValue = topic?.spec?.settings?.['cleanup.policy'];
|
|
31
|
+
if (configValue && currentValue !== configValue) {
|
|
32
|
+
parentTask.output = `Alter cleanup.policy from ${currentValue} to ${configValue}`;
|
|
33
|
+
await (0, listr2_1.delay)(3e3);
|
|
34
|
+
await admin.alterConfigs({
|
|
35
|
+
validateOnly: false,
|
|
36
|
+
resources: [
|
|
37
|
+
{
|
|
38
|
+
type: kafkajs_1.ConfigResourceTypes.TOPIC,
|
|
39
|
+
configEntries: [
|
|
40
|
+
{
|
|
41
|
+
value: configValue,
|
|
42
|
+
name: 'cleanup.policy',
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
name: topic.name,
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
});
|
|
49
|
+
parentTask.output = `Alter cleanup.policy from ${currentValue} to ${configValue} completed!`;
|
|
50
|
+
await (0, listr2_1.delay)(3e3);
|
|
51
|
+
}
|
|
52
|
+
parentTask.title = `topic ${topic.name} exists and respond config`;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
exports.KafkaTopicConfigurator = KafkaTopicConfigurator;
|
|
56
|
+
//# sourceMappingURL=check-exist.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-exist.js","sourceRoot":"","sources":["../../src/sync/check-exist.ts"],"names":[],"mappings":";;;AAEA,qCAA8C;AAE9C,mCAA+B;AAI/B,MAAa,sBAAsB;IACjC,MAAM,CAAC,KAAK,CAAC,SAAS,CACpB,KAAiC,EACjC,KAAY,EACZ,UAA2D;QAE3D,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,kBAAkB,CAAC;YAC9C,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC;SACrB,CAAC,CAAC;QACH,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC;QACxD,IAAI,KAAK,CAAC,IAAI,EAAE,UAAU,IAAI,UAAU,KAAK,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;YACnE,MAAM,IAAI,KAAK,CACb,kBAAkB,KAAK,CAAC,IAAI,eAAe,UAAU,kBAAkB,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE,CAC/F,CAAC;QACJ,CAAC;QACD,MAAM,WAAW,GAAG,MAAM,KAAK,CAAC,eAAe,CAAC;YAC9C,SAAS,EAAE;gBACT;oBACE,IAAI,EAAE,6BAAmB,CAAC,KAAK;oBAC/B,WAAW,EAAE,CAAC,gBAAgB,CAAC;oBAC/B,IAAI,EAAE,KAAK,CAAC,IAAI;iBACjB;aACF;YACD,eAAe,EAAE,IAAI;SACtB,CAAC,CAAC;QAEH,MAAM,aAAa,GAAG,WAAW,CAAC,SAAS,CAAC,IAAI,CAC9C,CAAC,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC,YAAY,KAAK,KAAK,CAAC,IAAI,CAClD,CAAC;QACF,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;QAC7C,CAAC;QACD,MAAM,YAAY,GAAG,aAAa,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;QACjE,MAAM,WAAW,GAAG,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,gBAAgB,CAAC,CAAC;QAE9D,IAAI,WAAW,IAAI,YAAY,KAAK,WAAW,EAAE,CAAC;YAChD,UAAU,CAAC,MAAM,GAAG,6BAA6B,YAAY,OAAO,WAAW,EAAE,CAAC;YAClF,MAAM,IAAA,cAAK,EAAC,GAAG,CAAC,CAAC;YACjB,MAAM,KAAK,CAAC,YAAY,CAAC;gBACvB,YAAY,EAAE,KAAK;gBACnB,SAAS,EAAE;oBACT;wBACE,IAAI,EAAE,6BAAmB,CAAC,KAAK;wBAC/B,aAAa,EAAE;4BACb;gCACE,KAAK,EAAE,WAAW;gCAClB,IAAI,EAAE,gBAAgB;6BACvB;yBACF;wBACD,IAAI,EAAE,KAAK,CAAC,IAAI;qBACjB;iBACF;aACF,CAAC,CAAC;YACH,UAAU,CAAC,MAAM,GAAG,6BAA6B,YAAY,OAAO,WAAW,aAAa,CAAC;YAC7F,MAAM,IAAA,cAAK,EAAC,GAAG,CAAC,CAAC;QACnB,CAAC;QACD,UAAU,CAAC,KAAK,GAAG,SAAS,KAAK,CAAC,IAAI,4BAA4B,CAAC;IACrE,CAAC;CACF;AA1DD,wDA0DC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/sync/context.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Static } from '@sinclair/typebox';
|
|
2
|
+
import type { Admin } from 'kafkajs';
|
|
3
|
+
import type { ListrRendererFactory, ListrTaskWrapper } from 'listr2';
|
|
4
|
+
import type { TopicSchema } from '../config.schema';
|
|
5
|
+
export declare function createTopic(topic: Static<typeof TopicSchema>, admin: Admin, parentTask: ListrTaskWrapper<unknown, ListrRendererFactory>): Promise<void>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createTopic = void 0;
|
|
4
|
+
const listr2_1 = require("listr2");
|
|
5
|
+
async function createTopic(topic, admin, parentTask) {
|
|
6
|
+
await (0, listr2_1.delay)(1000);
|
|
7
|
+
const numPartitions = topic.spec?.partitions ?? 2;
|
|
8
|
+
const replicationFactor = topic.spec?.replicationFactor;
|
|
9
|
+
const result = await admin.createTopics({
|
|
10
|
+
topics: [
|
|
11
|
+
{
|
|
12
|
+
topic: topic.name,
|
|
13
|
+
...(replicationFactor && {
|
|
14
|
+
replicationFactor: replicationFactor,
|
|
15
|
+
}),
|
|
16
|
+
numPartitions: numPartitions,
|
|
17
|
+
},
|
|
18
|
+
],
|
|
19
|
+
});
|
|
20
|
+
if (result) {
|
|
21
|
+
console.log('create topic %s complete!', topic.name);
|
|
22
|
+
parentTask.title = `create topic ${topic.name} complete!`;
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
throw new Error(`create topic ${topic.name} failed!`);
|
|
26
|
+
}
|
|
27
|
+
exports.createTopic = createTopic;
|
|
28
|
+
//# sourceMappingURL=create-topic.task.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-topic.task.js","sourceRoot":"","sources":["../../src/sync/create-topic.task.ts"],"names":[],"mappings":";;;AAGA,mCAA+B;AAIxB,KAAK,UAAU,WAAW,CAC/B,KAAiC,EACjC,KAAY,EACZ,UAA2D;IAE3D,MAAM,IAAA,cAAK,EAAC,IAAI,CAAC,CAAC;IAClB,MAAM,aAAa,GAAG,KAAK,CAAC,IAAI,EAAE,UAAU,IAAI,CAAC,CAAC;IAElD,MAAM,iBAAiB,GAAG,KAAK,CAAC,IAAI,EAAE,iBAAiB,CAAC;IAExD,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,YAAY,CAAC;QACtC,MAAM,EAAE;YACN;gBACE,KAAK,EAAE,KAAK,CAAC,IAAI;gBACjB,GAAG,CAAC,iBAAiB,IAAI;oBACvB,iBAAiB,EAAE,iBAAiB;iBACrC,CAAC;gBACF,aAAa,EAAE,aAAa;aAC7B;SACF;KACF,CAAC,CAAC;IACH,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,CAAC,GAAG,CAAC,2BAA2B,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QACrD,UAAU,CAAC,KAAK,GAAG,gBAAgB,KAAK,CAAC,IAAI,YAAY,CAAC;QAC1D,OAAO;IACT,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,gBAAgB,KAAK,CAAC,IAAI,UAAU,CAAC,CAAC;AACxD,CAAC;AA3BD,kCA2BC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.KafkaExpectedConfigProvider = void 0;
|
|
7
|
+
const promises_1 = require("node:fs/promises");
|
|
8
|
+
const node_path_1 = require("node:path");
|
|
9
|
+
const yaml_1 = __importDefault(require("yaml"));
|
|
10
|
+
const config_schema_1 = require("../config.schema");
|
|
11
|
+
class KafkaExpectedConfigProvider {
|
|
12
|
+
static async getConfig() {
|
|
13
|
+
const kafkaYml = await (0, promises_1.readFile)((0, node_path_1.resolve)('kafka.yml'), {
|
|
14
|
+
encoding: 'utf8',
|
|
15
|
+
});
|
|
16
|
+
const config = yaml_1.default.parse(kafkaYml);
|
|
17
|
+
const isValid = config_schema_1.CliKafkaConfigSchemaChecker.Check(config);
|
|
18
|
+
if (!isValid) {
|
|
19
|
+
throw new Error('Invalid config', {
|
|
20
|
+
cause: [...config_schema_1.CliKafkaConfigSchemaChecker.Errors(config)],
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
return config;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
exports.KafkaExpectedConfigProvider = KafkaExpectedConfigProvider;
|
|
27
|
+
//# sourceMappingURL=get-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-config.js","sourceRoot":"","sources":["../../src/sync/get-config.ts"],"names":[],"mappings":";;;;;;AACA,+CAA4C;AAC5C,yCAAoC;AACpC,gDAAwB;AAGxB,oDAA+D;AAE/D,MAAa,2BAA2B;IACtC,MAAM,CAAC,KAAK,CAAC,SAAS;QACpB,MAAM,QAAQ,GAAG,MAAM,IAAA,mBAAQ,EAAC,IAAA,mBAAO,EAAC,WAAW,CAAC,EAAE;YACpD,QAAQ,EAAE,MAAM;SACjB,CAAC,CAAC;QACH,MAAM,MAAM,GAAwC,cAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAEzE,MAAM,OAAO,GAAG,2CAA2B,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAC1D,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,gBAAgB,EAAE;gBAChC,KAAK,EAAE,CAAC,GAAG,2CAA2B,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;aACvD,CAAC,CAAC;QACL,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;CACF;AAfD,kEAeC"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
var KafkaCmd_1;
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.KafkaCmd = void 0;
|
|
17
|
+
const cli_common_1 = require("@rsdk/cli.common");
|
|
18
|
+
const logging_1 = require("@rsdk/logging");
|
|
19
|
+
const kafkajs_1 = require("kafkajs");
|
|
20
|
+
const listr2_1 = require("listr2");
|
|
21
|
+
const kafka_config_extractor_1 = require("../extract/kafka-config.extractor");
|
|
22
|
+
const print_schema_1 = require("../schema/print-schema");
|
|
23
|
+
const check_exist_1 = require("./check-exist");
|
|
24
|
+
const create_topic_task_1 = require("./create-topic.task");
|
|
25
|
+
const get_config_1 = require("./get-config");
|
|
26
|
+
const kafka_creds_provider_1 = require("./kafka.creds-provider");
|
|
27
|
+
async function createAdmin(kafkaCreds) {
|
|
28
|
+
const kafka = new kafkajs_1.Kafka(kafkaCreds);
|
|
29
|
+
const admin = kafka.admin();
|
|
30
|
+
await admin.connect();
|
|
31
|
+
return admin;
|
|
32
|
+
}
|
|
33
|
+
let KafkaCmd = class KafkaCmd {
|
|
34
|
+
static { KafkaCmd_1 = this; }
|
|
35
|
+
async sync(fromRsdk) {
|
|
36
|
+
const config = fromRsdk
|
|
37
|
+
? await kafka_config_extractor_1.KafkaConfigExtractor.extract()
|
|
38
|
+
: await get_config_1.KafkaExpectedConfigProvider.getConfig();
|
|
39
|
+
const kafkaCreds = kafka_creds_provider_1.KafkaCredsProvider.getKafkaCreds();
|
|
40
|
+
const admin = await createAdmin(kafkaCreds);
|
|
41
|
+
const existedTopic = await admin.listTopics();
|
|
42
|
+
await new listr2_1.Listr(config.topics.map((topic) => ({
|
|
43
|
+
title: topic.name,
|
|
44
|
+
task: async (_ctx, parentTask) => {
|
|
45
|
+
const requireCreate = !existedTopic.includes(topic.name);
|
|
46
|
+
return parentTask.newListr([
|
|
47
|
+
{
|
|
48
|
+
title: requireCreate ? 'create' : 'configure',
|
|
49
|
+
task: async () => {
|
|
50
|
+
if (requireCreate) {
|
|
51
|
+
await (0, create_topic_task_1.createTopic)(topic, admin, parentTask);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
await check_exist_1.KafkaTopicConfigurator.configure(topic, admin, parentTask);
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
], { concurrent: false });
|
|
58
|
+
},
|
|
59
|
+
})), { concurrent: true }).run({ requireCreate: true });
|
|
60
|
+
await admin.disconnect();
|
|
61
|
+
}
|
|
62
|
+
async extract(fromSchema) {
|
|
63
|
+
if (fromSchema) {
|
|
64
|
+
await (0, print_schema_1.printSchema)({ outFile: print_schema_1.printDefaultOutFile, pretty: true });
|
|
65
|
+
}
|
|
66
|
+
await kafka_config_extractor_1.KafkaConfigExtractor.extractCommand(print_schema_1.printDefaultOutFile);
|
|
67
|
+
}
|
|
68
|
+
static logger = logging_1.LoggerFactory.create(KafkaCmd_1);
|
|
69
|
+
};
|
|
70
|
+
exports.KafkaCmd = KafkaCmd;
|
|
71
|
+
__decorate([
|
|
72
|
+
(0, cli_common_1.SubCmd)('sync', 'Try sync kafka state from kafka.yml file'),
|
|
73
|
+
__param(0, (0, cli_common_1.Option)('from-rsdk', 'from rsdk', Boolean)),
|
|
74
|
+
__metadata("design:type", Function),
|
|
75
|
+
__metadata("design:paramtypes", [Boolean]),
|
|
76
|
+
__metadata("design:returntype", Promise)
|
|
77
|
+
], KafkaCmd.prototype, "sync", null);
|
|
78
|
+
__decorate([
|
|
79
|
+
(0, cli_common_1.SubCmd)('extract', 'extract kafka.yml from rsdk.json'),
|
|
80
|
+
__param(0, (0, cli_common_1.Option)('from-schema', 'make from schema', Boolean)),
|
|
81
|
+
__metadata("design:type", Function),
|
|
82
|
+
__metadata("design:paramtypes", [Boolean]),
|
|
83
|
+
__metadata("design:returntype", Promise)
|
|
84
|
+
], KafkaCmd.prototype, "extract", null);
|
|
85
|
+
exports.KafkaCmd = KafkaCmd = KafkaCmd_1 = __decorate([
|
|
86
|
+
(0, cli_common_1.Cmd)('kafka', 'kafka commands')
|
|
87
|
+
], KafkaCmd);
|
|
88
|
+
//# sourceMappingURL=kafka.cmd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kafka.cmd.js","sourceRoot":"","sources":["../../src/sync/kafka.cmd.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,iDAAuD;AACvD,2CAA8C;AAE9C,qCAAgC;AAChC,mCAA+B;AAE/B,8EAAyE;AACzE,yDAA0E;AAE1E,+CAAuD;AAEvD,2DAAkD;AAClD,6CAA2D;AAC3D,iEAA4D;AAE5D,KAAK,UAAU,WAAW,CAAC,UAAuB;IAChD,MAAM,KAAK,GAAG,IAAI,eAAK,CAAC,UAAU,CAAC,CAAC;IACpC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC;IAE5B,MAAM,KAAK,CAAC,OAAO,EAAE,CAAC;IACtB,OAAO,KAAK,CAAC;AACf,CAAC;AAGM,IAAM,QAAQ,GAAd,MAAM,QAAQ;;IAEb,AAAN,KAAK,CAAC,IAAI,CACmC,QAAiB;QAE5D,MAAM,MAAM,GAAG,QAAQ;YACrB,CAAC,CAAC,MAAM,6CAAoB,CAAC,OAAO,EAAE;YACtC,CAAC,CAAC,MAAM,wCAA2B,CAAC,SAAS,EAAE,CAAC;QAElD,MAAM,UAAU,GAAG,yCAAkB,CAAC,aAAa,EAAE,CAAC;QACtD,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,UAAU,CAAC,CAAC;QAE5C,MAAM,YAAY,GAAG,MAAM,KAAK,CAAC,UAAU,EAAE,CAAC;QAE9C,MAAM,IAAI,cAAK,CACb,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YAC5B,KAAK,EAAE,KAAK,CAAC,IAAI;YACjB,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAA4B,EAAE;gBACzD,MAAM,aAAa,GAAG,CAAC,YAAY,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAEzD,OAAO,UAAU,CAAC,QAAQ,CACxB;oBACE;wBACE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW;wBAC7C,IAAI,EAAE,KAAK,IAA2B,EAAE;4BACtC,IAAI,aAAa,EAAE,CAAC;gCAClB,MAAM,IAAA,+BAAW,EAAC,KAAK,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC;gCAC5C,OAAO;4BACT,CAAC;4BACD,MAAM,oCAAsB,CAAC,SAAS,CACpC,KAAK,EACL,KAAK,EACL,UAAU,CACX,CAAC;wBACJ,CAAC;qBACF;iBACF,EACD,EAAE,UAAU,EAAE,KAAK,EAAE,CACtB,CAAC;YACJ,CAAC;SACF,CAAC,CAAC,EACH,EAAE,UAAU,EAAE,IAAI,EAAE,CACrB,CAAC,GAAG,CAAC,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/B,MAAM,KAAK,CAAC,UAAU,EAAE,CAAC;IAC3B,CAAC;IAGK,AAAN,KAAK,CAAC,OAAO,CACyC,UAAmB;QAEvE,IAAI,UAAU,EAAE,CAAC;YACf,MAAM,IAAA,0BAAW,EAAC,EAAE,OAAO,EAAE,kCAAmB,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QACpE,CAAC;QACD,MAAM,6CAAoB,CAAC,cAAc,CAAC,kCAAmB,CAAC,CAAC;IACjE,CAAC;IAEO,MAAM,CAAC,MAAM,GAAG,uBAAa,CAAC,MAAM,CAAC,UAAQ,CAAC,CAAC;;AAxD5C,4BAAQ;AAEb;IADL,IAAA,mBAAM,EAAC,MAAM,EAAE,0CAA0C,CAAC;IAExD,WAAA,IAAA,mBAAM,EAAC,WAAW,EAAE,WAAW,EAAE,OAAO,CAAC,CAAA;;;;oCAyC3C;AAGK;IADL,IAAA,mBAAM,EAAC,SAAS,EAAE,kCAAkC,CAAC;IAEnD,WAAA,IAAA,mBAAM,EAAC,aAAa,EAAE,kBAAkB,EAAE,OAAO,CAAC,CAAA;;;;uCAMpD;mBAtDU,QAAQ;IADpB,IAAA,gBAAG,EAAC,OAAO,EAAE,gBAAgB,CAAC;GAClB,QAAQ,CAyDpB"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.KafkaCredsProvider = void 0;
|
|
7
|
+
const dotenv_1 = __importDefault(require("dotenv"));
|
|
8
|
+
class KafkaCredsProvider {
|
|
9
|
+
static getKafkaCreds() {
|
|
10
|
+
dotenv_1.default.config();
|
|
11
|
+
const kafkaHost = process.env.KAFKA_HOST;
|
|
12
|
+
if (!kafkaHost) {
|
|
13
|
+
throw new Error('KAFKA_HOST not found');
|
|
14
|
+
}
|
|
15
|
+
return {
|
|
16
|
+
brokers: [kafkaHost],
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
exports.KafkaCredsProvider = KafkaCredsProvider;
|
|
21
|
+
//# sourceMappingURL=kafka.creds-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kafka.creds-provider.js","sourceRoot":"","sources":["../../src/sync/kafka.creds-provider.ts"],"names":[],"mappings":";;;;;;AAAA,oDAA4B;AAG5B,MAAa,kBAAkB;IAC7B,MAAM,CAAC,aAAa;QAClB,gBAAM,CAAC,MAAM,EAAE,CAAC;QAChB,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC;QACzC,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;QAC1C,CAAC;QACD,OAAO;YACL,OAAO,EAAE,CAAC,SAAS,CAAC;SACrB,CAAC;IACJ,CAAC;CACF;AAXD,gDAWC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rsdk/cli.cmd.kafka",
|
|
3
|
+
"version": "4.3.0-next.0",
|
|
4
|
+
"description": "Start command for rsdk cli",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"rsdk": "bin.js"
|
|
8
|
+
},
|
|
9
|
+
"publishConfig": {
|
|
10
|
+
"access": "public"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"rsdk",
|
|
14
|
+
"cli"
|
|
15
|
+
],
|
|
16
|
+
"license": "Apache License 2.0",
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@nestjs/cli": "^10.0.0",
|
|
19
|
+
"@sinclair/typebox": "^0.32.13",
|
|
20
|
+
"commander": "^12.0.0",
|
|
21
|
+
"dotenv": "^16.3.1",
|
|
22
|
+
"execa": "5",
|
|
23
|
+
"kafkajs": "^2.2.4",
|
|
24
|
+
"listr2": "^6.6.1",
|
|
25
|
+
"yaml": "^2.3.1"
|
|
26
|
+
},
|
|
27
|
+
"peerDependencies": {
|
|
28
|
+
"@rsdk/cli.common": "^4.3.0-next.0",
|
|
29
|
+
"@rsdk/core": "^4.3.0-next.0",
|
|
30
|
+
"@rsdk/exception": "workspace:^",
|
|
31
|
+
"@rsdk/logging": "^4.3.0-next.0"
|
|
32
|
+
},
|
|
33
|
+
"gitHead": "68619cc6fc60db01568eede7df182d9882e857dd"
|
|
34
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Type } from '@sinclair/typebox';
|
|
2
|
+
import { TypeCompiler } from '@sinclair/typebox/compiler';
|
|
3
|
+
|
|
4
|
+
import { StringEnum } from './schemas/string-enum';
|
|
5
|
+
|
|
6
|
+
const specSchema = Type.Optional(
|
|
7
|
+
Type.Partial(
|
|
8
|
+
Type.Object({
|
|
9
|
+
partitions: Type.Integer({
|
|
10
|
+
default: 2,
|
|
11
|
+
}),
|
|
12
|
+
replicationFactor: Type.Integer({
|
|
13
|
+
default: 1,
|
|
14
|
+
}),
|
|
15
|
+
settings: Type.Object({
|
|
16
|
+
'cleanup.policy': StringEnum(['delete', 'compact']),
|
|
17
|
+
}),
|
|
18
|
+
}),
|
|
19
|
+
),
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
export const TopicSchema = Type.Object({
|
|
23
|
+
name: Type.String(),
|
|
24
|
+
spec: Type.Optional(specSchema),
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
export const CliKafkaConfigSchema = Type.Object({
|
|
28
|
+
topics: Type.Array(TopicSchema),
|
|
29
|
+
});
|
|
30
|
+
export const CliKafkaConfigSchemaChecker =
|
|
31
|
+
TypeCompiler.Compile(CliKafkaConfigSchema);
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { Static } from '@sinclair/typebox';
|
|
2
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { resolve } from 'node:path';
|
|
4
|
+
import yaml from 'yaml';
|
|
5
|
+
|
|
6
|
+
import type { CliKafkaConfigSchema } from '../config.schema';
|
|
7
|
+
|
|
8
|
+
import type { Root } from './types';
|
|
9
|
+
|
|
10
|
+
export class KafkaConfigExtractor {
|
|
11
|
+
static async extractCommand(includeSchema?: string): Promise<void> {
|
|
12
|
+
const resultKafkaConfig = await this.extract();
|
|
13
|
+
|
|
14
|
+
await writeFile(
|
|
15
|
+
resolve('kafka.yml'),
|
|
16
|
+
yaml.stringify({
|
|
17
|
+
...(includeSchema && { $schema: includeSchema }),
|
|
18
|
+
...resultKafkaConfig,
|
|
19
|
+
}),
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
static async extract(): Promise<Static<typeof CliKafkaConfigSchema>> {
|
|
24
|
+
const pathToRsdkJson = resolve('autodoc/rsdk.json');
|
|
25
|
+
const rsdkJson: Root = JSON.parse(await readFile(pathToRsdkJson, 'utf8'));
|
|
26
|
+
|
|
27
|
+
const kafkaMetadata = rsdkJson.rsdkMetadata
|
|
28
|
+
.filter(({ scope }) => scope === 'kafka-topic')
|
|
29
|
+
.map(({ value }) => value);
|
|
30
|
+
|
|
31
|
+
const topics: Static<typeof CliKafkaConfigSchema>['topics'] =
|
|
32
|
+
kafkaMetadata.map((meta) => {
|
|
33
|
+
const topicName = meta.topicName;
|
|
34
|
+
if (!topicName) {
|
|
35
|
+
throw new Error('topicName must be provided', {
|
|
36
|
+
cause: meta,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
name: topicName,
|
|
41
|
+
};
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
return { topics };
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
export interface Root {
|
|
2
|
+
metadata: Metadata;
|
|
3
|
+
rsdkMetadata: RsdkMetadaum[];
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export interface Metadata {
|
|
7
|
+
name: string;
|
|
8
|
+
version: string;
|
|
9
|
+
description: string;
|
|
10
|
+
protocols: string[];
|
|
11
|
+
config: Config;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface Config {
|
|
15
|
+
prefix: string;
|
|
16
|
+
sections: Section[];
|
|
17
|
+
sources: any[];
|
|
18
|
+
properties: any[];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface Section {
|
|
22
|
+
tags?: string[];
|
|
23
|
+
constructorName: string;
|
|
24
|
+
properties: Property[];
|
|
25
|
+
name?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface Property {
|
|
29
|
+
expectedInEnv: boolean;
|
|
30
|
+
key: string;
|
|
31
|
+
description: string;
|
|
32
|
+
parser: Parser;
|
|
33
|
+
defaultValue: any;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface Parser {
|
|
37
|
+
type: string;
|
|
38
|
+
description: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface RsdkMetadaum {
|
|
42
|
+
scope: string;
|
|
43
|
+
value: Value;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface Value {
|
|
47
|
+
global?: boolean;
|
|
48
|
+
imports?: Import[];
|
|
49
|
+
providers?: Provider2[];
|
|
50
|
+
exports?: string[];
|
|
51
|
+
token?: string;
|
|
52
|
+
partitionKeyField: any;
|
|
53
|
+
topicName?: string;
|
|
54
|
+
group?: string;
|
|
55
|
+
type?: number;
|
|
56
|
+
eventType?: EventType;
|
|
57
|
+
options?: Options3;
|
|
58
|
+
constructorName?: string;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface Import {
|
|
62
|
+
providers: Provider[];
|
|
63
|
+
exports: Export[];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface Provider {
|
|
67
|
+
inject: Inject | undefined[];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface Inject {
|
|
71
|
+
optional: boolean;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface Export {
|
|
75
|
+
inject: Inject2 | undefined[];
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface Inject2 {
|
|
79
|
+
optional: boolean;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface Provider2 {
|
|
83
|
+
provide: string;
|
|
84
|
+
useValue: UseValue;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export interface UseValue {
|
|
88
|
+
context: string;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export interface EventType {
|
|
92
|
+
$group: string;
|
|
93
|
+
$partitionKeyField: any;
|
|
94
|
+
$type: string;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export interface Options3 {
|
|
98
|
+
key: string;
|
|
99
|
+
scope: string;
|
|
100
|
+
description: string;
|
|
101
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { RsdkCliCommand } from '@rsdk/cli.common';
|
|
2
|
+
import { getCommanderCommand } from '@rsdk/cli.common';
|
|
3
|
+
import type { Command } from 'commander';
|
|
4
|
+
|
|
5
|
+
import { KafkaCmd } from './sync/kafka.cmd';
|
|
6
|
+
|
|
7
|
+
class KafkaRsdkCmd implements RsdkCliCommand {
|
|
8
|
+
getCommands(): Command[] {
|
|
9
|
+
return [...getCommanderCommand(KafkaCmd)];
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const Cmd = new KafkaRsdkCmd();
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { writeFile } from 'node:fs/promises';
|
|
2
|
+
|
|
3
|
+
import { CliKafkaConfigSchema } from '../config.schema';
|
|
4
|
+
|
|
5
|
+
export const printDefaultOutFile = './kafka.schema.json';
|
|
6
|
+
|
|
7
|
+
export async function printSchema(options?: {
|
|
8
|
+
outFile?: string;
|
|
9
|
+
pretty?: boolean;
|
|
10
|
+
}): Promise<void> {
|
|
11
|
+
await writeFile(
|
|
12
|
+
options?.outFile ?? printDefaultOutFile,
|
|
13
|
+
JSON.stringify(CliKafkaConfigSchema, null, options?.pretty ? 2 : 0),
|
|
14
|
+
);
|
|
15
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
|
|
3
|
+
import { printSchema } from './print-schema';
|
|
4
|
+
|
|
5
|
+
export const SchemaCommand = new Command('schema')
|
|
6
|
+
.description('print json schema for kafka.yml')
|
|
7
|
+
.option('-o, --out-file', 'output file name', 'kafka.schema.json')
|
|
8
|
+
.action(async (_, cmd: Command) => {
|
|
9
|
+
await printSchema(cmd.opts().outFile);
|
|
10
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { TUnsafe } from '@sinclair/typebox';
|
|
2
|
+
import { Kind, Type, TypeRegistry } from '@sinclair/typebox';
|
|
3
|
+
|
|
4
|
+
TypeRegistry.Set('StringEnum', (schema: any, value: any) => {
|
|
5
|
+
return schema.enum.includes(value);
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
export const StringEnum = <T extends string[]>(
|
|
9
|
+
values: [...T],
|
|
10
|
+
): TUnsafe<T[number]> =>
|
|
11
|
+
Type.Unsafe<T[number]>({
|
|
12
|
+
[Kind]: 'StringEnum',
|
|
13
|
+
type: 'string',
|
|
14
|
+
enum: values,
|
|
15
|
+
});
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { Static } from '@sinclair/typebox';
|
|
2
|
+
import type { Admin } from 'kafkajs';
|
|
3
|
+
import { ConfigResourceTypes } from 'kafkajs';
|
|
4
|
+
import type { Listr, ListrRendererFactory, ListrTaskWrapper } from 'listr2';
|
|
5
|
+
import { delay } from 'listr2';
|
|
6
|
+
|
|
7
|
+
import type { TopicSchema } from '../config.schema';
|
|
8
|
+
|
|
9
|
+
export class KafkaTopicConfigurator {
|
|
10
|
+
static async configure(
|
|
11
|
+
topic: Static<typeof TopicSchema>,
|
|
12
|
+
admin: Admin,
|
|
13
|
+
parentTask: ListrTaskWrapper<unknown, ListrRendererFactory>,
|
|
14
|
+
): Promise<Listr | void> {
|
|
15
|
+
const metadata = await admin.fetchTopicMetadata({
|
|
16
|
+
topics: [topic.name],
|
|
17
|
+
});
|
|
18
|
+
const partitions = metadata.topics[0].partitions.length;
|
|
19
|
+
if (topic.spec?.partitions && partitions !== topic.spec.partitions) {
|
|
20
|
+
throw new Error(
|
|
21
|
+
`partitoins for ${topic.name} settled to ${partitions}, but expected ${topic.spec.partitions}`,
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
const topicConfig = await admin.describeConfigs({
|
|
25
|
+
resources: [
|
|
26
|
+
{
|
|
27
|
+
type: ConfigResourceTypes.TOPIC,
|
|
28
|
+
configNames: ['cleanup.policy'],
|
|
29
|
+
name: topic.name,
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
includeSynonyms: true,
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const cleanupPolicy = topicConfig.resources.find(
|
|
36
|
+
({ resourceName }) => resourceName === topic.name,
|
|
37
|
+
);
|
|
38
|
+
if (!cleanupPolicy) {
|
|
39
|
+
throw new Error('cleanupPolicy not found');
|
|
40
|
+
}
|
|
41
|
+
const currentValue = cleanupPolicy?.configEntries[0].configValue;
|
|
42
|
+
const configValue = topic?.spec?.settings?.['cleanup.policy'];
|
|
43
|
+
|
|
44
|
+
if (configValue && currentValue !== configValue) {
|
|
45
|
+
parentTask.output = `Alter cleanup.policy from ${currentValue} to ${configValue}`;
|
|
46
|
+
await delay(3e3);
|
|
47
|
+
await admin.alterConfigs({
|
|
48
|
+
validateOnly: false,
|
|
49
|
+
resources: [
|
|
50
|
+
{
|
|
51
|
+
type: ConfigResourceTypes.TOPIC,
|
|
52
|
+
configEntries: [
|
|
53
|
+
{
|
|
54
|
+
value: configValue,
|
|
55
|
+
name: 'cleanup.policy',
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
name: topic.name,
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
});
|
|
62
|
+
parentTask.output = `Alter cleanup.policy from ${currentValue} to ${configValue} completed!`;
|
|
63
|
+
await delay(3e3);
|
|
64
|
+
}
|
|
65
|
+
parentTask.title = `topic ${topic.name} exists and respond config`;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { Static } from '@sinclair/typebox';
|
|
2
|
+
import type { Admin } from 'kafkajs';
|
|
3
|
+
import type { ListrRendererFactory, ListrTaskWrapper } from 'listr2';
|
|
4
|
+
import { delay } from 'listr2';
|
|
5
|
+
|
|
6
|
+
import type { TopicSchema } from '../config.schema';
|
|
7
|
+
|
|
8
|
+
export async function createTopic(
|
|
9
|
+
topic: Static<typeof TopicSchema>,
|
|
10
|
+
admin: Admin,
|
|
11
|
+
parentTask: ListrTaskWrapper<unknown, ListrRendererFactory>,
|
|
12
|
+
): Promise<void> {
|
|
13
|
+
await delay(1000);
|
|
14
|
+
const numPartitions = topic.spec?.partitions ?? 2;
|
|
15
|
+
|
|
16
|
+
const replicationFactor = topic.spec?.replicationFactor;
|
|
17
|
+
|
|
18
|
+
const result = await admin.createTopics({
|
|
19
|
+
topics: [
|
|
20
|
+
{
|
|
21
|
+
topic: topic.name,
|
|
22
|
+
...(replicationFactor && {
|
|
23
|
+
replicationFactor: replicationFactor,
|
|
24
|
+
}),
|
|
25
|
+
numPartitions: numPartitions,
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
});
|
|
29
|
+
if (result) {
|
|
30
|
+
console.log('create topic %s complete!', topic.name);
|
|
31
|
+
parentTask.title = `create topic ${topic.name} complete!`;
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
throw new Error(`create topic ${topic.name} failed!`);
|
|
35
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Static } from '@sinclair/typebox';
|
|
2
|
+
import { readFile } from 'node:fs/promises';
|
|
3
|
+
import { resolve } from 'node:path';
|
|
4
|
+
import yaml from 'yaml';
|
|
5
|
+
|
|
6
|
+
import type { CliKafkaConfigSchema } from '../config.schema';
|
|
7
|
+
import { CliKafkaConfigSchemaChecker } from '../config.schema';
|
|
8
|
+
|
|
9
|
+
export class KafkaExpectedConfigProvider {
|
|
10
|
+
static async getConfig(): Promise<Static<typeof CliKafkaConfigSchema>> {
|
|
11
|
+
const kafkaYml = await readFile(resolve('kafka.yml'), {
|
|
12
|
+
encoding: 'utf8',
|
|
13
|
+
});
|
|
14
|
+
const config: Static<typeof CliKafkaConfigSchema> = yaml.parse(kafkaYml);
|
|
15
|
+
|
|
16
|
+
const isValid = CliKafkaConfigSchemaChecker.Check(config);
|
|
17
|
+
if (!isValid) {
|
|
18
|
+
throw new Error('Invalid config', {
|
|
19
|
+
cause: [...CliKafkaConfigSchemaChecker.Errors(config)],
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
return config;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { Cmd, Option, SubCmd } from '@rsdk/cli.common';
|
|
2
|
+
import { LoggerFactory } from '@rsdk/logging';
|
|
3
|
+
import type { Admin, KafkaConfig } from 'kafkajs';
|
|
4
|
+
import { Kafka } from 'kafkajs';
|
|
5
|
+
import { Listr } from 'listr2';
|
|
6
|
+
|
|
7
|
+
import { KafkaConfigExtractor } from '../extract/kafka-config.extractor';
|
|
8
|
+
import { printDefaultOutFile, printSchema } from '../schema/print-schema';
|
|
9
|
+
|
|
10
|
+
import { KafkaTopicConfigurator } from './check-exist';
|
|
11
|
+
import type { Context } from './context';
|
|
12
|
+
import { createTopic } from './create-topic.task';
|
|
13
|
+
import { KafkaExpectedConfigProvider } from './get-config';
|
|
14
|
+
import { KafkaCredsProvider } from './kafka.creds-provider';
|
|
15
|
+
|
|
16
|
+
async function createAdmin(kafkaCreds: KafkaConfig): Promise<Admin> {
|
|
17
|
+
const kafka = new Kafka(kafkaCreds);
|
|
18
|
+
const admin = kafka.admin();
|
|
19
|
+
|
|
20
|
+
await admin.connect();
|
|
21
|
+
return admin;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
@Cmd('kafka', 'kafka commands')
|
|
25
|
+
export class KafkaCmd {
|
|
26
|
+
@SubCmd('sync', 'Try sync kafka state from kafka.yml file')
|
|
27
|
+
async sync(
|
|
28
|
+
@Option('from-rsdk', 'from rsdk', Boolean) fromRsdk: boolean,
|
|
29
|
+
): Promise<void> {
|
|
30
|
+
const config = fromRsdk
|
|
31
|
+
? await KafkaConfigExtractor.extract()
|
|
32
|
+
: await KafkaExpectedConfigProvider.getConfig();
|
|
33
|
+
|
|
34
|
+
const kafkaCreds = KafkaCredsProvider.getKafkaCreds();
|
|
35
|
+
const admin = await createAdmin(kafkaCreds);
|
|
36
|
+
|
|
37
|
+
const existedTopic = await admin.listTopics();
|
|
38
|
+
|
|
39
|
+
await new Listr<Context>(
|
|
40
|
+
config.topics.map((topic) => ({
|
|
41
|
+
title: topic.name,
|
|
42
|
+
task: async (_ctx, parentTask): Promise<boolean | Listr> => {
|
|
43
|
+
const requireCreate = !existedTopic.includes(topic.name);
|
|
44
|
+
|
|
45
|
+
return parentTask.newListr(
|
|
46
|
+
[
|
|
47
|
+
{
|
|
48
|
+
title: requireCreate ? 'create' : 'configure',
|
|
49
|
+
task: async (): Promise<void | Listr> => {
|
|
50
|
+
if (requireCreate) {
|
|
51
|
+
await createTopic(topic, admin, parentTask);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
await KafkaTopicConfigurator.configure(
|
|
55
|
+
topic,
|
|
56
|
+
admin,
|
|
57
|
+
parentTask,
|
|
58
|
+
);
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
{ concurrent: false },
|
|
63
|
+
);
|
|
64
|
+
},
|
|
65
|
+
})),
|
|
66
|
+
{ concurrent: true },
|
|
67
|
+
).run({ requireCreate: true });
|
|
68
|
+
await admin.disconnect();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
@SubCmd('extract', 'extract kafka.yml from rsdk.json')
|
|
72
|
+
async extract(
|
|
73
|
+
@Option('from-schema', 'make from schema', Boolean) fromSchema: boolean,
|
|
74
|
+
): Promise<void> {
|
|
75
|
+
if (fromSchema) {
|
|
76
|
+
await printSchema({ outFile: printDefaultOutFile, pretty: true });
|
|
77
|
+
}
|
|
78
|
+
await KafkaConfigExtractor.extractCommand(printDefaultOutFile);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
private static logger = LoggerFactory.create(KafkaCmd);
|
|
82
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import dotenv from 'dotenv';
|
|
2
|
+
import type { KafkaConfig } from 'kafkajs';
|
|
3
|
+
|
|
4
|
+
export class KafkaCredsProvider {
|
|
5
|
+
static getKafkaCreds(): KafkaConfig {
|
|
6
|
+
dotenv.config();
|
|
7
|
+
const kafkaHost = process.env.KAFKA_HOST;
|
|
8
|
+
if (!kafkaHost) {
|
|
9
|
+
throw new Error('KAFKA_HOST not found');
|
|
10
|
+
}
|
|
11
|
+
return {
|
|
12
|
+
brokers: [kafkaHost],
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
}
|