@yimingliao/cms 0.0.29 → 0.0.30

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.
@@ -153,7 +153,7 @@ interface TocItem {
153
153
  text: string;
154
154
  id: string;
155
155
  level: 2 | 3 | 4 | 5 | 6;
156
- children?: TocItem[];
156
+ children: TocItem[];
157
157
  }
158
158
 
159
159
  interface Post {
@@ -1,4 +1,4 @@
1
- import { mimeToExtension } from './chunk-YX7IPIGU.js';
1
+ import { mimeToExtension } from './chunk-I2DBI3WJ.js';
2
2
  import path from 'path/posix';
3
3
  import { ulid } from 'ulid';
4
4
 
@@ -185,4 +185,24 @@ var result = {
185
185
  error
186
186
  };
187
187
 
188
- export { FILE_TYPES, classifyFileType, formatFileSize, getMediaInfo, mimeToExtension, result };
188
+ // src/shared/units.ts
189
+ var SIZE = {
190
+ BYTE: 1,
191
+ KB: 1024,
192
+ MB: 1024 ** 2,
193
+ GB: 1024 ** 3,
194
+ TB: 1024 ** 4,
195
+ PB: 1024 ** 5
196
+ };
197
+ var TIME = {
198
+ MILLISECOND: 1,
199
+ SECOND: 1e3,
200
+ MINUTE: 60 * 1e3,
201
+ HOUR: 60 * 60 * 1e3,
202
+ DAY: 24 * 60 * 60 * 1e3,
203
+ WEEK: 7 * 24 * 60 * 60 * 1e3,
204
+ MONTH: 30 * 24 * 60 * 60 * 1e3,
205
+ YEAR: 365 * 24 * 60 * 60 * 1e3
206
+ };
207
+
208
+ export { FILE_TYPES, SIZE, TIME, classifyFileType, formatFileSize, getMediaInfo, mimeToExtension, result };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { F as FolderFull } from './base-DbGnfZr6.js';
2
- export { A as ADMIN_ROLES, a as Admin, b as AdminCard, c as AdminFull, d as AdminRefreshToken, e as AdminRole, f as AdminSafe, g as AdminTranslation, h as Alternate, B as BaseTranslation, D as DeviceInfo, E as ExternalLink, i as FILE_TYPES, j as Faq, k as File, l as FileCard, m as FileFull, n as FileTranslation, o as FileType, p as Folder, M as MultiItems, P as POST_TYPES, q as Post, r as PostFull, s as PostListCard, t as PostTranslation, u as PostType, S as SeoMetadata, v as SingleItem, T as TocItem, w as Translation } from './base-DbGnfZr6.js';
1
+ import { F as FolderFull } from './base-BUAGZ2YH.js';
2
+ export { A as ADMIN_ROLES, a as Admin, b as AdminCard, c as AdminFull, d as AdminRefreshToken, e as AdminRole, f as AdminSafe, g as AdminTranslation, h as Alternate, B as BaseTranslation, D as DeviceInfo, E as ExternalLink, i as FILE_TYPES, j as Faq, k as File, l as FileCard, m as FileFull, n as FileTranslation, o as FileType, p as Folder, M as MultiItems, P as POST_TYPES, q as Post, r as PostFull, s as PostListCard, t as PostTranslation, u as PostType, S as SeoMetadata, v as SingleItem, T as TocItem, w as Translation } from './base-BUAGZ2YH.js';
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';
@@ -44,4 +44,25 @@ declare const result: {
44
44
  error: typeof error;
45
45
  };
46
46
 
47
- export { ErrorDetail, ErrorResult, type ErrorResultParams, FolderFull, ROOT_FOLDER, ROOT_FOLDER_ID, ROOT_FOLDER_NAME, SIMPLE_UPLOAD_FOLDER_KEY, SIMPLE_UPLOAD_FOLDER_NAME, SuccessResult, type SuccessResultParams, classifyFileType, formatFileSize, getMediaInfo, mimeToExtension, result };
47
+ declare const SIZE: {
48
+ readonly BYTE: 1;
49
+ readonly KB: 1024;
50
+ readonly MB: number;
51
+ readonly GB: number;
52
+ readonly TB: number;
53
+ readonly PB: number;
54
+ };
55
+ type SizeUnit = keyof typeof SIZE;
56
+ declare const TIME: {
57
+ readonly MILLISECOND: 1;
58
+ readonly SECOND: 1000;
59
+ readonly MINUTE: number;
60
+ readonly HOUR: number;
61
+ readonly DAY: number;
62
+ readonly WEEK: number;
63
+ readonly MONTH: number;
64
+ readonly YEAR: number;
65
+ };
66
+ type TimeUnit = keyof typeof TIME;
67
+
68
+ export { ErrorDetail, ErrorResult, type ErrorResultParams, FolderFull, ROOT_FOLDER, ROOT_FOLDER_ID, ROOT_FOLDER_NAME, SIMPLE_UPLOAD_FOLDER_KEY, SIMPLE_UPLOAD_FOLDER_NAME, SIZE, type SizeUnit, SuccessResult, type SuccessResultParams, TIME, type TimeUnit, classifyFileType, formatFileSize, getMediaInfo, mimeToExtension, result };
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 } from './chunk-ZCOYQ5BG.js';
2
- export { FILE_TYPES, classifyFileType, formatFileSize, getMediaInfo, mimeToExtension, result } from './chunk-YX7IPIGU.js';
2
+ export { FILE_TYPES, SIZE, TIME, classifyFileType, formatFileSize, getMediaInfo, mimeToExtension, result } from './chunk-I2DBI3WJ.js';
@@ -3,17 +3,21 @@ 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 { e as AdminRole, v as SingleItem, B as BaseTranslation, a as Admin, c as AdminFull, f as AdminSafe, D as DeviceInfo, d as AdminRefreshToken, k as File, m as FileFull, o as FileType, p as Folder, F as FolderFull, u as PostType, M as MultiItems, E as ExternalLink, j as Faq, T as TocItem, q as Post, s as PostListCard, t as PostTranslation, r as PostFull, S as SeoMetadata, g as AdminTranslation, n as FileTranslation, h as Alternate } from '../base-DbGnfZr6.js';
6
+ import * as zod from 'zod';
7
+ import zod__default, { z, ZodType } from 'zod';
8
+ import { B as BlobFile } from '../types-0oS1A2K5.js';
9
+ import * as zod_v4_core from 'zod/v4/core';
10
+ import { T as TocItem, e as AdminRole, v as SingleItem, B as BaseTranslation, a as Admin, c as AdminFull, f as AdminSafe, D as DeviceInfo, d as AdminRefreshToken, k as File$1, m as FileFull, o as FileType, p as Folder, F as FolderFull, u as PostType, M as MultiItems, E as ExternalLink, j as Faq, q as Post, s as PostListCard, t as PostTranslation, r as PostFull, S as SeoMetadata, g as AdminTranslation, n as FileTranslation, h as Alternate } from '../base-BUAGZ2YH.js';
7
11
  import { BaseTranslator, LocaleMessages } from 'intor';
8
12
  import { S as SuccessResult, R as Result } from '../types-DHlRoJwv.js';
9
13
  import { NextResponse } from 'next/server';
10
14
 
11
- interface CreateJwtServiceOptions {
15
+ interface CreateJwtServiceParams {
12
16
  defaultSecret: string;
13
17
  issuer?: string;
14
18
  audience?: string;
15
19
  }
16
- declare function createJwtService({ defaultSecret, ...options }: CreateJwtServiceOptions): {
20
+ declare function createJwtService({ defaultSecret, ...options }: CreateJwtServiceParams): {
17
21
  sign: ({ payload, secret, expiresIn, }: {
18
22
  payload: object;
19
23
  secret: string;
@@ -30,10 +34,10 @@ declare function createArgon2Service(): {
30
34
  verify: (digest: string, password: string) => Promise<boolean>;
31
35
  };
32
36
 
33
- interface CreateCryptoServiceOptions {
37
+ interface CreateCryptoServiceParams {
34
38
  defaultSecret: string;
35
39
  }
36
- declare function createCryptoService({ defaultSecret, }: CreateCryptoServiceOptions): {
40
+ declare function createCryptoService({ defaultSecret, }: CreateCryptoServiceParams): {
37
41
  generateToken: () => string;
38
42
  hash: (value: BinaryLike) => string;
39
43
  hashBuffer: (value: BinaryLike) => Buffer;
@@ -74,12 +78,12 @@ declare function createCookieService(nextCookies: () => Promise<Awaited<ReturnTy
74
78
  }) => Promise<void>;
75
79
  };
76
80
 
77
- interface CreateServerCacheOptions {
81
+ interface CreateServerCacheParams {
78
82
  redisUrl: string;
79
83
  namespace: string;
80
84
  keyDelimiter?: string;
81
85
  }
82
- declare function createCache({ redisUrl, namespace, keyDelimiter, }: CreateServerCacheOptions): Keyv<unknown>;
86
+ declare function createCache({ redisUrl, namespace, keyDelimiter, }: CreateServerCacheParams): Keyv<unknown>;
83
87
 
84
88
  type RawCacheKey = string | Array<string | number | boolean | undefined | null>;
85
89
  declare const normalizeCacheKey: (key?: RawCacheKey, delimiter?: string) => string | null;
@@ -98,6 +102,92 @@ interface RateLimiterOptions {
98
102
  }
99
103
  declare function createIpRateLimiter(cache: Keyv<unknown>, appName: string): ({ key: rawKey, maxAttempts, timeWindow, }: RateLimiterOptions) => Promise<boolean>;
100
104
 
105
+ type Scope = {
106
+ name: string;
107
+ value: string;
108
+ cast?: string;
109
+ };
110
+ type UniqueOptions = {
111
+ table: string;
112
+ column: string;
113
+ scope?: Scope[];
114
+ excludeSelf?: Scope;
115
+ };
116
+ declare function createUnique(prisma: any): (value: string, options: UniqueOptions) => Promise<boolean>;
117
+
118
+ type ExistOptions = {
119
+ table: string;
120
+ column?: string;
121
+ };
122
+ declare function createExist(prisma: any): (value: string | number, options: ExistOptions) => Promise<boolean>;
123
+
124
+ declare module "zod" {
125
+ interface ZodString {
126
+ unique(options: UniqueOptions): this;
127
+ exist(options: ExistOptions): this;
128
+ bcp47(): this;
129
+ ogLocale(): this;
130
+ }
131
+ interface ZodEmail {
132
+ unique(options: UniqueOptions): this;
133
+ }
134
+ }
135
+ declare function createZod({ unique, exist, }: {
136
+ unique: ReturnType<typeof createUnique>;
137
+ exist: ReturnType<typeof createExist>;
138
+ }): typeof z;
139
+
140
+ declare function createSchemas({ z, localeArray, exist, }: {
141
+ z: ReturnType<typeof createZod>;
142
+ localeArray: string[];
143
+ exist: ReturnType<typeof createExist>;
144
+ }): {
145
+ text: () => zod__default.ZodString;
146
+ positiveNumber: () => zod__default.ZodPipe<zod__default.ZodTransform<number | undefined, unknown>, zod__default.ZodNumber>;
147
+ url: () => zod__default.ZodPipe<zod__default.ZodTransform<{} | null | undefined, unknown>, zod__default.ZodNullable<zod__default.ZodURL>>;
148
+ email: () => zod__default.ZodEmail;
149
+ password: () => zod__default.ZodString;
150
+ isoString: () => zod__default.ZodString;
151
+ array: <T extends ZodType>(schema: T) => zod__default.ZodPipe<zod__default.ZodArray<T>, zod__default.ZodTransform<NonNullable<zod__default.core.output<T>>[], zod__default.core.output<T>[]>>;
152
+ id: () => zod__default.ZodString;
153
+ key: () => zod__default.ZodString;
154
+ sha256Hash: () => zod__default.ZodString;
155
+ slug: () => zod__default.ZodString;
156
+ pathSegment: () => zod__default.ZodString;
157
+ locale: () => zod__default.ZodString;
158
+ singleItem: (options: ExistOptions) => zod__default.ZodNullable<zod__default.ZodObject<{
159
+ id: zod__default.ZodString;
160
+ }, zod__default.core.$strip>>;
161
+ multiItems: (options: ExistOptions) => zod__default.ZodPipe<zod__default.ZodArray<zod__default.ZodObject<{
162
+ id: zod__default.ZodString;
163
+ }, zod__default.core.$strip>>, zod__default.ZodTransform<{
164
+ id: string;
165
+ }[], {
166
+ id: string;
167
+ }[]>>;
168
+ };
169
+
170
+ declare function createFileSchema({ z, maxSizeInMb, }: {
171
+ z: ReturnType<typeof createZod>;
172
+ maxSizeInMb: number;
173
+ }): ({ size, extensions, }: {
174
+ size?: number;
175
+ extensions?: string[];
176
+ }) => zod.ZodPipe<zod.ZodCustom<File, File>, zod.ZodTransform<BlobFile, File>>;
177
+ declare function createMultiFileSchema({ z, fileSchema, maxSizeInMb, }: {
178
+ z: ReturnType<typeof createZod>;
179
+ fileSchema: ReturnType<typeof createFileSchema>;
180
+ maxSizeInMb: number;
181
+ }): ({ size, extensions, }?: {
182
+ size?: number;
183
+ extensions?: string[];
184
+ }) => void;
185
+
186
+ declare function createTocItemSchema({ z, schemas, }: {
187
+ z: ReturnType<typeof createZod>;
188
+ schemas: ReturnType<typeof createSchemas>;
189
+ }): ZodType<TocItem, unknown, zod_v4_core.$ZodTypeInternals<TocItem, unknown>>;
190
+
101
191
  interface CreateParams$4 {
102
192
  email: string;
103
193
  role: AdminRole;
@@ -214,7 +304,7 @@ interface CreateParams$2 {
214
304
  }
215
305
  interface UpdateParams$2 {
216
306
  id: string;
217
- file: File;
307
+ file: File$1;
218
308
  key: string;
219
309
  checksum: string;
220
310
  fileMeta: {
@@ -234,10 +324,10 @@ interface UpdateParams$2 {
234
324
 
235
325
  declare function createFileCommandRepository(prisma: any): {
236
326
  create: ({ fileMeta, folder, translations, ...params }: CreateParams$2) => Promise<FileFull>;
237
- update: ({ file, id, fileMeta, folder, translations, ...params }: UpdateParams$2) => Promise<File>;
327
+ update: ({ file, id, fileMeta, folder, translations, ...params }: UpdateParams$2) => Promise<File$1>;
238
328
  softDelete: ({ id }: {
239
329
  id: string;
240
- }) => Promise<File>;
330
+ }) => Promise<File$1>;
241
331
  softDeleteMany: ({ ids }: {
242
332
  ids: string[];
243
333
  }) => Promise<number>;
@@ -246,7 +336,7 @@ declare function createFileCommandRepository(prisma: any): {
246
336
  }) => Promise<number>;
247
337
  delete: ({ id }: {
248
338
  id: string;
249
- }) => Promise<File>;
339
+ }) => Promise<File$1>;
250
340
  };
251
341
 
252
342
  interface FindListCardsParams$2 {
@@ -530,7 +620,7 @@ declare function createPostQueryRepository(prisma: any): {
530
620
  author: AdminSafe & {
531
621
  translations: AdminTranslation[];
532
622
  };
533
- coverImage: File & {
623
+ coverImage: File$1 & {
534
624
  translations: FileTranslation[];
535
625
  };
536
626
  }) | null>;
@@ -602,25 +692,25 @@ declare const POST_ORDER_BY: ({
602
692
  type Action<D> = (translator: BaseTranslator<LocaleMessages>) => Promise<Omit<SuccessResult<D>, "success"> & {
603
693
  i18nKey?: string;
604
694
  }>;
605
- interface CreateExecuteActionOptions {
695
+ interface CreateExecuteActionParams {
606
696
  initI18n: () => Promise<BaseTranslator<LocaleMessages>>;
607
697
  cacheResult: <T>({ key, ttl, load }: CacheResultOptions<T>) => Promise<T>;
608
698
  cache: Keyv<unknown>;
609
699
  logger: Logger;
610
700
  }
611
- interface ServerActionOptions {
701
+ interface ServerActionParams {
612
702
  type?: "command" | "query";
613
703
  key?: RawCacheKey;
614
704
  ttl?: number;
615
705
  }
616
- declare function createExecuteAction({ initI18n, cacheResult, cache, logger, }: CreateExecuteActionOptions): <D = void>(fn: Action<D>, options?: ServerActionOptions) => Promise<Result<D>>;
706
+ declare function createExecuteAction({ initI18n, cacheResult, cache, logger, }: CreateExecuteActionParams): <D = void>(fn: Action<D>, options?: ServerActionParams) => Promise<Result<D>>;
617
707
 
618
708
  type Api = (translator: BaseTranslator<LocaleMessages>) => Promise<NextResponse<unknown>>;
619
- interface CreateExecuteApiOptions {
709
+ interface CreateExecuteApiParams {
620
710
  initI18n: () => Promise<BaseTranslator<LocaleMessages>>;
621
711
  logger: Logger;
622
712
  }
623
- declare function createExecuteApi({ initI18n, logger, }: CreateExecuteApiOptions): (fn: Api) => Promise<NextResponse<unknown>>;
713
+ declare function createExecuteApi({ initI18n, logger }: CreateExecuteApiParams): (fn: Api) => Promise<NextResponse<unknown>>;
624
714
 
625
715
  interface CreateAuthUseCases {
626
716
  prisma: any;
@@ -682,7 +772,7 @@ declare function createAuthUseCases({ prisma, adminQueryRepository, adminRefresh
682
772
  }) => Promise<AdminSafe>;
683
773
  };
684
774
 
685
- interface CreateVerifyAccessTokenOptions {
775
+ interface CreateVerifyAccessTokenParams {
686
776
  adminQueryRepository: ReturnType<typeof createAdminQueryRepository>;
687
777
  jwtService: ReturnType<typeof createJwtService>;
688
778
  cryptoService: ReturnType<typeof createCryptoService>;
@@ -692,11 +782,11 @@ interface CreateVerifyAccessTokenOptions {
692
782
  accessTokenSecret: string;
693
783
  };
694
784
  }
695
- declare function createVerifyAccessToken({ adminQueryRepository, jwtService, cryptoService, cookieService, config, }: CreateVerifyAccessTokenOptions): () => Promise<{
785
+ declare function createVerifyAccessToken({ adminQueryRepository, jwtService, cryptoService, cookieService, config, }: CreateVerifyAccessTokenParams): () => Promise<{
696
786
  admin: AdminFull;
697
787
  } | null>;
698
788
 
699
- interface CreateVerifyRefreshTokenOptions {
789
+ interface CreateVerifyRefreshTokenParams {
700
790
  adminQueryRepository: ReturnType<typeof createAdminQueryRepository>;
701
791
  adminRefreshTokenQueryRepository: ReturnType<typeof createAdminRefreshTokenQueryRepository>;
702
792
  cryptoService: ReturnType<typeof createCryptoService>;
@@ -705,19 +795,19 @@ interface CreateVerifyRefreshTokenOptions {
705
795
  refreshTokenName: string;
706
796
  };
707
797
  }
708
- declare function createVerifyRefreshToken({ adminQueryRepository, adminRefreshTokenQueryRepository, cryptoService, cookieService, config, }: CreateVerifyRefreshTokenOptions): () => Promise<{
798
+ declare function createVerifyRefreshToken({ adminQueryRepository, adminRefreshTokenQueryRepository, cryptoService, cookieService, config, }: CreateVerifyRefreshTokenParams): () => Promise<{
709
799
  adminRefreshToken: AdminRefreshToken;
710
800
  admin: AdminFull;
711
801
  } | null>;
712
802
 
713
- interface CreateAuthMiddlewareOptions {
803
+ interface CreateAuthMiddlewareParams {
714
804
  adminRefreshTokenCommandRepository: ReturnType<typeof createAdminRefreshTokenCommandRepository>;
715
805
  authUseCases: ReturnType<typeof createAuthUseCases>;
716
806
  verifyAccessToken: ReturnType<typeof createVerifyAccessToken>;
717
807
  verifyRefreshToken: ReturnType<typeof createVerifyRefreshToken>;
718
808
  headers: () => Promise<Headers>;
719
809
  }
720
- declare function createAuthMiddleware({ adminRefreshTokenCommandRepository, authUseCases, verifyAccessToken, verifyRefreshToken, headers, }: CreateAuthMiddlewareOptions): {
810
+ declare function createAuthMiddleware({ adminRefreshTokenCommandRepository, authUseCases, verifyAccessToken, verifyRefreshToken, headers, }: CreateAuthMiddlewareParams): {
721
811
  authenticate(): Promise<AdminFull>;
722
812
  };
723
813
 
@@ -739,4 +829,4 @@ declare class ServerError extends Error {
739
829
  static internalServerError(): ServerError;
740
830
  }
741
831
 
742
- export { ADMIN_ORDER_BY, ORDER_BY, POST_ORDER_BY, type RawCacheKey, ServerError, createAdminCommandRepository, createAdminQueryRepository, createAdminRefreshTokenCommandRepository, createAdminRefreshTokenQueryRepository, createArgon2Service, createAuthMiddleware, createAuthUseCases, createCache, createCacheResult, createCookieService, createCryptoService, createExecuteAction, createExecuteApi, createFileCommandRepository, createFileQueryRepository, createFolderCommandRepository, createFolderQueryRepository, createIpRateLimiter, createJwtService, createPostCommandRepository, createPostQueryRepository, createSeoMetadataCommandRepository, createVerifyAccessToken, createVerifyRefreshToken, normalizeCacheKey };
832
+ export { ADMIN_ORDER_BY, ORDER_BY, POST_ORDER_BY, type RawCacheKey, ServerError, createAdminCommandRepository, createAdminQueryRepository, createAdminRefreshTokenCommandRepository, createAdminRefreshTokenQueryRepository, createArgon2Service, createAuthMiddleware, createAuthUseCases, createCache, createCacheResult, createCookieService, createCryptoService, createExecuteAction, createExecuteApi, createFileCommandRepository, createFileQueryRepository, createFileSchema, createFolderCommandRepository, createFolderQueryRepository, createIpRateLimiter, createJwtService, createMultiFileSchema, createPostCommandRepository, createPostQueryRepository, createSchemas, createSeoMetadataCommandRepository, createTocItemSchema, createVerifyAccessToken, createVerifyRefreshToken, createZod, normalizeCacheKey };
@@ -1,13 +1,13 @@
1
1
  import { ADMIN_ROLES, ROOT_FOLDER_ID } from '../chunk-ZCOYQ5BG.js';
2
- import { result, mimeToExtension, classifyFileType } from '../chunk-YX7IPIGU.js';
2
+ import { SIZE, result, mimeToExtension, classifyFileType } from '../chunk-I2DBI3WJ.js';
3
3
  import jwt from 'jsonwebtoken';
4
4
  import argon2 from 'argon2';
5
5
  import crypto, { timingSafeEqual } from 'crypto';
6
6
  import { headers } from 'next/headers';
7
7
  import KeyvRedis from '@keyv/redis';
8
8
  import Keyv from 'keyv';
9
+ import { z, ZodError } from 'zod';
9
10
  import { ulid } from 'ulid';
10
- import { ZodError } from 'zod';
11
11
  import { NextResponse } from 'next/server';
12
12
 
13
13
  function createJwtService({
@@ -310,6 +310,241 @@ function createIpRateLimiter(cache, appName) {
310
310
  };
311
311
  }
312
312
 
313
+ // src/server/infrastructure/zod/rules/bcp47.ts
314
+ function bcp47(locale) {
315
+ if (typeof locale !== "string") return false;
316
+ const BCP47_REGEX = new RegExp(
317
+ "^[a-zA-Z]{2,3}(?:-[A-Z][a-z]{3})?" + // optional region
318
+ String.raw`(?:-(?:[A-Z]{2}|\d{3}))?` + // optional variants
319
+ String.raw`(?:-(?:[a-zA-Z0-9]{5,8}|\d[a-zA-Z0-9]{3}))*` + // optional extensions
320
+ "(?:-(?:[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})+)?$"
321
+ );
322
+ return BCP47_REGEX.test(locale);
323
+ }
324
+
325
+ // src/server/infrastructure/zod/rules/og-locale.ts
326
+ function ogLocale(locale) {
327
+ if (typeof locale !== "string") return false;
328
+ const OG_LOCALE_REGEX = /^[a-z]{2}_[A-Z]{2}$/;
329
+ return OG_LOCALE_REGEX.test(locale);
330
+ }
331
+
332
+ // src/server/infrastructure/zod/create-zod.ts
333
+ var patched = false;
334
+ function createZod({
335
+ unique,
336
+ exist
337
+ }) {
338
+ if (patched) return z;
339
+ patched = true;
340
+ const stringProto = z.ZodString.prototype;
341
+ const emailProto = z.ZodEmail.prototype;
342
+ Object.defineProperty(stringProto, "unique", {
343
+ configurable: true,
344
+ writable: false,
345
+ value: function(options) {
346
+ return this.refine(async (v) => unique(v, options), {
347
+ params: { i18nKey: "validator.unique" }
348
+ });
349
+ }
350
+ });
351
+ Object.defineProperty(stringProto, "exist", {
352
+ configurable: true,
353
+ writable: false,
354
+ value: function(options) {
355
+ return this.refine(async (v) => exist(v, options), {
356
+ params: { i18nKey: "validator.exist" }
357
+ });
358
+ }
359
+ });
360
+ Object.defineProperty(stringProto, "bcp47", {
361
+ configurable: true,
362
+ writable: false,
363
+ value: function() {
364
+ return this.refine((v) => bcp47(v), {
365
+ params: { i18nKey: "validator.bcp47" }
366
+ });
367
+ }
368
+ });
369
+ Object.defineProperty(stringProto, "ogLocale", {
370
+ configurable: true,
371
+ writable: false,
372
+ value: function() {
373
+ return this.refine((v) => ogLocale(v), {
374
+ params: { i18nKey: "validator.og-locale" }
375
+ });
376
+ }
377
+ });
378
+ Object.defineProperty(emailProto, "unique", {
379
+ configurable: true,
380
+ writable: false,
381
+ value: function(options) {
382
+ return this.refine(async (v) => unique(v, options), {
383
+ params: { i18nKey: "validator.unique" }
384
+ });
385
+ }
386
+ });
387
+ return z;
388
+ }
389
+
390
+ // src/server/infrastructure/zod/schemas/schemas.ts
391
+ function createSchemas({
392
+ z: z2,
393
+ localeArray,
394
+ exist
395
+ }) {
396
+ const trimmedString = () => z2.string().trim();
397
+ const MAX_NUMBER = 2147483647;
398
+ const MAX_STRING = 1e5;
399
+ const localeSet = new Set(localeArray);
400
+ function text() {
401
+ return trimmedString().max(MAX_STRING);
402
+ }
403
+ function positiveNumber() {
404
+ return z2.preprocess((val) => {
405
+ if (val == null || val === "") return;
406
+ const num = Number(String(val).trim());
407
+ return Number.isNaN(num) ? void 0 : num;
408
+ }, z2.number().min(0).max(MAX_NUMBER));
409
+ }
410
+ function url() {
411
+ return z2.preprocess((val) => {
412
+ if (typeof val === "string" && val.trim() === "" || val === null)
413
+ return null;
414
+ return val;
415
+ }, z2.url().max(2048).nullable());
416
+ }
417
+ function email() {
418
+ return z2.email().max(254).toLowerCase();
419
+ }
420
+ function password() {
421
+ return trimmedString().min(6).max(255);
422
+ }
423
+ function isoString() {
424
+ return trimmedString().regex(
425
+ /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/
426
+ );
427
+ }
428
+ function array(schema) {
429
+ return z2.array(schema).max(100).transform(
430
+ (arr) => arr.filter((v) => v != null)
431
+ );
432
+ }
433
+ function id() {
434
+ return trimmedString().length(26).regex(/^[0-9A-Z]{26}$/);
435
+ }
436
+ function key() {
437
+ return trimmedString().max(1024);
438
+ }
439
+ function sha256Hash() {
440
+ return trimmedString().length(64).regex(/^[a-f0-9]{64}$/);
441
+ }
442
+ function slug() {
443
+ return trimmedString().regex(/^$|^[\p{L}0-9-_]+$/u).max(100);
444
+ }
445
+ function pathSegment() {
446
+ return trimmedString().min(1).regex(/^(?!\.\.?$)[^\u0000-\u001F/\\]+$/u).max(255);
447
+ }
448
+ function locale() {
449
+ return trimmedString().refine((val) => localeSet.has(val), {
450
+ error: "Invalid locale"
451
+ });
452
+ }
453
+ function singleItem(options) {
454
+ return z2.object({
455
+ id: id().refine((v) => exist(v, options), {
456
+ error: "Resource does not exist"
457
+ })
458
+ }).nullable();
459
+ }
460
+ function multiItems(options) {
461
+ return array(
462
+ z2.object({
463
+ id: id().refine((v) => exist(v, options), {
464
+ error: "Resource does not exist"
465
+ })
466
+ })
467
+ );
468
+ }
469
+ return {
470
+ // base
471
+ text,
472
+ positiveNumber,
473
+ url,
474
+ email,
475
+ password,
476
+ isoString,
477
+ array,
478
+ // resource related
479
+ id,
480
+ key,
481
+ sha256Hash,
482
+ slug,
483
+ pathSegment,
484
+ locale,
485
+ // item
486
+ singleItem,
487
+ multiItems
488
+ };
489
+ }
490
+
491
+ // src/server/infrastructure/zod/schemas/file.ts
492
+ function createFileSchema({
493
+ z: z2,
494
+ maxSizeInMb
495
+ }) {
496
+ return function fileSchema({
497
+ size = maxSizeInMb * SIZE.MB,
498
+ extensions = []
499
+ }) {
500
+ return z2.instanceof(File, { error: "Invalid file" }).refine((file) => file.size <= size, {
501
+ error: `File is too large, max ${size / SIZE.MB}MB`
502
+ }).refine(
503
+ (file) => {
504
+ if (extensions.length === 0) return true;
505
+ return extensions.some(
506
+ (ext) => file.name.toLocaleLowerCase().endsWith(ext)
507
+ );
508
+ },
509
+ { error: `Only ${extensions.join(", ")} files are allowed` }
510
+ ).transform((file) => file);
511
+ };
512
+ }
513
+ function createMultiFileSchema({
514
+ z: z2,
515
+ fileSchema,
516
+ maxSizeInMb
517
+ }) {
518
+ return function multiFilesSchema({
519
+ size = maxSizeInMb * SIZE.MB,
520
+ extensions = []
521
+ } = {}) {
522
+ z2.array(fileSchema({ size, extensions }));
523
+ };
524
+ }
525
+
526
+ // src/server/infrastructure/zod/schemas/toc-item.ts
527
+ function createTocItemSchema({
528
+ z: z2,
529
+ schemas
530
+ }) {
531
+ const tocItem = z2.lazy(
532
+ () => z2.object({
533
+ text: schemas.text(),
534
+ id: schemas.text(),
535
+ level: z2.union([
536
+ z2.literal(2),
537
+ z2.literal(3),
538
+ z2.literal(4),
539
+ z2.literal(5),
540
+ z2.literal(6)
541
+ ]),
542
+ children: z2.array(tocItem).default([])
543
+ })
544
+ );
545
+ return tocItem;
546
+ }
547
+
313
548
  // src/server/infrastructure/database/utils/connect.ts
314
549
  var ids = (items) => items.map(({ id }) => ({ id }));
315
550
  function connectOne(item) {
@@ -1521,10 +1756,7 @@ function createExecuteAction({
1521
1756
  }
1522
1757
  };
1523
1758
  }
1524
- function createExecuteApi({
1525
- initI18n,
1526
- logger
1527
- }) {
1759
+ function createExecuteApi({ initI18n, logger }) {
1528
1760
  return async function serverApi(fn) {
1529
1761
  const translator = await initI18n();
1530
1762
  try {
@@ -1753,4 +1985,4 @@ function createAuthUseCases({
1753
1985
  };
1754
1986
  }
1755
1987
 
1756
- export { ADMIN_ORDER_BY, ORDER_BY, POST_ORDER_BY, ServerError, createAdminCommandRepository, createAdminQueryRepository, createAdminRefreshTokenCommandRepository, createAdminRefreshTokenQueryRepository, createArgon2Service, createAuthMiddleware, createAuthUseCases, createCache, createCacheResult, createCookieService, createCryptoService, createExecuteAction, createExecuteApi, createFileCommandRepository, createFileQueryRepository, createFolderCommandRepository, createFolderQueryRepository, createIpRateLimiter, createJwtService, createPostCommandRepository, createPostQueryRepository, createSeoMetadataCommandRepository, createVerifyAccessToken, createVerifyRefreshToken, normalizeCacheKey };
1988
+ export { ADMIN_ORDER_BY, ORDER_BY, POST_ORDER_BY, ServerError, createAdminCommandRepository, createAdminQueryRepository, createAdminRefreshTokenCommandRepository, createAdminRefreshTokenQueryRepository, createArgon2Service, createAuthMiddleware, createAuthUseCases, createCache, createCacheResult, createCookieService, createCryptoService, createExecuteAction, createExecuteApi, createFileCommandRepository, createFileQueryRepository, createFileSchema, createFolderCommandRepository, createFolderQueryRepository, createIpRateLimiter, createJwtService, createMultiFileSchema, createPostCommandRepository, createPostQueryRepository, createSchemas, createSeoMetadataCommandRepository, createTocItemSchema, createVerifyAccessToken, createVerifyRefreshToken, createZod, normalizeCacheKey };
@@ -3,11 +3,11 @@ import { Logger } from 'logry';
3
3
  import { S as StorageService } from '../../types-J25u1G6t.js';
4
4
  import '../../types-0oS1A2K5.js';
5
5
 
6
- interface CreateR2ServiceOptions {
6
+ interface CreateR2ServiceParams {
7
7
  r2Client: S3Client;
8
8
  bucketName: string;
9
9
  logger: Logger;
10
10
  }
11
- declare function createR2Service({ r2Client, bucketName, logger, }: CreateR2ServiceOptions): StorageService;
11
+ declare function createR2Service({ r2Client, bucketName, logger, }: CreateR2ServiceParams): StorageService;
12
12
 
13
13
  export { createR2Service };
@@ -1,5 +1,5 @@
1
- import { createObjectKey } from '../../chunk-BTRPDDZJ.js';
2
- import '../../chunk-YX7IPIGU.js';
1
+ import { createObjectKey } from '../../chunk-DWFOB4P3.js';
2
+ import '../../chunk-I2DBI3WJ.js';
3
3
  import { PutObjectCommand, DeleteObjectCommand, CopyObjectCommand } from '@aws-sdk/client-s3';
4
4
 
5
5
  function createR2Service({
@@ -4,17 +4,17 @@ import SFTPClient from 'ssh2-sftp-client';
4
4
  import { S as StorageService } from '../../types-J25u1G6t.js';
5
5
  import '../../types-0oS1A2K5.js';
6
6
 
7
- interface CreateSftpServiceOptions {
7
+ interface CreateSftpServiceParams {
8
8
  sftpPool: Pool<SFTPClient>;
9
9
  basePath: string;
10
10
  logger: Logger;
11
11
  }
12
- declare function createSftpService({ sftpPool, basePath, logger, }: CreateSftpServiceOptions): StorageService;
12
+ declare function createSftpService({ sftpPool, basePath, logger, }: CreateSftpServiceParams): StorageService;
13
13
 
14
- interface CreateSftpPoolOptions {
14
+ interface CreateSftpPoolParams {
15
15
  sftpClientOptions: SFTPClient.ConnectOptions;
16
16
  logger: Logger;
17
17
  }
18
- declare const createSftpPool: ({ sftpClientOptions, logger, }: CreateSftpPoolOptions) => Pool<SFTPClient>;
18
+ declare const createSftpPool: ({ sftpClientOptions, logger, }: CreateSftpPoolParams) => Pool<SFTPClient>;
19
19
 
20
20
  export { createSftpPool, createSftpService };
@@ -1,5 +1,5 @@
1
- import { createObjectKey } from '../../chunk-BTRPDDZJ.js';
2
- import '../../chunk-YX7IPIGU.js';
1
+ import { createObjectKey } from '../../chunk-DWFOB4P3.js';
2
+ import '../../chunk-I2DBI3WJ.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.29",
3
+ "version": "0.0.30",
4
4
  "author": "Yiming Liao",
5
5
  "license": "MIT",
6
6
  "type": "module",