kozz-module-maker 0.1.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/.env +2 -0
- package/.prettierrc +8 -0
- package/jest.config.ts +196 -0
- package/package.json +33 -0
- package/readme.md +187 -0
- package/src/Instance/Common/ResourceMap/index.ts +26 -0
- package/src/Instance/Common/UseFns/index.ts +22 -0
- package/src/Instance/Common/index.ts +3 -0
- package/src/Instance/Common/onEvent/index.ts +105 -0
- package/src/Instance/GeneralModule/index.ts +98 -0
- package/src/Message/FromTemplate/index.ts +74 -0
- package/src/Message/PayloadCreation/Media.ts +62 -0
- package/src/Message/PayloadCreation/React.ts +16 -0
- package/src/Message/PayloadCreation/Reply.ts +63 -0
- package/src/Message/PayloadCreation/index.ts +1 -0
- package/src/Message/PayloadCreation/sendMessage.ts +27 -0
- package/src/Message/ProxiedMessage/index.ts +27 -0
- package/src/Message/RoutineCreation/AskResource/AskResourceApi/index.ts +43 -0
- package/src/Message/RoutineCreation/AskResource/index.ts +85 -0
- package/src/Message/RoutineCreation/Reply/WithMedia.ts +63 -0
- package/src/Message/RoutineCreation/Reply/WithSticker.ts +9 -0
- package/src/Message/RoutineCreation/Reply/WithTemplate.ts +28 -0
- package/src/Message/RoutineCreation/Reply/index.ts +3 -0
- package/src/Message/RoutineCreation/SendMessage/index.ts +64 -0
- package/src/Message/RoutineCreation/reply.ts +23 -0
- package/src/Message/index.ts +44 -0
- package/src/Message/kozz-md.parser/index.ts +138 -0
- package/src/Schema/index.ts +102 -0
- package/src/Socket/Events/Emit/ForwardEvent.ts +22 -0
- package/src/Socket/Events/Emit/Introduction.ts +28 -0
- package/src/Socket/Events/Emit/RequestProxy.ts +38 -0
- package/src/Socket/Events/Emit/RevokeProxy.ts +15 -0
- package/src/Socket/Events/Handle/AskResource.ts +37 -0
- package/src/Socket/Events/Handle/Command.ts +68 -0
- package/src/Socket/Events/Handle/ProxiedMessage.ts +28 -0
- package/src/Socket/index.ts +40 -0
- package/src/Validator/index.ts +81 -0
- package/src/index.ts +2 -0
- package/src/messages.kozz.md +52 -0
- package/src/util/index.ts +89 -0
- package/test.kozz.md +81 -0
- package/tsconfig.json +100 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import * as A from 'arcsecond';
|
|
2
|
+
|
|
3
|
+
// _________________
|
|
4
|
+
// Utility functions
|
|
5
|
+
// -----------------
|
|
6
|
+
|
|
7
|
+
const anything = A.regex(/^.*/);
|
|
8
|
+
|
|
9
|
+
const exceptChars = (chars: string) => new RegExp(`^[^${chars}\n]+`);
|
|
10
|
+
|
|
11
|
+
const betweenStrings = <Ident extends string>(
|
|
12
|
+
stringLeft: string,
|
|
13
|
+
stringRight: string,
|
|
14
|
+
identifier: Ident
|
|
15
|
+
) =>
|
|
16
|
+
A.sequenceOf([
|
|
17
|
+
A.str(stringLeft),
|
|
18
|
+
A.regex(exceptChars(stringRight)),
|
|
19
|
+
A.str(stringRight),
|
|
20
|
+
]).map(
|
|
21
|
+
x =>
|
|
22
|
+
({
|
|
23
|
+
style: identifier,
|
|
24
|
+
text: x[1],
|
|
25
|
+
} as const)
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
type TemplateData = {
|
|
29
|
+
[key: string]: unknown;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
let injectableData: TemplateData = {};
|
|
33
|
+
|
|
34
|
+
// _________________
|
|
35
|
+
// Parser itself ...
|
|
36
|
+
// -----------------
|
|
37
|
+
const paragraph = A.sequenceOf([A.str('#'), A.whitespace, anything]).map(
|
|
38
|
+
x =>
|
|
39
|
+
({
|
|
40
|
+
style: 'paragraph',
|
|
41
|
+
text: x[2],
|
|
42
|
+
} as const)
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
const italic = betweenStrings('_', '_', 'italic');
|
|
46
|
+
const stroke = betweenStrings('~', '~', 'stroke');
|
|
47
|
+
const bold = betweenStrings('**', '**', 'bold');
|
|
48
|
+
const boldAndItalic = betweenStrings('**_', '_**', 'boldAndItalic');
|
|
49
|
+
const code = betweenStrings('`', '`', 'code');
|
|
50
|
+
const template = betweenStrings('{{', '}}', 'template').map(x => ({
|
|
51
|
+
...x,
|
|
52
|
+
text: `${injectableData[x.text]}`,
|
|
53
|
+
}));
|
|
54
|
+
|
|
55
|
+
const normalText = A.regex(exceptChars('`~_*{>')).map(
|
|
56
|
+
x =>
|
|
57
|
+
({
|
|
58
|
+
style: 'normal',
|
|
59
|
+
text: x,
|
|
60
|
+
} as const)
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
const listItem = A.sequenceOf([A.str('-'), A.whitespace, anything]).map(
|
|
64
|
+
x =>
|
|
65
|
+
({
|
|
66
|
+
style: 'listItem',
|
|
67
|
+
text: x[2],
|
|
68
|
+
} as const)
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
const lineBreak = A.str('<br>').map(
|
|
72
|
+
() =>
|
|
73
|
+
({
|
|
74
|
+
style: 'lineBreak',
|
|
75
|
+
text: '',
|
|
76
|
+
} as const)
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
const textLine = A.sequenceOf([
|
|
80
|
+
A.many(A.whitespace),
|
|
81
|
+
A.many1(
|
|
82
|
+
A.choice([
|
|
83
|
+
paragraph,
|
|
84
|
+
stroke,
|
|
85
|
+
listItem,
|
|
86
|
+
boldAndItalic,
|
|
87
|
+
bold,
|
|
88
|
+
italic,
|
|
89
|
+
code,
|
|
90
|
+
template,
|
|
91
|
+
lineBreak,
|
|
92
|
+
normalText,
|
|
93
|
+
])
|
|
94
|
+
),
|
|
95
|
+
A.many(A.str('\n')),
|
|
96
|
+
]).map(x => ({
|
|
97
|
+
line: x[1],
|
|
98
|
+
}));
|
|
99
|
+
|
|
100
|
+
const messageDeclaration = A.sequenceOf([
|
|
101
|
+
A.str('>'),
|
|
102
|
+
A.whitespace,
|
|
103
|
+
A.str('@'),
|
|
104
|
+
anything,
|
|
105
|
+
]).map(x => x[3]);
|
|
106
|
+
|
|
107
|
+
const messageEnd = A.sequenceOf([
|
|
108
|
+
A.str('>'),
|
|
109
|
+
A.whitespace,
|
|
110
|
+
A.str('---'),
|
|
111
|
+
A.many(A.str('-')),
|
|
112
|
+
A.many(A.str('\n')),
|
|
113
|
+
]);
|
|
114
|
+
|
|
115
|
+
const message = A.sequenceOf([
|
|
116
|
+
A.many(A.str('\n')),
|
|
117
|
+
messageDeclaration,
|
|
118
|
+
A.many1(textLine),
|
|
119
|
+
A.many(A.str('\n')),
|
|
120
|
+
messageEnd,
|
|
121
|
+
]).map(x => ({
|
|
122
|
+
messageName: x[1],
|
|
123
|
+
messageBody: x[2],
|
|
124
|
+
}));
|
|
125
|
+
|
|
126
|
+
const document = A.many(message);
|
|
127
|
+
|
|
128
|
+
const parseDocument = (documentInString: string, data: TemplateData) => {
|
|
129
|
+
injectableData = data;
|
|
130
|
+
const result = document.run(documentInString);
|
|
131
|
+
if (result.isError) {
|
|
132
|
+
throw result.error;
|
|
133
|
+
} else {
|
|
134
|
+
return result;
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
export default parseDocument;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { MessageObj } from '../Message';
|
|
2
|
+
|
|
3
|
+
export type PrimaryTypeString = 'string' | 'number' | 'boolean';
|
|
4
|
+
export type ArrayTypeString =
|
|
5
|
+
| `${PrimaryTypeString}[]`
|
|
6
|
+
| `${PrimaryTypeString}[]?`;
|
|
7
|
+
|
|
8
|
+
export type OptionalTypeString =
|
|
9
|
+
| `${ArrayTypeString}?`
|
|
10
|
+
| `${PrimaryTypeString}?`;
|
|
11
|
+
|
|
12
|
+
export type TypeString =
|
|
13
|
+
| PrimaryTypeString
|
|
14
|
+
| ArrayTypeString
|
|
15
|
+
| OptionalTypeString;
|
|
16
|
+
|
|
17
|
+
export type StringTypeVariants =
|
|
18
|
+
| 'string'
|
|
19
|
+
| 'string[]'
|
|
20
|
+
| 'string[]?'
|
|
21
|
+
| 'string?';
|
|
22
|
+
|
|
23
|
+
export type NumberTypeVariants =
|
|
24
|
+
| 'number'
|
|
25
|
+
| 'number[]'
|
|
26
|
+
| 'number[]?'
|
|
27
|
+
| 'number?';
|
|
28
|
+
|
|
29
|
+
export type BooleanTypeVariants =
|
|
30
|
+
| 'boolean'
|
|
31
|
+
| 'boolean[]'
|
|
32
|
+
| 'boolean[]?'
|
|
33
|
+
| 'boolean?';
|
|
34
|
+
|
|
35
|
+
type ToPrimary<T extends TypeString> = T extends StringTypeVariants
|
|
36
|
+
? string
|
|
37
|
+
: T extends NumberTypeVariants
|
|
38
|
+
? number
|
|
39
|
+
: T extends BooleanTypeVariants
|
|
40
|
+
? boolean
|
|
41
|
+
: never;
|
|
42
|
+
|
|
43
|
+
type ToArray<T extends ArrayTypeString> = T extends ArrayTypeString
|
|
44
|
+
? ToPrimary<T>[]
|
|
45
|
+
: ToPrimary<T>;
|
|
46
|
+
|
|
47
|
+
type ToOptional<T extends OptionalTypeString> = T extends ArrayTypeString
|
|
48
|
+
? ToArray<T> | undefined
|
|
49
|
+
: T extends OptionalTypeString
|
|
50
|
+
? ToPrimary<T> | undefined
|
|
51
|
+
: T extends PrimaryTypeString
|
|
52
|
+
? ToPrimary<T>
|
|
53
|
+
: never;
|
|
54
|
+
|
|
55
|
+
type TypeFromString<T extends TypeString> = T extends OptionalTypeString
|
|
56
|
+
? ToOptional<T>
|
|
57
|
+
: T extends ArrayTypeString
|
|
58
|
+
? ToArray<T>
|
|
59
|
+
: T extends PrimaryTypeString
|
|
60
|
+
? ToPrimary<T>
|
|
61
|
+
: never;
|
|
62
|
+
|
|
63
|
+
export type MethodCreator = <
|
|
64
|
+
const T extends { [key: string]: TypeString },
|
|
65
|
+
const Name extends string
|
|
66
|
+
>(
|
|
67
|
+
name: Name,
|
|
68
|
+
callback: (
|
|
69
|
+
requester: MessageObj,
|
|
70
|
+
args: { [key in keyof T]: TypeFromString<T[key]> }
|
|
71
|
+
) => any,
|
|
72
|
+
args?: T
|
|
73
|
+
) => MethodMap<Name, T>;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Creates a command that can be inserted in any command Handler
|
|
77
|
+
* @param name
|
|
78
|
+
* @param callback
|
|
79
|
+
* @param args
|
|
80
|
+
* @returns
|
|
81
|
+
*/
|
|
82
|
+
//@ts-ignore
|
|
83
|
+
export const createMethod: MethodCreator = (name, callback, args = {}) => {
|
|
84
|
+
return {
|
|
85
|
+
[name]: {
|
|
86
|
+
args,
|
|
87
|
+
func: callback,
|
|
88
|
+
} as const,
|
|
89
|
+
};
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
export type Method<T extends { [key: string]: TypeString }> = {
|
|
93
|
+
readonly args: T;
|
|
94
|
+
readonly func: (message: MessageObj, args: any) => any;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
export type MethodMap<
|
|
98
|
+
Name extends string,
|
|
99
|
+
T extends { [key: string]: TypeString }
|
|
100
|
+
> = {
|
|
101
|
+
[key in `${Name}`]: Method<T>;
|
|
102
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ForwardEventPayload } from 'kozz-types';
|
|
2
|
+
import { Socket } from 'socket.io-client';
|
|
3
|
+
|
|
4
|
+
type EventCallback = (payload: any) => any;
|
|
5
|
+
|
|
6
|
+
export const listenBoundary =
|
|
7
|
+
(gatewaySocket: Socket, instanceName: string) => (boundaryId: string) => {
|
|
8
|
+
return {
|
|
9
|
+
when: (eventName: string, callback: EventCallback) => {
|
|
10
|
+
const payload: ForwardEventPayload = {
|
|
11
|
+
destination: {
|
|
12
|
+
id: instanceName,
|
|
13
|
+
type: 'Handler',
|
|
14
|
+
},
|
|
15
|
+
eventName,
|
|
16
|
+
sourceId: boundaryId,
|
|
17
|
+
};
|
|
18
|
+
gatewaySocket.emit('event_forward_request', payload);
|
|
19
|
+
gatewaySocket.on(eventName, callback);
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { HandlerIntroduction, SignaturelessPayload } from 'kozz-types/dist';
|
|
2
|
+
import { Socket } from 'socket.io-client';
|
|
3
|
+
import { Method, TypeString } from '../../../Schema';
|
|
4
|
+
import { signPayload } from 'src/util';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Emits the introduction payload to the gateway
|
|
8
|
+
* @param socket
|
|
9
|
+
* @param handlerName
|
|
10
|
+
* @param methods
|
|
11
|
+
* @param signature
|
|
12
|
+
*/
|
|
13
|
+
export const introduce = <
|
|
14
|
+
T extends Record<string, Method<Record<string, TypeString>>>
|
|
15
|
+
>(
|
|
16
|
+
socket: Socket,
|
|
17
|
+
handlerName: string,
|
|
18
|
+
methods: T,
|
|
19
|
+
signature?: string
|
|
20
|
+
) => {
|
|
21
|
+
const payload: SignaturelessPayload<HandlerIntroduction> = {
|
|
22
|
+
methods: Object.keys(methods),
|
|
23
|
+
name: handlerName,
|
|
24
|
+
role: 'handler',
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
socket.emit('introduction', signPayload(payload, signature));
|
|
28
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { ProxyRequestPayload, Source } from 'kozz-types';
|
|
2
|
+
import { Socket } from 'socket.io-client';
|
|
3
|
+
import { onProxiedMessage } from '../Handle/ProxiedMessage';
|
|
4
|
+
import { ProxiedMessageObject } from 'src/Message/ProxiedMessage';
|
|
5
|
+
|
|
6
|
+
export type ProxyInitParams = {
|
|
7
|
+
address: string;
|
|
8
|
+
source: Source;
|
|
9
|
+
name: string;
|
|
10
|
+
destinationOverride?: string;
|
|
11
|
+
signature?: string;
|
|
12
|
+
onMessage: (message: ProxiedMessageObject) => any;
|
|
13
|
+
keepProxyAlive?: boolean;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const createProxyRequestPayload = (
|
|
17
|
+
proxyInitParams: ProxyInitParams
|
|
18
|
+
): ProxyRequestPayload => {
|
|
19
|
+
return {
|
|
20
|
+
source: proxyInitParams.source,
|
|
21
|
+
keepAlive: proxyInitParams.keepProxyAlive,
|
|
22
|
+
destination: proxyInitParams.destinationOverride || proxyInitParams.name,
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Request proxy for a given
|
|
28
|
+
* @param socket
|
|
29
|
+
* @param proxyInitParams
|
|
30
|
+
*/
|
|
31
|
+
export const requestProxy = (
|
|
32
|
+
socket: Socket,
|
|
33
|
+
proxyInitParams: ProxyInitParams
|
|
34
|
+
) => {
|
|
35
|
+
onProxiedMessage(socket, proxyInitParams.source, proxyInitParams.onMessage);
|
|
36
|
+
|
|
37
|
+
socket.emit('request_proxy', createProxyRequestPayload(proxyInitParams));
|
|
38
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ProxyRevokePayload, Source } from 'kozz-types';
|
|
2
|
+
import { Socket } from 'socket.io-client';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Request the revoking of a proxy
|
|
6
|
+
* @param socket
|
|
7
|
+
* @param source
|
|
8
|
+
*/
|
|
9
|
+
export const revokeProxy = (socket: Socket, source: Source) => {
|
|
10
|
+
const payload: ProxyRevokePayload = {
|
|
11
|
+
source: source,
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
socket.emit('revoke_proxy', payload);
|
|
15
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Socket } from 'socket.io-client';
|
|
2
|
+
import { ResourceMap } from '../../../Instance/Common/ResourceMap';
|
|
3
|
+
import { AskResourcePayload, ProvideResourcePayload } from 'kozz-types/dist';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Provide the resource asked
|
|
7
|
+
* @param socket
|
|
8
|
+
* @param resourceMap
|
|
9
|
+
*/
|
|
10
|
+
export const onAskResource = (socket: Socket, resourceMap: ResourceMap) => {
|
|
11
|
+
socket.on('ask_resource', (payload: AskResourcePayload) => {
|
|
12
|
+
const resourceGetter = resourceMap[payload.request.resource];
|
|
13
|
+
if (!resourceGetter)
|
|
14
|
+
return socket.emit('reply_resource', {
|
|
15
|
+
...payload,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
promisify(resourceGetter(payload.request.data)).then(resource => {
|
|
19
|
+
const responsePayload: ProvideResourcePayload = {
|
|
20
|
+
...payload,
|
|
21
|
+
response: resource,
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
socket.emit('reply_resource', responsePayload);
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const promisify = (resource: unknown) => {
|
|
30
|
+
return new Promise(resolve => {
|
|
31
|
+
if (resource instanceof Promise) {
|
|
32
|
+
resource.then(resp => resolve(resp));
|
|
33
|
+
} else {
|
|
34
|
+
resolve(resource);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Socket } from 'socket.io-client';
|
|
2
|
+
import { Command } from 'kozz-types';
|
|
3
|
+
import { Method } from '../../..';
|
|
4
|
+
import { createMessageObject } from '../../../Message';
|
|
5
|
+
import { isArgsObjectValid } from '../../../Validator';
|
|
6
|
+
import { normalizeString, runUse } from '../../../util';
|
|
7
|
+
import { UseFn } from 'src/Instance/Common';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Handles the command received. It will check if the boundary should have it's command handled,
|
|
11
|
+
* find the correct method, parse, typecheck the args, run the middlewares and try to run the method
|
|
12
|
+
* @param socket
|
|
13
|
+
* @param methods
|
|
14
|
+
* @param moduleUseFns
|
|
15
|
+
* @param handlerName
|
|
16
|
+
* @param templatePath
|
|
17
|
+
* @param boundariesToHandle
|
|
18
|
+
*/
|
|
19
|
+
export const onCommand = <
|
|
20
|
+
T extends Record<string, Method<Record<string, any>>>
|
|
21
|
+
>(
|
|
22
|
+
socket: Socket,
|
|
23
|
+
methods: T,
|
|
24
|
+
moduleUseFns: UseFn[],
|
|
25
|
+
handlerName: string,
|
|
26
|
+
templatePath: string,
|
|
27
|
+
boundariesToHandle: string[]
|
|
28
|
+
) => {
|
|
29
|
+
socket.on('command', (command: Command) => {
|
|
30
|
+
// If the handler doesnt want to handle commands for the provided boundary
|
|
31
|
+
if (
|
|
32
|
+
!boundariesToHandle.includes(command.boundaryName) &&
|
|
33
|
+
!boundariesToHandle.includes('*')
|
|
34
|
+
) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const actualMethod =
|
|
39
|
+
methods[normalizeString(normalizeString(command.method))] ||
|
|
40
|
+
methods['fallback'];
|
|
41
|
+
if (!actualMethod) return;
|
|
42
|
+
|
|
43
|
+
if (isArgsObjectValid(command.namedArgs || {}, actualMethod.args)) {
|
|
44
|
+
const updatedCommand = runUse(moduleUseFns, command);
|
|
45
|
+
|
|
46
|
+
const message = createMessageObject(
|
|
47
|
+
socket,
|
|
48
|
+
command.message,
|
|
49
|
+
handlerName,
|
|
50
|
+
templatePath
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
socket.emit('react_message', {
|
|
54
|
+
messageId: command.message.id,
|
|
55
|
+
boundaryId: command.boundaryId,
|
|
56
|
+
emote: '✔',
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
actualMethod.func(message, updatedCommand.namedArgs || {});
|
|
60
|
+
} else {
|
|
61
|
+
socket.emit('react_message', {
|
|
62
|
+
messageId: command.message.id,
|
|
63
|
+
boundaryId: command.boundaryId,
|
|
64
|
+
emote: '❌',
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Source } from 'kozz-types';
|
|
2
|
+
import { Socket } from 'socket.io-client';
|
|
3
|
+
import {
|
|
4
|
+
ProxiedMessageObject,
|
|
5
|
+
createProxiedMessageOject,
|
|
6
|
+
} from 'src/Message/ProxiedMessage';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Handles the message proxied to the handler
|
|
10
|
+
* @param socket
|
|
11
|
+
* @param source
|
|
12
|
+
* @param cb
|
|
13
|
+
*/
|
|
14
|
+
export const onProxiedMessage = (
|
|
15
|
+
socket: Socket,
|
|
16
|
+
source: Source,
|
|
17
|
+
cb: (message: ProxiedMessageObject) => any
|
|
18
|
+
) => {
|
|
19
|
+
socket.on('proxied_message', payload => {
|
|
20
|
+
const proxiedMessageObject = createProxiedMessageOject(
|
|
21
|
+
socket,
|
|
22
|
+
source,
|
|
23
|
+
payload,
|
|
24
|
+
source.split('/')[0]
|
|
25
|
+
);
|
|
26
|
+
cb(proxiedMessageObject);
|
|
27
|
+
});
|
|
28
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { io } from 'socket.io-client';
|
|
2
|
+
import { introduce } from './Events/Emit/Introduction';
|
|
3
|
+
import { Method } from '../Schema';
|
|
4
|
+
import { UseFn } from '../Instance/Common';
|
|
5
|
+
import { onCommand } from './Events/Handle/Command';
|
|
6
|
+
|
|
7
|
+
export const connect = <T extends Record<string, any>>(
|
|
8
|
+
address: string,
|
|
9
|
+
moduleUseFns: UseFn[],
|
|
10
|
+
templatePath: string,
|
|
11
|
+
handlerName: string,
|
|
12
|
+
methods: T,
|
|
13
|
+
boundariesToHandle: string[],
|
|
14
|
+
signature?: string
|
|
15
|
+
) => {
|
|
16
|
+
const socket = io(address);
|
|
17
|
+
|
|
18
|
+
socket.on('connect', () => {
|
|
19
|
+
introduce(socket, handlerName, methods, signature);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const registerMethods = <
|
|
23
|
+
T extends Record<string, Method<Record<string, any>>>
|
|
24
|
+
>(
|
|
25
|
+
methods: T
|
|
26
|
+
) =>
|
|
27
|
+
onCommand(
|
|
28
|
+
socket,
|
|
29
|
+
methods,
|
|
30
|
+
moduleUseFns,
|
|
31
|
+
handlerName,
|
|
32
|
+
templatePath,
|
|
33
|
+
boundariesToHandle
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
socket,
|
|
38
|
+
registerMethods,
|
|
39
|
+
};
|
|
40
|
+
};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ArrayTypeString,
|
|
3
|
+
OptionalTypeString,
|
|
4
|
+
PrimaryTypeString,
|
|
5
|
+
TypeString,
|
|
6
|
+
} from '../Schema';
|
|
7
|
+
|
|
8
|
+
type TypeDescriptor<T extends TypeString> = {
|
|
9
|
+
array: T extends ArrayTypeString ? true : false;
|
|
10
|
+
optional: T extends OptionalTypeString ? true : false;
|
|
11
|
+
type: T extends PrimaryTypeString
|
|
12
|
+
? T
|
|
13
|
+
: T extends `${infer Type}[]?`
|
|
14
|
+
? Type
|
|
15
|
+
: T extends `${infer Type}?`
|
|
16
|
+
? Type
|
|
17
|
+
: T extends `${infer Type}[]`
|
|
18
|
+
? Type
|
|
19
|
+
: never;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const typeIsArray = (type: TypeString): type is ArrayTypeString => {
|
|
23
|
+
return type.includes('[]');
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const typeIsOptional = (type: TypeString): type is OptionalTypeString => {
|
|
27
|
+
return type.includes('?');
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const toPrimitiveType = (type: TypeString): PrimaryTypeString => {
|
|
31
|
+
if (type.includes('boolean')) {
|
|
32
|
+
return 'boolean';
|
|
33
|
+
}
|
|
34
|
+
if (type.includes('number')) {
|
|
35
|
+
return 'number';
|
|
36
|
+
}
|
|
37
|
+
return 'string';
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export const describeType = <Type extends TypeString>(type: Type) =>
|
|
41
|
+
({
|
|
42
|
+
array: typeIsArray(type),
|
|
43
|
+
optional: typeIsOptional(type),
|
|
44
|
+
type: toPrimitiveType(type),
|
|
45
|
+
} as TypeDescriptor<Type>);
|
|
46
|
+
|
|
47
|
+
export const isArgValid = <Type extends TypeString>(
|
|
48
|
+
arg: unknown,
|
|
49
|
+
typeDescriptor: TypeDescriptor<Type>
|
|
50
|
+
) => {
|
|
51
|
+
if (arg === undefined && typeDescriptor.optional) {
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
if (Array.isArray(arg) !== typeDescriptor.array) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
if (Array.isArray(arg) && typeDescriptor.array && arg.length === 0) {
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
if (Array.isArray(arg) && typeDescriptor.array && arg.length > 0) {
|
|
61
|
+
return arg.reduce((valid, arg) => {
|
|
62
|
+
return valid && typeof arg === typeDescriptor.type;
|
|
63
|
+
}, true);
|
|
64
|
+
}
|
|
65
|
+
return typeof arg === typeDescriptor.type;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Check ifm the arguments of a provided command are valid
|
|
70
|
+
* @param args
|
|
71
|
+
* @param descriptionMap
|
|
72
|
+
* @returns
|
|
73
|
+
*/
|
|
74
|
+
export const isArgsObjectValid = <Type extends TypeString>(
|
|
75
|
+
args: Record<string, unknown>,
|
|
76
|
+
descriptionMap: Record<string, Type> = {}
|
|
77
|
+
) => {
|
|
78
|
+
return Object.entries(descriptionMap).reduce((valid, [argName, argType]) => {
|
|
79
|
+
return valid && isArgValid(args[argName], describeType(argType));
|
|
80
|
+
}, true);
|
|
81
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
> @foo
|
|
2
|
+
|
|
3
|
+
# This is the foo message
|
|
4
|
+
|
|
5
|
+
The foo message says "Hi" to {{name}}
|
|
6
|
+
|
|
7
|
+
_Nice to meet you!_
|
|
8
|
+
|
|
9
|
+
> ---
|
|
10
|
+
|
|
11
|
+
> @bar
|
|
12
|
+
|
|
13
|
+
# This is the bar message
|
|
14
|
+
|
|
15
|
+
The foo message says "GoodBye" to {{name}}
|
|
16
|
+
|
|
17
|
+
_See you soon!_
|
|
18
|
+
|
|
19
|
+
> ---
|
|
20
|
+
|
|
21
|
+
> @list
|
|
22
|
+
|
|
23
|
+
# This is the header. It can't interpolate variables.
|
|
24
|
+
|
|
25
|
+
# This is a list. The items can't interpolate variables or styles yet.
|
|
26
|
+
|
|
27
|
+
- item 1
|
|
28
|
+
- item 2
|
|
29
|
+
- item 3
|
|
30
|
+
<br>
|
|
31
|
+
|
|
32
|
+
# This is a table:
|
|
33
|
+
|
|
34
|
+
`| Command | Bot's Response |`
|
|
35
|
+
`| ------------- | -------------------------------- |`
|
|
36
|
+
`| !ping | pong! |`
|
|
37
|
+
`| !ping default | pong! |`
|
|
38
|
+
`| !ping blah | Ooops, this method doesn't exist |`
|
|
39
|
+
<br>
|
|
40
|
+
|
|
41
|
+
_Note:_ Be careful not to make wide tables, most chat's will automatically break lines that become too long.
|
|
42
|
+
<br>
|
|
43
|
+
|
|
44
|
+
Text _*bold*_ _italic_ and `monospace` can appear in the same line, but you can't mix and match them
|
|
45
|
+
In order to skip a line, use a line with nothing but `"<br>"`
|
|
46
|
+
<br>
|
|
47
|
+
<br>
|
|
48
|
+
<br>
|
|
49
|
+
|
|
50
|
+
Messages start with `"> @messageName"` and end with `"> ---"`
|
|
51
|
+
|
|
52
|
+
> ---
|