import { INestApplication } from '@nestjs/common';
import { DocumentBuilder, OpenAPIObject, SwaggerModule } from '@nestjs/swagger';
import { DECORATORS } from '@nestjs/swagger/dist/constants';
import { BasicAuthFunction } from '@waha/core/auth/basicAuth';
import { DashboardConfigServiceCore } from '@waha/core/config/DashboardConfigServiceCore';
import { Logger } from 'nestjs-pino';
import { WhatsappConfigService } from '../config.service';
import { VERSION } from '../version';
import { SwaggerConfigServiceCore } from './config/SwaggerConfigServiceCore';
export class SwaggerConfiguratorCore {
protected logger: any;
private config: SwaggerConfigServiceCore;
constructor(protected app: INestApplication) {
this.logger = app.get(Logger);
this.config = app.get(SwaggerConfigServiceCore);
}
get title() {
return this.config.title || 'WAHA - WhatsApp HTTP API';
}
get description() {
if (this.config.description) {
return this.config.description;
}
return (
'WhatsApp HTTP API that you can run in a click!
' +
'📊 Dashboard
' +
'
' +
'Learn more:' +
'
' +
'Support the project and get WAHA Plus version!
' +
''
);
}
get externalDocUrl() {
return this.config.externalDocUrl || 'https://waha.devlike.pro/';
}
configure(webhooks: any[]) {
if (!this.config.enabled) {
return;
}
const credentials = this.config.credentials;
if (credentials) {
this.setUpAuth(credentials);
}
const app = this.app;
const builder = new DocumentBuilder();
builder
.setTitle(this.title)
.setDescription(this.description)
.setExternalDoc(this.title, this.externalDocUrl)
.setVersion(VERSION.version)
.addTag('🖥️ Sessions', 'Control WhatsApp sessions (accounts)')
.addTag('🧩 Apps', 'Applications (built-in integrations)')
.addTag('🔑 Auth', 'Authentication')
.addTag('🆔 Profile', 'Your profile information')
.addTag('🖼️ Screenshot', 'Get screenshot of WhatsApp and show QR code')
.addTag('📤 Chatting', 'Chatting methods')
.addTag('📢 Channels', 'Channels (newsletters) methods')
.addTag('🟢 Status', 'Status (aka stories) methods')
.addTag('💬 Chats', `Chats methods`)
.addTag(
'👤 Contacts',
`Contacts methods.
Use phone number (without +) or phone number and \`@c.us\` at the end as \`contactId\`.
'E.g: \`12312312310\` OR \`12312312310@c.us\`
`,
)
.addTag('👥 Groups', `Groups methods.
`)
.addTag('✅ Presence', `Presence information`)
.addTag('📅 Events', `Event Message`)
.addTag(
'🏷️ Labels',
'Labels - available only for WhatsApp Business accounts',
)
.addTag('🖼️ Media', 'Media methods')
.addTag('🔍 Observability', 'Other methods')
.addTag('🗄️ Storage', 'Storage methods')
.addApiKey({
type: 'apiKey',
description: 'Your secret api key',
name: 'X-Api-Key',
});
const config = app.get(WhatsappConfigService);
const swaggerConfig = app.get(SwaggerConfigServiceCore);
if (swaggerConfig.advancedConfigEnabled) {
builder.addServer('{protocol}://{host}:{port}/{baseUrl}', '', {
protocol: {
default: 'http',
enum: ['http', 'https'],
description: 'The protocol used to access the server.',
},
host: {
default: config.hostname,
description: 'The hostname or IP address of the server.',
},
port: {
default: config.port,
description:
'The port number on which the server is listening for requests',
},
baseUrl: {
default: '',
description:
'The base URL path for all API endpoints. This can be used to group related endpoints together under a common path.',
},
});
}
const swaggerDocumentConfig = builder.build();
const swaggerDocumentOptions = {
extraModels: webhooks,
};
let document = SwaggerModule.createDocument(
app,
swaggerDocumentConfig,
swaggerDocumentOptions,
);
document = this.configureWebhooks(document, webhooks);
SwaggerModule.setup('', app, document, {
customSiteTitle: this.title,
});
}
private configureWebhooks(document: OpenAPIObject, supportedWebhooks) {
document.openapi = '3.1.0';
const webhooks = {};
for (const webhook of supportedWebhooks) {
const eventMetadata = Reflect.getMetadata(
DECORATORS.API_MODEL_PROPERTIES,
webhook.prototype,
'event',
);
const event = new webhook().event;
const schemaName = webhook.name;
webhooks[event] = {
post: {
summary: eventMetadata.description,
deprecated: eventMetadata.deprecated || false,
requestBody: {
content: {
'application/json': {
schema: {
$ref: `#/components/schemas/${schemaName}`,
},
},
},
},
responses: {
'200': {
description:
'Return a 200 status to indicate that the data was received successfully',
},
},
},
};
}
// @ts-ignore
document.webhooks = webhooks;
return document;
}
setUpAuth(credentials: [string, string]): void {
const [username, password] = credentials;
const dashboardConfig = this.app.get(DashboardConfigServiceCore);
const exclude = [
'/api/',
dashboardConfig.dashboardUri,
'/health',
'/ws',
'/webhooks/',
];
const authFunction = BasicAuthFunction(username, password, exclude);
this.app.use(authFunction);
}
}