nextjs-cms 0.5.9 → 0.5.11
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/api/axios/axiosInstance.d.ts +1 -1
- package/dist/api/axios/axiosInstance.js +8 -8
- package/dist/api/index.d.ts +855 -855
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +12 -12
- package/dist/api/lib/serverActions.d.ts +239 -239
- package/dist/api/lib/serverActions.d.ts.map +1 -1
- package/dist/api/lib/serverActions.js +834 -834
- package/dist/api/root.d.ts +828 -828
- package/dist/api/root.js +30 -30
- package/dist/api/routers/accountSettings.d.ts +60 -60
- package/dist/api/routers/accountSettings.js +108 -108
- package/dist/api/routers/admins.d.ts +105 -105
- package/dist/api/routers/admins.js +219 -219
- package/dist/api/routers/auth.d.ts +47 -47
- package/dist/api/routers/auth.js +25 -25
- package/dist/api/routers/categorySection.d.ts +103 -103
- package/dist/api/routers/categorySection.js +38 -38
- package/dist/api/routers/cmsSettings.d.ts +48 -48
- package/dist/api/routers/cmsSettings.js +51 -51
- package/dist/api/routers/cpanel.d.ts +83 -83
- package/dist/api/routers/cpanel.js +216 -216
- package/dist/api/routers/files.d.ts +47 -47
- package/dist/api/routers/files.js +23 -23
- package/dist/api/routers/gallery.d.ts +35 -35
- package/dist/api/routers/gallery.js +62 -62
- package/dist/api/routers/googleAnalytics.d.ts +30 -30
- package/dist/api/routers/googleAnalytics.js +7 -7
- package/dist/api/routers/hasItemsSection.d.ts +139 -139
- package/dist/api/routers/hasItemsSection.js +34 -34
- package/dist/api/routers/navigation.d.ts +51 -51
- package/dist/api/routers/navigation.js +11 -11
- package/dist/api/routers/simpleSection.d.ts +57 -57
- package/dist/api/routers/simpleSection.js +12 -12
- package/dist/api/trpc.d.ts +106 -106
- package/dist/api/trpc.js +72 -72
- package/dist/auth/axios/axiosInstance.d.ts +1 -1
- package/dist/auth/axios/axiosInstance.js +8 -8
- package/dist/auth/csrf.d.ts +29 -29
- package/dist/auth/csrf.js +76 -76
- package/dist/auth/hooks/index.d.ts +3 -3
- package/dist/auth/hooks/index.d.ts.map +1 -1
- package/dist/auth/hooks/index.js +3 -3
- package/dist/auth/hooks/useAxiosPrivate.d.ts +4 -4
- package/dist/auth/hooks/useAxiosPrivate.js +74 -74
- package/dist/auth/hooks/useRefreshToken.d.ts +6 -6
- package/dist/auth/hooks/useRefreshToken.js +79 -79
- package/dist/auth/index.d.ts +22 -22
- package/dist/auth/index.js +44 -44
- package/dist/auth/jwt.d.ts +5 -5
- package/dist/auth/jwt.js +25 -25
- package/dist/auth/lib/actions.d.ts +32 -32
- package/dist/auth/lib/actions.d.ts.map +1 -1
- package/dist/auth/lib/actions.js +209 -209
- package/dist/auth/lib/client.d.ts +3 -3
- package/dist/auth/lib/client.js +46 -46
- package/dist/auth/lib/index.d.ts +2 -2
- package/dist/auth/lib/index.d.ts.map +1 -1
- package/dist/auth/lib/index.js +2 -2
- package/dist/auth/react.d.ts +105 -105
- package/dist/auth/react.d.ts.map +1 -1
- package/dist/auth/react.js +347 -347
- package/dist/auth/trpc.d.ts +5 -5
- package/dist/auth/trpc.d.ts.map +1 -1
- package/dist/auth/trpc.js +81 -81
- package/dist/core/config/config-loader.d.ts +91 -91
- package/dist/core/config/config-loader.js +230 -230
- package/dist/core/config/index.d.ts +2 -2
- package/dist/core/config/index.d.ts.map +1 -1
- package/dist/core/config/index.js +1 -1
- package/dist/core/config/loader.d.ts +1 -1
- package/dist/core/config/loader.js +42 -42
- package/dist/core/db/index.d.ts +1 -1
- package/dist/core/db/index.d.ts.map +1 -1
- package/dist/core/db/index.js +1 -1
- package/dist/core/db/table-checker/DbTable.d.ts +5 -5
- package/dist/core/db/table-checker/DbTable.js +5 -5
- package/dist/core/db/table-checker/MysqlTable.d.ts +33 -33
- package/dist/core/db/table-checker/MysqlTable.d.ts.map +1 -1
- package/dist/core/db/table-checker/MysqlTable.js +94 -94
- package/dist/core/db/table-checker/index.d.ts +1 -1
- package/dist/core/db/table-checker/index.d.ts.map +1 -1
- package/dist/core/db/table-checker/index.js +1 -1
- package/dist/core/factories/FieldFactory.d.ts +123 -123
- package/dist/core/factories/FieldFactory.d.ts.map +1 -1
- package/dist/core/factories/FieldFactory.js +411 -411
- package/dist/core/factories/SectionFactory.d.ts +109 -109
- package/dist/core/factories/SectionFactory.d.ts.map +1 -1
- package/dist/core/factories/SectionFactory.js +415 -415
- package/dist/core/factories/index.d.ts +2 -2
- package/dist/core/factories/index.d.ts.map +1 -1
- package/dist/core/factories/index.js +2 -2
- package/dist/core/fields/checkbox.d.ts +62 -62
- package/dist/core/fields/checkbox.d.ts.map +1 -1
- package/dist/core/fields/checkbox.js +62 -62
- package/dist/core/fields/color.d.ts +83 -83
- package/dist/core/fields/color.d.ts.map +1 -1
- package/dist/core/fields/color.js +91 -91
- package/dist/core/fields/date.d.ts +99 -99
- package/dist/core/fields/date.d.ts.map +1 -1
- package/dist/core/fields/date.js +108 -108
- package/dist/core/fields/document.d.ts +179 -179
- package/dist/core/fields/document.d.ts.map +1 -1
- package/dist/core/fields/document.js +277 -277
- package/dist/core/fields/field-group.d.ts +17 -17
- package/dist/core/fields/field-group.d.ts.map +1 -1
- package/dist/core/fields/field-group.js +6 -6
- package/dist/core/fields/field.d.ts +125 -125
- package/dist/core/fields/field.d.ts.map +1 -1
- package/dist/core/fields/field.js +148 -148
- package/dist/core/fields/fileField.d.ts +14 -14
- package/dist/core/fields/fileField.d.ts.map +1 -1
- package/dist/core/fields/fileField.js +5 -5
- package/dist/core/fields/index.d.ts +64 -64
- package/dist/core/fields/index.d.ts.map +1 -1
- package/dist/core/fields/index.js +18 -18
- package/dist/core/fields/map.d.ts +166 -166
- package/dist/core/fields/map.d.ts.map +1 -1
- package/dist/core/fields/map.js +152 -152
- package/dist/core/fields/number.d.ts +185 -185
- package/dist/core/fields/number.d.ts.map +1 -1
- package/dist/core/fields/number.js +241 -241
- package/dist/core/fields/password.d.ts +108 -108
- package/dist/core/fields/password.d.ts.map +1 -1
- package/dist/core/fields/password.js +133 -133
- package/dist/core/fields/photo.d.ts +288 -288
- package/dist/core/fields/photo.d.ts.map +1 -1
- package/dist/core/fields/photo.js +410 -410
- package/dist/core/fields/richText.d.ts +294 -294
- package/dist/core/fields/richText.d.ts.map +1 -1
- package/dist/core/fields/richText.js +338 -338
- package/dist/core/fields/select.d.ts +365 -365
- package/dist/core/fields/select.d.ts.map +1 -1
- package/dist/core/fields/select.js +499 -499
- package/dist/core/fields/selectMultiple.d.ts +235 -235
- package/dist/core/fields/selectMultiple.d.ts.map +1 -1
- package/dist/core/fields/selectMultiple.js +417 -417
- package/dist/core/fields/tags.d.ts +130 -130
- package/dist/core/fields/tags.d.ts.map +1 -1
- package/dist/core/fields/tags.js +105 -105
- package/dist/core/fields/text.d.ts +135 -135
- package/dist/core/fields/text.d.ts.map +1 -1
- package/dist/core/fields/text.js +157 -157
- package/dist/core/fields/textArea.d.ts +106 -106
- package/dist/core/fields/textArea.d.ts.map +1 -1
- package/dist/core/fields/textArea.js +126 -126
- package/dist/core/fields/video.d.ts +147 -147
- package/dist/core/fields/video.d.ts.map +1 -1
- package/dist/core/fields/video.js +248 -248
- package/dist/core/helpers/entity.d.ts +7 -7
- package/dist/core/helpers/entity.js +27 -27
- package/dist/core/helpers/index.d.ts +4 -4
- package/dist/core/helpers/index.d.ts.map +1 -1
- package/dist/core/helpers/index.js +3 -3
- package/dist/core/index.d.ts +7 -7
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +7 -7
- package/dist/core/sections/category.d.ts +282 -282
- package/dist/core/sections/category.d.ts.map +1 -1
- package/dist/core/sections/category.js +147 -147
- package/dist/core/sections/hasItems.d.ts +631 -631
- package/dist/core/sections/hasItems.d.ts.map +1 -1
- package/dist/core/sections/hasItems.js +144 -144
- package/dist/core/sections/index.d.ts +4 -4
- package/dist/core/sections/index.d.ts.map +1 -1
- package/dist/core/sections/index.js +4 -4
- package/dist/core/sections/section.d.ts +225 -225
- package/dist/core/sections/section.d.ts.map +1 -1
- package/dist/core/sections/section.js +341 -341
- package/dist/core/sections/simple.d.ts +98 -98
- package/dist/core/sections/simple.d.ts.map +1 -1
- package/dist/core/sections/simple.js +95 -95
- package/dist/core/security/dom.d.ts +10 -10
- package/dist/core/security/dom.js +92 -92
- package/dist/core/submit/ItemEditSubmit.d.ts +75 -75
- package/dist/core/submit/ItemEditSubmit.js +186 -186
- package/dist/core/submit/NewItemSubmit.d.ts +13 -13
- package/dist/core/submit/NewItemSubmit.js +93 -93
- package/dist/core/submit/SimpleSectionSubmit.d.ts +12 -12
- package/dist/core/submit/SimpleSectionSubmit.js +93 -93
- package/dist/core/submit/index.d.ts +4 -4
- package/dist/core/submit/index.js +4 -4
- package/dist/core/submit/submit.d.ts +115 -115
- package/dist/core/submit/submit.js +479 -479
- package/dist/core/types/index.d.ts +279 -279
- package/dist/core/types/index.d.ts.map +1 -1
- package/dist/core/types/index.js +1 -1
- package/dist/db/client.d.ts +8 -8
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +19 -19
- package/dist/db/config.d.ts +5 -5
- package/dist/db/config.js +22 -22
- package/dist/db/drizzle.config.d.ts +5 -5
- package/dist/db/drizzle.config.js +18 -18
- package/dist/db/index.d.ts +2 -2
- package/dist/db/index.js +3 -3
- package/dist/db/schema.d.ts +638 -638
- package/dist/db/schema.js +73 -73
- package/dist/index.d.ts +7 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -7
- package/dist/translations/index.d.ts +2 -2
- package/dist/translations/index.js +15 -15
- package/dist/utils/CpanelApi.d.ts +24 -24
- package/dist/utils/CpanelApi.js +64 -64
- package/dist/utils/constants.d.ts +13 -13
- package/dist/utils/constants.js +61 -61
- package/dist/utils/index.d.ts +4 -4
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +4 -4
- package/dist/utils/utils.d.ts +59 -59
- package/dist/utils/utils.js +132 -132
- package/dist/validators/checkbox.d.ts +3 -3
- package/dist/validators/checkbox.d.ts.map +1 -1
- package/dist/validators/checkbox.js +12 -12
- package/dist/validators/color.d.ts +3 -3
- package/dist/validators/color.d.ts.map +1 -1
- package/dist/validators/color.js +7 -7
- package/dist/validators/date.d.ts +3 -3
- package/dist/validators/date.d.ts.map +1 -1
- package/dist/validators/date.js +5 -5
- package/dist/validators/document.d.ts +3 -3
- package/dist/validators/document.d.ts.map +1 -1
- package/dist/validators/document.js +57 -57
- package/dist/validators/index.d.ts +14 -14
- package/dist/validators/index.d.ts.map +1 -1
- package/dist/validators/index.js +14 -14
- package/dist/validators/map.d.ts +3 -3
- package/dist/validators/map.d.ts.map +1 -1
- package/dist/validators/map.js +5 -5
- package/dist/validators/number.d.ts +3 -3
- package/dist/validators/number.d.ts.map +1 -1
- package/dist/validators/number.js +20 -20
- package/dist/validators/password.d.ts +3 -3
- package/dist/validators/password.d.ts.map +1 -1
- package/dist/validators/password.js +11 -11
- package/dist/validators/photo.d.ts +3 -3
- package/dist/validators/photo.d.ts.map +1 -1
- package/dist/validators/photo.js +100 -100
- package/dist/validators/richText.d.ts +3 -3
- package/dist/validators/richText.d.ts.map +1 -1
- package/dist/validators/richText.js +8 -8
- package/dist/validators/select-multiple.d.ts +9 -9
- package/dist/validators/select-multiple.d.ts.map +1 -1
- package/dist/validators/select-multiple.js +20 -20
- package/dist/validators/select.d.ts +3 -3
- package/dist/validators/select.d.ts.map +1 -1
- package/dist/validators/select.js +5 -5
- package/dist/validators/text.d.ts +3 -3
- package/dist/validators/text.d.ts.map +1 -1
- package/dist/validators/text.js +7 -7
- package/dist/validators/textarea.d.ts +3 -3
- package/dist/validators/textarea.d.ts.map +1 -1
- package/dist/validators/textarea.js +7 -7
- package/dist/validators/video.d.ts +3 -3
- package/dist/validators/video.d.ts.map +1 -1
- package/dist/validators/video.js +57 -57
- package/package.json +4 -5
|
@@ -1,277 +1,277 @@
|
|
|
1
|
-
import { baseFieldConfigSchema } from
|
|
2
|
-
import { entityKind } from
|
|
3
|
-
import * as z from 'zod';
|
|
4
|
-
import fs from 'fs';
|
|
5
|
-
import { customAlphabet } from 'nanoid';
|
|
6
|
-
import path from 'path';
|
|
7
|
-
import { FileField } from
|
|
8
|
-
import { getCMSConfig } from
|
|
9
|
-
const maxFileSizeSchema = z.strictObject({
|
|
10
|
-
size: z.number().describe('Maximum file size'),
|
|
11
|
-
unit: z.enum(['kb', 'mb']).describe('Size unit'),
|
|
12
|
-
});
|
|
13
|
-
const configSchema = z.strictObject({
|
|
14
|
-
/**
|
|
15
|
-
* Maximum file size
|
|
16
|
-
* @example
|
|
17
|
-
* maxFileSize: {
|
|
18
|
-
* size: 512,
|
|
19
|
-
* unit: 'kb',
|
|
20
|
-
* }
|
|
21
|
-
*/
|
|
22
|
-
maxFileSize: maxFileSizeSchema.optional(),
|
|
23
|
-
/**
|
|
24
|
-
* Allowed document types
|
|
25
|
-
* @example
|
|
26
|
-
* type: ['pdf', 'doc', 'docx']
|
|
27
|
-
* @default ['pdf']
|
|
28
|
-
*/
|
|
29
|
-
type: z.array(z.enum(['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'csv'])).optional(),
|
|
30
|
-
});
|
|
31
|
-
export class DocumentField extends FileField {
|
|
32
|
-
static [entityKind] = 'DocumentField';
|
|
33
|
-
maxFileSize;
|
|
34
|
-
mimeType;
|
|
35
|
-
extensions;
|
|
36
|
-
possibleExtensions = ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'csv'];
|
|
37
|
-
/**
|
|
38
|
-
* _file is the file object if it's present
|
|
39
|
-
* Whereas the value is the path to the file
|
|
40
|
-
*/
|
|
41
|
-
_file;
|
|
42
|
-
_buffer;
|
|
43
|
-
_folder;
|
|
44
|
-
_allowedExtensions;
|
|
45
|
-
uploadsFolder = getCMSConfig().files.upload.uploadPath;
|
|
46
|
-
constructor(config, file) {
|
|
47
|
-
super(config, 'document');
|
|
48
|
-
if (file) {
|
|
49
|
-
this._file = file;
|
|
50
|
-
}
|
|
51
|
-
this.maxFileSize = config.maxFileSize ?? { size: 2, unit: 'mb' };
|
|
52
|
-
/**
|
|
53
|
-
* Check if the config type is valid
|
|
54
|
-
*/
|
|
55
|
-
if (config.type && config.type.some((type) => !this.possibleExtensions.includes(type))) {
|
|
56
|
-
throw new Error(`Invalid document type provided: ${config.type.join(', ')}, allowed types are: ${this.possibleExtensions.join(', ')}`);
|
|
57
|
-
}
|
|
58
|
-
this.extensions = config.type ?? ['pdf'];
|
|
59
|
-
/**
|
|
60
|
-
* Extract the mime types from the extensions
|
|
61
|
-
* @link https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types
|
|
62
|
-
*/
|
|
63
|
-
this.mimeType = this.extensions.map((e) => {
|
|
64
|
-
switch (e) {
|
|
65
|
-
case 'pdf':
|
|
66
|
-
return 'application/pdf';
|
|
67
|
-
case 'doc':
|
|
68
|
-
return 'application/msword';
|
|
69
|
-
case 'docx':
|
|
70
|
-
return 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
|
|
71
|
-
case 'xls':
|
|
72
|
-
return 'application/vnd.ms-excel';
|
|
73
|
-
case 'xlsx':
|
|
74
|
-
return 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
|
|
75
|
-
case 'ppt':
|
|
76
|
-
return 'application/vnd.ms-powerpoint';
|
|
77
|
-
case 'pptx':
|
|
78
|
-
return 'application/vnd.openxmlformats-officedocument.presentationml.presentation';
|
|
79
|
-
case 'txt':
|
|
80
|
-
return 'text/plain';
|
|
81
|
-
case 'csv':
|
|
82
|
-
return 'text/csv';
|
|
83
|
-
default:
|
|
84
|
-
throw new Error(`Invalid image extension provided: ${e}`);
|
|
85
|
-
}
|
|
86
|
-
});
|
|
87
|
-
/**
|
|
88
|
-
* Set the allowed extensions, add jpg if jpeg is present
|
|
89
|
-
*/
|
|
90
|
-
this._allowedExtensions = this.extensions;
|
|
91
|
-
}
|
|
92
|
-
exportForClient() {
|
|
93
|
-
return {
|
|
94
|
-
...super.exportForClient(),
|
|
95
|
-
maxFileSize: this.maxFileSize,
|
|
96
|
-
extensions: this._allowedExtensions,
|
|
97
|
-
mimeType: this.mimeType,
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
async readChunkFromFile({ arrayBuffer, length, startPosition = 0, }) {
|
|
101
|
-
return new Promise(async (resolve, reject) => {
|
|
102
|
-
try {
|
|
103
|
-
if (arrayBuffer) {
|
|
104
|
-
const buffer = new Uint8Array(arrayBuffer, startPosition, length);
|
|
105
|
-
resolve(buffer);
|
|
106
|
-
}
|
|
107
|
-
else {
|
|
108
|
-
reject(new Error('Error reading file'));
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
catch (error) {
|
|
112
|
-
reject(new Error('Error reading file'));
|
|
113
|
-
}
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
/**
|
|
117
|
-
* Write the file to the disk
|
|
118
|
-
*/
|
|
119
|
-
async writeToFile() {
|
|
120
|
-
if (!this._folder) {
|
|
121
|
-
throw new Error(`${this.label}: Folder is not set. Make sure to set the folder by call postSubmit() before writing the file to disk`);
|
|
122
|
-
}
|
|
123
|
-
if (!this._buffer) {
|
|
124
|
-
throw new Error(`${this.label}: Buffer is not set. Make sure to call prepareForSubmission() before writing the file to disk`);
|
|
125
|
-
}
|
|
126
|
-
try {
|
|
127
|
-
/**
|
|
128
|
-
* If .documents, and 'sectionName' folders don't exist, create them
|
|
129
|
-
*/
|
|
130
|
-
const documentsFolder = path.join(this.uploadsFolder, '.documents', this._folder);
|
|
131
|
-
if (!fs.existsSync(documentsFolder)) {
|
|
132
|
-
fs.mkdirSync(documentsFolder, { recursive: true });
|
|
133
|
-
}
|
|
134
|
-
/**
|
|
135
|
-
* Write the file to disk
|
|
136
|
-
*/
|
|
137
|
-
await fs.promises.writeFile(path.join(this.uploadsFolder, '.documents', this._folder, this.value), this._buffer);
|
|
138
|
-
}
|
|
139
|
-
catch (error) {
|
|
140
|
-
throw new Error(`${this.label}: Error writing file to disk ${error.message}`);
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
async postSubmit(folder) {
|
|
144
|
-
if (!this._file)
|
|
145
|
-
return;
|
|
146
|
-
this._folder = folder;
|
|
147
|
-
await this.writeToFile();
|
|
148
|
-
}
|
|
149
|
-
async postSubmitRollback() {
|
|
150
|
-
if (!this._file)
|
|
151
|
-
return;
|
|
152
|
-
if (!this._folder) {
|
|
153
|
-
throw new Error(`${this.label}: Folder is not set. Make sure to set the folder before writing the file to disk`);
|
|
154
|
-
}
|
|
155
|
-
try {
|
|
156
|
-
const pathToFile = path.join(this.uploadsFolder, '.documents', this._folder, this.value);
|
|
157
|
-
await fs.promises.unlink(pathToFile);
|
|
158
|
-
}
|
|
159
|
-
catch (error) {
|
|
160
|
-
throw new Error(`${this.label}: Error deleting file from disk`);
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
/**
|
|
164
|
-
* Get the value of the field
|
|
165
|
-
*/
|
|
166
|
-
getValue() {
|
|
167
|
-
return this.value;
|
|
168
|
-
}
|
|
169
|
-
setFileName(value) {
|
|
170
|
-
this.value = value;
|
|
171
|
-
}
|
|
172
|
-
setValue(value) {
|
|
173
|
-
if (typeof value === 'string') {
|
|
174
|
-
this.setFileName(value);
|
|
175
|
-
return;
|
|
176
|
-
}
|
|
177
|
-
this.setFile(value);
|
|
178
|
-
}
|
|
179
|
-
setFile(file) {
|
|
180
|
-
if (!file || file.size === 0 || file.name?.trim() === '')
|
|
181
|
-
return;
|
|
182
|
-
this._file = file;
|
|
183
|
-
}
|
|
184
|
-
checkRequired() {
|
|
185
|
-
/**
|
|
186
|
-
* Check if the field is required
|
|
187
|
-
* If it is, check if the file is present
|
|
188
|
-
* If it's not, throw an error
|
|
189
|
-
* Note: Those values are coming from the browser (not safe)
|
|
190
|
-
*/
|
|
191
|
-
if (!this.required)
|
|
192
|
-
return;
|
|
193
|
-
if (!this._file || !this._file?.type || !this._file?.name || !this._file?.size) {
|
|
194
|
-
throw new Error(`Field ${this.label} is required`);
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
/**
|
|
198
|
-
* Prepare the field for submission
|
|
199
|
-
*/
|
|
200
|
-
async prepareForSubmission() {
|
|
201
|
-
if (!this._file)
|
|
202
|
-
return;
|
|
203
|
-
/**
|
|
204
|
-
* Check the actual file size
|
|
205
|
-
*/
|
|
206
|
-
const arrayBuffer = await this._file.arrayBuffer();
|
|
207
|
-
this._buffer = Buffer.from(arrayBuffer);
|
|
208
|
-
if (!this._buffer.length) {
|
|
209
|
-
throw new Error(`Field ${this.label} is required`);
|
|
210
|
-
}
|
|
211
|
-
/**
|
|
212
|
-
* Check extension
|
|
213
|
-
*/
|
|
214
|
-
const ext = this._file.name.split('.').pop();
|
|
215
|
-
if (!ext || !this.extensions.includes(ext)) {
|
|
216
|
-
throw new Error(`${this.label}: Invalid file type or extension. Allowed extensions: ${this.extensions.join(', ')}`);
|
|
217
|
-
}
|
|
218
|
-
/**
|
|
219
|
-
* Read the first 4100 bytes of the file
|
|
220
|
-
*/
|
|
221
|
-
const chunkBuffer = await this.readChunkFromFile({ arrayBuffer, length: 4100 });
|
|
222
|
-
/**
|
|
223
|
-
* Get the file type from the buffer
|
|
224
|
-
*/
|
|
225
|
-
const { fileTypeFromBuffer } = await import('file-type');
|
|
226
|
-
const fileType = await fileTypeFromBuffer(chunkBuffer);
|
|
227
|
-
/**
|
|
228
|
-
* If the file type is invalid, return an error
|
|
229
|
-
*/
|
|
230
|
-
if (!fileType) {
|
|
231
|
-
throw new Error(`${this.label}: Invalid file type`);
|
|
232
|
-
}
|
|
233
|
-
/**
|
|
234
|
-
* Don't just trust the file extension
|
|
235
|
-
* Check the `fileType.ext` against the allowed extensions
|
|
236
|
-
*/
|
|
237
|
-
if (!fileType.ext || !this.extensions.includes(fileType.ext)) {
|
|
238
|
-
throw new Error(`${this.label}: Invalid file type or extension. Allowed extensions: ${this.extensions.join(', ')}`);
|
|
239
|
-
}
|
|
240
|
-
/**
|
|
241
|
-
* Generate a random name for the file
|
|
242
|
-
*/
|
|
243
|
-
this.value = customAlphabet('1234567890abcdef', 21)();
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
const optionsSchema = z.strictObject({
|
|
247
|
-
...baseFieldConfigSchema.shape,
|
|
248
|
-
...configSchema.shape,
|
|
249
|
-
});
|
|
250
|
-
const documentFieldConfigSchema = z.strictObject({
|
|
251
|
-
...optionsSchema.shape,
|
|
252
|
-
type: z.literal('document').describe('The type of the field'),
|
|
253
|
-
build: z.function().output(z.instanceof(DocumentField)).describe('Build a DocumentField instance from this config'),
|
|
254
|
-
});
|
|
255
|
-
/**
|
|
256
|
-
* Helper function to create a document field configuration
|
|
257
|
-
* Returns a config object with a build() method that can be serialized and used anywhere
|
|
258
|
-
* @param field
|
|
259
|
-
*/
|
|
260
|
-
export function documentField(field) {
|
|
261
|
-
/**
|
|
262
|
-
* Validate the field config
|
|
263
|
-
*/
|
|
264
|
-
const result = optionsSchema.safeParse(field);
|
|
265
|
-
if (!result.success) {
|
|
266
|
-
throw new Error(`[Field: ${field.name}]: ${z.prettifyError(result.error)}`);
|
|
267
|
-
}
|
|
268
|
-
const config = {
|
|
269
|
-
...field,
|
|
270
|
-
type: 'document',
|
|
271
|
-
build() {
|
|
272
|
-
// Use the original field config directly (it doesn't have build() method)
|
|
273
|
-
return new DocumentField(field);
|
|
274
|
-
},
|
|
275
|
-
};
|
|
276
|
-
return config;
|
|
277
|
-
}
|
|
1
|
+
import { baseFieldConfigSchema } from './field.js';
|
|
2
|
+
import { entityKind } from '../helpers/index.js';
|
|
3
|
+
import * as z from 'zod';
|
|
4
|
+
import fs from 'fs';
|
|
5
|
+
import { customAlphabet } from 'nanoid';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
import { FileField } from './fileField.js';
|
|
8
|
+
import { getCMSConfig } from '../config/index.js';
|
|
9
|
+
const maxFileSizeSchema = z.strictObject({
|
|
10
|
+
size: z.number().describe('Maximum file size'),
|
|
11
|
+
unit: z.enum(['kb', 'mb']).describe('Size unit'),
|
|
12
|
+
});
|
|
13
|
+
const configSchema = z.strictObject({
|
|
14
|
+
/**
|
|
15
|
+
* Maximum file size
|
|
16
|
+
* @example
|
|
17
|
+
* maxFileSize: {
|
|
18
|
+
* size: 512,
|
|
19
|
+
* unit: 'kb',
|
|
20
|
+
* }
|
|
21
|
+
*/
|
|
22
|
+
maxFileSize: maxFileSizeSchema.optional(),
|
|
23
|
+
/**
|
|
24
|
+
* Allowed document types
|
|
25
|
+
* @example
|
|
26
|
+
* type: ['pdf', 'doc', 'docx']
|
|
27
|
+
* @default ['pdf']
|
|
28
|
+
*/
|
|
29
|
+
type: z.array(z.enum(['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'csv'])).optional(),
|
|
30
|
+
});
|
|
31
|
+
export class DocumentField extends FileField {
|
|
32
|
+
static [entityKind] = 'DocumentField';
|
|
33
|
+
maxFileSize;
|
|
34
|
+
mimeType;
|
|
35
|
+
extensions;
|
|
36
|
+
possibleExtensions = ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'csv'];
|
|
37
|
+
/**
|
|
38
|
+
* _file is the file object if it's present
|
|
39
|
+
* Whereas the value is the path to the file
|
|
40
|
+
*/
|
|
41
|
+
_file;
|
|
42
|
+
_buffer;
|
|
43
|
+
_folder;
|
|
44
|
+
_allowedExtensions;
|
|
45
|
+
uploadsFolder = getCMSConfig().files.upload.uploadPath;
|
|
46
|
+
constructor(config, file) {
|
|
47
|
+
super(config, 'document');
|
|
48
|
+
if (file) {
|
|
49
|
+
this._file = file;
|
|
50
|
+
}
|
|
51
|
+
this.maxFileSize = config.maxFileSize ?? { size: 2, unit: 'mb' };
|
|
52
|
+
/**
|
|
53
|
+
* Check if the config type is valid
|
|
54
|
+
*/
|
|
55
|
+
if (config.type && config.type.some((type) => !this.possibleExtensions.includes(type))) {
|
|
56
|
+
throw new Error(`Invalid document type provided: ${config.type.join(', ')}, allowed types are: ${this.possibleExtensions.join(', ')}`);
|
|
57
|
+
}
|
|
58
|
+
this.extensions = config.type ?? ['pdf'];
|
|
59
|
+
/**
|
|
60
|
+
* Extract the mime types from the extensions
|
|
61
|
+
* @link https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types
|
|
62
|
+
*/
|
|
63
|
+
this.mimeType = this.extensions.map((e) => {
|
|
64
|
+
switch (e) {
|
|
65
|
+
case 'pdf':
|
|
66
|
+
return 'application/pdf';
|
|
67
|
+
case 'doc':
|
|
68
|
+
return 'application/msword';
|
|
69
|
+
case 'docx':
|
|
70
|
+
return 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
|
|
71
|
+
case 'xls':
|
|
72
|
+
return 'application/vnd.ms-excel';
|
|
73
|
+
case 'xlsx':
|
|
74
|
+
return 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
|
|
75
|
+
case 'ppt':
|
|
76
|
+
return 'application/vnd.ms-powerpoint';
|
|
77
|
+
case 'pptx':
|
|
78
|
+
return 'application/vnd.openxmlformats-officedocument.presentationml.presentation';
|
|
79
|
+
case 'txt':
|
|
80
|
+
return 'text/plain';
|
|
81
|
+
case 'csv':
|
|
82
|
+
return 'text/csv';
|
|
83
|
+
default:
|
|
84
|
+
throw new Error(`Invalid image extension provided: ${e}`);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
/**
|
|
88
|
+
* Set the allowed extensions, add jpg if jpeg is present
|
|
89
|
+
*/
|
|
90
|
+
this._allowedExtensions = this.extensions;
|
|
91
|
+
}
|
|
92
|
+
exportForClient() {
|
|
93
|
+
return {
|
|
94
|
+
...super.exportForClient(),
|
|
95
|
+
maxFileSize: this.maxFileSize,
|
|
96
|
+
extensions: this._allowedExtensions,
|
|
97
|
+
mimeType: this.mimeType,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
async readChunkFromFile({ arrayBuffer, length, startPosition = 0, }) {
|
|
101
|
+
return new Promise(async (resolve, reject) => {
|
|
102
|
+
try {
|
|
103
|
+
if (arrayBuffer) {
|
|
104
|
+
const buffer = new Uint8Array(arrayBuffer, startPosition, length);
|
|
105
|
+
resolve(buffer);
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
reject(new Error('Error reading file'));
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
reject(new Error('Error reading file'));
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Write the file to the disk
|
|
118
|
+
*/
|
|
119
|
+
async writeToFile() {
|
|
120
|
+
if (!this._folder) {
|
|
121
|
+
throw new Error(`${this.label}: Folder is not set. Make sure to set the folder by call postSubmit() before writing the file to disk`);
|
|
122
|
+
}
|
|
123
|
+
if (!this._buffer) {
|
|
124
|
+
throw new Error(`${this.label}: Buffer is not set. Make sure to call prepareForSubmission() before writing the file to disk`);
|
|
125
|
+
}
|
|
126
|
+
try {
|
|
127
|
+
/**
|
|
128
|
+
* If .documents, and 'sectionName' folders don't exist, create them
|
|
129
|
+
*/
|
|
130
|
+
const documentsFolder = path.join(this.uploadsFolder, '.documents', this._folder);
|
|
131
|
+
if (!fs.existsSync(documentsFolder)) {
|
|
132
|
+
fs.mkdirSync(documentsFolder, { recursive: true });
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Write the file to disk
|
|
136
|
+
*/
|
|
137
|
+
await fs.promises.writeFile(path.join(this.uploadsFolder, '.documents', this._folder, this.value), this._buffer);
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
throw new Error(`${this.label}: Error writing file to disk ${error.message}`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
async postSubmit(folder) {
|
|
144
|
+
if (!this._file)
|
|
145
|
+
return;
|
|
146
|
+
this._folder = folder;
|
|
147
|
+
await this.writeToFile();
|
|
148
|
+
}
|
|
149
|
+
async postSubmitRollback() {
|
|
150
|
+
if (!this._file)
|
|
151
|
+
return;
|
|
152
|
+
if (!this._folder) {
|
|
153
|
+
throw new Error(`${this.label}: Folder is not set. Make sure to set the folder before writing the file to disk`);
|
|
154
|
+
}
|
|
155
|
+
try {
|
|
156
|
+
const pathToFile = path.join(this.uploadsFolder, '.documents', this._folder, this.value);
|
|
157
|
+
await fs.promises.unlink(pathToFile);
|
|
158
|
+
}
|
|
159
|
+
catch (error) {
|
|
160
|
+
throw new Error(`${this.label}: Error deleting file from disk`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Get the value of the field
|
|
165
|
+
*/
|
|
166
|
+
getValue() {
|
|
167
|
+
return this.value;
|
|
168
|
+
}
|
|
169
|
+
setFileName(value) {
|
|
170
|
+
this.value = value;
|
|
171
|
+
}
|
|
172
|
+
setValue(value) {
|
|
173
|
+
if (typeof value === 'string') {
|
|
174
|
+
this.setFileName(value);
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
this.setFile(value);
|
|
178
|
+
}
|
|
179
|
+
setFile(file) {
|
|
180
|
+
if (!file || file.size === 0 || file.name?.trim() === '')
|
|
181
|
+
return;
|
|
182
|
+
this._file = file;
|
|
183
|
+
}
|
|
184
|
+
checkRequired() {
|
|
185
|
+
/**
|
|
186
|
+
* Check if the field is required
|
|
187
|
+
* If it is, check if the file is present
|
|
188
|
+
* If it's not, throw an error
|
|
189
|
+
* Note: Those values are coming from the browser (not safe)
|
|
190
|
+
*/
|
|
191
|
+
if (!this.required)
|
|
192
|
+
return;
|
|
193
|
+
if (!this._file || !this._file?.type || !this._file?.name || !this._file?.size) {
|
|
194
|
+
throw new Error(`Field ${this.label} is required`);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Prepare the field for submission
|
|
199
|
+
*/
|
|
200
|
+
async prepareForSubmission() {
|
|
201
|
+
if (!this._file)
|
|
202
|
+
return;
|
|
203
|
+
/**
|
|
204
|
+
* Check the actual file size
|
|
205
|
+
*/
|
|
206
|
+
const arrayBuffer = await this._file.arrayBuffer();
|
|
207
|
+
this._buffer = Buffer.from(arrayBuffer);
|
|
208
|
+
if (!this._buffer.length) {
|
|
209
|
+
throw new Error(`Field ${this.label} is required`);
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Check extension
|
|
213
|
+
*/
|
|
214
|
+
const ext = this._file.name.split('.').pop();
|
|
215
|
+
if (!ext || !this.extensions.includes(ext)) {
|
|
216
|
+
throw new Error(`${this.label}: Invalid file type or extension. Allowed extensions: ${this.extensions.join(', ')}`);
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Read the first 4100 bytes of the file
|
|
220
|
+
*/
|
|
221
|
+
const chunkBuffer = await this.readChunkFromFile({ arrayBuffer, length: 4100 });
|
|
222
|
+
/**
|
|
223
|
+
* Get the file type from the buffer
|
|
224
|
+
*/
|
|
225
|
+
const { fileTypeFromBuffer } = await import('file-type');
|
|
226
|
+
const fileType = await fileTypeFromBuffer(chunkBuffer);
|
|
227
|
+
/**
|
|
228
|
+
* If the file type is invalid, return an error
|
|
229
|
+
*/
|
|
230
|
+
if (!fileType) {
|
|
231
|
+
throw new Error(`${this.label}: Invalid file type`);
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Don't just trust the file extension
|
|
235
|
+
* Check the `fileType.ext` against the allowed extensions
|
|
236
|
+
*/
|
|
237
|
+
if (!fileType.ext || !this.extensions.includes(fileType.ext)) {
|
|
238
|
+
throw new Error(`${this.label}: Invalid file type or extension. Allowed extensions: ${this.extensions.join(', ')}`);
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Generate a random name for the file
|
|
242
|
+
*/
|
|
243
|
+
this.value = customAlphabet('1234567890abcdef', 21)();
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
const optionsSchema = z.strictObject({
|
|
247
|
+
...baseFieldConfigSchema.shape,
|
|
248
|
+
...configSchema.shape,
|
|
249
|
+
});
|
|
250
|
+
const documentFieldConfigSchema = z.strictObject({
|
|
251
|
+
...optionsSchema.shape,
|
|
252
|
+
type: z.literal('document').describe('The type of the field'),
|
|
253
|
+
build: z.function().output(z.instanceof(DocumentField)).describe('Build a DocumentField instance from this config'),
|
|
254
|
+
});
|
|
255
|
+
/**
|
|
256
|
+
* Helper function to create a document field configuration
|
|
257
|
+
* Returns a config object with a build() method that can be serialized and used anywhere
|
|
258
|
+
* @param field
|
|
259
|
+
*/
|
|
260
|
+
export function documentField(field) {
|
|
261
|
+
/**
|
|
262
|
+
* Validate the field config
|
|
263
|
+
*/
|
|
264
|
+
const result = optionsSchema.safeParse(field);
|
|
265
|
+
if (!result.success) {
|
|
266
|
+
throw new Error(`[Field: ${field.name}]: ${z.prettifyError(result.error)}`);
|
|
267
|
+
}
|
|
268
|
+
const config = {
|
|
269
|
+
...field,
|
|
270
|
+
type: 'document',
|
|
271
|
+
build() {
|
|
272
|
+
// Use the original field config directly (it doesn't have build() method)
|
|
273
|
+
return new DocumentField(field);
|
|
274
|
+
},
|
|
275
|
+
};
|
|
276
|
+
return config;
|
|
277
|
+
}
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import type { Field, FieldConfig } from
|
|
2
|
-
import type { Prettify } from
|
|
3
|
-
export type FieldGroupOptions = {
|
|
4
|
-
title?: string;
|
|
5
|
-
order?: number;
|
|
6
|
-
fields: FieldConfig[];
|
|
7
|
-
};
|
|
8
|
-
export type FieldGroupConfig = Prettify<FieldGroupOptions> & {
|
|
9
|
-
type: 'field_group';
|
|
10
|
-
};
|
|
11
|
-
export type FieldGroup = {
|
|
12
|
-
id: number;
|
|
13
|
-
title?: string;
|
|
14
|
-
order?: number;
|
|
15
|
-
fields: Field[];
|
|
16
|
-
};
|
|
17
|
-
export declare function fieldGroup(group: FieldGroupOptions): FieldGroupConfig;
|
|
1
|
+
import type { Field, FieldConfig } from './index.js';
|
|
2
|
+
import type { Prettify } from '../types/index.js';
|
|
3
|
+
export type FieldGroupOptions = {
|
|
4
|
+
title?: string;
|
|
5
|
+
order?: number;
|
|
6
|
+
fields: FieldConfig[];
|
|
7
|
+
};
|
|
8
|
+
export type FieldGroupConfig = Prettify<FieldGroupOptions> & {
|
|
9
|
+
type: 'field_group';
|
|
10
|
+
};
|
|
11
|
+
export type FieldGroup = {
|
|
12
|
+
id: number;
|
|
13
|
+
title?: string;
|
|
14
|
+
order?: number;
|
|
15
|
+
fields: Field[];
|
|
16
|
+
};
|
|
17
|
+
export declare function fieldGroup(group: FieldGroupOptions): FieldGroupConfig;
|
|
18
18
|
//# sourceMappingURL=field-group.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"field-group.d.ts","sourceRoot":"","sources":["../../../src/core/fields/field-group.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"field-group.d.ts","sourceRoot":"","sources":["../../../src/core/fields/field-group.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AACpD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAEjD,MAAM,MAAM,iBAAiB,GAAG;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,WAAW,EAAE,CAAA;CACxB,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CAAC,iBAAiB,CAAC,GAAG;IACzD,IAAI,EAAE,aAAa,CAAA;CACtB,CAAA;AAED,MAAM,MAAM,UAAU,GAAG;IACrB,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,KAAK,EAAE,CAAA;CAClB,CAAA;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,iBAAiB,GAAG,gBAAgB,CAKrE"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export function fieldGroup(group) {
|
|
2
|
-
return {
|
|
3
|
-
...group,
|
|
4
|
-
type: 'field_group',
|
|
5
|
-
};
|
|
6
|
-
}
|
|
1
|
+
export function fieldGroup(group) {
|
|
2
|
+
return {
|
|
3
|
+
...group,
|
|
4
|
+
type: 'field_group',
|
|
5
|
+
};
|
|
6
|
+
}
|