@wabot-dev/framework 0.9.2 → 0.9.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/dist/src/addon/async/pg/PgCronJobRepository.js +7 -5
- package/dist/src/addon/async/pg/PgJobRepository.js +7 -5
- package/dist/src/addon/async/pg/PgTransactionAdapter.js +4 -4
- package/dist/src/addon/auth/api-key/ApiKey.js +4 -4
- package/dist/src/addon/auth/api-key/PgApiKeyRepository.js +9 -8
- package/dist/src/addon/auth/jwt/JwtRefreshToken.js +4 -4
- package/dist/src/addon/auth/jwt/PgJwtRefreshTokenRepository.js +6 -5
- package/dist/src/addon/chat-bot/pg/PgChatMemory.js +8 -7
- package/dist/src/addon/chat-bot/pg/PgChatRepository.js +7 -6
- package/dist/src/addon/chat-controller/cmd/@cmd.js +7 -2
- package/dist/src/addon/chat-controller/cmd/CmdChannel.js +85 -61
- package/dist/src/addon/chat-controller/cmd/CmdChannelConfig.js +8 -0
- package/dist/src/addon/chat-controller/cmd/CmdChannelServer.js +169 -0
- package/dist/src/addon/chat-controller/cmd/cmdChannelSocketPath.js +16 -0
- package/dist/src/addon/chat-controller/cmd/runCmdClient.js +226 -0
- package/dist/src/core/repository/CrudRepository.js +25 -0
- package/dist/src/feature/pg/@pgExtension.js +33 -0
- package/dist/src/feature/pg/PgJsonRepositoryAdapter.js +50 -0
- package/dist/src/feature/pg/index.js +4 -7
- package/dist/src/feature/project-runner/ProjectRunner.js +33 -10
- package/dist/src/feature/repository/@memoryExtension.js +29 -0
- package/dist/src/feature/repository/@query.js +22 -0
- package/dist/src/feature/repository/@queryExtension.js +21 -0
- package/dist/src/feature/repository/@repository.js +170 -0
- package/dist/src/feature/repository/MemoryRepositoryAdapter.js +110 -0
- package/dist/src/feature/repository/RepositoryAdapterRegistry.js +27 -0
- package/dist/src/feature/repository/RepositoryMetadataStore.js +102 -0
- package/dist/src/feature/repository/evaluateQueryAst.js +134 -0
- package/dist/src/index.d.ts +195 -47
- package/dist/src/index.js +18 -7
- package/package.json +4 -2
- package/dist/src/feature/pg/query/@pgJsonRepository.js +0 -73
- package/dist/src/feature/pg/query/@query.js +0 -14
- package/dist/src/feature/pg/query/PgJsonRepository.js +0 -23
- package/dist/src/feature/pg/query/PgRepositoryMetadataStore.js +0 -44
- /package/dist/src/feature/pg/{query/buildQuerySql.js → buildQuerySql.js} +0 -0
- /package/dist/src/feature/{pg/query → repository}/parseQueryMethodName.js +0 -0
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { __decorate, __metadata } from 'tslib';
|
|
2
2
|
import { singleton } from '../../../core/injection/index.js';
|
|
3
3
|
import { CronJob } from '../../../feature/async/CronJob.js';
|
|
4
|
-
import
|
|
5
|
-
import '../../../
|
|
4
|
+
import 'short-uuid';
|
|
5
|
+
import '../../../core/error/setupErrorHandlers.js';
|
|
6
|
+
import '../../../feature/repository/RepositoryMetadataStore.js';
|
|
7
|
+
import '../../../feature/repository/RepositoryAdapterRegistry.js';
|
|
8
|
+
import '../../../feature/pg/withPgClient.js';
|
|
6
9
|
import 'debug';
|
|
10
|
+
import '../../../feature/pg/PgLocker.js';
|
|
11
|
+
import { PgCrudRepository } from '../../../feature/pg/PgCrudRepository.js';
|
|
7
12
|
import 'node:crypto';
|
|
8
|
-
import '../../../feature/pg/withPgClient.js';
|
|
9
13
|
import '../../../feature/pg/pgStorage.js';
|
|
10
|
-
import '../../../feature/pg/query/PgJsonRepository.js';
|
|
11
|
-
import '../../../feature/pg/query/PgRepositoryMetadataStore.js';
|
|
12
14
|
import { Pool } from 'pg';
|
|
13
15
|
|
|
14
16
|
let PgCronJobRepository = class PgCronJobRepository extends PgCrudRepository {
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { __decorate, __metadata } from 'tslib';
|
|
2
2
|
import { Pool } from 'pg';
|
|
3
3
|
import { singleton } from '../../../core/injection/index.js';
|
|
4
|
-
import
|
|
5
|
-
import '../../../
|
|
4
|
+
import 'short-uuid';
|
|
5
|
+
import '../../../core/error/setupErrorHandlers.js';
|
|
6
|
+
import '../../../feature/repository/RepositoryMetadataStore.js';
|
|
7
|
+
import '../../../feature/repository/RepositoryAdapterRegistry.js';
|
|
8
|
+
import { withPgClient } from '../../../feature/pg/withPgClient.js';
|
|
6
9
|
import 'debug';
|
|
10
|
+
import '../../../feature/pg/PgLocker.js';
|
|
11
|
+
import { PgCrudRepository } from '../../../feature/pg/PgCrudRepository.js';
|
|
7
12
|
import 'node:crypto';
|
|
8
|
-
import { withPgClient } from '../../../feature/pg/withPgClient.js';
|
|
9
13
|
import '../../../feature/pg/pgStorage.js';
|
|
10
|
-
import '../../../feature/pg/query/PgJsonRepository.js';
|
|
11
|
-
import '../../../feature/pg/query/PgRepositoryMetadataStore.js';
|
|
12
14
|
import '../../../feature/async/AsyncMetadataStore.js';
|
|
13
15
|
import '../../../feature/async/TransactionMetadataStore.js';
|
|
14
16
|
import '../../../feature/async/Async.js';
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
+
import '../../../core/injection/index.js';
|
|
1
2
|
import 'short-uuid';
|
|
3
|
+
import '../../../core/error/setupErrorHandlers.js';
|
|
4
|
+
import '../../../feature/repository/RepositoryMetadataStore.js';
|
|
5
|
+
import '../../../feature/repository/RepositoryAdapterRegistry.js';
|
|
2
6
|
import { withPgClient } from '../../../feature/pg/withPgClient.js';
|
|
3
7
|
import 'debug';
|
|
4
8
|
import '../../../feature/pg/PgLocker.js';
|
|
5
|
-
import '../../../core/error/setupErrorHandlers.js';
|
|
6
9
|
import 'node:crypto';
|
|
7
10
|
import '../../../feature/pg/pgStorage.js';
|
|
8
|
-
import '../../../core/injection/index.js';
|
|
9
|
-
import '../../../feature/pg/query/PgJsonRepository.js';
|
|
10
|
-
import '../../../feature/pg/query/PgRepositoryMetadataStore.js';
|
|
11
11
|
import { withPgTransaction } from '../../../feature/pg/withPgTransaction.js';
|
|
12
12
|
|
|
13
13
|
class PgTransactionAdapter {
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { Entity } from '../../../core/entity/Entity.js';
|
|
2
2
|
import { CustomError } from '../../../core/error/CustomError.js';
|
|
3
3
|
import '../../../core/error/setupErrorHandlers.js';
|
|
4
|
-
import
|
|
4
|
+
import crypto__default from 'node:crypto';
|
|
5
5
|
|
|
6
6
|
class ApiKey extends Entity {
|
|
7
7
|
static PREFIX = 'sk_';
|
|
8
8
|
static hashSecret(secret) {
|
|
9
|
-
return
|
|
9
|
+
return crypto__default.createHash('sha256').update(secret).digest('hex');
|
|
10
10
|
}
|
|
11
11
|
get authInfo() {
|
|
12
12
|
return this.data.authInfo;
|
|
@@ -24,7 +24,7 @@ class ApiKey extends Entity {
|
|
|
24
24
|
if (this.data.secretHash) {
|
|
25
25
|
throw new Error('This API key already has a secret');
|
|
26
26
|
}
|
|
27
|
-
const secret = `${ApiKey.PREFIX}${
|
|
27
|
+
const secret = `${ApiKey.PREFIX}${crypto__default.randomBytes(32).toString('hex')}`;
|
|
28
28
|
this.data.secretHash = ApiKey.hashSecret(secret);
|
|
29
29
|
return secret;
|
|
30
30
|
}
|
|
@@ -37,7 +37,7 @@ class ApiKey extends Entity {
|
|
|
37
37
|
const stored = this.data.secretHash;
|
|
38
38
|
const hashedBuf = Buffer.from(hashed, 'hex');
|
|
39
39
|
const storedBuf = Buffer.from(stored, 'hex');
|
|
40
|
-
return hashedBuf.length === storedBuf.length &&
|
|
40
|
+
return hashedBuf.length === storedBuf.length && crypto__default.timingSafeEqual(hashedBuf, storedBuf);
|
|
41
41
|
}
|
|
42
42
|
validateSecret(secret) {
|
|
43
43
|
if (!this.isValidSecret(secret)) {
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import { __decorate, __metadata } from 'tslib';
|
|
2
|
-
import {
|
|
3
|
-
import '
|
|
4
|
-
import 'debug';
|
|
2
|
+
import { singleton } from '../../../core/injection/index.js';
|
|
3
|
+
import 'short-uuid';
|
|
5
4
|
import { CustomError } from '../../../core/error/CustomError.js';
|
|
6
|
-
import '
|
|
5
|
+
import '../../../core/error/setupErrorHandlers.js';
|
|
6
|
+
import '../../../feature/repository/RepositoryMetadataStore.js';
|
|
7
|
+
import '../../../feature/repository/RepositoryAdapterRegistry.js';
|
|
7
8
|
import '../../../feature/pg/withPgClient.js';
|
|
9
|
+
import 'debug';
|
|
10
|
+
import '../../../feature/pg/PgLocker.js';
|
|
11
|
+
import { PgCrudRepository } from '../../../feature/pg/PgCrudRepository.js';
|
|
12
|
+
import 'node:crypto';
|
|
8
13
|
import '../../../feature/pg/pgStorage.js';
|
|
9
|
-
import { singleton } from '../../../core/injection/index.js';
|
|
10
|
-
import '../../../feature/pg/query/PgJsonRepository.js';
|
|
11
|
-
import '../../../feature/pg/query/PgRepositoryMetadataStore.js';
|
|
12
14
|
import { Pool } from 'pg';
|
|
13
15
|
import { ApiKey } from './ApiKey.js';
|
|
14
|
-
import '../../../core/error/setupErrorHandlers.js';
|
|
15
16
|
|
|
16
17
|
let PgApiKeyRepository = class PgApiKeyRepository extends PgCrudRepository {
|
|
17
18
|
constructor(pool) {
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { Entity } from '../../../core/entity/Entity.js';
|
|
2
2
|
import { CustomError } from '../../../core/error/CustomError.js';
|
|
3
3
|
import '../../../core/error/setupErrorHandlers.js';
|
|
4
|
-
import
|
|
4
|
+
import crypto__default from 'node:crypto';
|
|
5
5
|
|
|
6
6
|
class JwtRefreshToken extends Entity {
|
|
7
7
|
static PREFIX = 'rt_';
|
|
8
8
|
static hashSecret(secret) {
|
|
9
|
-
return
|
|
9
|
+
return crypto__default.createHash('sha256').update(secret).digest('hex');
|
|
10
10
|
}
|
|
11
11
|
get authInfo() {
|
|
12
12
|
return this.data.authInfo;
|
|
@@ -30,7 +30,7 @@ class JwtRefreshToken extends Entity {
|
|
|
30
30
|
if (this.data.secretHash) {
|
|
31
31
|
throw new Error('This Token key already has a secret');
|
|
32
32
|
}
|
|
33
|
-
const secret = `${JwtRefreshToken.PREFIX}${
|
|
33
|
+
const secret = `${JwtRefreshToken.PREFIX}${crypto__default.randomBytes(32).toString('hex')}`;
|
|
34
34
|
this.data.secretHash = JwtRefreshToken.hashSecret(secret);
|
|
35
35
|
return secret;
|
|
36
36
|
}
|
|
@@ -43,7 +43,7 @@ class JwtRefreshToken extends Entity {
|
|
|
43
43
|
const stored = this.data.secretHash;
|
|
44
44
|
const hashedBuf = Buffer.from(hashed, 'hex');
|
|
45
45
|
const storedBuf = Buffer.from(stored, 'hex');
|
|
46
|
-
return hashedBuf.length === storedBuf.length &&
|
|
46
|
+
return hashedBuf.length === storedBuf.length && crypto__default.timingSafeEqual(hashedBuf, storedBuf);
|
|
47
47
|
}
|
|
48
48
|
isValidToken(secret) {
|
|
49
49
|
if (this.isExpired())
|
|
@@ -2,14 +2,15 @@ import { __decorate, __metadata } from 'tslib';
|
|
|
2
2
|
import { singleton } from '../../../core/injection/index.js';
|
|
3
3
|
import { CustomError } from '../../../core/error/CustomError.js';
|
|
4
4
|
import '../../../core/error/setupErrorHandlers.js';
|
|
5
|
-
import
|
|
6
|
-
import '../../../feature/
|
|
5
|
+
import 'short-uuid';
|
|
6
|
+
import '../../../feature/repository/RepositoryMetadataStore.js';
|
|
7
|
+
import '../../../feature/repository/RepositoryAdapterRegistry.js';
|
|
8
|
+
import '../../../feature/pg/withPgClient.js';
|
|
7
9
|
import 'debug';
|
|
10
|
+
import '../../../feature/pg/PgLocker.js';
|
|
11
|
+
import { PgCrudRepository } from '../../../feature/pg/PgCrudRepository.js';
|
|
8
12
|
import 'node:crypto';
|
|
9
|
-
import '../../../feature/pg/withPgClient.js';
|
|
10
13
|
import '../../../feature/pg/pgStorage.js';
|
|
11
|
-
import '../../../feature/pg/query/PgJsonRepository.js';
|
|
12
|
-
import '../../../feature/pg/query/PgRepositoryMetadataStore.js';
|
|
13
14
|
import { Pool } from 'pg';
|
|
14
15
|
import { JwtRefreshToken } from './JwtRefreshToken.js';
|
|
15
16
|
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import
|
|
2
|
-
import '
|
|
1
|
+
import '../../../core/injection/index.js';
|
|
2
|
+
import 'short-uuid';
|
|
3
|
+
import '../../../core/error/setupErrorHandlers.js';
|
|
4
|
+
import '../../../feature/repository/RepositoryMetadataStore.js';
|
|
5
|
+
import '../../../feature/repository/RepositoryAdapterRegistry.js';
|
|
6
|
+
import '../../../feature/pg/withPgClient.js';
|
|
3
7
|
import 'debug';
|
|
8
|
+
import '../../../feature/pg/PgLocker.js';
|
|
9
|
+
import { PgCrudRepository } from '../../../feature/pg/PgCrudRepository.js';
|
|
4
10
|
import 'node:crypto';
|
|
5
|
-
import '../../../feature/pg/withPgClient.js';
|
|
6
11
|
import '../../../feature/pg/pgStorage.js';
|
|
7
|
-
import '../../../core/injection/index.js';
|
|
8
|
-
import '../../../feature/pg/query/PgJsonRepository.js';
|
|
9
|
-
import '../../../feature/pg/query/PgRepositoryMetadataStore.js';
|
|
10
12
|
import '../../../feature/chat-bot/ChatAdapterRegistry.js';
|
|
11
13
|
import '../../../feature/chat-bot/ChatBot.js';
|
|
12
14
|
import { ChatItem } from '../../../feature/chat-bot/ChatItem.js';
|
|
@@ -15,7 +17,6 @@ import '../../../feature/chat-bot/UnionChatAdapter.js';
|
|
|
15
17
|
import '../../../feature/chat-bot/metadata/ChatAdapterMetadataStore.js';
|
|
16
18
|
import 'uuid';
|
|
17
19
|
import '../../../feature/chat-bot/metadata/ChatBotMetadataStore.js';
|
|
18
|
-
import '../../../core/error/setupErrorHandlers.js';
|
|
19
20
|
|
|
20
21
|
class PgChatMemory extends PgCrudRepository {
|
|
21
22
|
chatId;
|
|
@@ -2,14 +2,16 @@ import { __decorate, __metadata } from 'tslib';
|
|
|
2
2
|
import { Pool } from 'pg';
|
|
3
3
|
import { PgChatMemory } from './PgChatMemory.js';
|
|
4
4
|
import { singleton } from '../../../core/injection/index.js';
|
|
5
|
-
import
|
|
6
|
-
import '../../../
|
|
5
|
+
import 'short-uuid';
|
|
6
|
+
import '../../../core/error/setupErrorHandlers.js';
|
|
7
|
+
import '../../../feature/repository/RepositoryMetadataStore.js';
|
|
8
|
+
import '../../../feature/repository/RepositoryAdapterRegistry.js';
|
|
9
|
+
import '../../../feature/pg/withPgClient.js';
|
|
7
10
|
import 'debug';
|
|
11
|
+
import '../../../feature/pg/PgLocker.js';
|
|
12
|
+
import { PgCrudRepository } from '../../../feature/pg/PgCrudRepository.js';
|
|
8
13
|
import 'node:crypto';
|
|
9
|
-
import '../../../feature/pg/withPgClient.js';
|
|
10
14
|
import '../../../feature/pg/pgStorage.js';
|
|
11
|
-
import '../../../feature/pg/query/PgJsonRepository.js';
|
|
12
|
-
import '../../../feature/pg/query/PgRepositoryMetadataStore.js';
|
|
13
15
|
import { Chat } from '../../../feature/chat-bot/Chat.js';
|
|
14
16
|
import '../../../feature/chat-bot/ChatAdapterRegistry.js';
|
|
15
17
|
import '../../../feature/chat-bot/ChatBot.js';
|
|
@@ -18,7 +20,6 @@ import '../../../feature/chat-bot/UnionChatAdapter.js';
|
|
|
18
20
|
import '../../../feature/chat-bot/metadata/ChatAdapterMetadataStore.js';
|
|
19
21
|
import 'uuid';
|
|
20
22
|
import '../../../feature/chat-bot/metadata/ChatBotMetadataStore.js';
|
|
21
|
-
import '../../../core/error/setupErrorHandlers.js';
|
|
22
23
|
|
|
23
24
|
let PgChatRepository = class PgChatRepository extends PgCrudRepository {
|
|
24
25
|
constructor(pool) {
|
|
@@ -3,14 +3,19 @@ import { ControllerMetadataStore } from '../../../feature/chat-controller/metada
|
|
|
3
3
|
import '../../../feature/chat-controller/ChatResolver.js';
|
|
4
4
|
import '../../../feature/chat-controller/runChatControllers.js';
|
|
5
5
|
import { CmdChannel } from './CmdChannel.js';
|
|
6
|
+
import { CmdChannelConfig } from './CmdChannelConfig.js';
|
|
6
7
|
|
|
7
8
|
function cmd() {
|
|
8
9
|
return function (target, propertyKey) {
|
|
9
10
|
const store = container.resolve(ControllerMetadataStore);
|
|
11
|
+
const controllerConstructor = target.constructor;
|
|
12
|
+
const functionName = propertyKey.toString();
|
|
13
|
+
const route = `${controllerConstructor.name}.${functionName}`;
|
|
10
14
|
store.saveChannelMetadata({
|
|
11
15
|
channelConstructor: CmdChannel,
|
|
12
|
-
functionName
|
|
13
|
-
controllerConstructor
|
|
16
|
+
functionName,
|
|
17
|
+
controllerConstructor,
|
|
18
|
+
channelConfig: new CmdChannelConfig(route),
|
|
14
19
|
});
|
|
15
20
|
};
|
|
16
21
|
}
|
|
@@ -1,97 +1,121 @@
|
|
|
1
1
|
import { __decorate, __metadata } from 'tslib';
|
|
2
|
-
import { injectable } from '../../../core/injection/index.js';
|
|
3
|
-
import { Logger } from '../../../core/logger/Logger.js';
|
|
4
|
-
import { cmdChannelName } from './cmdChannelName.js';
|
|
5
|
-
import * as readline from 'node:readline';
|
|
6
2
|
import * as fs from 'node:fs';
|
|
7
3
|
import * as path from 'node:path';
|
|
4
|
+
import { injectable } from '../../../core/injection/index.js';
|
|
5
|
+
import { Logger } from '../../../core/logger/Logger.js';
|
|
8
6
|
import { Random } from '../../../core/random/Random.js';
|
|
9
7
|
import { Auth } from '../../../core/auth/Auth.js';
|
|
8
|
+
import { CmdChannelConfig } from './CmdChannelConfig.js';
|
|
9
|
+
import { CmdChannelServer } from './CmdChannelServer.js';
|
|
10
|
+
import { cmdChannelName } from './cmdChannelName.js';
|
|
10
11
|
|
|
11
12
|
var CmdChannel_1;
|
|
12
|
-
const
|
|
13
|
-
const authInfoPath = '.cmd-channel/auth-info.json';
|
|
13
|
+
const fileLogger = new Logger('wabot:cmd-channel');
|
|
14
14
|
let CmdChannel = class CmdChannel {
|
|
15
15
|
static { CmdChannel_1 = this; }
|
|
16
16
|
auth;
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
input: process.stdin,
|
|
20
|
-
output: process.stdout,
|
|
21
|
-
});
|
|
17
|
+
server;
|
|
18
|
+
config;
|
|
22
19
|
static channelName = cmdChannelName;
|
|
20
|
+
chatId = undefined;
|
|
23
21
|
callBack = null;
|
|
24
|
-
constructor(auth) {
|
|
22
|
+
constructor(auth, server, config) {
|
|
25
23
|
this.auth = auth;
|
|
24
|
+
this.server = server;
|
|
25
|
+
this.config = config;
|
|
26
26
|
}
|
|
27
27
|
listen(callback) {
|
|
28
28
|
this.callBack = callback;
|
|
29
29
|
}
|
|
30
30
|
disconnect() {
|
|
31
|
-
this.
|
|
32
|
-
this.rl.close();
|
|
31
|
+
this.server.unregister(this.config.route);
|
|
33
32
|
this.callBack = null;
|
|
34
33
|
}
|
|
35
34
|
connect() {
|
|
36
|
-
this.
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
this.
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
this.auth.assign(authInfo);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
await this.callBack({
|
|
67
|
-
channel: cmdChannelName,
|
|
68
|
-
chatConnection,
|
|
69
|
-
message: {
|
|
70
|
-
text: trimmedInput,
|
|
71
|
-
},
|
|
72
|
-
reply: async (message) => {
|
|
73
|
-
console.log(`\n[${message.senderName}]: ${message.text}\n`);
|
|
74
|
-
this.rl.prompt();
|
|
75
|
-
if (this.auth.isAssigned()) {
|
|
76
|
-
writeJsonToFile(authInfoPath, this.auth.require());
|
|
77
|
-
}
|
|
78
|
-
},
|
|
79
|
-
injectInstances: [[Auth, this.auth]],
|
|
80
|
-
});
|
|
35
|
+
this.server.register(this.config.route, {
|
|
36
|
+
onMessage: async (text, reply) => {
|
|
37
|
+
if (!this.callBack)
|
|
38
|
+
return;
|
|
39
|
+
this.ensureChatId();
|
|
40
|
+
this.ensureAuthLoaded();
|
|
41
|
+
const chatConnection = {
|
|
42
|
+
id: this.chatId,
|
|
43
|
+
chatType: 'PRIVATE',
|
|
44
|
+
channelName: CmdChannel_1.channelName,
|
|
45
|
+
};
|
|
46
|
+
await this.callBack({
|
|
47
|
+
channel: cmdChannelName,
|
|
48
|
+
chatConnection,
|
|
49
|
+
message: { text },
|
|
50
|
+
reply: async (message) => {
|
|
51
|
+
reply({
|
|
52
|
+
senderName: message.senderName,
|
|
53
|
+
text: extractDisplayText(message),
|
|
54
|
+
});
|
|
55
|
+
if (this.auth.isAssigned()) {
|
|
56
|
+
writeJsonToFile(this.authInfoPath(), this.auth.require());
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
injectInstances: [[Auth, this.auth]],
|
|
60
|
+
});
|
|
61
|
+
},
|
|
81
62
|
});
|
|
82
63
|
}
|
|
64
|
+
routeSlug() {
|
|
65
|
+
return this.config.route.replace(/[^a-zA-Z0-9._-]/g, '_');
|
|
66
|
+
}
|
|
67
|
+
chatIdPath() {
|
|
68
|
+
return path.join('.cmd-channel', this.routeSlug(), 'id.json');
|
|
69
|
+
}
|
|
70
|
+
authInfoPath() {
|
|
71
|
+
return path.join('.cmd-channel', this.routeSlug(), 'auth-info.json');
|
|
72
|
+
}
|
|
73
|
+
ensureChatId() {
|
|
74
|
+
if (this.chatId !== undefined)
|
|
75
|
+
return;
|
|
76
|
+
this.chatId = readJsonFromFile(this.chatIdPath()) ?? undefined;
|
|
77
|
+
if (!this.chatId) {
|
|
78
|
+
this.chatId = Random.alphaNumericLowerCase(10);
|
|
79
|
+
writeJsonToFile(this.chatIdPath(), this.chatId);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
ensureAuthLoaded() {
|
|
83
|
+
if (this.auth.isAssigned())
|
|
84
|
+
return;
|
|
85
|
+
const authInfo = readJsonFromFile(this.authInfoPath());
|
|
86
|
+
if (authInfo) {
|
|
87
|
+
this.auth.assign(authInfo);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
83
90
|
};
|
|
84
91
|
CmdChannel = CmdChannel_1 = __decorate([
|
|
85
92
|
injectable(),
|
|
86
|
-
__metadata("design:paramtypes", [Auth
|
|
93
|
+
__metadata("design:paramtypes", [Auth,
|
|
94
|
+
CmdChannelServer,
|
|
95
|
+
CmdChannelConfig])
|
|
87
96
|
], CmdChannel);
|
|
97
|
+
function extractDisplayText(message) {
|
|
98
|
+
const raw = message.text ?? '';
|
|
99
|
+
const trimmed = raw.trim();
|
|
100
|
+
if (!trimmed.startsWith('{') && !trimmed.startsWith('['))
|
|
101
|
+
return raw;
|
|
102
|
+
try {
|
|
103
|
+
const parsed = JSON.parse(trimmed);
|
|
104
|
+
if (parsed && typeof parsed === 'object' && typeof parsed.text === 'string') {
|
|
105
|
+
return parsed.text;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
// not JSON — fall through and return raw
|
|
110
|
+
}
|
|
111
|
+
return raw;
|
|
112
|
+
}
|
|
88
113
|
function writeJsonToFile(filename, data) {
|
|
89
114
|
const filePath = path.resolve(process.cwd(), filename);
|
|
90
115
|
const dir = path.dirname(filePath);
|
|
91
116
|
fs.mkdirSync(dir, { recursive: true });
|
|
92
117
|
fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf-8');
|
|
93
118
|
}
|
|
94
|
-
const fileLogger = new Logger('wabot:cmd-channel');
|
|
95
119
|
function readJsonFromFile(filename) {
|
|
96
120
|
const filePath = path.resolve(process.cwd(), filename);
|
|
97
121
|
if (!fs.existsSync(filePath)) {
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { __decorate } from 'tslib';
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import * as net from 'node:net';
|
|
4
|
+
import * as path from 'node:path';
|
|
5
|
+
import { singleton } from '../../../core/injection/index.js';
|
|
6
|
+
import { Logger } from '../../../core/logger/Logger.js';
|
|
7
|
+
import { cmdChannelSocketPath } from './cmdChannelSocketPath.js';
|
|
8
|
+
|
|
9
|
+
const logger = new Logger('wabot:cmd-channel-server');
|
|
10
|
+
let CmdChannelServer = class CmdChannelServer {
|
|
11
|
+
server = null;
|
|
12
|
+
channels = new Map();
|
|
13
|
+
client = null;
|
|
14
|
+
buffer = '';
|
|
15
|
+
activeRoute = null;
|
|
16
|
+
register(route, handlers) {
|
|
17
|
+
this.channels.set(route, handlers);
|
|
18
|
+
this.ensureStarted();
|
|
19
|
+
}
|
|
20
|
+
unregister(route) {
|
|
21
|
+
this.channels.delete(route);
|
|
22
|
+
if (this.activeRoute === route) {
|
|
23
|
+
this.activeRoute = null;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
ensureStarted() {
|
|
27
|
+
if (this.server)
|
|
28
|
+
return;
|
|
29
|
+
const socketPath = cmdChannelSocketPath();
|
|
30
|
+
if (process.platform !== 'win32') {
|
|
31
|
+
try {
|
|
32
|
+
fs.unlinkSync(socketPath);
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// ignore: socket file did not exist
|
|
36
|
+
}
|
|
37
|
+
fs.mkdirSync(path.dirname(socketPath), { recursive: true });
|
|
38
|
+
}
|
|
39
|
+
this.server = net.createServer((socket) => this.handleConnection(socket));
|
|
40
|
+
this.server.on('error', (err) => logger.error('cmd channel server error', err));
|
|
41
|
+
this.server.listen(socketPath, () => {
|
|
42
|
+
logger.info(`cmd channel server listening at ${socketPath}`);
|
|
43
|
+
});
|
|
44
|
+
process.once('exit', () => this.shutdown());
|
|
45
|
+
process.once('SIGINT', () => {
|
|
46
|
+
this.shutdown();
|
|
47
|
+
process.exit(0);
|
|
48
|
+
});
|
|
49
|
+
process.once('SIGTERM', () => {
|
|
50
|
+
this.shutdown();
|
|
51
|
+
process.exit(0);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
shutdown() {
|
|
55
|
+
if (this.client) {
|
|
56
|
+
this.client.destroy();
|
|
57
|
+
this.client = null;
|
|
58
|
+
}
|
|
59
|
+
if (this.server) {
|
|
60
|
+
this.server.close();
|
|
61
|
+
this.server = null;
|
|
62
|
+
}
|
|
63
|
+
if (process.platform !== 'win32') {
|
|
64
|
+
try {
|
|
65
|
+
fs.unlinkSync(cmdChannelSocketPath());
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
// ignore
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
handleConnection(socket) {
|
|
73
|
+
if (this.client) {
|
|
74
|
+
this.send(socket, {
|
|
75
|
+
type: 'error',
|
|
76
|
+
message: 'Another cmd client is already connected',
|
|
77
|
+
});
|
|
78
|
+
socket.end();
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
this.client = socket;
|
|
82
|
+
this.buffer = '';
|
|
83
|
+
this.activeRoute = null;
|
|
84
|
+
socket.on('data', (chunk) => this.handleData(chunk.toString()));
|
|
85
|
+
socket.on('close', () => {
|
|
86
|
+
if (this.client === socket) {
|
|
87
|
+
this.client = null;
|
|
88
|
+
this.activeRoute = null;
|
|
89
|
+
this.buffer = '';
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
socket.on('error', (err) => {
|
|
93
|
+
logger.warn('cmd client connection error', err);
|
|
94
|
+
if (this.client === socket) {
|
|
95
|
+
this.client = null;
|
|
96
|
+
this.activeRoute = null;
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
handleData(data) {
|
|
101
|
+
this.buffer += data;
|
|
102
|
+
let idx;
|
|
103
|
+
while ((idx = this.buffer.indexOf('\n')) !== -1) {
|
|
104
|
+
const line = this.buffer.slice(0, idx);
|
|
105
|
+
this.buffer = this.buffer.slice(idx + 1);
|
|
106
|
+
if (!line)
|
|
107
|
+
continue;
|
|
108
|
+
let msg;
|
|
109
|
+
try {
|
|
110
|
+
msg = JSON.parse(line);
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
this.sendToClient({ type: 'error', message: 'invalid json' });
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
this.handleMessage(msg).catch((err) => {
|
|
117
|
+
logger.error('cmd channel server error handling message', err);
|
|
118
|
+
this.sendToClient({ type: 'error', message: err.message });
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
async handleMessage(msg) {
|
|
123
|
+
switch (msg.type) {
|
|
124
|
+
case 'hello':
|
|
125
|
+
this.sendToClient({
|
|
126
|
+
type: 'channels',
|
|
127
|
+
list: Array.from(this.channels.keys()).map((route) => ({ route })),
|
|
128
|
+
});
|
|
129
|
+
return;
|
|
130
|
+
case 'select':
|
|
131
|
+
if (!this.channels.has(msg.route)) {
|
|
132
|
+
this.sendToClient({ type: 'error', message: `unknown route: ${msg.route}` });
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
this.activeRoute = msg.route;
|
|
136
|
+
this.sendToClient({ type: 'selected', route: msg.route });
|
|
137
|
+
return;
|
|
138
|
+
case 'message': {
|
|
139
|
+
if (!this.activeRoute) {
|
|
140
|
+
this.sendToClient({ type: 'error', message: 'no channel selected' });
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
const handlers = this.channels.get(this.activeRoute);
|
|
144
|
+
if (!handlers) {
|
|
145
|
+
this.sendToClient({ type: 'error', message: 'channel no longer available' });
|
|
146
|
+
this.activeRoute = null;
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
await handlers.onMessage(msg.text, (reply) => {
|
|
150
|
+
this.sendToClient({ type: 'reply', ...reply });
|
|
151
|
+
});
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
sendToClient(msg) {
|
|
157
|
+
if (!this.client)
|
|
158
|
+
return;
|
|
159
|
+
this.send(this.client, msg);
|
|
160
|
+
}
|
|
161
|
+
send(socket, msg) {
|
|
162
|
+
socket.write(JSON.stringify(msg) + '\n');
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
CmdChannelServer = __decorate([
|
|
166
|
+
singleton()
|
|
167
|
+
], CmdChannelServer);
|
|
168
|
+
|
|
169
|
+
export { CmdChannelServer };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as crypto from 'node:crypto';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
|
|
4
|
+
function cmdChannelSocketPath() {
|
|
5
|
+
if (process.platform === 'win32') {
|
|
6
|
+
const cwdHash = crypto
|
|
7
|
+
.createHash('sha1')
|
|
8
|
+
.update(process.cwd())
|
|
9
|
+
.digest('hex')
|
|
10
|
+
.slice(0, 12);
|
|
11
|
+
return `\\\\.\\pipe\\wabot-cmd-channel-${cwdHash}`;
|
|
12
|
+
}
|
|
13
|
+
return path.resolve(process.cwd(), '.cmd-channel/socket');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export { cmdChannelSocketPath };
|