@yimingliao/cms 0.0.65 → 0.0.67

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
 
@@ -1,4 +1,3 @@
1
- import { R as Result } from '../types-DHlRoJwv.js';
2
1
  import { Logger } from 'logry';
3
2
 
4
3
  interface FetchContext {
@@ -11,13 +10,13 @@ interface FetchContext {
11
10
  };
12
11
  }
13
12
  type RequestInterceptor = (ctx: FetchContext) => Promise<FetchContext> | FetchContext;
14
- type ResponseInterceptor = <T>(response: Response, ctx: FetchContext) => Promise<Result<T>>;
13
+ type ResponseInterceptor = <T>(response: Response, ctx: FetchContext) => Promise<T>;
15
14
 
16
15
  declare function createSmartFetch({ requestInterceptor, responseInterceptor, logger, }: {
17
16
  requestInterceptor: RequestInterceptor;
18
17
  responseInterceptor: ResponseInterceptor;
19
18
  logger: Logger;
20
- }): <T>(input: string, init?: RequestInit) => Promise<Result<T>>;
19
+ }): <T>(input: string, init?: RequestInit) => Promise<T>;
21
20
 
22
21
  declare function createRequestInterceptor({ baseUrl }: {
23
22
  baseUrl: string;
package/dist/index.d.ts CHANGED
@@ -1,10 +1,8 @@
1
- import { F as FolderFull, a as Folder, b as FileFull, c as FileCard, P as PostFull, B as BaseTranslation } from './card-BG2vtuIz.js';
2
- export { A as ADMIN_ROLES, d as Admin, e as AdminCard, f as AdminFull, g as AdminRefreshToken, h as AdminRole, i as AdminSafe, j as AdminTranslation, k as Alternate, D as DeviceInfo, E as ExternalLink, l as FILE_TYPES, m as Faq, n as File, o as FileTranslation, p as FileType, M as MultiItems, q as POST_TYPES, r as Post, s as PostListCard, t as PostTranslation, u as PostType, S as SeoMetadata, v as SingleItem, T as TocItem, w as Translation } from './card-BG2vtuIz.js';
1
+ import { F as FolderFull, a as Folder, b as FileFull, c as FileCard, E as ErrorDetail, S as SuccessResult, d as ErrorResult, P as PostFull, B as BaseTranslation } from './types-BGsFazJr.js';
2
+ export { A as ADMIN_ROLES, e as Admin, f as AdminCard, g as AdminFull, h as AdminRefreshToken, i as AdminRole, j as AdminSafe, k as AdminTranslation, l as Alternate, D as DeviceInfo, m as ExternalLink, n as FILE_TYPES, o as Faq, p as File, q as FileTranslation, r as FileType, M as MultiItems, s as POST_TYPES, t as Post, u as PostListCard, v as PostTranslation, w as PostType, R as Result, x as SeoMetadata, y as SingleItem, T as TocItem, z as Translation } from './types-BGsFazJr.js';
3
3
  export { B as BlobFile } from './types-0oS1A2K5.js';
4
- import { E as ErrorDetail, S as SuccessResult, a as ErrorResult } from './types-DHlRoJwv.js';
5
- export { R as Result } from './types-DHlRoJwv.js';
6
- import { Metadata } from 'next';
7
4
  import { Robots } from 'next/dist/lib/metadata/types/metadata-types';
5
+ import { Metadata } from 'next';
8
6
 
9
7
  declare const isFolderLocked: (folder?: FolderFull | Folder) => boolean;
10
8
 
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,15 @@ 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
- 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
+ import { T as TocItem, i as AdminRole, y as SingleItem, B as BaseTranslation, e as Admin, g as AdminFull, j as AdminSafe, D as DeviceInfo, h as AdminRefreshToken, p as File$1, b as FileFull, r as FileType, a as Folder, F as FolderFull, w as PostType, M as MultiItems, m as ExternalLink, o as Faq, t as Post, u as PostListCard, v as PostTranslation, P as PostFull, l as Alternate, S as SuccessResult, R as Result, f as AdminCard, c as FileCard } from '../types-BGsFazJr.js';
11
12
  import * as nodemailer_lib_smtp_transport from 'nodemailer/lib/smtp-transport';
12
- import nodemailer, { Transporter } from 'nodemailer';
13
+ import nodemailer, { Transporter, SentMessageInfo } from 'nodemailer';
13
14
  import { BaseTranslator, LocaleMessages } from 'intor';
14
- import { S as SuccessResult, R as Result } from '../types-DHlRoJwv.js';
15
15
  import { NextResponse } from 'next/server';
16
16
  import { S as StorageService } from '../types-J25u1G6t.js';
17
17
 
@@ -109,6 +109,12 @@ declare function createIpRateLimiter({ appName, cache, headers, }: {
109
109
  headers: () => Promise<Headers>;
110
110
  }): ({ key: rawKey, maxAttempts, timeWindow, }: RateLimiterOptions) => Promise<boolean>;
111
111
 
112
+ type ExistOptions = {
113
+ table: string;
114
+ column?: string;
115
+ };
116
+ declare function createExist(prisma: PrismaClient): (value: string | number, options: ExistOptions) => Promise<boolean>;
117
+
112
118
  type Scope = {
113
119
  name: string;
114
120
  value: string;
@@ -120,13 +126,7 @@ type UniqueOptions = {
120
126
  scope?: Scope[];
121
127
  excludeSelf?: Scope;
122
128
  };
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>;
129
+ declare function createUnique(prisma: PrismaClient): (value: string, options: UniqueOptions) => Promise<boolean>;
130
130
 
131
131
  declare module "zod" {
132
132
  interface ZodString {
@@ -216,7 +216,7 @@ declare function createSendEmail({ transporter, config, }: {
216
216
  replyToName: string;
217
217
  replyToaddress: string;
218
218
  };
219
- }): (options: SendEmailOptions) => Promise<any>;
219
+ }): (options: SendEmailOptions) => Promise<SentMessageInfo>;
220
220
 
221
221
  declare function createRenderEmailTemplate({ siteName, webUrl, logoUrl, logger, }: {
222
222
  siteName: string;
@@ -263,7 +263,7 @@ interface UpdateParams$3 {
263
263
  emailVerifiedAt: Date | null;
264
264
  }
265
265
 
266
- declare function createAdminCommandRepository(prisma: any): {
266
+ declare function createAdminCommandRepository(prisma: PrismaClient): {
267
267
  create: ({ role, email, passwordHash, socialLinks, avatarImage, translations, }: CreateParams$4) => Promise<Admin>;
268
268
  update: ({ id, role, email, socialLinks, avatarImage, translations, emailVerifiedAt, }: UpdateParams$3) => Promise<Admin>;
269
269
  delete: ({ id }: {
@@ -284,7 +284,7 @@ interface FindParams$2 {
284
284
  email?: string;
285
285
  }
286
286
 
287
- declare function createAdminQueryRepository(prisma: any): {
287
+ declare function createAdminQueryRepository(prisma: PrismaClient): {
288
288
  findListCards: ({ locale, searchString, role, adminIds, page, pageSize, }: FindListCardsParams$3) => Promise<{
289
289
  items: AdminFull[];
290
290
  total: number;
@@ -307,13 +307,13 @@ interface DeleteParams {
307
307
  tokenHash?: string;
308
308
  }
309
309
 
310
- declare function createAdminRefreshTokenCommandRepository(prisma: any): {
310
+ declare function createAdminRefreshTokenCommandRepository(prisma: PrismaClient): {
311
311
  create: ({ adminId, ...params }: CreateParams$3) => Promise<AdminRefreshToken>;
312
312
  delete: ({ id, tokenHash }: DeleteParams) => Promise<void>;
313
313
  deleteManyByExpired: () => Promise<number>;
314
314
  };
315
315
 
316
- declare function createAdminRefreshTokenQueryRepository(prisma: any): {
316
+ declare function createAdminRefreshTokenQueryRepository(prisma: PrismaClient): {
317
317
  findManyByAdminId: ({ adminId, }: {
318
318
  adminId: string;
319
319
  }) => Promise<AdminRefreshToken[]>;
@@ -359,7 +359,7 @@ interface UpdateParams$2 {
359
359
  })[];
360
360
  }
361
361
 
362
- declare function createFileCommandRepository(prisma: any): {
362
+ declare function createFileCommandRepository(prisma: PrismaClient): {
363
363
  create: ({ key, checksum, fileMeta, width, height, duration, folder, translations, }: CreateParams$2) => Promise<FileFull>;
364
364
  update: ({ file, id, key, checksum, fileMeta, width, height, duration, folder, translations, }: UpdateParams$2) => Promise<File$1>;
365
365
  softDelete: ({ id }: {
@@ -388,7 +388,7 @@ interface FindListCardsParams$2 {
388
388
  pageSize?: number;
389
389
  }
390
390
 
391
- declare function createFileQueryRepository(prisma: any): {
391
+ declare function createFileQueryRepository(prisma: PrismaClient): {
392
392
  findListCards: ({ locale, page, pageSize, searchString, type, folderId, isLocked, isDeleted, fileIds, }: FindListCardsParams$2) => Promise<{
393
393
  items: FileFull[];
394
394
  total: number;
@@ -413,7 +413,7 @@ interface UpdateParams$1 {
413
413
  parentFolder: Folder | null;
414
414
  }
415
415
 
416
- declare function createFolderCommandRepository(prisma: any): {
416
+ declare function createFolderCommandRepository(prisma: PrismaClient): {
417
417
  create: ({ key, name, parentFolder, }: CreateParams$1) => Promise<Folder>;
418
418
  update: ({ id, key, name, parentFolder, }: UpdateParams$1) => Promise<Folder>;
419
419
  delete: ({ id }: {
@@ -433,7 +433,7 @@ interface FindParams$1 {
433
433
  key?: string;
434
434
  }
435
435
 
436
- declare function createFolderQueryRepository(prisma: any): {
436
+ declare function createFolderQueryRepository(prisma: PrismaClient): {
437
437
  findListCards: ({ searchString, parentFolderId, folderIds, page, pageSize, }: FindListCardsParams$1) => Promise<{
438
438
  items: FolderFull[];
439
439
  total: number;
@@ -591,7 +591,7 @@ interface UpdateParams {
591
591
  })[];
592
592
  }
593
593
 
594
- declare function createPostCommandRepository(prisma: any): {
594
+ declare function createPostCommandRepository(prisma: PrismaClient): {
595
595
  create: ({ slug, author, topicId, parents, tags, relatedPosts, coverImage, contentImageIds, images1, images2, image1, image2, image3, image4, translations, ...params }: CreateParams) => Promise<Post>;
596
596
  update: ({ id, slug, author, topicId, parents, tags, relatedPosts, coverImage, contentImageIds, images1, images2, image1, image2, image3, image4, translations, ...params }: UpdateParams) => Promise<Post>;
597
597
  delete: ({ id }: {
@@ -639,7 +639,7 @@ interface FindManyParams {
639
639
  topicId?: string;
640
640
  }
641
641
 
642
- declare function createPostQueryRepository(prisma: any): {
642
+ declare function createPostQueryRepository(prisma: PrismaClient): {
643
643
  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
644
  items: PostListCard[];
645
645
  total: number;
@@ -686,7 +686,7 @@ interface UpsertParams {
686
686
  })[];
687
687
  }
688
688
 
689
- declare function createSeoMetadataCommandRepository(prisma: any): {
689
+ declare function createSeoMetadataCommandRepository(prisma: PrismaClient): {
690
690
  upsert: ({ postId, translations, }: UpsertParams) => Promise<void>;
691
691
  };
692
692
 
@@ -739,8 +739,36 @@ interface CreateExecuteApiParams {
739
739
  }
740
740
  declare function createExecuteApi({ initI18n, logger }: CreateExecuteApiParams): (fn: Api) => Promise<NextResponse<unknown>>;
741
741
 
742
+ interface CreateVerifyAccessTokenParams {
743
+ adminQueryRepository: ReturnType<typeof createAdminQueryRepository>;
744
+ jwtService: ReturnType<typeof createJwtService>;
745
+ cryptoService: ReturnType<typeof createCryptoService>;
746
+ cookieService: ReturnType<typeof createCookieService>;
747
+ config: {
748
+ accessTokenName: string;
749
+ accessTokenSecret: string;
750
+ };
751
+ }
752
+ declare function createVerifyAccessToken({ adminQueryRepository, jwtService, cryptoService, cookieService, config, }: CreateVerifyAccessTokenParams): () => Promise<{
753
+ admin: AdminFull;
754
+ } | null>;
755
+
756
+ interface CreateVerifyRefreshTokenParams {
757
+ adminQueryRepository: ReturnType<typeof createAdminQueryRepository>;
758
+ adminRefreshTokenQueryRepository: ReturnType<typeof createAdminRefreshTokenQueryRepository>;
759
+ cryptoService: ReturnType<typeof createCryptoService>;
760
+ cookieService: ReturnType<typeof createCookieService>;
761
+ config: {
762
+ refreshTokenName: string;
763
+ };
764
+ }
765
+ declare function createVerifyRefreshToken({ adminQueryRepository, adminRefreshTokenQueryRepository, cryptoService, cookieService, config, }: CreateVerifyRefreshTokenParams): () => Promise<{
766
+ adminRefreshToken: AdminRefreshToken;
767
+ admin: AdminFull;
768
+ } | null>;
769
+
742
770
  interface CreateAuthUseCases {
743
- prisma: any;
771
+ prisma: PrismaClient;
744
772
  adminQueryRepository: ReturnType<typeof createAdminQueryRepository>;
745
773
  adminRefreshTokenCommandRepository: ReturnType<typeof createAdminRefreshTokenCommandRepository>;
746
774
  jwtService: ReturnType<typeof createJwtService>;
@@ -832,34 +860,6 @@ declare function createForgotPasswordEmail({ renderEmailTemplate, sendEmail, aut
832
860
  send: ({ translator, admin }: SendParams) => Promise<any>;
833
861
  };
834
862
 
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
863
  interface CreateAuthMiddlewareParams {
864
864
  adminRefreshTokenCommandRepository: ReturnType<typeof createAdminRefreshTokenCommandRepository>;
865
865
  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';
@@ -338,4 +338,23 @@ type AdminCard = AdminSafe & {
338
338
  translations: AdminTranslation[];
339
339
  };
340
340
 
341
- export { ADMIN_ROLES as A, type BaseTranslation as B, type DeviceInfo as D, type ExternalLink as E, type FolderFull as F, type MultiItems as M, type PostFull as P, type SeoMetadata as S, type TocItem as T, type Folder as a, type FileFull as b, type FileCard as c, type Admin as d, type AdminCard as e, type AdminFull as f, type AdminRefreshToken as g, type AdminRole as h, type AdminSafe as i, type AdminTranslation as j, type Alternate as k, FILE_TYPES as l, type Faq as m, type File as n, type FileTranslation as o, type FileType as p, POST_TYPES as q, type Post as r, type PostListCard as s, type PostTranslation as t, type PostType as u, type SingleItem as v, type Translation as w };
341
+ interface SuccessResult<D = unknown> {
342
+ success: true;
343
+ message?: string;
344
+ data?: D;
345
+ meta?: Record<string, unknown>;
346
+ }
347
+ interface ErrorResult {
348
+ success: false;
349
+ message?: string;
350
+ errors?: ErrorDetail[];
351
+ code?: string;
352
+ }
353
+ interface ErrorDetail {
354
+ field?: string;
355
+ message?: string;
356
+ code?: string;
357
+ }
358
+ type Result<D = unknown> = SuccessResult<D> | ErrorResult;
359
+
360
+ export { ADMIN_ROLES as A, type BaseTranslation as B, type DeviceInfo as D, type ErrorDetail as E, type FolderFull as F, type MultiItems as M, type PostFull as P, type Result as R, type SuccessResult as S, type TocItem as T, type Folder as a, type FileFull as b, type FileCard as c, type ErrorResult as d, type Admin as e, type AdminCard as f, type AdminFull as g, type AdminRefreshToken as h, type AdminRole as i, type AdminSafe as j, type AdminTranslation as k, type Alternate as l, type ExternalLink as m, FILE_TYPES as n, type Faq as o, type File as p, type FileTranslation as q, type FileType as r, POST_TYPES as s, type Post as t, type PostListCard as u, type PostTranslation as v, type PostType as w, type SeoMetadata as x, type SingleItem as y, type Translation as z };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yimingliao/cms",
3
- "version": "0.0.65",
3
+ "version": "0.0.67",
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": {
@@ -1,20 +0,0 @@
1
- interface SuccessResult<D = unknown> {
2
- success: true;
3
- message?: string;
4
- data?: D;
5
- meta?: Record<string, unknown>;
6
- }
7
- interface ErrorResult {
8
- success: false;
9
- message?: string;
10
- errors?: ErrorDetail[];
11
- code?: string;
12
- }
13
- interface ErrorDetail {
14
- field?: string;
15
- message?: string;
16
- code?: string;
17
- }
18
- type Result<D = unknown> = SuccessResult<D> | ErrorResult;
19
-
20
- export type { ErrorDetail as E, Result as R, SuccessResult as S, ErrorResult as a };
@@ -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