nextjs-cms 0.5.23 → 0.5.24

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.
@@ -3,7 +3,7 @@ import { db } from '../../db/client.js';
3
3
  import { AdminsTable } from '../../db/schema.js';
4
4
  import { eq } from 'drizzle-orm';
5
5
  import * as z from 'zod';
6
- import bcrypt from 'bcryptjs';
6
+ import bcrypt from 'bcrypt';
7
7
  import { TRPCError } from '@trpc/server';
8
8
  export const accountSettings = router({
9
9
  get: privateProcedure.query(async ({ ctx }) => {
@@ -5,7 +5,7 @@ import { db } from '../../db/client.js';
5
5
  import { AdminPrivilegesTable, AdminsTable } from '../../db/schema.js';
6
6
  import { eq } from 'drizzle-orm';
7
7
  import { TRPCError } from '@trpc/server';
8
- import bcrypt from 'bcryptjs';
8
+ import bcrypt from 'bcrypt';
9
9
  import { customAlphabet } from 'nanoid';
10
10
  import getString from '../../translations/index.js';
11
11
  import path from 'path';
@@ -1,7 +1,7 @@
1
1
  import { db } from '../../db/client.js';
2
2
  import { AccessTokensTable, AdminsTable } from '../../db/schema.js';
3
3
  import { and, eq } from 'drizzle-orm';
4
- import bcrypt from 'bcryptjs';
4
+ import bcrypt from 'bcrypt';
5
5
  import { decodeRefreshToken, encodeJWT, encodeRefreshToken } from '../jwt.js';
6
6
  import { cookies } from 'next/headers';
7
7
  export const authRefresh = async (refreshToken) => {
@@ -18,13 +18,24 @@ declare const configSchema: z.ZodObject<{
18
18
  type Config = z.infer<typeof configSchema>;
19
19
  export declare class DateField extends Field<'date', Config> {
20
20
  static readonly [entityKind]: string;
21
+ /**
22
+ * TODO:
23
+ * 1- timestamp should only be allowed when adminGenerated is false.
24
+ * 2- time format should be added as well.
25
+ */
21
26
  readonly format: 'date' | 'datetime' | 'timestamp';
22
27
  private readonly _defaultValue;
23
28
  constructor(config: BaseFieldConfig<Config>);
24
29
  /**
25
- * Get the value of the field
30
+ * Parse the raw value into a Date object
31
+ * Returns null if the value is not a valid date
32
+ */
33
+ private parseDate;
34
+ /**
35
+ * Get the value of the field in the required format
36
+ * Returns the value formatted according to the field's format setting
26
37
  */
27
- getValue(): string;
38
+ getValue(): string | null;
28
39
  exportForClient(): {
29
40
  format: "date" | "datetime" | "timestamp";
30
41
  type: "date";
@@ -40,6 +51,7 @@ export declare class DateField extends Field<'date', Config> {
40
51
  hasSqlNameAndValue(): boolean;
41
52
  /**
42
53
  * Prepare the field for submission
54
+ * Normalizes the value to ISO string format for storage
43
55
  */
44
56
  prepareForSubmission(): Promise<void>;
45
57
  }
@@ -1 +1 @@
1
- {"version":3,"file":"date.d.ts","sourceRoot":"","sources":["../../../src/core/fields/date.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AACjD,OAAO,EAAE,KAAK,EAAyB,MAAM,YAAY,CAAA;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAChD,OAAO,KAAK,CAAC,MAAM,KAAK,CAAA;AAExB,QAAA,MAAM,YAAY;;;;;;IAEd;;;;OAIG;;kBAEL,CAAA;AAEF,KAAK,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAA;AAE1C,qBAAa,SAAU,SAAQ,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC;IAChD,gBAAyB,CAAC,UAAU,CAAC,EAAE,MAAM,CAAc;IAC3D,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,GAAG,WAAW,CAAA;IAClD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAkB;gBACpC,MAAM,EAAE,eAAe,CAAC,MAAM,CAAC;IAU3C;;OAEG;IACH,QAAQ,IAAI,MAAM;IAYT,eAAe;;;;;;;;;;;IAOxB,aAAa;IAWJ,kBAAkB,IAAI,OAAO;IAOtC;;OAEG;IACG,oBAAoB;CAU7B;AAED,MAAM,MAAM,qBAAqB,GAAG,UAAU,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC,CAAA;AAE5E,QAAA,MAAM,aAAa;;;;;;IAjFf;;;;OAIG;;;;;;;;kBAgFL,CAAA;AAEF,QAAA,MAAM,qBAAqB;;;;;;;;IAtFvB;;;;OAIG;;;;;;;;kBAsFL,CAAA;AAEF;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAA;AAEnE;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,GAAG,eAAe,CAmB/E"}
1
+ {"version":3,"file":"date.d.ts","sourceRoot":"","sources":["../../../src/core/fields/date.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AACjD,OAAO,EAAE,KAAK,EAAyB,MAAM,YAAY,CAAA;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAChD,OAAO,KAAK,CAAC,MAAM,KAAK,CAAA;AAGxB,QAAA,MAAM,YAAY;;;;;;IAEd;;;;OAIG;;kBAEL,CAAA;AAEF,KAAK,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAA;AAE1C,qBAAa,SAAU,SAAQ,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC;IAChD,gBAAyB,CAAC,UAAU,CAAC,EAAE,MAAM,CAAc;IAE3D;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,GAAG,WAAW,CAAA;IAClD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAkB;gBACpC,MAAM,EAAE,eAAe,CAAC,MAAM,CAAC;IAU3C;;;OAGG;IACH,OAAO,CAAC,SAAS;IAQjB;;;OAGG;IACH,QAAQ,IAAI,MAAM,GAAG,IAAI;IAsBhB,eAAe;;;;;;;;;;;IAOxB,aAAa;IAYJ,kBAAkB,IAAI,OAAO;IAOtC;;;OAGG;IACG,oBAAoB;CAS7B;AAED,MAAM,MAAM,qBAAqB,GAAG,UAAU,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC,CAAA;AAE5E,QAAA,MAAM,aAAa;;;;;;IA/Gf;;;;OAIG;;;;;;;;kBA8GL,CAAA;AAEF,QAAA,MAAM,qBAAqB;;;;;;;;IApHvB;;;;OAIG;;;;;;;;kBAoHL,CAAA;AAEF;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAA;AAEnE;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,GAAG,eAAe,CAmB/E"}
@@ -1,6 +1,7 @@
1
1
  import { Field, baseFieldConfigSchema } from './field.js';
2
2
  import { entityKind } from '../helpers/index.js';
3
3
  import * as z from 'zod';
4
+ import dayjs from 'dayjs';
4
5
  const configSchema = z.strictObject({
5
6
  format: z.enum(['date', 'datetime', 'timestamp']).optional().describe('The format of the date field'),
6
7
  /**
@@ -12,6 +13,11 @@ const configSchema = z.strictObject({
12
13
  });
13
14
  export class DateField extends Field {
14
15
  static [entityKind] = 'DateField';
16
+ /**
17
+ * TODO:
18
+ * 1- timestamp should only be allowed when adminGenerated is false.
19
+ * 2- time format should be added as well.
20
+ */
15
21
  format;
16
22
  _defaultValue;
17
23
  constructor(config) {
@@ -20,21 +26,42 @@ export class DateField extends Field {
20
26
  /**
21
27
  * Set the default date if not provided
22
28
  */
23
- this.value = config.defaultValue ?? new Date(Date.now());
29
+ this.value = config.defaultValue ?? undefined;
24
30
  this._defaultValue = config.defaultValue;
25
31
  }
26
32
  /**
27
- * Get the value of the field
33
+ * Parse the raw value into a Date object
34
+ * Returns null if the value is not a valid date
35
+ */
36
+ parseDate() {
37
+ if (this.value === undefined || this.value === null || this.value === '') {
38
+ return null;
39
+ }
40
+ const date = new Date(this.value);
41
+ return isNaN(date.getTime()) ? null : date;
42
+ }
43
+ /**
44
+ * Get the value of the field in the required format
45
+ * Returns the value formatted according to the field's format setting
28
46
  */
29
47
  getValue() {
48
+ const date = this.parseDate();
49
+ if (!date) {
50
+ return null;
51
+ }
30
52
  switch (this.format) {
31
53
  case 'timestamp':
32
- return new Date(this.value).getTime().toString();
54
+ return dayjs(date).format('YYYY-MM-DD HH:mm:ss.SSS');
33
55
  case 'datetime':
34
- return this.value;
56
+ /**
57
+ * Return the date in ISO string format
58
+ * Example: 2025-12-18T12:00:00.000Z
59
+ */
60
+ return dayjs(date).format('YYYY-MM-DD HH:mm:ss');
35
61
  case 'date':
36
62
  default:
37
- return this.value.split('T')[0];
63
+ // Return YYYY-MM-DD format
64
+ return dayjs(date).format('YYYY-MM-DD');
38
65
  }
39
66
  }
40
67
  exportForClient() {
@@ -48,7 +75,8 @@ export class DateField extends Field {
48
75
  * Check if the field is required
49
76
  */
50
77
  if (this.required) {
51
- if (!this.value || this.value.trim().length === 0) {
78
+ const date = this.parseDate();
79
+ if (!date) {
52
80
  throw new Error(`Field ${this.label} is required`);
53
81
  }
54
82
  }
@@ -61,17 +89,17 @@ export class DateField extends Field {
61
89
  }
62
90
  /**
63
91
  * Prepare the field for submission
92
+ * Normalizes the value to ISO string format for storage
64
93
  */
65
94
  async prepareForSubmission() {
66
- /**
67
- * Check if the value represents a date
68
- */
69
- try {
70
- this.value = new Date(this.value).toISOString();
95
+ const date = this.parseDate();
96
+ if (date) {
97
+ this.value = date.toISOString();
71
98
  }
72
- catch (error) {
99
+ else if (this.required) {
73
100
  throw new Error(`Field ${this.label}: Invalid date, please provide a valid date`);
74
101
  }
102
+ // If not required and no valid date, keep value as-is (null/undefined)
75
103
  }
76
104
  }
77
105
  const optionsSchema = z.strictObject({
@@ -1,6 +1,6 @@
1
1
  import { Field, baseFieldConfigSchema } from './field.js';
2
2
  import { entityKind } from '../helpers/index.js';
3
- import bcrypt from 'bcryptjs';
3
+ import bcrypt from 'bcrypt';
4
4
  import * as z from 'zod';
5
5
  const passwordValidationTypeSchema = z.strictObject({
6
6
  regex: z.custom().describe('The regex pattern for validation'),
@@ -50,6 +50,10 @@ export declare class TagsField extends Field<'tags', Config> {
50
50
  value: any;
51
51
  };
52
52
  checkRequired(): void;
53
+ /**
54
+ * TODO: This is a temporary solution to convert the value to an array of tags
55
+ * The tags class is not complete
56
+ */
53
57
  prepareForSubmission(): Promise<void>;
54
58
  }
55
59
  export type TagsFieldClientConfig = ReturnType<TagsField['exportForClient']>;
@@ -1 +1 @@
1
- {"version":3,"file":"tags.d.ts","sourceRoot":"","sources":["../../../src/core/fields/tags.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AACjD,OAAO,EAAE,KAAK,EAAyB,MAAM,YAAY,CAAA;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAChD,OAAO,KAAK,CAAC,MAAM,KAAK,CAAA;AAGxB,QAAA,MAAM,YAAY;IACd;;;OAGG;;;;;;;;;;;IAiBH;;;;;OAKG;;kBAEL,CAAA;AAEF,KAAK,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAA;AAE1C,qBAAa,SAAU,SAAQ,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC;IAChD,gBAAyB,CAAC,UAAU,CAAC,EAAE,MAAM,CAAc;IAC3D,SAAkB,aAAa,CAAC,EAAE;QAC9B,KAAK,EAAE,MAAM,CAAA;QACb,cAAc,EAAE,MAAM,CAAA;QACtB,gBAAgB,EAAE,MAAM,CAAA;KAC3B,CAAA;IACD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;gBAEd,MAAM,EAAE,eAAe,CAAC,MAAM,CAAC;IAO3C,QAAQ;IAIQ,eAAe;;;;;;;;;;;;IAQ/B,aAAa;IAMP,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC;CAa9C;AAED,MAAM,MAAM,qBAAqB,GAAG,UAAU,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC,CAAA;AAE5E,QAAA,MAAM,aAAa;IAnFf;;;OAGG;;;;;;;;;;;IAiBH;;;;;OAKG;;;;;;;;;kBA6DL,CAAA;AAEF,QAAA,MAAM,qBAAqB;;;IAxFvB;;;OAGG;;;;;;;;;;;IAiBH;;;;;OAKG;;;;;;;;;kBAmEL,CAAA;AAEF;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAA;AAEnE;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,GAAG,eAAe,CAmB/E"}
1
+ {"version":3,"file":"tags.d.ts","sourceRoot":"","sources":["../../../src/core/fields/tags.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AACjD,OAAO,EAAE,KAAK,EAAyB,MAAM,YAAY,CAAA;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAChD,OAAO,KAAK,CAAC,MAAM,KAAK,CAAA;AAGxB,QAAA,MAAM,YAAY;IACd;;;OAGG;;;;;;;;;;;IAiBH;;;;;OAKG;;kBAEL,CAAA;AAEF,KAAK,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAA;AAE1C,qBAAa,SAAU,SAAQ,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC;IAChD,gBAAyB,CAAC,UAAU,CAAC,EAAE,MAAM,CAAc;IAC3D,SAAkB,aAAa,CAAC,EAAE;QAC9B,KAAK,EAAE,MAAM,CAAA;QACb,cAAc,EAAE,MAAM,CAAA;QACtB,gBAAgB,EAAE,MAAM,CAAA;KAC3B,CAAA;IACD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;gBAEd,MAAM,EAAE,eAAe,CAAC,MAAM,CAAC;IAO3C,QAAQ;IAGQ,eAAe;;;;;;;;;;;;IAQ/B,aAAa;IAMb;;;OAGG;IACG,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC;CAe9C;AAED,MAAM,MAAM,qBAAqB,GAAG,UAAU,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC,CAAA;AAE5E,QAAA,MAAM,aAAa;IAxFf;;;OAGG;;;;;;;;;;;IAiBH;;;;;OAKG;;;;;;;;;kBAkEL,CAAA;AAEF,QAAA,MAAM,qBAAqB;;;IA7FvB;;;OAGG;;;;;;;;;;;IAiBH;;;;;OAKG;;;;;;;;;kBAwEL,CAAA;AAEF;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAA;AAEnE;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,GAAG,eAAe,CAmB/E"}
@@ -39,7 +39,7 @@ export class TagsField extends Field {
39
39
  constructor(config) {
40
40
  super(config, 'tags');
41
41
  this.destinationDb = config.destinationDb;
42
- this.placeholder = config.placeholder || '';
42
+ this.placeholder = config.placeholder || 'Hit enter or comma to add a tag...';
43
43
  this.sanitize = config.sanitize ?? false;
44
44
  }
45
45
  getValue() {
@@ -57,16 +57,22 @@ export class TagsField extends Field {
57
57
  throw new Error(`Field ${this.label} is required`);
58
58
  }
59
59
  }
60
+ /**
61
+ * TODO: This is a temporary solution to convert the value to an array of tags
62
+ * The tags class is not complete
63
+ */
60
64
  async prepareForSubmission() {
61
65
  if (this.value) {
62
- if (!Array.isArray(this.value)) {
66
+ let _tags = this.value.split(',');
67
+ if (!Array.isArray(_tags)) {
63
68
  throw new Error(`Field ${this.label} must be an array of tags`);
64
69
  }
65
- if (this.value.some((tag) => typeof tag !== 'string')) {
70
+ if (_tags.some((tag) => typeof tag !== 'string')) {
66
71
  throw new Error(`Field ${this.label} must contain only string tags`);
67
72
  }
68
73
  if (this.sanitize) {
69
- this.value = this.value.map((tag) => escapeHTML(tag) || tag);
74
+ _tags = _tags.map((tag) => escapeHTML(tag) || tag);
75
+ this.value = _tags.join(',');
70
76
  }
71
77
  }
72
78
  }
@@ -275,5 +275,6 @@
275
275
  "seeAll": "عرض الكل",
276
276
  "allowedExtensions": "الامتدادات المسموح بها",
277
277
  "recursiveCategoryDelete": "حذف الأقسام الفرعية أيضاً",
278
- "recursiveCategoryDeleteWarning": "انتباه! سيتم حذف جميع الأقسام الفرعية"
278
+ "recursiveCategoryDeleteWarning": "انتباه! سيتم حذف جميع الأقسام الفرعية",
279
+ "unset": "إلغاء"
279
280
  }
@@ -275,5 +275,6 @@
275
275
  "seeAll": "See All",
276
276
  "allowedExtensions": "Allowed extensions",
277
277
  "recursiveCategoryDelete": "Delete this category and all its children",
278
- "recursiveCategoryDeleteWarning": "Warning! All child items will be deleted as well"
278
+ "recursiveCategoryDeleteWarning": "Warning! All child items will be deleted as well",
279
+ "unset": "Unset"
279
280
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nextjs-cms",
3
- "version": "0.5.23",
3
+ "version": "0.5.24",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "type": "module",
@@ -105,55 +105,43 @@
105
105
  "LICENSE"
106
106
  ],
107
107
  "dependencies": {
108
- "@clack/prompts": "^0.10.0",
109
- "@google-cloud/language": "^7.0.2",
110
- "@t3-oss/env-nextjs": "^0.13.8",
111
108
  "@trpc/server": "^11.4.2",
112
109
  "axios": "^1.8.4",
113
- "bcryptjs": "^3.0.3",
110
+ "bcrypt": "^6.0.0",
114
111
  "chalk": "^5.4.1",
115
112
  "chokidar": "3.6.0",
116
- "commander": "^14.0.2",
117
- "devalue": "^5.1.1",
118
- "dotenv": "^16.4.7",
113
+ "dayjs": "^1.11.19",
114
+ "dotenv": "^17.2.3",
119
115
  "drizzle-orm": "^0.44.6",
120
- "drizzle-zod": "^0.7.0",
121
116
  "esbuild-register": "^3.6.0",
122
117
  "glob": "^11.0.3",
123
- "i18next": "^25.2.1",
124
118
  "jose": "^6.0.11",
125
119
  "jsonwebtoken": "^9.0.2",
126
120
  "lodash-es": "^4.17.21",
127
121
  "mysql2": "^3.12.0",
128
- "nodemailer": "^7.0.3",
122
+ "next": "^15.5.5",
129
123
  "react": "19.0.0",
130
124
  "react-dom": "19.0.0",
131
- "sharp": "^0.34.5",
132
125
  "superjson": "^2.2.2",
133
126
  "through2": "^4.0.2",
134
- "zod": "4.1.12",
135
- "zod-i18n-map": "^2.27.0"
127
+ "zod": "4.1.12"
136
128
  },
137
129
  "devDependencies": {
130
+ "@types/bcrypt": "^6.0.0",
138
131
  "@types/jsonwebtoken": "^9.0.9",
139
132
  "@types/lodash-es": "^4.17.12",
140
- "@types/nodemailer": "^6.4.17",
141
133
  "@types/react": "~19.0.0",
142
134
  "@types/react-dom": "^19.0.0",
143
135
  "@types/through2": "^2.0.41",
144
- "date-fns": "^4.1.0",
145
136
  "dotenv-cli": "^7.4.4",
146
137
  "drizzle-kit": "^0.31.5",
147
138
  "eslint": "^9.12.0",
148
- "i18n-js": "^4.5.1",
149
139
  "nanoid": "^5.1.5",
150
140
  "prettier": "^3.3.3",
151
- "recast": "^0.23.11",
152
- "tsup": "^8.3.6",
153
- "tsx": "^4.21.0",
154
- "typescript": "^5.9.3",
155
- "@lzcms/prettier-config": "0.1.0",
141
+ "tsx": "^4.20.6",
142
+ "typescript": "^5.9.2",
156
143
  "@lzcms/eslint-config": "0.3.0",
144
+ "@lzcms/prettier-config": "0.1.0",
157
145
  "@lzcms/tsconfig": "0.1.0"
158
146
  },
159
147
  "license": "MIT",