Merge branch 'main' into refactor/category-dialog

This commit is contained in:
yassinedorbozgithub 2025-02-03 14:49:53 +01:00
commit 7d93792f3a
9 changed files with 130 additions and 125 deletions

11
api/package-lock.json generated
View File

@ -57,7 +57,8 @@
"sanitize-filename": "^1.6.3", "sanitize-filename": "^1.6.3",
"slug": "^8.2.2", "slug": "^8.2.2",
"ts-migrate-mongoose": "^3.8.4", "ts-migrate-mongoose": "^3.8.4",
"uuid": "^9.0.1" "uuid": "^9.0.1",
"zod": "^3.24.1"
}, },
"devDependencies": { "devDependencies": {
"@compodoc/compodoc": "^1.1.24", "@compodoc/compodoc": "^1.1.24",
@ -20280,6 +20281,14 @@
"resolved": "https://registry.npmjs.org/zepto/-/zepto-1.2.0.tgz", "resolved": "https://registry.npmjs.org/zepto/-/zepto-1.2.0.tgz",
"integrity": "sha512-C1x6lfvBICFTQIMgbt3JqMOno3VOtkWat/xEakLTOurskYIHPmzJrzd1e8BnmtdDVJlGuk5D+FxyCA8MPmkIyA==", "integrity": "sha512-C1x6lfvBICFTQIMgbt3JqMOno3VOtkWat/xEakLTOurskYIHPmzJrzd1e8BnmtdDVJlGuk5D+FxyCA8MPmkIyA==",
"dev": true "dev": true
},
"node_modules/zod": {
"version": "3.24.1",
"resolved": "https://registry.npmjs.org/zod/-/zod-3.24.1.tgz",
"integrity": "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==",
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
} }
} }
} }

View File

@ -92,7 +92,8 @@
"sanitize-filename": "^1.6.3", "sanitize-filename": "^1.6.3",
"slug": "^8.2.2", "slug": "^8.2.2",
"ts-migrate-mongoose": "^3.8.4", "ts-migrate-mongoose": "^3.8.4",
"uuid": "^9.0.1" "uuid": "^9.0.1",
"zod": "^3.24.1"
}, },
"devDependencies": { "devDependencies": {
"@compodoc/compodoc": "^1.1.24", "@compodoc/compodoc": "^1.1.24",
@ -144,8 +145,8 @@
}, },
"optionalDependencies": { "optionalDependencies": {
"@css-inline/css-inline-linux-arm64-musl": "^0.14.1", "@css-inline/css-inline-linux-arm64-musl": "^0.14.1",
"@resvg/resvg-js-linux-arm64-musl": "^2.6.2", "@resvg/resvg-js-darwin-arm64": "^2.6.2",
"@resvg/resvg-js-darwin-arm64": "^2.6.2" "@resvg/resvg-js-linux-arm64-musl": "^2.6.2"
}, },
"overrides": { "overrides": {
"mjml": "5.0.0-alpha.4" "mjml": "5.0.0-alpha.4"

View File

@ -6,6 +6,8 @@
* 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file). * 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file).
*/ */
import { z } from 'zod';
export enum FileType { export enum FileType {
image = 'image', image = 'image',
video = 'video', video = 'video',
@ -14,6 +16,8 @@ export enum FileType {
unknown = 'unknown', unknown = 'unknown',
} }
export const fileTypeSchema = z.nativeEnum(FileType);
/** /**
* The `AttachmentRef` type defines two possible ways to reference an attachment: * The `AttachmentRef` type defines two possible ways to reference an attachment:
* 1. By `id`: This is used when the attachment is uploaded and stored in the Hexabot system. * 1. By `id`: This is used when the attachment is uploaded and stored in the Hexabot system.
@ -22,20 +26,24 @@ export enum FileType {
* the content is generated or retrieved by a plugin that consumes a third-party API. * the content is generated or retrieved by a plugin that consumes a third-party API.
* In this case, the `url` field contains the direct link to the external resource. * In this case, the `url` field contains the direct link to the external resource.
*/ */
export type AttachmentRef =
| {
id: string | null;
}
| {
/** @deprecated To be used only for external URLs (plugins), for stored attachments use "id" instead */
url: string;
};
/** IMPORTANT: No need to use generic type here */ export const attachmentRefSchema = z.union([
export interface AttachmentPayload<T extends AttachmentRef = AttachmentRef> { z.object({
type: FileType; id: z.string().nullable(),
payload: T; }),
} z.object({
url: z.string(),
}),
]);
export type AttachmentRef = z.infer<typeof attachmentRefSchema>;
export const attachmentPayloadSchema = z.object({
type: fileTypeSchema,
payload: attachmentRefSchema,
});
export type AttachmentPayload = z.infer<typeof attachmentPayloadSchema>;
/** @deprecated */ /** @deprecated */
export type WithUrl<A> = A & { url?: string }; export type WithUrl<A> = A & { url?: string };

View File

@ -1,15 +1,19 @@
/* /*
* Copyright © 2024 Hexastack. All rights reserved. * Copyright © 2025 Hexastack. All rights reserved.
* *
* Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms: * Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms:
* 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission. * 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission.
* 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file). * 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file).
*/ */
export interface CaptureVar { import { z } from 'zod';
// entity=`-1` to match text message
// entity=`-2` for postback payload // entity=`-1` to match text message
// entity is `String` for NLP entities // entity=`-2` for postback payload
entity: number | string; // entity is `String` for NLP entities
context_var: string; export const captureVarSchema = z.object({
} entity: z.union([z.number().min(-2).max(-1), z.string()]),
context_var: z.string(),
});
export type CaptureVar = z.infer<typeof captureVarSchema>;

View File

@ -1,29 +1,42 @@
/* /*
* Copyright © 2024 Hexastack. All rights reserved. * Copyright © 2025 Hexastack. All rights reserved.
* *
* Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms: * Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms:
* 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission. * 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission.
* 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file). * 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file).
*/ */
import { z } from 'zod';
import { PayloadType } from './message'; import { PayloadType } from './message';
export interface PayloadPattern { export const payloadPatternSchema = z.object({
label: string; label: z.string(),
value: string; value: z.string(),
// @todo : rename 'attachment' to 'attachments' type: z.nativeEnum(PayloadType).optional(),
type?: PayloadType; });
}
export type NlpPattern = export type PayloadPattern = z.infer<typeof payloadPatternSchema>;
| {
entity: string;
match: 'entity';
}
| {
entity: string;
match: 'value';
value: string;
};
export type Pattern = string | RegExp | PayloadPattern | NlpPattern[]; export const nlpPatternSchema = z.discriminatedUnion('match', [
z.object({
entity: z.string(),
match: z.literal('entity'),
}),
z.object({
entity: z.string(),
match: z.literal('value'),
value: z.string(),
}),
]);
export type NlpPattern = z.infer<typeof nlpPatternSchema>;
export const patternSchema = z.union([
z.string(),
z.instanceof(RegExp),
payloadPatternSchema,
z.array(nlpPatternSchema),
]);
export type Pattern = z.infer<typeof patternSchema>;

View File

@ -1,12 +1,16 @@
/* /*
* Copyright © 2024 Hexastack. All rights reserved. * Copyright © 2025 Hexastack. All rights reserved.
* *
* Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms: * Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms:
* 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission. * 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission.
* 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file). * 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file).
*/ */
export type Position = { import { z } from 'zod';
x: number;
y: number; export const positionSchema = z.object({
}; x: z.number(),
y: z.number(),
});
export type Position = z.infer<typeof positionSchema>;

View File

@ -6,21 +6,10 @@
* 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file). * 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file).
*/ */
import { AttachmentPayload } from './attachment'; import { z } from 'zod';
import { PayloadType } from './message';
export type Payload = import { attachmentPayloadSchema } from './attachment';
| { import { PayloadType } from './message';
type: PayloadType.location;
coordinates: {
lat: number;
lon: number;
};
}
| {
type: PayloadType.attachments;
attachment: AttachmentPayload;
};
export enum QuickReplyType { export enum QuickReplyType {
text = 'text', text = 'text',
@ -29,8 +18,28 @@ export enum QuickReplyType {
user_email = 'user_email', user_email = 'user_email',
} }
export interface StdQuickReply { export const cordinatesSchema = z.object({
content_type: QuickReplyType; lat: z.number(),
title: string; lon: z.number(),
payload: string; });
}
export const payloadSchema = z.discriminatedUnion('type', [
z.object({
type: z.literal(PayloadType.location),
coordinates: cordinatesSchema,
}),
z.object({
type: z.literal(PayloadType.attachments),
attachment: attachmentPayloadSchema,
}),
]);
export const stdQuickReplySchema = z.object({
content_type: z.nativeEnum(QuickReplyType),
title: z.string(),
payload: z.string(),
});
export type Payload = z.infer<typeof payloadSchema>;
export type StdQuickReply = z.infer<typeof stdQuickReplySchema>;

View File

@ -1,11 +1,15 @@
/* /*
* Copyright © 2024 Hexastack. All rights reserved. * Copyright © 2025 Hexastack. All rights reserved.
* *
* Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms: * Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms:
* 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission. * 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission.
* 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file). * 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file).
*/ */
export interface SubscriberContext { import { z } from 'zod';
vars?: { [key: string]: any };
} export const subscriberContextSchema = z.object({
vars: z.record(z.any()).optional(),
});
export type SubscriberContext = z.infer<typeof subscriberContextSchema>;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Hexastack. All rights reserved. * Copyright © 2025 Hexastack. All rights reserved.
* *
* Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms: * Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms:
* 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission. * 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission.
@ -12,62 +12,15 @@ import {
ValidatorConstraint, ValidatorConstraint,
ValidatorConstraintInterface, ValidatorConstraintInterface,
} from 'class-validator'; } from 'class-validator';
import Joi from 'joi';
import { Pattern } from '../schemas/types/pattern'; import { Pattern, patternSchema } from '../schemas/types/pattern';
export function isPatternList(patterns: Pattern[]) { export function isPatternList(patterns: Pattern[]) {
return ( if (!Array.isArray(patterns)) {
Array.isArray(patterns) &&
patterns.every((pattern) => {
if (typeof pattern === 'string') {
// Check if valid regex
if (pattern.endsWith('/') && pattern.startsWith('/')) {
try {
new RegExp(pattern.slice(1, -1), 'gi');
} catch (err) {
return false; return false;
} }
return true;
} return patterns.every((pattern) => patternSchema.safeParse(pattern).success);
// Check if valid string (Equals/Like)
return pattern !== '';
} else if (Array.isArray(pattern)) {
// Check if valid NLP pattern
const nlpSchema = Joi.array()
.items(
Joi.object().keys({
entity: Joi.string().required(),
match: Joi.string().valid('entity', 'value').required(),
value: Joi.string().required(),
}),
)
.min(1);
const nlpCheck = nlpSchema.validate(pattern);
if (nlpCheck.error) {
// console.log('Message validation failed! ', nlpCheck);
}
return !nlpCheck.error;
} else if (typeof pattern === 'object') {
// Invalid structure?
const payloadSchema = Joi.object().keys({
label: Joi.string().required(),
value: Joi.any().required(),
type: Joi.string(),
});
const payloadCheck = payloadSchema.validate(pattern);
if (payloadCheck.error) {
// console.log(
// 'Message validation failed! ',
// payloadCheck,
// );
}
return !payloadCheck.error;
} else {
return false;
}
})
);
} }
@ValidatorConstraint({ async: false }) @ValidatorConstraint({ async: false })