@yimingliao/cms 0.0.65 → 0.0.66

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.
@@ -1,4 +1,4 @@
1
- import { mimeToExtension } from './chunk-HMJ53TVF.js';
1
+ import { mimeToExtension } from './chunk-N2PRNBP2.js';
2
2
  import path from 'path/posix';
3
3
  import { ulid } from 'ulid';
4
4
 
@@ -60,7 +60,10 @@ function createResponseInterceptor({ logger }) {
60
60
  url: ctx.meta.url,
61
61
  duration
62
62
  });
63
- return data;
63
+ return {
64
+ success: true,
65
+ data
66
+ };
64
67
  };
65
68
  return responseInterceptor;
66
69
  }
package/dist/index.d.ts CHANGED
@@ -3,8 +3,8 @@ export { A as ADMIN_ROLES, d as Admin, e as AdminCard, f as AdminFull, g as Admi
3
3
  export { B as BlobFile } from './types-0oS1A2K5.js';
4
4
  import { E as ErrorDetail, S as SuccessResult, a as ErrorResult } from './types-DHlRoJwv.js';
5
5
  export { R as Result } from './types-DHlRoJwv.js';
6
- import { Metadata } from 'next';
7
6
  import { Robots } from 'next/dist/lib/metadata/types/metadata-types';
7
+ import { Metadata } from 'next';
8
8
 
9
9
  declare const isFolderLocked: (folder?: FolderFull | Folder) => boolean;
10
10
 
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
1
  export { ADMIN_ROLES, POST_TYPES, ROOT_FOLDER, ROOT_FOLDER_ID, ROOT_FOLDER_NAME, SIMPLE_UPLOAD_FOLDER_KEY, SIMPLE_UPLOAD_FOLDER_NAME, isFileLocked, isFolderLocked } from './chunk-FUAJWL2N.js';
2
- export { FILE_TYPES, OG_TYPE_ARRAY, SIZE, TWITTER_CARD_ARRAY, classifyFileType, createBuildArticleMetadata, createBuildTranslations, createBuildWebsiteMetadata, datetimeToDb, datetimeToUi, findTranslation, formatFileSize, getMediaInfo, jsonArrayToDb, jsonArrayToUi, mimeToExtension, result, serializeJsonLd } from './chunk-HMJ53TVF.js';
2
+ export { FILE_TYPES, OG_TYPE_ARRAY, SIZE, TWITTER_CARD_ARRAY, classifyFileType, createBuildArticleMetadata, createBuildTranslations, createBuildWebsiteMetadata, datetimeToDb, datetimeToUi, findTranslation, formatFileSize, getMediaInfo, jsonArrayToDb, jsonArrayToUi, mimeToExtension, result, serializeJsonLd } from './chunk-N2PRNBP2.js';
@@ -3,15 +3,16 @@ import { BinaryLike } from 'node:crypto';
3
3
  import { cookies } from 'next/headers';
4
4
  import Keyv from 'keyv';
5
5
  import { Logger } from 'logry';
6
+ import { PrismaClient } from '@prisma/client';
6
7
  import * as zod from 'zod';
7
8
  import zod__default, { z, ZodType } from 'zod';
8
9
  import { B as BlobFile } from '../types-0oS1A2K5.js';
9
10
  import * as zod_v4_core from 'zod/v4/core';
10
11
  import { T as TocItem, h as AdminRole, v as SingleItem, B as BaseTranslation, d as Admin, f as AdminFull, i as AdminSafe, D as DeviceInfo, g as AdminRefreshToken, n as File$1, b as FileFull, p as FileType, a as Folder, F as FolderFull, u as PostType, M as MultiItems, E as ExternalLink, m as Faq, r as Post, s as PostListCard, t as PostTranslation, P as PostFull, k as Alternate, e as AdminCard, c as FileCard } from '../card-BG2vtuIz.js';
11
12
  import * as nodemailer_lib_smtp_transport from 'nodemailer/lib/smtp-transport';
12
- import nodemailer, { Transporter } from 'nodemailer';
13
- import { BaseTranslator, LocaleMessages } from 'intor';
13
+ import nodemailer, { Transporter, SentMessageInfo } from 'nodemailer';
14
14
  import { S as SuccessResult, R as Result } from '../types-DHlRoJwv.js';
15
+ import { BaseTranslator, LocaleMessages } from 'intor';
15
16
  import { NextResponse } from 'next/server';
16
17
  import { S as StorageService } from '../types-J25u1G6t.js';
17
18
 
@@ -109,6 +110,12 @@ declare function createIpRateLimiter({ appName, cache, headers, }: {
109
110
  headers: () => Promise<Headers>;
110
111
  }): ({ key: rawKey, maxAttempts, timeWindow, }: RateLimiterOptions) => Promise<boolean>;
111
112
 
113
+ type ExistOptions = {
114
+ table: string;
115
+ column?: string;
116
+ };
117
+ declare function createExist(prisma: PrismaClient): (value: string | number, options: ExistOptions) => Promise<boolean>;
118
+
112
119
  type Scope = {
113
120
  name: string;
114
121
  value: string;
@@ -120,13 +127,7 @@ type UniqueOptions = {
120
127
  scope?: Scope[];
121
128
  excludeSelf?: Scope;
122
129
  };
123
- declare function createUnique(prisma: any): (value: string, options: UniqueOptions) => Promise<boolean>;
124
-
125
- type ExistOptions = {
126
- table: string;
127
- column?: string;
128
- };
129
- declare function createExist(prisma: any): (value: string | number, options: ExistOptions) => Promise<boolean>;
130
+ declare function createUnique(prisma: PrismaClient): (value: string, options: UniqueOptions) => Promise<boolean>;
130
131
 
131
132
  declare module "zod" {
132
133
  interface ZodString {
@@ -216,7 +217,7 @@ declare function createSendEmail({ transporter, config, }: {
216
217
  replyToName: string;
217
218
  replyToaddress: string;
218
219
  };
219
- }): (options: SendEmailOptions) => Promise<any>;
220
+ }): (options: SendEmailOptions) => Promise<SentMessageInfo>;
220
221
 
221
222
  declare function createRenderEmailTemplate({ siteName, webUrl, logoUrl, logger, }: {
222
223
  siteName: string;
@@ -263,7 +264,7 @@ interface UpdateParams$3 {
263
264
  emailVerifiedAt: Date | null;
264
265
  }
265
266
 
266
- declare function createAdminCommandRepository(prisma: any): {
267
+ declare function createAdminCommandRepository(prisma: PrismaClient): {
267
268
  create: ({ role, email, passwordHash, socialLinks, avatarImage, translations, }: CreateParams$4) => Promise<Admin>;
268
269
  update: ({ id, role, email, socialLinks, avatarImage, translations, emailVerifiedAt, }: UpdateParams$3) => Promise<Admin>;
269
270
  delete: ({ id }: {
@@ -284,7 +285,7 @@ interface FindParams$2 {
284
285
  email?: string;
285
286
  }
286
287
 
287
- declare function createAdminQueryRepository(prisma: any): {
288
+ declare function createAdminQueryRepository(prisma: PrismaClient): {
288
289
  findListCards: ({ locale, searchString, role, adminIds, page, pageSize, }: FindListCardsParams$3) => Promise<{
289
290
  items: AdminFull[];
290
291
  total: number;
@@ -307,13 +308,13 @@ interface DeleteParams {
307
308
  tokenHash?: string;
308
309
  }
309
310
 
310
- declare function createAdminRefreshTokenCommandRepository(prisma: any): {
311
+ declare function createAdminRefreshTokenCommandRepository(prisma: PrismaClient): {
311
312
  create: ({ adminId, ...params }: CreateParams$3) => Promise<AdminRefreshToken>;
312
313
  delete: ({ id, tokenHash }: DeleteParams) => Promise<void>;
313
314
  deleteManyByExpired: () => Promise<number>;
314
315
  };
315
316
 
316
- declare function createAdminRefreshTokenQueryRepository(prisma: any): {
317
+ declare function createAdminRefreshTokenQueryRepository(prisma: PrismaClient): {
317
318
  findManyByAdminId: ({ adminId, }: {
318
319
  adminId: string;
319
320
  }) => Promise<AdminRefreshToken[]>;
@@ -359,7 +360,7 @@ interface UpdateParams$2 {
359
360
  })[];
360
361
  }
361
362
 
362
- declare function createFileCommandRepository(prisma: any): {
363
+ declare function createFileCommandRepository(prisma: PrismaClient): {
363
364
  create: ({ key, checksum, fileMeta, width, height, duration, folder, translations, }: CreateParams$2) => Promise<FileFull>;
364
365
  update: ({ file, id, key, checksum, fileMeta, width, height, duration, folder, translations, }: UpdateParams$2) => Promise<File$1>;
365
366
  softDelete: ({ id }: {
@@ -388,7 +389,7 @@ interface FindListCardsParams$2 {
388
389
  pageSize?: number;
389
390
  }
390
391
 
391
- declare function createFileQueryRepository(prisma: any): {
392
+ declare function createFileQueryRepository(prisma: PrismaClient): {
392
393
  findListCards: ({ locale, page, pageSize, searchString, type, folderId, isLocked, isDeleted, fileIds, }: FindListCardsParams$2) => Promise<{
393
394
  items: FileFull[];
394
395
  total: number;
@@ -413,7 +414,7 @@ interface UpdateParams$1 {
413
414
  parentFolder: Folder | null;
414
415
  }
415
416
 
416
- declare function createFolderCommandRepository(prisma: any): {
417
+ declare function createFolderCommandRepository(prisma: PrismaClient): {
417
418
  create: ({ key, name, parentFolder, }: CreateParams$1) => Promise<Folder>;
418
419
  update: ({ id, key, name, parentFolder, }: UpdateParams$1) => Promise<Folder>;
419
420
  delete: ({ id }: {
@@ -433,7 +434,7 @@ interface FindParams$1 {
433
434
  key?: string;
434
435
  }
435
436
 
436
- declare function createFolderQueryRepository(prisma: any): {
437
+ declare function createFolderQueryRepository(prisma: PrismaClient): {
437
438
  findListCards: ({ searchString, parentFolderId, folderIds, page, pageSize, }: FindListCardsParams$1) => Promise<{
438
439
  items: FolderFull[];
439
440
  total: number;
@@ -591,7 +592,7 @@ interface UpdateParams {
591
592
  })[];
592
593
  }
593
594
 
594
- declare function createPostCommandRepository(prisma: any): {
595
+ declare function createPostCommandRepository(prisma: PrismaClient): {
595
596
  create: ({ slug, author, topicId, parents, tags, relatedPosts, coverImage, contentImageIds, images1, images2, image1, image2, image3, image4, translations, ...params }: CreateParams) => Promise<Post>;
596
597
  update: ({ id, slug, author, topicId, parents, tags, relatedPosts, coverImage, contentImageIds, images1, images2, image1, image2, image3, image4, translations, ...params }: UpdateParams) => Promise<Post>;
597
598
  delete: ({ id }: {
@@ -639,7 +640,7 @@ interface FindManyParams {
639
640
  topicId?: string;
640
641
  }
641
642
 
642
- declare function createPostQueryRepository(prisma: any): {
643
+ declare function createPostQueryRepository(prisma: PrismaClient): {
643
644
  findListCards: ({ locale, searchString, type, isActive, isIndexActive, isSlugActive, isFeatured, isShownOnHome, state1, state2, state3, state4, state5, state6, state7, state8, state9, state10, topicId, topicSlug, categoryId, categorySlug, postIds, excludeIds, page, pageSize, }: FindListCardsParams) => Promise<{
644
645
  items: PostListCard[];
645
646
  total: number;
@@ -686,7 +687,7 @@ interface UpsertParams {
686
687
  })[];
687
688
  }
688
689
 
689
- declare function createSeoMetadataCommandRepository(prisma: any): {
690
+ declare function createSeoMetadataCommandRepository(prisma: PrismaClient): {
690
691
  upsert: ({ postId, translations, }: UpsertParams) => Promise<void>;
691
692
  };
692
693
 
@@ -739,8 +740,36 @@ interface CreateExecuteApiParams {
739
740
  }
740
741
  declare function createExecuteApi({ initI18n, logger }: CreateExecuteApiParams): (fn: Api) => Promise<NextResponse<unknown>>;
741
742
 
743
+ interface CreateVerifyAccessTokenParams {
744
+ adminQueryRepository: ReturnType<typeof createAdminQueryRepository>;
745
+ jwtService: ReturnType<typeof createJwtService>;
746
+ cryptoService: ReturnType<typeof createCryptoService>;
747
+ cookieService: ReturnType<typeof createCookieService>;
748
+ config: {
749
+ accessTokenName: string;
750
+ accessTokenSecret: string;
751
+ };
752
+ }
753
+ declare function createVerifyAccessToken({ adminQueryRepository, jwtService, cryptoService, cookieService, config, }: CreateVerifyAccessTokenParams): () => Promise<{
754
+ admin: AdminFull;
755
+ } | null>;
756
+
757
+ interface CreateVerifyRefreshTokenParams {
758
+ adminQueryRepository: ReturnType<typeof createAdminQueryRepository>;
759
+ adminRefreshTokenQueryRepository: ReturnType<typeof createAdminRefreshTokenQueryRepository>;
760
+ cryptoService: ReturnType<typeof createCryptoService>;
761
+ cookieService: ReturnType<typeof createCookieService>;
762
+ config: {
763
+ refreshTokenName: string;
764
+ };
765
+ }
766
+ declare function createVerifyRefreshToken({ adminQueryRepository, adminRefreshTokenQueryRepository, cryptoService, cookieService, config, }: CreateVerifyRefreshTokenParams): () => Promise<{
767
+ adminRefreshToken: AdminRefreshToken;
768
+ admin: AdminFull;
769
+ } | null>;
770
+
742
771
  interface CreateAuthUseCases {
743
- prisma: any;
772
+ prisma: PrismaClient;
744
773
  adminQueryRepository: ReturnType<typeof createAdminQueryRepository>;
745
774
  adminRefreshTokenCommandRepository: ReturnType<typeof createAdminRefreshTokenCommandRepository>;
746
775
  jwtService: ReturnType<typeof createJwtService>;
@@ -832,34 +861,6 @@ declare function createForgotPasswordEmail({ renderEmailTemplate, sendEmail, aut
832
861
  send: ({ translator, admin }: SendParams) => Promise<any>;
833
862
  };
834
863
 
835
- interface CreateVerifyAccessTokenParams {
836
- adminQueryRepository: ReturnType<typeof createAdminQueryRepository>;
837
- jwtService: ReturnType<typeof createJwtService>;
838
- cryptoService: ReturnType<typeof createCryptoService>;
839
- cookieService: ReturnType<typeof createCookieService>;
840
- config: {
841
- accessTokenName: string;
842
- accessTokenSecret: string;
843
- };
844
- }
845
- declare function createVerifyAccessToken({ adminQueryRepository, jwtService, cryptoService, cookieService, config, }: CreateVerifyAccessTokenParams): () => Promise<{
846
- admin: AdminFull;
847
- } | null>;
848
-
849
- interface CreateVerifyRefreshTokenParams {
850
- adminQueryRepository: ReturnType<typeof createAdminQueryRepository>;
851
- adminRefreshTokenQueryRepository: ReturnType<typeof createAdminRefreshTokenQueryRepository>;
852
- cryptoService: ReturnType<typeof createCryptoService>;
853
- cookieService: ReturnType<typeof createCookieService>;
854
- config: {
855
- refreshTokenName: string;
856
- };
857
- }
858
- declare function createVerifyRefreshToken({ adminQueryRepository, adminRefreshTokenQueryRepository, cryptoService, cookieService, config, }: CreateVerifyRefreshTokenParams): () => Promise<{
859
- adminRefreshToken: AdminRefreshToken;
860
- admin: AdminFull;
861
- } | null>;
862
-
863
864
  interface CreateAuthMiddlewareParams {
864
865
  adminRefreshTokenCommandRepository: ReturnType<typeof createAdminRefreshTokenCommandRepository>;
865
866
  authUseCases: ReturnType<typeof createAuthUseCases>;
@@ -1,9 +1,8 @@
1
1
  import { ADMIN_ROLES, isFileLocked, isFolderLocked, ROOT_FOLDER_ID, ROOT_FOLDER, POST_TYPES } from '../chunk-FUAJWL2N.js';
2
- import { SIZE, result, datetimeToDb, jsonArrayToDb, mimeToExtension, classifyFileType, TWITTER_CARD_ARRAY, OG_TYPE_ARRAY } from '../chunk-HMJ53TVF.js';
2
+ import { SIZE, result, datetimeToDb, jsonArrayToDb, mimeToExtension, classifyFileType, TWITTER_CARD_ARRAY, OG_TYPE_ARRAY } from '../chunk-N2PRNBP2.js';
3
3
  import jwt from 'jsonwebtoken';
4
4
  import argon2 from 'argon2';
5
5
  import crypto, { timingSafeEqual } from 'crypto';
6
- import 'next/headers';
7
6
  import KeyvRedis from '@keyv/redis';
8
7
  import Keyv from 'keyv';
9
8
  import { z, ZodError } from 'zod';
@@ -279,6 +278,8 @@ function createCacheResult(cache2, logger) {
279
278
  }
280
279
  };
281
280
  }
281
+
282
+ // src/server/infrastructure/cache/create-ip-rate-limiter.ts
282
283
  var DEFAULT_MAX_ATTEMPTS = 10;
283
284
  var DEFAULT_TIME_WINDOW = 60;
284
285
  var lua = `
@@ -318,6 +319,49 @@ function createIpRateLimiter({
318
319
  };
319
320
  }
320
321
 
322
+ // src/server/infrastructure/zod/rules/bcp47.ts
323
+ function bcp47(locale) {
324
+ if (typeof locale !== "string") return false;
325
+ const BCP47_REGEX = new RegExp(
326
+ "^[a-zA-Z]{2,3}(?:-[A-Z][a-z]{3})?" + // optional region
327
+ String.raw`(?:-(?:[A-Z]{2}|\d{3}))?` + // optional variants
328
+ String.raw`(?:-(?:[a-zA-Z0-9]{5,8}|\d[a-zA-Z0-9]{3}))*` + // optional extensions
329
+ "(?:-(?:[0-9A-WY-Za-wy-z]-[a-zA-Z0-9]{2,8}(?:-[a-zA-Z0-9]{2,8})*))*(?:-x(?:-[a-zA-Z0-9]{1,8})+)?$"
330
+ );
331
+ return BCP47_REGEX.test(locale);
332
+ }
333
+
334
+ // src/server/infrastructure/zod/rules/exist.ts
335
+ function createExist(prisma) {
336
+ return async function exist(value, options) {
337
+ if (!value) return false;
338
+ const column = options.column || "id";
339
+ const query = `
340
+ SELECT COUNT(*) AS count
341
+ FROM ${options.table}
342
+ WHERE ${column} = $1
343
+ `;
344
+ try {
345
+ const result2 = await prisma.$queryRawUnsafe(
346
+ query,
347
+ value
348
+ );
349
+ const count = Number(result2[0]?.count || 0);
350
+ return count > 0;
351
+ } catch (error) {
352
+ console.error("Exist check failed:", error);
353
+ return false;
354
+ }
355
+ };
356
+ }
357
+
358
+ // src/server/infrastructure/zod/rules/og-locale.ts
359
+ function ogLocale(locale) {
360
+ if (typeof locale !== "string") return false;
361
+ const OG_LOCALE_REGEX = /^[a-z]{2}_[A-Z]{2}$/;
362
+ return OG_LOCALE_REGEX.test(locale);
363
+ }
364
+
321
365
  // src/server/infrastructure/zod/rules/unique.ts
322
366
  function createUnique(prisma) {
323
367
  return async function unique(value, options) {
@@ -353,56 +397,13 @@ function createUnique(prisma) {
353
397
  };
354
398
  }
355
399
 
356
- // src/server/infrastructure/zod/rules/exist.ts
357
- function createExist(prisma) {
358
- return async function exist(value, options) {
359
- if (!value) return false;
360
- const column = options.column || "id";
361
- const query = `
362
- SELECT COUNT(*) AS count
363
- FROM ${options.table}
364
- WHERE ${column} = $1
365
- `;
366
- try {
367
- const result2 = await prisma.$queryRawUnsafe(
368
- query,
369
- value
370
- );
371
- const count = Number(result2[0]?.count || 0);
372
- return count > 0;
373
- } catch (error) {
374
- console.error("Exist check failed:", error);
375
- return false;
376
- }
377
- };
378
- }
379
-
380
- // src/server/infrastructure/zod/rules/bcp47.ts
381
- function bcp47(locale) {
382
- if (typeof locale !== "string") return false;
383
- const BCP47_REGEX = new RegExp(
384
- "^[a-zA-Z]{2,3}(?:-[A-Z][a-z]{3})?" + // optional region
385
- String.raw`(?:-(?:[A-Z]{2}|\d{3}))?` + // optional variants
386
- String.raw`(?:-(?:[a-zA-Z0-9]{5,8}|\d[a-zA-Z0-9]{3}))*` + // optional extensions
387
- "(?:-(?:[0-9A-WY-Za-wy-z]-[a-zA-Z0-9]{2,8}(?:-[a-zA-Z0-9]{2,8})*))*(?:-x(?:-[a-zA-Z0-9]{1,8})+)?$"
388
- );
389
- return BCP47_REGEX.test(locale);
390
- }
391
-
392
- // src/server/infrastructure/zod/rules/og-locale.ts
393
- function ogLocale(locale) {
394
- if (typeof locale !== "string") return false;
395
- const OG_LOCALE_REGEX = /^[a-z]{2}_[A-Z]{2}$/;
396
- return OG_LOCALE_REGEX.test(locale);
397
- }
398
-
399
400
  // src/server/infrastructure/zod/create-zod.ts
400
401
  function createZod({
401
402
  unique,
402
403
  exist
403
404
  }) {
404
- const stringProto = z.ZodString.prototype;
405
- const emailProto = z.ZodEmail.prototype;
405
+ const stringProto = z.string().constructor.prototype;
406
+ const emailProto = z.email().constructor.prototype;
406
407
  if (!stringProto.unique) {
407
408
  Object.defineProperty(stringProto, "unique", {
408
409
  configurable: true,
@@ -477,7 +478,7 @@ function createSchemas({
477
478
  function positiveNumber() {
478
479
  return z2.preprocess((val) => {
479
480
  if (val == null || val === "") return;
480
- const num = Number(String(val).trim());
481
+ const num = Number(typeof val === "string" ? val.trim() : val);
481
482
  return Number.isNaN(num) ? void 0 : num;
482
483
  }, z2.number().min(0).max(MAX_NUMBER));
483
484
  }
@@ -659,7 +660,9 @@ async function readTemplate(filePath) {
659
660
  if (!isDev) cache.set(filePath, html);
660
661
  return html;
661
662
  } catch (error) {
662
- throw new Error(`Email template file not found: ${filePath}`);
663
+ throw new Error(`Email template file not found: ${filePath}`, {
664
+ cause: error
665
+ });
663
666
  }
664
667
  }
665
668
  function applyReplacements(html, replacements, logger) {
@@ -689,7 +692,7 @@ function createRenderEmailTemplate({
689
692
  ...replacements
690
693
  };
691
694
  const layoutHtml = await readTemplate(LAYOUT_PATH);
692
- let contentHtml = await readTemplate(contentPath);
695
+ const contentHtml = await readTemplate(contentPath);
693
696
  const merged = layoutHtml.replaceAll("{{{content}}}", contentHtml);
694
697
  return applyReplacements(merged, vars, logger);
695
698
  } catch (error) {
@@ -699,7 +702,7 @@ function createRenderEmailTemplate({
699
702
  templateDir: TEMPLATE_DIR,
700
703
  error
701
704
  });
702
- throw new Error(`Email template error: ${templateKey}`);
705
+ throw new Error(`Email template error: ${templateKey}`, { cause: error });
703
706
  }
704
707
  };
705
708
  }
@@ -839,25 +842,14 @@ var POST_ORDER_BY = [
839
842
  ...ORDER_BY
840
843
  ];
841
844
 
842
- // src/server/infrastructure/database/admin/include.ts
843
- var ADMIN_FULL_INCLUDE = {
844
- // ---------------------------
845
- // relations: AdminRefreshToken
846
- // ---------------------------
847
- adminRefreshTokens: true,
848
- // ---------------------------
849
- // relations: File
850
- // ---------------------------
851
- avatarImage: { include: { translations: true } },
852
- // ---------------------------
853
- // relations: Post
854
- // ---------------------------
855
- posts: true,
856
- // ---------------------------
857
- // translation
858
- // ---------------------------
859
- translations: true
860
- };
845
+ // src/server/infrastructure/database/utils/create-pagination.ts
846
+ function createPagination(page, pageSize) {
847
+ if (!page || !pageSize) return {};
848
+ return {
849
+ skip: (page - 1) * pageSize,
850
+ take: pageSize
851
+ };
852
+ }
861
853
 
862
854
  // src/server/infrastructure/database/utils/create-search.ts
863
855
  function buildContainsOr(fields, value) {
@@ -891,14 +883,25 @@ function createSearch({
891
883
  return conditions.length > 0 ? { OR: conditions } : {};
892
884
  }
893
885
 
894
- // src/server/infrastructure/database/utils/create-pagination.ts
895
- function createPagination(page, pageSize) {
896
- if (!page || !pageSize) return {};
897
- return {
898
- skip: (page - 1) * pageSize,
899
- take: pageSize
900
- };
901
- }
886
+ // src/server/infrastructure/database/admin/include.ts
887
+ var ADMIN_FULL_INCLUDE = {
888
+ // ---------------------------
889
+ // relations: AdminRefreshToken
890
+ // ---------------------------
891
+ adminRefreshTokens: true,
892
+ // ---------------------------
893
+ // relations: File
894
+ // ---------------------------
895
+ avatarImage: { include: { translations: true } },
896
+ // ---------------------------
897
+ // relations: Post
898
+ // ---------------------------
899
+ posts: true,
900
+ // ---------------------------
901
+ // translation
902
+ // ---------------------------
903
+ translations: true
904
+ };
902
905
 
903
906
  // src/server/infrastructure/database/admin/query/create-admin-query-repository.ts
904
907
  var OMIT_PASSWORD = { omit: { passwordHash: true } };
@@ -1841,8 +1844,8 @@ function createSeoMetadataCommandRepository(prisma) {
1841
1844
  seoMetadatas: {
1842
1845
  upsert: translations.map((t) => ({
1843
1846
  where: { postId_locale: { postId, locale: t.locale } },
1844
- update: t,
1845
- create: t
1847
+ update: { ...t, alternate: t.alternate },
1848
+ create: { ...t, alternate: t.alternate }
1846
1849
  }))
1847
1850
  }
1848
1851
  }
@@ -1934,7 +1937,7 @@ function createExecuteAction({
1934
1937
  ...options.ttl ? { ttl: options.ttl } : {},
1935
1938
  load: async () => fn(translator)
1936
1939
  }) : await fn(translator);
1937
- if (options.type === "command") cache2.clear();
1940
+ if (options.type === "command") await cache2.clear();
1938
1941
  const finalMessage = i18nKey ? translator.t(i18nKey) : message;
1939
1942
  return result.success({
1940
1943
  ...finalMessage ? { message: finalMessage } : {},
@@ -2815,6 +2818,8 @@ var fileUpdateValidator = (schemas) => schemas.z.object({
2815
2818
  })
2816
2819
  )
2817
2820
  });
2821
+
2822
+ // src/server/interfaces/actions/resources/file/commands/update/create-file-update-action.ts
2818
2823
  function createFileUpdateAction(ctx) {
2819
2824
  const {
2820
2825
  services: { storageService },
@@ -2869,43 +2874,6 @@ function createFileUpdateAction(ctx) {
2869
2874
  };
2870
2875
  }
2871
2876
 
2872
- // src/server/interfaces/actions/resources/file/commands/create-many/file-create-many-validator.ts
2873
- var fileCreateManyValidator = (schemas) => schemas.z.object({
2874
- uploadResults: schemas.array(
2875
- schemas.z.object({
2876
- // core
2877
- key: schemas.key(),
2878
- checksum: schemas.sha256Hash(),
2879
- // file meta
2880
- fileMeta: schemas.z.object({
2881
- type: schemas.text(),
2882
- size: schemas.positiveNumber(),
2883
- name: schemas.text()
2884
- }),
2885
- // media info
2886
- width: schemas.positiveNumber().nullable(),
2887
- height: schemas.positiveNumber().nullable(),
2888
- duration: schemas.positiveNumber().nullable(),
2889
- // ----------------------------------------------------------------------------
2890
- // translation
2891
- // ----------------------------------------------------------------------------
2892
- translations: schemas.array(
2893
- schemas.z.object({
2894
- // core
2895
- locale: schemas.locale(),
2896
- // text
2897
- name: schemas.text().nullable(),
2898
- alt: schemas.text().nullable()
2899
- })
2900
- )
2901
- })
2902
- ),
2903
- // ----------------------------------------------------------------------------
2904
- // relations
2905
- // ----------------------------------------------------------------------------
2906
- folder: schemas.z.object({ id: schemas.id().exist({ table: "folders", column: "id" }) }).nullable().optional()
2907
- });
2908
-
2909
2877
  // node_modules/yocto-queue/index.js
2910
2878
  var Node = class {
2911
2879
  value;
@@ -3046,6 +3014,43 @@ function validateConcurrency(concurrency) {
3046
3014
  }
3047
3015
  }
3048
3016
 
3017
+ // src/server/interfaces/actions/resources/file/commands/create-many/file-create-many-validator.ts
3018
+ var fileCreateManyValidator = (schemas) => schemas.z.object({
3019
+ uploadResults: schemas.array(
3020
+ schemas.z.object({
3021
+ // core
3022
+ key: schemas.key(),
3023
+ checksum: schemas.sha256Hash(),
3024
+ // file meta
3025
+ fileMeta: schemas.z.object({
3026
+ type: schemas.text(),
3027
+ size: schemas.positiveNumber(),
3028
+ name: schemas.text()
3029
+ }),
3030
+ // media info
3031
+ width: schemas.positiveNumber().nullable(),
3032
+ height: schemas.positiveNumber().nullable(),
3033
+ duration: schemas.positiveNumber().nullable(),
3034
+ // ----------------------------------------------------------------------------
3035
+ // translation
3036
+ // ----------------------------------------------------------------------------
3037
+ translations: schemas.array(
3038
+ schemas.z.object({
3039
+ // core
3040
+ locale: schemas.locale(),
3041
+ // text
3042
+ name: schemas.text().nullable(),
3043
+ alt: schemas.text().nullable()
3044
+ })
3045
+ )
3046
+ })
3047
+ ),
3048
+ // ----------------------------------------------------------------------------
3049
+ // relations
3050
+ // ----------------------------------------------------------------------------
3051
+ folder: schemas.z.object({ id: schemas.id().exist({ table: "folders", column: "id" }) }).nullable().optional()
3052
+ });
3053
+
3049
3054
  // src/server/interfaces/actions/resources/file/commands/create-many/create-file-create-many-action.ts
3050
3055
  function createFileCreateManyAction(ctx) {
3051
3056
  const {
@@ -3299,6 +3304,8 @@ var folderCreateValidator = (schemas) => schemas.z.object({
3299
3304
  // Folder
3300
3305
  parentFolder: schemas.z.object({ id: schemas.id().exist({ table: "folders", column: "id" }) }).nullable()
3301
3306
  });
3307
+
3308
+ // src/server/interfaces/actions/resources/folder/commands/create/create-folder-create-action.ts
3302
3309
  function createFolderCreateAction(ctx) {
3303
3310
  const {
3304
3311
  repositories: { folderCommandRepository },
@@ -3350,6 +3357,8 @@ var folderUpdateValidator = (schemas, id) => schemas.z.object({
3350
3357
  // Folder
3351
3358
  parentFolder: schemas.z.object({ id: schemas.id().exist({ table: "folders", column: "id" }) }).nullable()
3352
3359
  });
3360
+
3361
+ // src/server/interfaces/actions/resources/folder/commands/update/create-folder-update-action.ts
3353
3362
  function createFolderUpdateAction(ctx) {
3354
3363
  const {
3355
3364
  repositories: { folderCommandRepository },
@@ -4227,12 +4236,11 @@ function createAuthUseCases({
4227
4236
  token,
4228
4237
  admin
4229
4238
  }) {
4230
- let updatedAdmin = admin;
4231
4239
  jwtService.verify({
4232
4240
  token,
4233
4241
  secret: config.verifyEmailSecret
4234
4242
  });
4235
- updatedAdmin = await prisma.admin.update({
4243
+ const updatedAdmin = await prisma.admin.update({
4236
4244
  where: { email: admin.email },
4237
4245
  data: { emailVerifiedAt: /* @__PURE__ */ new Date() }
4238
4246
  });
@@ -4295,7 +4303,7 @@ function createForgotPasswordEmail({
4295
4303
  const passwordResetToken = authUseCases.signPasswordResetToken({ admin });
4296
4304
  const passwordResetUrl = `${webUrl}/cms/reset-password?passwordResetToken=${passwordResetToken}`;
4297
4305
  const html = await generateHtml({ passwordResetUrl });
4298
- return await sendEmail({
4306
+ return sendEmail({
4299
4307
  to: admin.email,
4300
4308
  subject: translator.t("email.forgot-password.text"),
4301
4309
  html
@@ -1,6 +1,6 @@
1
+ import { S as StorageService } from '../../types-J25u1G6t.js';
1
2
  import { S3Client } from '@aws-sdk/client-s3';
2
3
  import { Logger } from 'logry';
3
- import { S as StorageService } from '../../types-J25u1G6t.js';
4
4
  import '../../types-0oS1A2K5.js';
5
5
 
6
6
  interface CreateR2ServiceParams {
@@ -1,5 +1,5 @@
1
- import { createObjectKey } from '../../chunk-3BIU5JZA.js';
2
- import '../../chunk-HMJ53TVF.js';
1
+ import { createObjectKey } from '../../chunk-3J5YR2NA.js';
2
+ import '../../chunk-N2PRNBP2.js';
3
3
  import { PutObjectCommand, DeleteObjectCommand, CopyObjectCommand } from '@aws-sdk/client-s3';
4
4
 
5
5
  function createR2Service({
@@ -1,7 +1,7 @@
1
- import { Logger } from 'logry';
1
+ import { S as StorageService } from '../../types-J25u1G6t.js';
2
2
  import { Pool } from 'generic-pool';
3
+ import { Logger } from 'logry';
3
4
  import SFTPClient from 'ssh2-sftp-client';
4
- import { S as StorageService } from '../../types-J25u1G6t.js';
5
5
  import '../../types-0oS1A2K5.js';
6
6
 
7
7
  interface CreateSftpServiceParams {
@@ -1,5 +1,5 @@
1
- import { createObjectKey } from '../../chunk-3BIU5JZA.js';
2
- import '../../chunk-HMJ53TVF.js';
1
+ import { createObjectKey } from '../../chunk-3J5YR2NA.js';
2
+ import '../../chunk-N2PRNBP2.js';
3
3
  import path from 'path/posix';
4
4
  import { createPool } from 'generic-pool';
5
5
  import SFTPClient from 'ssh2-sftp-client';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yimingliao/cms",
3
- "version": "0.0.65",
3
+ "version": "0.0.66",
4
4
  "author": "Yiming Liao",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -37,6 +37,8 @@
37
37
  ],
38
38
  "scripts": {
39
39
  "type": "tsc --noEmit",
40
+ "lint": "eslint",
41
+ "knip": "knip --config .config/knip.config.ts",
40
42
  "build": "tsup",
41
43
  "prepublishOnly": "yarn build"
42
44
  },
@@ -52,17 +54,28 @@
52
54
  },
53
55
  "devDependencies": {
54
56
  "@aws-sdk/client-s3": "^3.1004.0",
57
+ "@eslint/js": "^10.0.1",
55
58
  "@prisma/client": "6.5.0",
56
59
  "@types/jsonwebtoken": "^9.0.10",
57
60
  "@types/mime-types": "^3.0.1",
58
61
  "@types/nodemailer": "^7.0.11",
59
62
  "@types/ssh2-sftp-client": "^9.0.6",
63
+ "eslint": "^9",
64
+ "eslint-import-resolver-typescript": "^4.4.4",
65
+ "eslint-plugin-import": "^2.32.0",
66
+ "eslint-plugin-prettier": "^5.5.5",
67
+ "eslint-plugin-react": "^7.37.5",
68
+ "eslint-plugin-react-hooks": "^7.0.1",
69
+ "eslint-plugin-unicorn": "^63.0.0",
70
+ "eslint-plugin-unused-imports": "^4.4.1",
60
71
  "generic-pool": "^3.9.0",
61
72
  "intor": "^2.5.0",
73
+ "knip": "^5.86.0",
62
74
  "next": "^16.1.6",
63
75
  "prisma": "6.5.0",
64
76
  "tsup": "^8.5.1",
65
77
  "typescript": "^5.9.3",
78
+ "typescript-eslint": "^8.56.1",
66
79
  "zod": "^4.3.6"
67
80
  },
68
81
  "peerDependencies": {
@@ -240,13 +240,6 @@ var buildAlternateMap = (alternates = []) => {
240
240
  }
241
241
  return result2;
242
242
  };
243
-
244
- // src/shared/seo-metadata/utils/ensure-og-type.ts
245
- var ensureOgType = (fallback, ogType) => {
246
- if (typeof ogType !== "string") return fallback;
247
- const isValid = OG_TYPE_ARRAY.includes(ogType);
248
- return isValid ? ogType : fallback;
249
- };
250
243
  var buildOgImages = (url, alt, type, width, height) => {
251
244
  if (!url) return void 0;
252
245
  const mimeType = lookup(url);
@@ -262,12 +255,11 @@ var buildOgImages = (url, alt, type, width, height) => {
262
255
  ];
263
256
  };
264
257
 
265
- // src/shared/seo-metadata/utils/sanitize-string-array.ts
266
- var sanitizeStringArray = (array) => {
267
- if (!Array.isArray(array)) return void 0;
268
- return array.filter(
269
- (a) => typeof a === "string" && a.trim() !== ""
270
- );
258
+ // src/shared/seo-metadata/utils/ensure-og-type.ts
259
+ var ensureOgType = (fallback, ogType) => {
260
+ if (typeof ogType !== "string") return fallback;
261
+ const isValid = OG_TYPE_ARRAY.includes(ogType);
262
+ return isValid ? ogType : fallback;
271
263
  };
272
264
 
273
265
  // src/shared/seo-metadata/utils/ensure-twitter-card.ts
@@ -277,6 +269,14 @@ var ensureTwitterCard = (fallback, twitterCard) => {
277
269
  return isValid ? twitterCard : fallback;
278
270
  };
279
271
 
272
+ // src/shared/seo-metadata/utils/sanitize-string-array.ts
273
+ var sanitizeStringArray = (array) => {
274
+ if (!Array.isArray(array)) return void 0;
275
+ return array.filter(
276
+ (a) => typeof a === "string" && a.trim() !== ""
277
+ );
278
+ };
279
+
280
280
  // src/shared/seo-metadata/build-website-metadata.ts
281
281
  function createBuildWebsiteMetadata({
282
282
  defaults