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.
Files changed (42) hide show
  1. package/.env +2 -0
  2. package/.prettierrc +8 -0
  3. package/jest.config.ts +196 -0
  4. package/package.json +33 -0
  5. package/readme.md +187 -0
  6. package/src/Instance/Common/ResourceMap/index.ts +26 -0
  7. package/src/Instance/Common/UseFns/index.ts +22 -0
  8. package/src/Instance/Common/index.ts +3 -0
  9. package/src/Instance/Common/onEvent/index.ts +105 -0
  10. package/src/Instance/GeneralModule/index.ts +98 -0
  11. package/src/Message/FromTemplate/index.ts +74 -0
  12. package/src/Message/PayloadCreation/Media.ts +62 -0
  13. package/src/Message/PayloadCreation/React.ts +16 -0
  14. package/src/Message/PayloadCreation/Reply.ts +63 -0
  15. package/src/Message/PayloadCreation/index.ts +1 -0
  16. package/src/Message/PayloadCreation/sendMessage.ts +27 -0
  17. package/src/Message/ProxiedMessage/index.ts +27 -0
  18. package/src/Message/RoutineCreation/AskResource/AskResourceApi/index.ts +43 -0
  19. package/src/Message/RoutineCreation/AskResource/index.ts +85 -0
  20. package/src/Message/RoutineCreation/Reply/WithMedia.ts +63 -0
  21. package/src/Message/RoutineCreation/Reply/WithSticker.ts +9 -0
  22. package/src/Message/RoutineCreation/Reply/WithTemplate.ts +28 -0
  23. package/src/Message/RoutineCreation/Reply/index.ts +3 -0
  24. package/src/Message/RoutineCreation/SendMessage/index.ts +64 -0
  25. package/src/Message/RoutineCreation/reply.ts +23 -0
  26. package/src/Message/index.ts +44 -0
  27. package/src/Message/kozz-md.parser/index.ts +138 -0
  28. package/src/Schema/index.ts +102 -0
  29. package/src/Socket/Events/Emit/ForwardEvent.ts +22 -0
  30. package/src/Socket/Events/Emit/Introduction.ts +28 -0
  31. package/src/Socket/Events/Emit/RequestProxy.ts +38 -0
  32. package/src/Socket/Events/Emit/RevokeProxy.ts +15 -0
  33. package/src/Socket/Events/Handle/AskResource.ts +37 -0
  34. package/src/Socket/Events/Handle/Command.ts +68 -0
  35. package/src/Socket/Events/Handle/ProxiedMessage.ts +28 -0
  36. package/src/Socket/index.ts +40 -0
  37. package/src/Validator/index.ts +81 -0
  38. package/src/index.ts +2 -0
  39. package/src/messages.kozz.md +52 -0
  40. package/src/util/index.ts +89 -0
  41. package/test.kozz.md +81 -0
  42. package/tsconfig.json +100 -0
@@ -0,0 +1,74 @@
1
+ import fs from 'fs/promises';
2
+ import parseDocument from '../kozz-md.parser';
3
+
4
+ export type Line = {
5
+ line: Text[];
6
+ };
7
+
8
+ export type Text = {
9
+ style: keyof typeof styleMap;
10
+ text: string;
11
+ };
12
+
13
+ export const bold = (s: string) => `*${s}*`;
14
+ export const italic = (s: string) => `_${s}_`;
15
+ export const stroke = (s: string) => `~${s}~`;
16
+ export const monospace = (s: string) => `\`\`\`${s}\`\`\``;
17
+
18
+ const styleMap = {
19
+ bold: bold,
20
+ stroke: stroke,
21
+ italic: italic,
22
+ code: monospace,
23
+ boldAndItalic: (s: string) => bold(italic(s)),
24
+ normal: (s: string) => s,
25
+ template: (s: string) => s,
26
+ paragraph: (s: string) => `${bold(s)}\n`,
27
+ listItem: (s: string) => ` - ${s}`,
28
+ lineBreak: (s: string) => '',
29
+ };
30
+
31
+ export const getTemplates = (path: string) =>
32
+ fs.readFile(path, { encoding: 'utf-8' });
33
+
34
+ const textMessageFromTemplate = (
35
+ templateName: string,
36
+ documentAsString: string,
37
+ templateData: Record<string, any> = {}
38
+ ) => {
39
+ const { result } = parseDocument(documentAsString, templateData);
40
+
41
+ const myMessage = result.filter(msg => msg.messageName === templateName)[0];
42
+
43
+ if (!myMessage) {
44
+ return console.error('No message found for the provided name');
45
+ }
46
+
47
+ return myMessage.messageBody.reduce((msg, { line }) => {
48
+ line.forEach(styledText => {
49
+ // I know this type asting is ugly
50
+ const stylingFn = styleMap[styledText.style as keyof typeof styleMap];
51
+ return (msg += stylingFn(styledText.text));
52
+ });
53
+ return (msg += '\n');
54
+ }, '');
55
+ };
56
+
57
+ /**
58
+ * Creates the ability to send messages from a message template
59
+ * @param path
60
+ * @returns
61
+ */
62
+ export const loadTemplates = (path: string) => {
63
+ const getTextFromTemplate = (
64
+ templateName: string,
65
+ templateData: Record<string, any> = {}
66
+ ) => {
67
+ return getTemplates(path).then(templates => {
68
+ return textMessageFromTemplate(templateName, templates, templateData);
69
+ });
70
+ };
71
+ return {
72
+ getTextFromTemplate,
73
+ };
74
+ };
@@ -0,0 +1,62 @@
1
+ import fs from 'fs/promises';
2
+ import { Media } from 'kozz-types';
3
+
4
+ export type MimeType =
5
+ | 'video/mp4'
6
+ | 'image/gif'
7
+ | 'image'
8
+ | 'video'
9
+ | 'video/mpeg'
10
+ | 'audio/webm';
11
+
12
+ export const loadMediaFromPath = async (
13
+ filePath: string,
14
+ mimeType: MimeType
15
+ ): Promise<Media> => {
16
+ const b64 = await fs.readFile(filePath, 'base64');
17
+ const fileName = null;
18
+
19
+ return {
20
+ data: b64,
21
+ fileName,
22
+ mimeType,
23
+ sizeInBytes: Buffer.from(b64, 'base64').length,
24
+ transportType: 'b64',
25
+ };
26
+ };
27
+
28
+ export const createMediaFromBuffer = (
29
+ buffer: Buffer,
30
+ mimeType: MimeType,
31
+ fileName?: string
32
+ ): Media => ({
33
+ data: buffer.toString('base64'),
34
+ fileName: fileName || null,
35
+ mimeType: mimeType,
36
+ sizeInBytes: buffer.length,
37
+ transportType: 'b64',
38
+ });
39
+
40
+ export const createMediaFromB64 = (
41
+ b64: string,
42
+ mimeType: MimeType,
43
+ fileName?: string
44
+ ): Media => ({
45
+ data: b64,
46
+ fileName: fileName || mimeType,
47
+ mimeType: mimeType,
48
+ sizeInBytes: Buffer.from(b64, 'base64').length,
49
+ transportType: 'b64',
50
+ });
51
+
52
+ export const createMediaFromUrl = (
53
+ url: string,
54
+ mimeType: MimeType,
55
+ fileName?: string
56
+ ): Media => ({
57
+ data: url,
58
+ fileName: fileName || mimeType,
59
+ mimeType: mimeType,
60
+ sizeInBytes: null,
61
+ transportType: 'url',
62
+ });
@@ -0,0 +1,16 @@
1
+ import { Command, MessageReceivedByGateway } from 'kozz-types';
2
+ import { Socket } from 'socket.io-client';
3
+
4
+ export const createReact = (
5
+ socket: Socket,
6
+ messagePayload: MessageReceivedByGateway
7
+ ) => {
8
+ const react = (emote: string) =>
9
+ socket.emit('react_message', {
10
+ messageId: messagePayload.id,
11
+ boundaryId: messagePayload.boundaryId,
12
+ emote,
13
+ });
14
+
15
+ return react;
16
+ };
@@ -0,0 +1,63 @@
1
+ import {
2
+ Command,
3
+ Media,
4
+ MessageReceivedByGateway,
5
+ SendMessagePayload,
6
+ } from 'kozz-types';
7
+
8
+ export const replyWithText = (
9
+ messagePayload: MessageReceivedByGateway,
10
+ string: string
11
+ ): SendMessagePayload => ({
12
+ body: string,
13
+ boundaryId: messagePayload.boundaryId,
14
+ chatId: messagePayload.to,
15
+ contact: messagePayload.contact,
16
+ platform: messagePayload.platform,
17
+ timestamp: new Date().getTime(),
18
+ quoteId: messagePayload.id,
19
+ });
20
+
21
+ export const replyWithSticker = (
22
+ messagePayload: MessageReceivedByGateway,
23
+ media: Media
24
+ ): SendMessagePayload => ({
25
+ body: '',
26
+ media: media,
27
+ chatId: messagePayload.to,
28
+ platform: 'WA',
29
+ timestamp: new Date().getTime(),
30
+ quoteId: messagePayload.id,
31
+ boundaryId: messagePayload.boundaryId,
32
+ contact: messagePayload.contact,
33
+ });
34
+
35
+ export const replyWithMedia = (
36
+ messagePayload: MessageReceivedByGateway,
37
+ media: Media,
38
+ caption?: string
39
+ ): SendMessagePayload => ({
40
+ body: caption || '',
41
+ media: media,
42
+ chatId: messagePayload.to,
43
+ platform: 'WA',
44
+ timestamp: new Date().getTime(),
45
+ quoteId: messagePayload.id,
46
+ boundaryId: messagePayload.boundaryId,
47
+ contact: messagePayload.contact,
48
+ });
49
+
50
+ export const replyWithMediaFromUrl = (
51
+ messagePayload: MessageReceivedByGateway,
52
+ media: Media,
53
+ caption?: string
54
+ ): SendMessagePayload => ({
55
+ body: caption || '',
56
+ media: media,
57
+ chatId: messagePayload.to,
58
+ platform: 'WA',
59
+ timestamp: new Date().getTime(),
60
+ quoteId: messagePayload.id,
61
+ boundaryId: messagePayload.boundaryId,
62
+ contact: messagePayload.contact,
63
+ });
@@ -0,0 +1 @@
1
+ export * from './Reply';
@@ -0,0 +1,27 @@
1
+ import { Media, SendMessagePayload } from 'kozz-types';
2
+
3
+ export const createSendMessagePayload = (
4
+ handlerName: string,
5
+ contactId: string,
6
+ boundaryId: string,
7
+ body: string,
8
+ media?: Media
9
+ ): SendMessagePayload => {
10
+ return {
11
+ body,
12
+ boundaryId: boundaryId,
13
+ chatId: contactId,
14
+ contact: {
15
+ publicName: handlerName,
16
+ privateName: handlerName,
17
+ id: handlerName,
18
+ isBlocked: false,
19
+ hostAdded: true,
20
+ isGroup: false,
21
+ },
22
+ platform: 'WA',
23
+ timestamp: new Date().getTime(),
24
+ quoteId: undefined,
25
+ media,
26
+ };
27
+ };
@@ -0,0 +1,27 @@
1
+ import {
2
+ Command,
3
+ MessageReceived,
4
+ MessageReceivedByGateway,
5
+ Source,
6
+ } from 'kozz-types';
7
+ import { Socket } from 'socket.io-client';
8
+ import { createMessageObject } from '..';
9
+ import { revokeProxy } from '../../Socket/Events/Emit/RevokeProxy';
10
+
11
+ export type ProxiedMessageObject = ReturnType<typeof createProxiedMessageOject>;
12
+
13
+ export const createProxiedMessageOject = (
14
+ socket: Socket,
15
+ source: Source,
16
+ message: MessageReceivedByGateway,
17
+ handlerName: string
18
+ ) => {
19
+ const messageObject = createMessageObject(socket, message, handlerName);
20
+
21
+ const revoke = () => revokeProxy(socket, source);
22
+
23
+ return {
24
+ ...messageObject,
25
+ revoke,
26
+ };
27
+ };
@@ -0,0 +1,43 @@
1
+ import { Socket } from 'socket.io-client';
2
+ import { AskResourcePayload, ProvideResourcePayload } from 'kozz-types';
3
+
4
+ type RequestData = {
5
+ [key in keyof AskResourcePayload]: key extends 'request'
6
+ ? Omit<AskResourcePayload[key], 'id'>
7
+ : AskResourcePayload[key];
8
+ };
9
+
10
+ /**
11
+ * Promisified interface for askin resource to other entities connected to the
12
+ * gateway
13
+ * @param socket
14
+ * @param requestData
15
+ * @returns {Promise<ProvideResourcePayload>}
16
+ */
17
+ export const ask = async (
18
+ socket: Socket,
19
+ requestData: RequestData
20
+ ): Promise<ProvideResourcePayload> => {
21
+ const requestId: `${string}/${number}` = `${requestData.responder.id}/${
22
+ requestData.timestamp * 100 + Math.random() * 100
23
+ }`;
24
+
25
+ const requestPayload: AskResourcePayload = {
26
+ ...requestData,
27
+ request: {
28
+ ...requestData.request,
29
+ id: requestId,
30
+ },
31
+ };
32
+
33
+ socket.emit('ask_resource', requestPayload);
34
+
35
+ return new Promise(resolve => {
36
+ socket.once(
37
+ `reply_resource/${requestId}`,
38
+ (payload: ProvideResourcePayload) => {
39
+ resolve(payload);
40
+ }
41
+ );
42
+ });
43
+ };
@@ -0,0 +1,85 @@
1
+ import { AskResourcePayload } from 'kozz-types/dist';
2
+ import { Socket } from 'socket.io-client';
3
+ import { ask as askResourceFn } from './AskResourceApi';
4
+
5
+ type RequestResourceArgs = {
6
+ requester: AskResourcePayload['requester'];
7
+ };
8
+
9
+ type AskResourceArgs = {
10
+ resource: Omit<AskResourcePayload['request'], 'id'>;
11
+ responder: AskResourcePayload['responder'];
12
+ };
13
+
14
+ export const createAskResource = (
15
+ socket: Socket,
16
+ args: RequestResourceArgs
17
+ ) => {
18
+ const ask = async (askArgs: AskResourceArgs) => {
19
+ const response = await askResourceFn(socket, {
20
+ request: askArgs.resource,
21
+ responder: askArgs.responder,
22
+ requester: args.requester,
23
+ timestamp: new Date().getTime(),
24
+ });
25
+ return response;
26
+ };
27
+
28
+ ask.boundary = (
29
+ boundaryId: string,
30
+ resourceName: string,
31
+ requestArgs: AskResourceArgs['resource']['data'] = {}
32
+ ) => {
33
+ return askResourceFn(socket, {
34
+ request: {
35
+ resource: resourceName,
36
+ data: requestArgs,
37
+ },
38
+ requester: args.requester,
39
+ timestamp: new Date().getTime(),
40
+ responder: {
41
+ id: boundaryId,
42
+ type: 'Boundary',
43
+ },
44
+ });
45
+ };
46
+
47
+ ask.handler = (
48
+ handlerId: string,
49
+ resourceName: string,
50
+ requestArgs: AskResourceArgs['resource']['data'] = {}
51
+ ) => {
52
+ return askResourceFn(socket, {
53
+ request: {
54
+ resource: resourceName,
55
+ data: requestArgs,
56
+ },
57
+ requester: args.requester,
58
+ timestamp: new Date().getTime(),
59
+ responder: {
60
+ id: handlerId,
61
+ type: 'Handler',
62
+ },
63
+ });
64
+ };
65
+
66
+ ask.gateway = (
67
+ resourceName: string,
68
+ requestArgs: AskResourceArgs['resource']['data'] = {}
69
+ ) => {
70
+ return askResourceFn(socket, {
71
+ request: {
72
+ resource: resourceName,
73
+ data: requestArgs,
74
+ },
75
+ requester: args.requester,
76
+ timestamp: new Date().getTime(),
77
+ responder: {
78
+ id: 'Gateway',
79
+ type: 'Gateway',
80
+ },
81
+ });
82
+ };
83
+
84
+ return ask;
85
+ };
@@ -0,0 +1,63 @@
1
+ import { Command, Media, MessageReceivedByGateway } from 'kozz-types/dist';
2
+ import { Socket } from 'socket.io-client';
3
+ import { replyWithMedia } from '../../../Message/PayloadCreation';
4
+ import {
5
+ MimeType,
6
+ loadMediaFromPath,
7
+ createMediaFromBuffer,
8
+ createMediaFromB64,
9
+ createMediaFromUrl,
10
+ } from '../../../Message/PayloadCreation/Media';
11
+
12
+ export const withMedia = (
13
+ socket: Socket,
14
+ messagePayload: MessageReceivedByGateway
15
+ ) => {
16
+ /**
17
+ * Replies with a media
18
+ * @param {Media} media
19
+ * @param {string} caption
20
+ */
21
+ const replyMedia = (media: Media, caption?: string) => {
22
+ socket.emit(
23
+ 'reply_with_media',
24
+ replyWithMedia(messagePayload, media, caption)
25
+ );
26
+ };
27
+
28
+ replyMedia.fromPath = async (
29
+ path: string,
30
+ mimeType: MimeType,
31
+ caption?: string
32
+ ) => {
33
+ const media = await loadMediaFromPath(path, mimeType);
34
+ replyMedia(media, caption);
35
+ };
36
+
37
+ replyMedia.fromBuffer = (
38
+ buffer: Buffer,
39
+ mimeType: MimeType,
40
+ caption?: string,
41
+ fileName?: string
42
+ ) => {
43
+ const media = createMediaFromBuffer(buffer, mimeType, fileName);
44
+ replyMedia(media, caption);
45
+ };
46
+
47
+ replyMedia.fromB64 = (
48
+ b64: string,
49
+ mimeType: MimeType,
50
+ caption?: string,
51
+ fileName?: string
52
+ ) => {
53
+ const media = createMediaFromB64(b64, mimeType, fileName);
54
+ replyMedia(media, caption);
55
+ };
56
+
57
+ replyMedia.fromUrl = (url: string, mimeType: MimeType, caption?: string) => {
58
+ const media = createMediaFromUrl(url, mimeType);
59
+ replyMedia(media, caption);
60
+ };
61
+
62
+ return replyMedia;
63
+ };
@@ -0,0 +1,9 @@
1
+ import { Media, Command, MessageReceivedByGateway } from 'kozz-types/dist';
2
+ import { Socket } from 'socket.io-client';
3
+ import { replyWithSticker } from '../../PayloadCreation';
4
+
5
+ export const withSticker =
6
+ (socket: Socket, messagePayload: MessageReceivedByGateway) =>
7
+ (media: Media) => {
8
+ socket.emit('reply_with_sticker', replyWithSticker(messagePayload, media));
9
+ };
@@ -0,0 +1,28 @@
1
+ import { Command, MessageReceivedByGateway } from 'kozz-types/dist';
2
+ import { Socket } from 'socket.io-client';
3
+ import { loadTemplates } from '../../../Message/FromTemplate';
4
+ import { replyWithText } from '../../../Message/PayloadCreation';
5
+
6
+ export const withTemplate =
7
+ (
8
+ socket: Socket,
9
+ messagePayload: MessageReceivedByGateway,
10
+ templatePath?: string
11
+ ) =>
12
+ (templateName: string, templateData: Record<string, any> = {}) => {
13
+ if (!templatePath) {
14
+ throw 'Trying to reply with template but no template path was provided';
15
+ }
16
+
17
+ loadTemplates(templatePath)
18
+ .getTextFromTemplate(templateName, templateData)
19
+ .then(textResponse => {
20
+ if (!textResponse) {
21
+ throw `Error while trying to reply from template ${templateName}, could not find it's template in ${templatePath}`;
22
+ }
23
+ socket.emit(
24
+ 'reply_with_text',
25
+ replyWithText(messagePayload, textResponse)
26
+ );
27
+ });
28
+ };
@@ -0,0 +1,3 @@
1
+ export { withTemplate } from './WithTemplate';
2
+ export { withSticker } from './WithSticker';
3
+ export { withMedia } from './WithMedia';
@@ -0,0 +1,64 @@
1
+ import { Command, Media, MessageReceivedByGateway } from 'kozz-types';
2
+ import { Socket } from 'socket.io-client';
3
+ import { createSendMessagePayload } from '../../../Message/PayloadCreation/sendMessage';
4
+
5
+ export const sendMessageToContactOnRequesterObject = (
6
+ socket: Socket,
7
+ handlerName: string,
8
+ boundaryId: string
9
+ ) => {
10
+ const sendMessage = (contactId: string, body: string) => {
11
+ socket.emit(
12
+ 'send_message',
13
+ createSendMessagePayload(handlerName, contactId, boundaryId, body)
14
+ );
15
+ };
16
+
17
+ sendMessage.withMedia = (
18
+ contactId: string,
19
+ caption: string,
20
+ media: Media
21
+ ) => {
22
+ socket.emit(
23
+ 'send_message',
24
+ createSendMessagePayload(
25
+ handlerName,
26
+ contactId,
27
+ boundaryId,
28
+ caption,
29
+ media
30
+ )
31
+ );
32
+ };
33
+
34
+ return sendMessage;
35
+ };
36
+
37
+ export const sendMessageToContact = (socket: Socket, handlerName: string) => {
38
+ const sendMessage = (contactId: string, boundaryId: string, body: string) => {
39
+ socket.emit(
40
+ 'send_message',
41
+ createSendMessagePayload(handlerName, contactId, boundaryId, body)
42
+ );
43
+ };
44
+
45
+ sendMessage.withMedia = (
46
+ contactId: string,
47
+ boundaryId: string,
48
+ caption: string,
49
+ media: Media
50
+ ) => {
51
+ socket.emit(
52
+ 'send_message',
53
+ createSendMessagePayload(
54
+ handlerName,
55
+ contactId,
56
+ boundaryId,
57
+ caption,
58
+ media
59
+ )
60
+ );
61
+ };
62
+
63
+ return sendMessage;
64
+ };
@@ -0,0 +1,23 @@
1
+ import { Command, MessageReceivedByGateway } from 'kozz-types';
2
+ import { Socket } from 'socket.io-client';
3
+ import { replyWithText } from '../PayloadCreation';
4
+
5
+ import { withMedia } from './Reply/WithMedia';
6
+ import { withSticker } from './Reply/WithSticker';
7
+ import { withTemplate } from './Reply/WithTemplate';
8
+
9
+ export const createReply = (
10
+ socket: Socket,
11
+ messagePayload: MessageReceivedByGateway,
12
+ templatePath?: string
13
+ ) => {
14
+ const reply = (text: string) => {
15
+ socket.emit('reply_with_text', replyWithText(messagePayload, text));
16
+ };
17
+
18
+ reply.withSticker = withSticker(socket, messagePayload);
19
+ reply.withTemplate = withTemplate(socket, messagePayload, templatePath);
20
+ reply.withMedia = withMedia(socket, messagePayload);
21
+
22
+ return reply;
23
+ };
@@ -0,0 +1,44 @@
1
+ import { Command, MessageReceivedByGateway } from 'kozz-types';
2
+ import { Socket } from 'socket.io-client';
3
+ import { createReply } from './RoutineCreation/reply';
4
+ import { createAskResource } from './RoutineCreation/AskResource';
5
+ import { sendMessageToContactOnRequesterObject } from './RoutineCreation/SendMessage';
6
+ import { createReact } from './PayloadCreation/React';
7
+ export * from './FromTemplate';
8
+
9
+ export type MessageObj = ReturnType<typeof createMessageObject>;
10
+
11
+ export const createMessageObject = (
12
+ socket: Socket,
13
+ messagePayload: MessageReceivedByGateway,
14
+ handlerId: string,
15
+ templatePath?: string,
16
+ command?: Command
17
+ ) => {
18
+ /**
19
+ * Replies the requester of the command.
20
+ */
21
+ const reply = createReply(socket, messagePayload, templatePath);
22
+ const sendMessage = sendMessageToContactOnRequesterObject(
23
+ socket,
24
+ handlerId,
25
+ messagePayload.from
26
+ );
27
+
28
+ const ask = createAskResource(socket, {
29
+ requester: {
30
+ id: handlerId,
31
+ type: 'Handler',
32
+ },
33
+ });
34
+ const react = createReact(socket, messagePayload);
35
+
36
+ return {
37
+ ask,
38
+ sendMessage,
39
+ react,
40
+ rawCommand: command,
41
+ message: messagePayload,
42
+ reply,
43
+ };
44
+ };