Refactoring 3
This commit is contained in:
parent
e4b78ceec2
commit
d1fb9b4d06
20 changed files with 201 additions and 123 deletions
|
|
@ -10,12 +10,12 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hapi/wreck": "^18.1.0",
|
"@hapi/wreck": "^18.1.0",
|
||||||
|
"bridge-common": "*",
|
||||||
"fluent-ffmpeg": "^2.1.2",
|
"fluent-ffmpeg": "^2.1.2",
|
||||||
"graphile-worker": "^0.16.5",
|
"graphile-worker": "^0.16.5",
|
||||||
"html-to-text": "^9.0.5",
|
"html-to-text": "^9.0.5",
|
||||||
"jest": "^29.7.0",
|
"jest": "^29.7.0",
|
||||||
"kysely": "^0.27.3",
|
"kysely": "^0.27.3",
|
||||||
"bridge-common": "*",
|
|
||||||
"pg": "^8.11.5",
|
"pg": "^8.11.5",
|
||||||
"remeda": "^1.61.0",
|
"remeda": "^1.61.0",
|
||||||
"twilio": "^5.0.4"
|
"twilio": "^5.0.4"
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
"@babel/preset-env": "7.24.4",
|
"@babel/preset-env": "7.24.4",
|
||||||
"@babel/preset-typescript": "7.24.1",
|
"@babel/preset-typescript": "7.24.1",
|
||||||
"@types/fluent-ffmpeg": "^2.1.24",
|
"@types/fluent-ffmpeg": "^2.1.24",
|
||||||
|
"dotenv": "^16.4.5",
|
||||||
"eslint": "^9.0.0",
|
"eslint": "^9.0.0",
|
||||||
"prettier": "^3.2.5",
|
"prettier": "^3.2.5",
|
||||||
"ts-config": "*",
|
"ts-config": "*",
|
||||||
|
|
|
||||||
|
|
@ -1,57 +0,0 @@
|
||||||
import Wreck from "@hapi/wreck";
|
|
||||||
import * as R from "remeda";
|
|
||||||
import { withDb, AppDatabase } from "../../lib/db";
|
|
||||||
// import logger from "../logger";
|
|
||||||
|
|
||||||
export interface WebhookOptions {
|
|
||||||
webhookId: string;
|
|
||||||
payload: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
const notifyWebhooksTask = async (options: WebhookOptions): Promise<void> =>
|
|
||||||
withDb(async (db: AppDatabase) => {
|
|
||||||
const { webhookId, payload } = options;
|
|
||||||
|
|
||||||
const webhook = await db.webhooks.findById({ id: webhookId });
|
|
||||||
if (!webhook) {
|
|
||||||
// logger.debug(
|
|
||||||
// { webhookId },
|
|
||||||
// "notify-webhook: no webhook registered with id",
|
|
||||||
// );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { endpointUrl, httpMethod, headers } = webhook;
|
|
||||||
const headersFormatted = R.reduce(
|
|
||||||
headers || [],
|
|
||||||
(acc: any, h: any) => {
|
|
||||||
acc[h.header] = h.value;
|
|
||||||
return acc;
|
|
||||||
},
|
|
||||||
{},
|
|
||||||
);
|
|
||||||
|
|
||||||
const wreck = Wreck.defaults({
|
|
||||||
json: true,
|
|
||||||
headers: headersFormatted,
|
|
||||||
});
|
|
||||||
|
|
||||||
// http errors will bubble up and cause the job to fail and be retried
|
|
||||||
try {
|
|
||||||
// logger.debug(
|
|
||||||
// { webhookId, endpointUrl, httpMethod },
|
|
||||||
// "notify-webhook: notifying",
|
|
||||||
// );
|
|
||||||
await (httpMethod === "post"
|
|
||||||
? wreck.post(endpointUrl, { payload })
|
|
||||||
: wreck.put(endpointUrl, { payload }));
|
|
||||||
} catch (error: any) {
|
|
||||||
// logger.error(
|
|
||||||
// { webhookId, error: error.output },
|
|
||||||
// "notify-webhook failed with this error",
|
|
||||||
// );
|
|
||||||
throw new Error(`webhook failed webhookId=${webhookId}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export default notifyWebhooksTask;
|
|
||||||
31
apps/bridge-worker/tasks/common/notify-webhooks.ts
Normal file
31
apps/bridge-worker/tasks/common/notify-webhooks.ts
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
import { db } from "bridge-common";
|
||||||
|
|
||||||
|
export interface NotifyWebhooksOptions {
|
||||||
|
backendId: string;
|
||||||
|
payload: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
const notifyWebhooksTask = async (
|
||||||
|
options: NotifyWebhooksOptions,
|
||||||
|
): Promise<void> => {
|
||||||
|
const { backendId, payload } = options;
|
||||||
|
|
||||||
|
const webhooks = await db
|
||||||
|
.selectFrom("Webhook")
|
||||||
|
.selectAll()
|
||||||
|
.where("backendId", "=", backendId)
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
for (const webhook of webhooks) {
|
||||||
|
const { endpointUrl, httpMethod, headers } = webhook;
|
||||||
|
const finalHeaders = { "Content-Type": "application/json", ...headers };
|
||||||
|
|
||||||
|
await fetch(endpointUrl, {
|
||||||
|
method: httpMethod,
|
||||||
|
headers: finalHeaders,
|
||||||
|
body: JSON.stringify(payload),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default notifyWebhooksTask;
|
||||||
|
|
@ -17,9 +17,13 @@ const receiveFacebookMessageTask = async ({
|
||||||
.selectAll()
|
.selectAll()
|
||||||
.where("pageId", "=", pageId)
|
.where("pageId", "=", pageId)
|
||||||
.executeTakeFirstOrThrow();
|
.executeTakeFirstOrThrow();
|
||||||
|
const backendId = row.id;
|
||||||
|
const payload = {
|
||||||
|
text: messaging.message.text,
|
||||||
|
recipient: messaging.sender.id,
|
||||||
|
};
|
||||||
|
|
||||||
console.log({ row });
|
await worker.addJob("common/notify-webhooks", { backendId, payload });
|
||||||
await worker.addJob("notify_webhooks", messaging);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,64 +1,34 @@
|
||||||
interface SendFacebookMessageTaskOptions {}
|
import { db } from "bridge-common";
|
||||||
|
|
||||||
|
interface SendFacebookMessageTaskOptions {
|
||||||
|
token: string;
|
||||||
|
message: any;
|
||||||
|
}
|
||||||
|
|
||||||
const sendFacebookMessageTask = async (
|
const sendFacebookMessageTask = async (
|
||||||
options: SendFacebookMessageTaskOptions,
|
options: SendFacebookMessageTaskOptions,
|
||||||
): Promise<void> => {
|
): Promise<void> => {
|
||||||
console.log(options);
|
const { token, message } = options;
|
||||||
|
const { pageId, pageAccessToken } = await db
|
||||||
|
|
||||||
const message = await req.json();
|
|
||||||
|
|
||||||
const message = await req.json();
|
|
||||||
for (const entry of message.entry) {
|
|
||||||
for (const messaging of entry.messaging) {
|
|
||||||
const pageId = messaging.recipient.id;
|
|
||||||
const row = await db
|
|
||||||
.selectFrom("FacebookBot")
|
.selectFrom("FacebookBot")
|
||||||
.selectAll()
|
.selectAll()
|
||||||
.where("pageId", "=", pageId)
|
.where("token", "=", token)
|
||||||
.executeTakeFirst();
|
.executeTakeFirstOrThrow();
|
||||||
|
|
||||||
console.log({ message });
|
|
||||||
const entry = message.entry[0];
|
|
||||||
console.log({ entry });
|
|
||||||
const messaging = entry?.messaging[0];
|
|
||||||
const pageId = messaging?.recipient?.id;
|
|
||||||
console.log({ pageId });
|
|
||||||
const row = await db
|
|
||||||
.selectFrom("FacebookBot")
|
|
||||||
.selectAll()
|
|
||||||
.where("pageId", "=", pageId)
|
|
||||||
.executeTakeFirst();
|
|
||||||
|
|
||||||
console.log({ row });
|
|
||||||
|
|
||||||
const endpoint = `https://graph.facebook.com/v19.0/${pageId}/messages`;
|
const endpoint = `https://graph.facebook.com/v19.0/${pageId}/messages`;
|
||||||
const inMessage = messaging?.message?.text;
|
|
||||||
const outgoingMessage = {
|
const outgoingMessage = {
|
||||||
recipient: { id: messaging?.sender?.id },
|
recipient: { id: message.recipient },
|
||||||
message: { text: `"${inMessage}", right back at you!` },
|
message: { text: `"${message.text}", right back at you!` },
|
||||||
messaging_type: "RESPONSE",
|
messaging_type: "RESPONSE",
|
||||||
access_token: row?.pageAccessToken,
|
access_token: pageAccessToken,
|
||||||
};
|
};
|
||||||
console.log({ outgoingMessage });
|
|
||||||
const response = await fetch(endpoint, {
|
await fetch(endpoint, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
body: JSON.stringify(outgoingMessage),
|
body: JSON.stringify(outgoingMessage),
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log({ response });
|
|
||||||
|
|
||||||
console.log(message);
|
|
||||||
const wu = await getWorkerUtils();
|
|
||||||
|
|
||||||
await wu.addJob("receive_facebook_message", message);
|
|
||||||
|
|
||||||
return NextResponse.json({ response: "ok" });
|
|
||||||
|
|
||||||
// withDb(async (db: AppDatabase) => {
|
|
||||||
// await notifyWebhooks(db, options);
|
|
||||||
// });
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default sendFacebookMessageTask;
|
export default sendFacebookMessageTask;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { db, getWorkerUtils } from "bridge-common";
|
||||||
|
|
||||||
|
interface ReceiveSignalMessageTaskOptions {
|
||||||
|
message: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
const receiveSignalMessageTask = async ({
|
||||||
|
message,
|
||||||
|
}: ReceiveSignalMessageTaskOptions): Promise<void> => {};
|
||||||
|
|
||||||
|
export default receiveSignalMessageTask;
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { db, getWorkerUtils } from "bridge-common";
|
||||||
|
|
||||||
|
interface SendSignalMessageTaskOptions {
|
||||||
|
message: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sendSignalMessageTask = async ({
|
||||||
|
message,
|
||||||
|
}: SendSignalMessageTaskOptions): Promise<void> => {};
|
||||||
|
|
||||||
|
export default sendSignalMessageTask;
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { db, getWorkerUtils } from "bridge-common";
|
||||||
|
|
||||||
|
interface ReceiveVoiceMessageTaskOptions {
|
||||||
|
message: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
const receiveVoiceMessageTask = async ({
|
||||||
|
message,
|
||||||
|
}: ReceiveVoiceMessageTaskOptions): Promise<void> => {};
|
||||||
|
|
||||||
|
export default receiveVoiceMessageTask;
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { db, getWorkerUtils } from "bridge-common";
|
||||||
|
|
||||||
|
interface SendVoiceMessageTaskOptions {
|
||||||
|
message: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sendVoiceMessageTask = async ({
|
||||||
|
message,
|
||||||
|
}: SendVoiceMessageTaskOptions): Promise<void> => {};
|
||||||
|
|
||||||
|
export default sendVoiceMessageTask;
|
||||||
|
|
@ -1,4 +1,17 @@
|
||||||
|
import { db, getWorkerUtils } from "bridge-common";
|
||||||
|
|
||||||
|
interface ReceiveWhatsappMessageTaskOptions {
|
||||||
|
message: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
const receiveWhatsappMessageTask = async ({
|
||||||
|
message,
|
||||||
|
}: ReceiveWhatsappMessageTaskOptions): Promise<void> => {};
|
||||||
|
|
||||||
|
export default receiveWhatsappMessageTask;
|
||||||
|
|
||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
|
/*
|
||||||
import { withDb, AppDatabase } from "../../lib/db";
|
import { withDb, AppDatabase } from "../../lib/db";
|
||||||
import workerUtils from "../../lib/utils";
|
import workerUtils from "../../lib/utils";
|
||||||
|
|
||||||
|
|
@ -93,3 +106,4 @@ const whatsappMessageTask = async (
|
||||||
};
|
};
|
||||||
|
|
||||||
export default whatsappMessageTask;
|
export default whatsappMessageTask;
|
||||||
|
*/
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { db, getWorkerUtils } from "bridge-common";
|
||||||
|
|
||||||
|
interface SendWhatsappMessageTaskOptions {
|
||||||
|
message: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sendWhatsappMessageTask = async ({
|
||||||
|
message,
|
||||||
|
}: SendWhatsappMessageTaskOptions): Promise<void> => {};
|
||||||
|
|
||||||
|
export default sendWhatsappMessageTask;
|
||||||
57
package-lock.json
generated
57
package-lock.json
generated
|
|
@ -36,6 +36,8 @@
|
||||||
"@mui/x-data-grid-pro": "^7.3.1",
|
"@mui/x-data-grid-pro": "^7.3.1",
|
||||||
"@mui/x-date-pickers-pro": "^7.3.1",
|
"@mui/x-date-pickers-pro": "^7.3.1",
|
||||||
"@mui/x-license": "^7.2.0",
|
"@mui/x-license": "^7.2.0",
|
||||||
|
"bridge-common": "*",
|
||||||
|
"bridge-ui": "*",
|
||||||
"date-fns": "^3.6.0",
|
"date-fns": "^3.6.0",
|
||||||
"dotenv": "^16.4.5",
|
"dotenv": "^16.4.5",
|
||||||
"graphile-worker": "^0.16.6",
|
"graphile-worker": "^0.16.6",
|
||||||
|
|
@ -152,6 +154,7 @@
|
||||||
"@babel/preset-env": "7.24.4",
|
"@babel/preset-env": "7.24.4",
|
||||||
"@babel/preset-typescript": "7.24.1",
|
"@babel/preset-typescript": "7.24.1",
|
||||||
"@types/fluent-ffmpeg": "^2.1.24",
|
"@types/fluent-ffmpeg": "^2.1.24",
|
||||||
|
"dotenv": "^16.4.5",
|
||||||
"eslint": "^9.0.0",
|
"eslint": "^9.0.0",
|
||||||
"prettier": "^3.2.5",
|
"prettier": "^3.2.5",
|
||||||
"ts-config": "*",
|
"ts-config": "*",
|
||||||
|
|
@ -16430,8 +16433,58 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"packages/bridge-ui": {
|
"packages/bridge-ui": {
|
||||||
"version": "1.0.0",
|
"version": "0.2.0",
|
||||||
"license": "ISC"
|
"dependencies": {
|
||||||
|
"@emotion/cache": "^11.11.0",
|
||||||
|
"@emotion/react": "^11.11.4",
|
||||||
|
"@emotion/server": "^11.11.0",
|
||||||
|
"@emotion/styled": "^11.11.5",
|
||||||
|
"@mui/icons-material": "^5",
|
||||||
|
"@mui/lab": "^5.0.0-alpha.170",
|
||||||
|
"@mui/material": "^5",
|
||||||
|
"@mui/x-data-grid-pro": "^7.3.1",
|
||||||
|
"@mui/x-date-pickers-pro": "^7.3.1",
|
||||||
|
"date-fns": "^3.6.0",
|
||||||
|
"material-ui-popup-state": "^5.1.0",
|
||||||
|
"next": "14.2.3",
|
||||||
|
"react": "18.3.0",
|
||||||
|
"react-cookie": "^7.1.4",
|
||||||
|
"react-cookie-consent": "^9.0.0",
|
||||||
|
"react-dom": "18.3.0",
|
||||||
|
"react-iframe": "^1.8.5",
|
||||||
|
"react-markdown": "^9.0.1",
|
||||||
|
"react-polyglot": "^0.7.2",
|
||||||
|
"tss-react": "^4.9.7",
|
||||||
|
"uuid": "^9.0.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/core": "^7.24.4",
|
||||||
|
"@types/node": "^20.12.7",
|
||||||
|
"@types/react": "18.3.0",
|
||||||
|
"@types/uuid": "^9.0.8",
|
||||||
|
"babel-loader": "^9.1.3",
|
||||||
|
"eslint": "^8.0.0",
|
||||||
|
"eslint-config-next": "^14.2.3",
|
||||||
|
"eslint-config-prettier": "^9.1.0",
|
||||||
|
"eslint-plugin-import": "^2.29.1",
|
||||||
|
"eslint-plugin-jsx-a11y": "^6.8.0",
|
||||||
|
"eslint-plugin-prettier": "^5.1.3",
|
||||||
|
"eslint-plugin-react": "^7.34.1",
|
||||||
|
"file-loader": "^6.2.0",
|
||||||
|
"typescript": "5.4.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"packages/bridge-ui/node_modules/uuid": {
|
||||||
|
"version": "9.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
|
||||||
|
"integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
|
||||||
|
"funding": [
|
||||||
|
"https://github.com/sponsors/broofa",
|
||||||
|
"https://github.com/sponsors/ctavan"
|
||||||
|
],
|
||||||
|
"bin": {
|
||||||
|
"uuid": "dist/bin/uuid"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"packages/eslint-config": {
|
"packages/eslint-config": {
|
||||||
"version": "0.3.10",
|
"version": "0.3.10",
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,9 @@ import type {
|
||||||
Insertable,
|
Insertable,
|
||||||
Updateable,
|
Updateable,
|
||||||
} from "kysely";
|
} from "kysely";
|
||||||
import { Pool, types } from "pg";
|
import pg from "pg";
|
||||||
import { KyselyAuth } from "@auth/kysely-adapter";
|
import { KyselyAuth } from "@auth/kysely-adapter";
|
||||||
|
const { Pool, types } = pg;
|
||||||
|
|
||||||
type Timestamp = ColumnType<Date, Date | string>;
|
type Timestamp = ColumnType<Date, Date | string>;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,7 @@
|
||||||
"author": "Darren Clarke <darren@redaranj.com>",
|
"author": "Darren Clarke <darren@redaranj.com>",
|
||||||
"license": "AGPL-3.0-or-later",
|
"license": "AGPL-3.0-or-later",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc -p tsconfig.json",
|
"build": "tsc -p tsconfig.json"
|
||||||
"dev": "NODE_OPTIONS=\"--loader ts-node/esm\" graphile-worker"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@auth/kysely-adapter": "^1.0.0",
|
"@auth/kysely-adapter": "^1.0.0",
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es5",
|
"target": "esnext",
|
||||||
"lib": ["dom", "dom.iterable", "esnext"],
|
"lib": ["esnext"],
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -25,7 +25,7 @@ export class Facebook extends Service {
|
||||||
|
|
||||||
const message = await req.json();
|
const message = await req.json();
|
||||||
const worker = await getWorkerUtils();
|
const worker = await getWorkerUtils();
|
||||||
await worker.addJob("receive_facebook_message", message);
|
await worker.addJob("facebook/receive-facebook-message", { message });
|
||||||
|
|
||||||
return NextResponse.json({ response: "ok" });
|
return NextResponse.json({ response: "ok" });
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,12 +48,16 @@ export type ServiceConfig = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ServiceParams = {
|
export type ServiceParams = {
|
||||||
|
params: {
|
||||||
service: string;
|
service: string;
|
||||||
token?: string;
|
token?: string;
|
||||||
};
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export class Service {
|
export class Service {
|
||||||
async getBot({ service, token }: ServiceParams): Promise<NextResponse> {
|
async getBot({
|
||||||
|
params: { service, token },
|
||||||
|
}: ServiceParams): Promise<NextResponse> {
|
||||||
const table = getServiceTable(service);
|
const table = getServiceTable(service);
|
||||||
const row = await db
|
const row = await db
|
||||||
.selectFrom(table)
|
.selectFrom(table)
|
||||||
|
|
@ -66,11 +70,14 @@ export class Service {
|
||||||
|
|
||||||
async sendMessage(
|
async sendMessage(
|
||||||
req: NextRequest,
|
req: NextRequest,
|
||||||
{ service, token }: ServiceParams,
|
{ params: { service, token } }: ServiceParams,
|
||||||
): Promise<NextResponse> {
|
): Promise<NextResponse> {
|
||||||
const message = await req.json();
|
const message = await req.json();
|
||||||
const worker = await getWorkerUtils();
|
const worker = await getWorkerUtils();
|
||||||
await worker.addJob(`send_${service}_message`, { token, message });
|
await worker.addJob(`${service}/send-${service}-message`, {
|
||||||
|
token,
|
||||||
|
message,
|
||||||
|
});
|
||||||
|
|
||||||
return NextResponse.json({ response: "ok" });
|
return NextResponse.json({ response: "ok" });
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { Facebook } from "./facebook";
|
||||||
import { Signal } from "./signal";
|
import { Signal } from "./signal";
|
||||||
import { Whatsapp } from "./whatsapp";
|
import { Whatsapp } from "./whatsapp";
|
||||||
|
|
||||||
export const getService = ({ service }: ServiceParams): Service => {
|
export const getService = ({ params: { service } }: ServiceParams): Service => {
|
||||||
if (service === "facebook") {
|
if (service === "facebook") {
|
||||||
return new Facebook();
|
return new Facebook();
|
||||||
} else if (service === "signal") {
|
} else if (service === "signal") {
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue