@nu-art/slack-backend 0.401.9 → 0.500.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.
@@ -3,7 +3,7 @@
3
3
  */
4
4
  import { Module } from '@nu-art/ts-common';
5
5
  import { WebClientOptions } from '@slack/web-api';
6
- import { PreSendSlackStructuredMessage } from '@nu-art/slack-shared';
6
+ import { API_Slack, PreSendSlackStructuredMessage } from '@nu-art/slack-shared';
7
7
  import { Stream } from 'stream';
8
8
  export type ConfigType_ModuleBE_Slack = {
9
9
  token: string;
@@ -28,9 +28,13 @@ export declare class ModuleBE_Slack_Class extends Module<ConfigType_ModuleBE_Sla
28
28
  private messageMap;
29
29
  constructor();
30
30
  protected init(): void;
31
- postMessage(text: string, channel?: string, thread?: ThreadPointer): Promise<ThreadPointer | undefined>;
31
+ postMessage(request: API_Slack['postMessage']['Body']): Promise<void>;
32
+ postStructuredMessage(request: API_Slack['postStructuredMessage']['Body']): Promise<API_Slack['postStructuredMessage']['Response']>;
33
+ sendFEMessage(request: API_Slack['sendFEMessage']['Body']): Promise<void>;
34
+ postFiles(request: API_Slack['postFiles']['Body']): Promise<API_Slack['postFiles']['Response']>;
35
+ sendText(text: string, channel?: string, thread?: ThreadPointer): Promise<ThreadPointer | undefined>;
32
36
  postFile(file: Buffer, name: string, thread?: ThreadPointer): Promise<import("@slack/web-api").FilesCompleteUploadExternalResponse>;
33
- postStructuredMessage(message: PreSendSlackStructuredMessage, thread?: ThreadPointer): Promise<ThreadPointer>;
37
+ sendStructured(message: PreSendSlackStructuredMessage, thread?: ThreadPointer): Promise<ThreadPointer>;
34
38
  private postMessageImpl;
35
39
  uploadFile: (file: Buffer | Stream, name: string, tp?: ThreadPointer) => Promise<import("@slack/web-api").FilesUploadResponse>;
36
40
  getUserIdByEmail(email: string): Promise<string | undefined>;
package/ModuleBE_Slack.js CHANGED
@@ -16,134 +16,188 @@
16
16
  * See the License for the specific language governing permissions and
17
17
  * limitations under the License.
18
18
  */
19
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
20
+ var useValue = arguments.length > 2;
21
+ for (var i = 0; i < initializers.length; i++) {
22
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
23
+ }
24
+ return useValue ? value : void 0;
25
+ };
26
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
27
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
28
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
29
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
30
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
31
+ var _, done = false;
32
+ for (var i = decorators.length - 1; i >= 0; i--) {
33
+ var context = {};
34
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
35
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
36
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
37
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
38
+ if (kind === "accessor") {
39
+ if (result === void 0) continue;
40
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
41
+ if (_ = accept(result.get)) descriptor.get = _;
42
+ if (_ = accept(result.set)) descriptor.set = _;
43
+ if (_ = accept(result.init)) initializers.unshift(_);
44
+ }
45
+ else if (_ = accept(result)) {
46
+ if (kind === "field") initializers.unshift(_);
47
+ else descriptor[key] = _;
48
+ }
49
+ }
50
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
51
+ done = true;
52
+ };
19
53
  /**
20
54
  * Created by AlanBen on 29/08/2019.
21
55
  */
22
56
  import { currentTimeMillis, ImplementationMissingException, md5, Minute, Module } from '@nu-art/ts-common';
23
57
  import { WebClient, } from '@slack/web-api';
24
- import { addRoutes, AxiosHttpModule, createBodyServerApi } from '@nu-art/thunderstorm-backend';
58
+ import { ApiHandler } from '@nu-art/http-server';
25
59
  import { ApiDef_Slack } from '@nu-art/slack-shared';
26
60
  import { postSlackMessageErrorHandler } from './utils.js';
27
61
  import { HttpCodes } from '@nu-art/ts-common/core/exceptions/http-codes';
28
62
  import { SlackBuilderBE } from './SlackBuilderBE.js';
29
- import { HttpMethod } from '@nu-art/thunderstorm-shared';
30
- export class ModuleBE_Slack_Class extends Module {
31
- web;
32
- messageMap = {};
33
- constructor() {
34
- super('slack');
35
- this.setDefaultConfig({ unfurl_links: false, unfurl_media: false });
36
- }
37
- init() {
38
- if (!this.config.token)
39
- throw new ImplementationMissingException('Missing config token for ModuleBE_Slack. Please add it');
40
- this.web = new WebClient(this.config.token, {
41
- rejectRateLimitedCalls: true,
42
- ...this.config.slackConfig
43
- });
44
- addRoutes([
45
- createBodyServerApi(ApiDef_Slack.vv1.postMessage, async (request) => {
46
- await this.postMessage(request.message, request.channel);
47
- }),
48
- createBodyServerApi(ApiDef_Slack.vv1.postStructuredMessage, async (request) => {
49
- return { threadPointer: await this.postStructuredMessage(request.message, request.thread) };
50
- }),
51
- createBodyServerApi(ApiDef_Slack.vv1.sendFEMessage, async (request) => {
52
- const slackMessage = new SlackBuilderBE(request.channel, request.messageBlocks, request.messageReplies);
53
- await slackMessage.send();
54
- }),
55
- createBodyServerApi(ApiDef_Slack.vv1.postFiles, async (request) => this.postFile(request.file, request.name, request.thread))
56
- ]);
57
- }
58
- async postMessage(text, channel, thread) {
59
- const message = {
60
- channel: channel ?? this.config.defaultChannel,
61
- };
62
- // @ts-ignore - no clue why, their api requires text but it is not in the te
63
- message.text = text;
64
- //Block same message on throttling time
65
- const time = this.messageMap[md5(text)];
66
- if (time && currentTimeMillis() - time < (this.config.throttlingTime || Minute))
67
- return;
68
- //Post and return thread
69
- return await this.postMessageImpl(message, thread);
70
- }
71
- async postFile(file, name, thread) {
72
- // Get a URL to upload
73
- const uploadUrlResponse = await this.web.files.getUploadURLExternal({
74
- filename: name,
75
- length: file.length
76
- });
77
- if (!uploadUrlResponse.ok)
78
- throw HttpCodes._5XX.INTERNAL_SERVER_ERROR(`Failed at getting a URL from slack: ${uploadUrlResponse.error}`);
79
- const { upload_url, file_id } = uploadUrlResponse;
80
- try {
81
- await AxiosHttpModule.createRequest({
82
- fullUrl: upload_url,
83
- path: '',
84
- method: HttpMethod.POST
85
- })
86
- .setBody(file)
87
- .executeSync();
63
+ let ModuleBE_Slack_Class = (() => {
64
+ let _classSuper = Module;
65
+ let _instanceExtraInitializers = [];
66
+ let _postMessage_decorators;
67
+ let _postStructuredMessage_decorators;
68
+ let _sendFEMessage_decorators;
69
+ let _postFiles_decorators;
70
+ return class ModuleBE_Slack_Class extends _classSuper {
71
+ static {
72
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
73
+ _postMessage_decorators = [ApiHandler(ApiDef_Slack.postMessage)];
74
+ _postStructuredMessage_decorators = [ApiHandler(ApiDef_Slack.postStructuredMessage)];
75
+ _sendFEMessage_decorators = [ApiHandler(ApiDef_Slack.sendFEMessage)];
76
+ _postFiles_decorators = [ApiHandler(ApiDef_Slack.postFiles)];
77
+ __esDecorate(this, null, _postMessage_decorators, { kind: "method", name: "postMessage", static: false, private: false, access: { has: obj => "postMessage" in obj, get: obj => obj.postMessage }, metadata: _metadata }, null, _instanceExtraInitializers);
78
+ __esDecorate(this, null, _postStructuredMessage_decorators, { kind: "method", name: "postStructuredMessage", static: false, private: false, access: { has: obj => "postStructuredMessage" in obj, get: obj => obj.postStructuredMessage }, metadata: _metadata }, null, _instanceExtraInitializers);
79
+ __esDecorate(this, null, _sendFEMessage_decorators, { kind: "method", name: "sendFEMessage", static: false, private: false, access: { has: obj => "sendFEMessage" in obj, get: obj => obj.sendFEMessage }, metadata: _metadata }, null, _instanceExtraInitializers);
80
+ __esDecorate(this, null, _postFiles_decorators, { kind: "method", name: "postFiles", static: false, private: false, access: { has: obj => "postFiles" in obj, get: obj => obj.postFiles }, metadata: _metadata }, null, _instanceExtraInitializers);
81
+ if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
88
82
  }
89
- catch (e) {
90
- throw HttpCodes._5XX.INTERNAL_SERVER_ERROR(`Failed at uploading file to url: ${e.message}`);
83
+ web = __runInitializers(this, _instanceExtraInitializers);
84
+ messageMap = {};
85
+ constructor() {
86
+ super('slack');
87
+ this.setDefaultConfig({ unfurl_links: false, unfurl_media: false });
91
88
  }
92
- // Complete the upload - post the file to slack message
93
- const completeResponse = await this.web.files.completeUploadExternal({
94
- files: [{ id: file_id }],
95
- channel_id: thread ? thread.channel : this.config.defaultChannel,
96
- thread_ts: thread?.ts,
97
- });
98
- if (!completeResponse.ok)
99
- throw HttpCodes._5XX.INTERNAL_SERVER_ERROR(`Failed at complete uploading: ${completeResponse.error}`);
100
- return completeResponse;
101
- }
102
- async postStructuredMessage(message, thread) {
103
- message.channel ??= this.config.defaultChannel;
104
- return await this.postMessageImpl(message, thread);
105
- }
106
- async postMessageImpl(message, threadPointer) {
107
- try {
108
- if (threadPointer) {
109
- message.thread_ts = threadPointer.ts;
110
- message.channel = threadPointer.channel;
89
+ init() {
90
+ if (!this.config.token)
91
+ throw new ImplementationMissingException('Missing config token for ModuleBE_Slack. Please add it');
92
+ this.web = new WebClient(this.config.token, {
93
+ rejectRateLimitedCalls: true,
94
+ ...this.config.slackConfig
95
+ });
96
+ }
97
+ async postMessage(request) {
98
+ await this.sendText(request.message, request.channel);
99
+ }
100
+ async postStructuredMessage(request) {
101
+ return { threadPointer: await this.sendStructured(request.message, request.thread) };
102
+ }
103
+ async sendFEMessage(request) {
104
+ const slackMessage = new SlackBuilderBE(request.channel, request.messageBlocks, request.messageReplies);
105
+ await slackMessage.send();
106
+ }
107
+ async postFiles(request) {
108
+ return this.postFile(request.file, request.name, request.thread);
109
+ }
110
+ async sendText(text, channel, thread) {
111
+ const message = {
112
+ channel: channel ?? this.config.defaultChannel,
113
+ };
114
+ // @ts-ignore - no clue why, their api requires text but it is not in the te
115
+ message.text = text;
116
+ //Block same message on throttling time
117
+ const time = this.messageMap[md5(text)];
118
+ if (time && currentTimeMillis() - time < (this.config.throttlingTime || Minute))
119
+ return;
120
+ //Post and return thread
121
+ return await this.postMessageImpl(message, thread);
122
+ }
123
+ async postFile(file, name, thread) {
124
+ // Get a URL to upload
125
+ const uploadUrlResponse = await this.web.files.getUploadURLExternal({
126
+ filename: name,
127
+ length: file.length
128
+ });
129
+ if (!uploadUrlResponse.ok)
130
+ throw HttpCodes._5XX.INTERNAL_SERVER_ERROR(`Failed at getting a URL from slack: ${uploadUrlResponse.error}`);
131
+ const { upload_url, file_id } = uploadUrlResponse;
132
+ try {
133
+ const res = await fetch(upload_url, {
134
+ method: 'POST',
135
+ body: file,
136
+ });
137
+ if (!res.ok)
138
+ throw new Error(`Upload failed: ${res.status} ${res.statusText}`);
111
139
  }
112
- message.unfurl_links = this.config.unfurl_links;
113
- message.unfurl_media = this.config.unfurl_media;
114
- this.logDebug(`Sending message in ${threadPointer ? 'thread' : 'channel'}`, message);
115
- const res = await this.web.chat.postMessage(message);
116
- return { ts: res.ts, channel: res.channel };
140
+ catch (e) {
141
+ const message = e instanceof Error ? e.message : String(e);
142
+ throw HttpCodes._5XX.INTERNAL_SERVER_ERROR(`Failed at uploading file to url: ${message}`);
143
+ }
144
+ // Complete the upload - post the file to slack message
145
+ const completeResponse = await this.web.files.completeUploadExternal({
146
+ files: [{ id: file_id }],
147
+ channel_id: thread ? thread.channel : this.config.defaultChannel,
148
+ thread_ts: thread?.ts,
149
+ });
150
+ if (!completeResponse.ok)
151
+ throw HttpCodes._5XX.INTERNAL_SERVER_ERROR(`Failed at complete uploading: ${completeResponse.error}`);
152
+ return completeResponse;
117
153
  }
118
- catch (err) {
119
- throw HttpCodes._5XX.INTERNAL_SERVER_ERROR(postSlackMessageErrorHandler(err, message.channel));
154
+ async sendStructured(message, thread) {
155
+ message.channel ??= this.config.defaultChannel;
156
+ return await this.postMessageImpl(message, thread);
120
157
  }
121
- }
122
- uploadFile = async (file, name, tp) => {
123
- const channel = tp?.channel || this.config.defaultChannel;
124
- const fileUploadBlob = {
125
- channels: channel,
126
- file: file,
127
- filename: name,
158
+ async postMessageImpl(message, threadPointer) {
159
+ try {
160
+ if (threadPointer) {
161
+ message.thread_ts = threadPointer.ts;
162
+ message.channel = threadPointer.channel;
163
+ }
164
+ message.unfurl_links = this.config.unfurl_links;
165
+ message.unfurl_media = this.config.unfurl_media;
166
+ this.logDebug(`Sending message in ${threadPointer ? 'thread' : 'channel'}`, message);
167
+ const res = await this.web.chat.postMessage(message);
168
+ return { ts: res.ts, channel: res.channel };
169
+ }
170
+ catch (err) {
171
+ throw HttpCodes._5XX.INTERNAL_SERVER_ERROR(postSlackMessageErrorHandler(err, message.channel));
172
+ }
173
+ }
174
+ uploadFile = async (file, name, tp) => {
175
+ const channel = tp?.channel || this.config.defaultChannel;
176
+ const fileUploadBlob = {
177
+ channels: channel,
178
+ file: file,
179
+ filename: name,
180
+ };
181
+ return await this.web.files.upload(fileUploadBlob);
128
182
  };
129
- return await this.web.files.upload(fileUploadBlob);
130
- };
131
- async getUserIdByEmail(email) {
132
- const result = await this.web.users.lookupByEmail({ email });
133
- if (result.ok)
134
- // @ts-ignore
135
- return result.user.id;
136
- return undefined;
137
- }
138
- async openDM(userIds) {
139
- const users = userIds.join(',');
140
- const result = await this.web.conversations.open({ users });
141
- if (result.ok) { // @ts-ignore
142
- return result.channel.id;
183
+ async getUserIdByEmail(email) {
184
+ const result = await this.web.users.lookupByEmail({ email });
185
+ if (result.ok)
186
+ // @ts-ignore
187
+ return result.user.id;
188
+ return undefined;
143
189
  }
144
- }
145
- getDefaultChannel = () => {
146
- return this.config.defaultChannel;
190
+ async openDM(userIds) {
191
+ const users = userIds.join(',');
192
+ const result = await this.web.conversations.open({ users });
193
+ if (result.ok) { // @ts-ignore
194
+ return result.channel.id;
195
+ }
196
+ }
197
+ getDefaultChannel = () => {
198
+ return this.config.defaultChannel;
199
+ };
147
200
  };
148
- }
201
+ })();
202
+ export { ModuleBE_Slack_Class };
149
203
  export const ModuleBE_Slack = new ModuleBE_Slack_Class();
package/SlackBuilderBE.js CHANGED
@@ -2,11 +2,9 @@ import { ModuleBE_Slack } from './ModuleBE_Slack.js';
2
2
  import { BaseSlackBuilder } from '@nu-art/slack-shared';
3
3
  import { __stringify, currentTimeMillis, formatTimestamp, generateHex } from '@nu-art/ts-common';
4
4
  export class SlackBuilderBE extends BaseSlackBuilder {
5
- // ######################## Builder Steps ########################
6
5
  constructor(channel, blocks, replies) {
7
6
  super(channel, blocks, replies);
8
7
  }
9
- // ######################## Internal Logic ########################
10
8
  convertLongSectionBlocks = () => {
11
9
  const convertBlock = (block) => {
12
10
  if (block.type !== 'section')
@@ -31,7 +29,7 @@ export class SlackBuilderBE extends BaseSlackBuilder {
31
29
  };
32
30
  sendMessage = async () => {
33
31
  this.convertLongSectionBlocks();
34
- return ModuleBE_Slack.postStructuredMessage({
32
+ return ModuleBE_Slack.sendStructured({
35
33
  channel: this.channel,
36
34
  blocks: this.blocks
37
35
  });
@@ -45,7 +43,7 @@ export class SlackBuilderBE extends BaseSlackBuilder {
45
43
  };
46
44
  sendReplies = async (tp) => {
47
45
  for (const reply of this.replies) {
48
- await ModuleBE_Slack.postStructuredMessage({
46
+ await ModuleBE_Slack.sendStructured({
49
47
  blocks: reply
50
48
  }, tp);
51
49
  }
@@ -74,7 +74,7 @@ export class Slack_ServerApiError_Class extends Module {
74
74
  if (message.includes(key))
75
75
  return;
76
76
  }
77
- return ModuleBE_Slack.postMessage(message, undefined, threadPointer);
77
+ return ModuleBE_Slack.sendText(message, undefined, threadPointer);
78
78
  }
79
79
  }
80
80
  export const Slack_ServerApiError = new Slack_ServerApiError_Class();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nu-art/slack-backend",
3
- "version": "0.401.9",
3
+ "version": "0.500.0",
4
4
  "description": "Storm - Express & Typescript based backend framework Backend",
5
5
  "keywords": [
6
6
  "TacB0sS",
@@ -31,10 +31,8 @@
31
31
  "build": "tsc"
32
32
  },
33
33
  "dependencies": {
34
- "@nu-art/slack-shared": "0.401.9",
35
- "@nu-art/thunderstorm-backend": "0.401.9",
36
- "@nu-art/thunderstorm-shared": "0.401.9",
37
- "@nu-art/ts-common": "0.401.9",
34
+ "@nu-art/slack-shared": "0.500.0",
35
+ "@nu-art/ts-common": "0.500.0",
38
36
  "@slack/web-api": "7.13.0",
39
37
  "firebase": "^11.9.0",
40
38
  "firebase-admin": "13.4.0",
@@ -43,7 +41,9 @@
43
41
  "moment": "^2.29.4",
44
42
  "react": "^18.0.0",
45
43
  "react-dom": "^18.0.0",
46
- "react-router-dom": "^6.9.0"
44
+ "react-router-dom": "^6.9.0",
45
+ "@nu-art/http-server": "{{THUNDERSTORM_VERSION}}",
46
+ "@nu-art/api-types": "{{THUNDERSTORM_VERSION}}"
47
47
  },
48
48
  "devDependencies": {
49
49
  "@types/react": "^18.0.0",