@droppii-org/chat-sdk 0.0.71 → 0.1.1
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.
- package/dist/assets/sdk/sql-wasm.wasm +0 -0
- package/dist/components/message/MessageList.d.ts.map +1 -1
- package/dist/components/message/MessageList.js +8 -2
- package/dist/components/message/footer/ActionBar.d.ts.map +1 -1
- package/dist/components/message/footer/ActionBar.js +18 -22
- package/dist/components/message/footer/PasteAndDropPlugin.d.ts +6 -0
- package/dist/components/message/footer/PasteAndDropPlugin.d.ts.map +1 -0
- package/dist/components/message/footer/PasteAndDropPlugin.js +115 -0
- package/dist/components/message/footer/index.d.ts.map +1 -1
- package/dist/components/message/footer/index.js +2 -1
- package/dist/components/message/item/TextMessage.d.ts.map +1 -1
- package/dist/components/message/item/TextMessage.js +4 -1
- package/dist/components/message/item/UrlTextMessage.d.ts.map +1 -1
- package/dist/components/message/item/UrlTextMessage.js +5 -3
- package/dist/components/message/item/index.d.ts.map +1 -1
- package/dist/components/message/item/index.js +2 -2
- package/dist/components/searchConversation/item/SearchItemAsMessage.js +2 -2
- package/dist/components/searchConversation/item/SearchItemAsUser.js +2 -2
- package/dist/hooks/global/useGlobalEvent.d.ts.map +1 -1
- package/dist/hooks/global/useGlobalEvent.js +9 -5
- package/dist/services/api.js +49 -0
- package/dist/store/auth.d.ts.map +1 -1
- package/dist/store/auth.js +5 -1
- package/dist/styles/global.css +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/chat.d.ts +12 -1
- package/dist/types/chat.d.ts.map +1 -1
- package/dist/utils/common.d.ts +13 -0
- package/dist/utils/common.d.ts.map +1 -1
- package/dist/utils/common.js +51 -0
- package/dist/utils/fileValidation.d.ts +26 -0
- package/dist/utils/fileValidation.d.ts.map +1 -0
- package/dist/utils/fileValidation.js +84 -0
- package/package.json +12 -11
package/dist/types/chat.d.ts
CHANGED
|
@@ -54,7 +54,7 @@ export interface MessageFooterContextType {
|
|
|
54
54
|
type: "text" | "file";
|
|
55
55
|
}) => void;
|
|
56
56
|
listUploadFiles: UploadFile[];
|
|
57
|
-
setListUploadFiles: (files: UploadFile[]) => void;
|
|
57
|
+
setListUploadFiles: (files: UploadFile[] | ((prev: UploadFile[]) => UploadFile[])) => void;
|
|
58
58
|
}
|
|
59
59
|
export interface ImageMsgParamsByFile extends ImageMsgParamsByURL {
|
|
60
60
|
file: File;
|
|
@@ -92,6 +92,17 @@ export interface DChatInitAndLoginConfig {
|
|
|
92
92
|
userID: string;
|
|
93
93
|
applicationType: DChatApplicationType;
|
|
94
94
|
isCrm?: boolean;
|
|
95
|
+
/**
|
|
96
|
+
* Callback to refresh access token when 401 detected.
|
|
97
|
+
* Consumer app should call refresh token API and return new accessToken.
|
|
98
|
+
* If not provided, 401s will trigger authFailed event.
|
|
99
|
+
*/
|
|
100
|
+
onTokenRefresh?: () => Promise<string>;
|
|
101
|
+
/**
|
|
102
|
+
* Callback when authentication fails (e.g., refresh token expired).
|
|
103
|
+
* Consumer should handle logout and redirect.
|
|
104
|
+
*/
|
|
105
|
+
onAuthError?: (error: Error) => void;
|
|
95
106
|
}
|
|
96
107
|
export declare enum SessionStatus {
|
|
97
108
|
UNASSIGNED = "UNASSIGNED",
|
package/dist/types/chat.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../src/types/chat.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,WAAW,EACX,QAAQ,EACR,YAAY,EACZ,mBAAmB,EACpB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAElC,oBAAY,oBAAoB;IAC9B,KAAK,UAAU;CAChB;AAED,oBAAY,aAAa;IACvB,YAAY,IAAI;IAChB,SAAS,IAAI;IACb,UAAU,IAAI;CACf;AAED,oBAAY,UAAU;IACpB,OAAO,IAAI;IACX,OAAO,IAAI;IACX,MAAM,IAAI;CACX;AAED,oBAAY,UAAU;IACpB,aAAa,MAAM;IACnB,aAAa,MAAM;IACnB,aAAa,MAAM;IACnB,aAAa,MAAM;IACnB,aAAa,MAAM;CACpB;AAED,oBAAY,iBAAiB;IAC3B,GAAG,MAAM;CACV;AAED,MAAM,MAAM,gBAAgB,GAAG,iBAAiB,GAAG,WAAW,CAAC;AAE/D,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,YAAY,GAAG,IAAI,CAAC;IAC1B,aAAa,EAAE,aAAa,CAAC;IAC7B,UAAU,EAAE,UAAU,CAAC;IACvB,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,mBAAmB,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,CAAC;IACrD,gBAAgB,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;CAChD;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,MAAM,EAAE,uBAAuB,GAAG,IAAI,CAAC;CACxC;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,CAAC,EAAE;QACZ,IAAI,EAAE,cAAc,CAAC;QACrB,IAAI,EAAE;YACJ,IAAI,EAAE,WAAW,CAAC;YAClB,OAAO,EAAE,MAAM,CAAC;SACjB,CAAC;KACH,CAAC;IACF,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,oBAAoB,CAAC;CACvC;AAED,MAAM,WAAW,wBAAwB;IACvC,aAAa,EAAE,CAAC,EACd,SAAS,EACT,QAAQ,EACR,IAAI,GACL,EAAE;QACD,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;KACvB,KAAK,IAAI,CAAC;IACX,eAAe,EAAE,UAAU,EAAE,CAAC;IAC9B,kBAAkB,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../src/types/chat.ts"],"names":[],"mappings":"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"}
|
package/dist/utils/common.d.ts
CHANGED
|
@@ -12,5 +12,18 @@ export declare const urlRegex: RegExp;
|
|
|
12
12
|
export declare function extractLinks(text: string): string[];
|
|
13
13
|
export declare function wrapLinksInHtml(htmlContent: string): string;
|
|
14
14
|
export declare const getHostFromUrl: (url: string) => string | null;
|
|
15
|
+
/**
|
|
16
|
+
* Sanitizes HTML content to prevent XSS attacks
|
|
17
|
+
* Uses DOMPurify to remove all potentially malicious code
|
|
18
|
+
*
|
|
19
|
+
* @param html - Raw HTML content that may contain malicious scripts
|
|
20
|
+
* @returns Sanitized HTML safe for rendering
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* const userInput = '<img src=x onerror=alert("XSS")>';
|
|
24
|
+
* const safe = sanitizeHtml(userInput);
|
|
25
|
+
* // Returns: '<img src="x">' (onerror removed)
|
|
26
|
+
*/
|
|
27
|
+
export declare function sanitizeHtml(html: string): string;
|
|
15
28
|
export {};
|
|
16
29
|
//# sourceMappingURL=common.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../src/utils/common.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../src/utils/common.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAItD,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAapD;AAED,eAAO,MAAM,iCAAiC,GAC5C,aAAa,WAAW,EACxB,YAAY,MAAM,WAkBnB,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAC7B,WAAW,MAAM,EACjB,gBAAgB,MAAM,EACtB,IAAI,GAAG,uBA2CR,CAAC;AAEF,eAAO,MAAM,eAAe,GAC1B,MAAM,MAAM,EACZ,SAAS,MAAM,EACf,kBAAc,WA2Cf,CAAC;AAEF,UAAU,aAAa;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,eAAe,CAC7B,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,aAAa,GACtB,MAAM,CAqBR;AAED,eAAO,MAAM,QAAQ,QAAkD,CAAC;AAExE,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAEnD;AAED,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAqC3D;AAED,eAAO,MAAM,cAAc,GAAI,KAAK,MAAM,KAAG,MAAM,GAAG,IAOrD,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAwCjD"}
|
package/dist/utils/common.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { MessageType } from "@openim/wasm-client-sdk";
|
|
2
2
|
import dayjs from "dayjs";
|
|
3
|
+
import DOMPurify from "dompurify";
|
|
3
4
|
export function renderFileSize(bytes) {
|
|
4
5
|
if (!bytes || bytes <= 0)
|
|
5
6
|
return "0 B";
|
|
@@ -165,3 +166,53 @@ export const getHostFromUrl = (url) => {
|
|
|
165
166
|
return null;
|
|
166
167
|
}
|
|
167
168
|
};
|
|
169
|
+
/**
|
|
170
|
+
* Sanitizes HTML content to prevent XSS attacks
|
|
171
|
+
* Uses DOMPurify to remove all potentially malicious code
|
|
172
|
+
*
|
|
173
|
+
* @param html - Raw HTML content that may contain malicious scripts
|
|
174
|
+
* @returns Sanitized HTML safe for rendering
|
|
175
|
+
*
|
|
176
|
+
* @example
|
|
177
|
+
* const userInput = '<img src=x onerror=alert("XSS")>';
|
|
178
|
+
* const safe = sanitizeHtml(userInput);
|
|
179
|
+
* // Returns: '<img src="x">' (onerror removed)
|
|
180
|
+
*/
|
|
181
|
+
export function sanitizeHtml(html) {
|
|
182
|
+
if (!html)
|
|
183
|
+
return "";
|
|
184
|
+
// Configure DOMPurify hooks
|
|
185
|
+
DOMPurify.addHook("afterSanitizeAttributes", (node) => {
|
|
186
|
+
// Ensure all links open in new tab with security attributes
|
|
187
|
+
if (node.tagName === "A") {
|
|
188
|
+
node.setAttribute("target", "_blank");
|
|
189
|
+
node.setAttribute("rel", "noopener noreferrer");
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
const sanitized = DOMPurify.sanitize(html, {
|
|
193
|
+
ALLOWED_TAGS: [
|
|
194
|
+
// Text formatting
|
|
195
|
+
"b", "i", "u", "strong", "em", "mark", "small", "del", "ins", "sub", "sup",
|
|
196
|
+
// Structure
|
|
197
|
+
"p", "br", "div", "span", "blockquote", "pre", "code",
|
|
198
|
+
// Lists
|
|
199
|
+
"ul", "ol", "li",
|
|
200
|
+
// Links
|
|
201
|
+
"a",
|
|
202
|
+
// Headers
|
|
203
|
+
"h1", "h2", "h3", "h4", "h5", "h6",
|
|
204
|
+
],
|
|
205
|
+
ALLOWED_ATTR: [
|
|
206
|
+
"href",
|
|
207
|
+
"target",
|
|
208
|
+
"rel",
|
|
209
|
+
"class",
|
|
210
|
+
"style", // Allow style for basic formatting
|
|
211
|
+
],
|
|
212
|
+
ALLOW_DATA_ATTR: false, // Prevent data-* attributes
|
|
213
|
+
ALLOWED_URI_REGEXP: /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i,
|
|
214
|
+
});
|
|
215
|
+
// Remove hooks after sanitization
|
|
216
|
+
DOMPurify.removeHook("afterSanitizeAttributes");
|
|
217
|
+
return sanitized;
|
|
218
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { UploadFile } from "antd";
|
|
2
|
+
import { TFunction } from "i18next";
|
|
3
|
+
export declare const ACCEPTED_IMAGE_TYPES: string[];
|
|
4
|
+
export declare const MAX_IMAGE_SIZE_MB = 5;
|
|
5
|
+
export declare const MAX_VIDEO_SIZE_MB = 200;
|
|
6
|
+
export interface FileValidationOptions {
|
|
7
|
+
t: TFunction;
|
|
8
|
+
currentUploadedFiles?: UploadFile[];
|
|
9
|
+
}
|
|
10
|
+
export interface FileValidationResult {
|
|
11
|
+
isValid: boolean;
|
|
12
|
+
error?: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Validates a single file for type and size
|
|
16
|
+
*/
|
|
17
|
+
export declare const validateFile: (file: File, t: TFunction) => FileValidationResult;
|
|
18
|
+
/**
|
|
19
|
+
* Validates video count limit (max 1 video)
|
|
20
|
+
*/
|
|
21
|
+
export declare const validateVideoLimit: (newFiles: File[], currentUploadedFiles: UploadFile[], t: TFunction) => FileValidationResult;
|
|
22
|
+
/**
|
|
23
|
+
* Process and validate multiple files, converting to UploadFile format
|
|
24
|
+
*/
|
|
25
|
+
export declare const processAndValidateFiles: (files: File[], options: FileValidationOptions) => UploadFile[];
|
|
26
|
+
//# sourceMappingURL=fileValidation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fileValidation.d.ts","sourceRoot":"","sources":["../../src/utils/fileValidation.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,UAAU,EAAE,MAAM,MAAM,CAAC;AAE1D,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEpC,eAAO,MAAM,oBAAoB,UAA2C,CAAC;AAC7E,eAAO,MAAM,iBAAiB,IAAI,CAAC;AACnC,eAAO,MAAM,iBAAiB,MAAM,CAAC;AAErC,MAAM,WAAW,qBAAqB;IACpC,CAAC,EAAE,SAAS,CAAC;IACb,oBAAoB,CAAC,EAAE,UAAU,EAAE,CAAC;CACrC;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,eAAO,MAAM,YAAY,GACvB,MAAM,IAAI,EACV,GAAG,SAAS,KACX,oBAyBF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,kBAAkB,GAC7B,UAAU,IAAI,EAAE,EAChB,sBAAsB,UAAU,EAAE,EAClC,GAAG,SAAS,KACX,oBAcF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,uBAAuB,GAClC,OAAO,IAAI,EAAE,EACb,SAAS,qBAAqB,KAC7B,UAAU,EAyCZ,CAAC"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { message as antdMessage } from "antd";
|
|
2
|
+
export const ACCEPTED_IMAGE_TYPES = ["image/jpeg", "image/png", "image/jpg"];
|
|
3
|
+
export const MAX_IMAGE_SIZE_MB = 5;
|
|
4
|
+
export const MAX_VIDEO_SIZE_MB = 200;
|
|
5
|
+
/**
|
|
6
|
+
* Validates a single file for type and size
|
|
7
|
+
*/
|
|
8
|
+
export const validateFile = (file, t) => {
|
|
9
|
+
const isImage = ACCEPTED_IMAGE_TYPES.includes(file.type);
|
|
10
|
+
const isVideo = file.type.startsWith("video/");
|
|
11
|
+
if (!isImage && !isVideo) {
|
|
12
|
+
const error = t("invalid_file_format", {
|
|
13
|
+
defaultValue: `${file.name} không đúng định dạng JPG, JPEG, PNG hoặc VIDEO`,
|
|
14
|
+
fileName: file.name,
|
|
15
|
+
});
|
|
16
|
+
return { isValid: false, error };
|
|
17
|
+
}
|
|
18
|
+
const maxSize = isVideo ? MAX_VIDEO_SIZE_MB : MAX_IMAGE_SIZE_MB;
|
|
19
|
+
const fileSizeMB = file.size / 1024 / 1024;
|
|
20
|
+
if (fileSizeMB > maxSize) {
|
|
21
|
+
const error = t("file_size_exceeded", {
|
|
22
|
+
defaultValue: `${file.name} có kích thước tập tin vượt quá ${maxSize}MB`,
|
|
23
|
+
fileName: file.name,
|
|
24
|
+
maxSize,
|
|
25
|
+
});
|
|
26
|
+
return { isValid: false, error };
|
|
27
|
+
}
|
|
28
|
+
return { isValid: true };
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Validates video count limit (max 1 video)
|
|
32
|
+
*/
|
|
33
|
+
export const validateVideoLimit = (newFiles, currentUploadedFiles, t) => {
|
|
34
|
+
const newVideos = newFiles.filter((f) => f.type.startsWith("video/"));
|
|
35
|
+
const currentVideos = currentUploadedFiles.filter((f) => { var _a; return (_a = f.type) === null || _a === void 0 ? void 0 : _a.startsWith("video/"); });
|
|
36
|
+
if (newVideos.length > 1 || currentVideos.length + newVideos.length > 1) {
|
|
37
|
+
const error = t("video_limit_exceeded", {
|
|
38
|
+
defaultValue: "Chỉ được phép tải lên 1 video duy nhất",
|
|
39
|
+
});
|
|
40
|
+
return { isValid: false, error };
|
|
41
|
+
}
|
|
42
|
+
return { isValid: true };
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Process and validate multiple files, converting to UploadFile format
|
|
46
|
+
*/
|
|
47
|
+
export const processAndValidateFiles = (files, options) => {
|
|
48
|
+
const { t, currentUploadedFiles = [] } = options;
|
|
49
|
+
try {
|
|
50
|
+
const validFiles = [];
|
|
51
|
+
// Check video limit first
|
|
52
|
+
const videoLimitCheck = validateVideoLimit(files, currentUploadedFiles, t);
|
|
53
|
+
if (!videoLimitCheck.isValid) {
|
|
54
|
+
antdMessage.error(videoLimitCheck.error);
|
|
55
|
+
return [];
|
|
56
|
+
}
|
|
57
|
+
// Validate each file
|
|
58
|
+
files.forEach((file) => {
|
|
59
|
+
const validation = validateFile(file, t);
|
|
60
|
+
if (validation.isValid) {
|
|
61
|
+
const uploadFile = {
|
|
62
|
+
uid: `${Date.now()}-${Math.random().toString(36).substring(2, 11)}`,
|
|
63
|
+
name: file.name,
|
|
64
|
+
status: "done",
|
|
65
|
+
type: file.type,
|
|
66
|
+
size: file.size,
|
|
67
|
+
originFileObj: file,
|
|
68
|
+
};
|
|
69
|
+
validFiles.push(uploadFile);
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
antdMessage.error(validation.error);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
return validFiles;
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
console.error("Error processing files:", error);
|
|
79
|
+
antdMessage.error(t("file_processing_error", {
|
|
80
|
+
defaultValue: "Đã xảy ra lỗi khi xử lý tệp",
|
|
81
|
+
}));
|
|
82
|
+
return [];
|
|
83
|
+
}
|
|
84
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@droppii-org/chat-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Droppii React Chat SDK",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -55,15 +55,6 @@
|
|
|
55
55
|
"files": [
|
|
56
56
|
"dist"
|
|
57
57
|
],
|
|
58
|
-
"scripts": {
|
|
59
|
-
"build": "pnpm build:css && tsc -p tsconfig.build.json && pnpm copy-assets",
|
|
60
|
-
"build:css": "tailwindcss -i ./src/styles/global.css -o ./dist/styles/global.css --minify",
|
|
61
|
-
"dev": "tsc --noEmit --watch",
|
|
62
|
-
"lint": "eslint src/",
|
|
63
|
-
"type-check": "tsc --noEmit",
|
|
64
|
-
"prepublishOnly": "pnpm build",
|
|
65
|
-
"copy-assets": "cp -R src/assets dist && cp -R src/locales dist"
|
|
66
|
-
},
|
|
67
58
|
"keywords": [
|
|
68
59
|
"chat",
|
|
69
60
|
"sdk",
|
|
@@ -91,6 +82,7 @@
|
|
|
91
82
|
"axios": "^1.11.0",
|
|
92
83
|
"clsx": "^2.0.0",
|
|
93
84
|
"dayjs": "^1.11.13",
|
|
85
|
+
"dompurify": "^3.3.1",
|
|
94
86
|
"i18next": "^25.5.2",
|
|
95
87
|
"jwt-decode": "^4.0.0",
|
|
96
88
|
"lexical": "^0.34.0",
|
|
@@ -114,10 +106,19 @@
|
|
|
114
106
|
"react-dom": "^18.0.0"
|
|
115
107
|
},
|
|
116
108
|
"devDependencies": {
|
|
109
|
+
"@types/dompurify": "^3.2.0",
|
|
117
110
|
"@types/lodash": "^4.17.20",
|
|
118
111
|
"@types/node": "^20.0.0",
|
|
119
112
|
"@types/react": "^18.2.37",
|
|
120
113
|
"@types/react-dom": "^18.2.15",
|
|
121
114
|
"typescript": "^5.2.2"
|
|
115
|
+
},
|
|
116
|
+
"scripts": {
|
|
117
|
+
"build": "pnpm build:css && tsc -p tsconfig.build.json && pnpm copy-assets",
|
|
118
|
+
"build:css": "tailwindcss -i ./src/styles/global.css -o ./dist/styles/global.css --minify",
|
|
119
|
+
"dev": "tsc --noEmit --watch",
|
|
120
|
+
"lint": "eslint src/",
|
|
121
|
+
"type-check": "tsc --noEmit",
|
|
122
|
+
"copy-assets": "cp -R src/assets dist && cp -R src/locales dist"
|
|
122
123
|
}
|
|
123
|
-
}
|
|
124
|
+
}
|