@yimingliao/cms 0.0.5 → 0.0.7

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.
Files changed (3) hide show
  1. package/dist/index.d.ts +110 -64
  2. package/dist/index.js +188 -74
  3. package/package.json +1 -1
package/dist/index.d.ts CHANGED
@@ -83,6 +83,20 @@ declare function createCookieService(nextCookies: () => Promise<Awaited<ReturnTy
83
83
  }) => Promise<void>;
84
84
  };
85
85
 
86
+ type SingleItem = {
87
+ id: string;
88
+ } | null;
89
+ type MultiItems = {
90
+ id: string;
91
+ }[];
92
+
93
+ type BaseTranslation<T extends string = string> = {
94
+ locale: T;
95
+ };
96
+ type Translation<T extends string = string> = BaseTranslation<T> & {
97
+ [k: string]: unknown;
98
+ };
99
+
86
100
  declare const ADMIN_ROLES: {
87
101
  SUPER_ADMIN: "SUPER_ADMIN";
88
102
  ADMIN: "ADMIN";
@@ -103,13 +117,6 @@ interface Admin {
103
117
  }
104
118
  type AdminSafe = Omit<Admin, "passwordHash">;
105
119
 
106
- type BaseTranslation<T extends string = string> = {
107
- locale: T;
108
- };
109
- type Translation<T extends string = string> = BaseTranslation<T> & {
110
- [k: string]: unknown;
111
- };
112
-
113
120
  interface AdminTranslation extends Translation {
114
121
  id: string;
115
122
  locale: string;
@@ -163,7 +170,7 @@ declare const FILE_TYPES: {
163
170
  };
164
171
  type FileType = (typeof FILE_TYPES)[keyof typeof FILE_TYPES];
165
172
 
166
- interface File {
173
+ interface File$1 {
167
174
  id: string;
168
175
  key: string;
169
176
  checksum: string;
@@ -205,10 +212,10 @@ interface Folder {
205
212
  type FolderFull = Folder & {
206
213
  parentFolder: (Folder & {
207
214
  subFolders: Folder[];
208
- files: File[];
215
+ files: File$1[];
209
216
  }) | null;
210
217
  subFolders: Folder[];
211
- files: File[];
218
+ files: File$1[];
212
219
  };
213
220
 
214
221
  declare const POST_TYPES: {
@@ -320,7 +327,7 @@ type PostListCard = Post & {
320
327
  postsInTopic: Post[];
321
328
  children: Post[];
322
329
  taggedPosts: Post[];
323
- coverImage: File | null;
330
+ coverImage: File$1 | null;
324
331
  translations: PostTranslation[];
325
332
  };
326
333
 
@@ -344,7 +351,7 @@ type PostFull = Post & {
344
351
  translations: PostTranslation[];
345
352
  };
346
353
 
347
- type FileFull = File & {
354
+ type FileFull = File$1 & {
348
355
  folder: Folder | null;
349
356
  adminAsAvatarImage: Admin[];
350
357
  postsAsCoverImage: Post[];
@@ -358,13 +365,13 @@ type FileFull = File & {
358
365
  translations: FileTranslation[];
359
366
  };
360
367
 
361
- type FileCard = File & {
368
+ type FileCard = File$1 & {
362
369
  translations: FileTranslation[];
363
370
  };
364
371
 
365
372
  type AdminFull = AdminSafe & {
366
373
  adminRefreshTokens: AdminRefreshToken[];
367
- avatarImage: (File & {
374
+ avatarImage: (File$1 & {
368
375
  translations: FileTranslation[];
369
376
  }) | null;
370
377
  posts: Post[];
@@ -375,12 +382,45 @@ type AdminCard = AdminSafe & {
375
382
  translations: AdminTranslation[];
376
383
  };
377
384
 
378
- type SingleItem = {
379
- id: string;
380
- } | null;
381
- type MultiItems = {
385
+ interface Alternate {
386
+ hreflang: string;
387
+ href: string | null;
388
+ }
389
+
390
+ interface SeoMetadata {
382
391
  id: string;
383
- }[];
392
+ locale: string;
393
+ title: string | null;
394
+ description: string | null;
395
+ author: string | null;
396
+ canonical: string | null;
397
+ alternate: Alternate[];
398
+ robots: string | null;
399
+ ogTitle: string | null;
400
+ ogDescription: string | null;
401
+ ogUrl: string | null;
402
+ ogType: string | null;
403
+ ogSiteName: string | null;
404
+ ogImage: string | null;
405
+ ogImageAlt: string | null;
406
+ ogImageType: string | null;
407
+ ogImageWidth: number | null;
408
+ ogImageHeight: number | null;
409
+ ogLocale: string | null;
410
+ ogLocaleAlternate: string[];
411
+ ogArticlePublishedTime: Date | null;
412
+ ogArticleModifiedTime: Date | null;
413
+ ogArticleAuthor: string | null;
414
+ ogArticleSection: string | null;
415
+ ogArticleTag: string[];
416
+ twitterCard: string | null;
417
+ twitterSite: string | null;
418
+ twitterCreator: string | null;
419
+ jsonLd: object[];
420
+ postId: string;
421
+ createdAt: Date;
422
+ updatedAt: Date;
423
+ }
384
424
 
385
425
  interface CreateParams$4 {
386
426
  email: string;
@@ -498,7 +538,7 @@ interface CreateParams$2 {
498
538
  }
499
539
  interface UpdateParams$2 {
500
540
  id: string;
501
- file: File;
541
+ file: File$1;
502
542
  key: string;
503
543
  checksum: string;
504
544
  fileMeta: {
@@ -518,10 +558,10 @@ interface UpdateParams$2 {
518
558
 
519
559
  declare function createFileCommandRepository(prisma: any): {
520
560
  create: ({ fileMeta, folder, translations, ...params }: CreateParams$2) => Promise<FileFull>;
521
- update: ({ file, id, fileMeta, folder, translations, ...params }: UpdateParams$2) => Promise<File>;
561
+ update: ({ file, id, fileMeta, folder, translations, ...params }: UpdateParams$2) => Promise<File$1>;
522
562
  softDelete: ({ id }: {
523
563
  id: string;
524
- }) => Promise<File>;
564
+ }) => Promise<File$1>;
525
565
  softDeleteMany: ({ ids }: {
526
566
  ids: string[];
527
567
  }) => Promise<number>;
@@ -530,7 +570,7 @@ declare function createFileCommandRepository(prisma: any): {
530
570
  }) => Promise<number>;
531
571
  delete: ({ id }: {
532
572
  id: string;
533
- }) => Promise<File>;
573
+ }) => Promise<File$1>;
534
574
  };
535
575
 
536
576
  interface FindListCardsParams$2 {
@@ -756,46 +796,6 @@ declare function createPostCommandRepository(prisma: any): {
756
796
  }) => Promise<Post>;
757
797
  };
758
798
 
759
- interface Alternate {
760
- hreflang: string;
761
- href: string | null;
762
- }
763
-
764
- interface SeoMetadata {
765
- id: string;
766
- locale: string;
767
- title: string | null;
768
- description: string | null;
769
- author: string | null;
770
- canonical: string | null;
771
- alternate: Alternate[];
772
- robots: string | null;
773
- ogTitle: string | null;
774
- ogDescription: string | null;
775
- ogUrl: string | null;
776
- ogType: string | null;
777
- ogSiteName: string | null;
778
- ogImage: string | null;
779
- ogImageAlt: string | null;
780
- ogImageType: string | null;
781
- ogImageWidth: number | null;
782
- ogImageHeight: number | null;
783
- ogLocale: string | null;
784
- ogLocaleAlternate: string[];
785
- ogArticlePublishedTime: Date | null;
786
- ogArticleModifiedTime: Date | null;
787
- ogArticleAuthor: string | null;
788
- ogArticleSection: string | null;
789
- ogArticleTag: string[];
790
- twitterCard: string | null;
791
- twitterSite: string | null;
792
- twitterCreator: string | null;
793
- jsonLd: object[];
794
- postId: string;
795
- createdAt: Date;
796
- updatedAt: Date;
797
- }
798
-
799
799
  interface FindListCardsParams {
800
800
  locale: string;
801
801
  type: PostType | null;
@@ -875,4 +875,50 @@ declare function createSeoMetadataCommandRepository(prisma: any): {
875
875
  upsert: ({ postId, translations, }: UpsertParams) => Promise<void>;
876
876
  };
877
877
 
878
- export { ADMIN_ROLES, type Admin, type AdminCard, type AdminFull, type AdminRefreshToken, type AdminRole, type AdminSafe, type AdminTranslation, type Alternate, type BaseTranslation, type DeviceInfo, type ExternalLink, FILE_TYPES, type Faq, type File, type FileCard, type FileFull, type FileTranslation, type FileType, type Folder, type FolderFull, type MultiItems, POST_TYPES, type Post, type PostFull, type PostListCard, type PostTranslation, type PostType, type SeoMetadata, type SingleItem, type TocItem, type Translation, createAdminCommandRepository, createAdminQueryRepository, createAdminRefreshTokenCommandRepository, createAdminRefreshTokenQueryRepository, createArgon2Service, createCookieService, createCryptoService, createFileCommandRepository, createFileQueryRepository, createFolderCommandRepository, createFolderQueryRepository, createJwtService, createPostCommandRepository, createPostQueryRepository, createSeoMetadataCommandRepository };
878
+ declare const ORDER_BY: readonly [{
879
+ readonly updatedAt: "desc";
880
+ }, {
881
+ readonly createdAt: "desc";
882
+ }, {
883
+ readonly id: "asc";
884
+ }];
885
+ declare const ADMIN_ORDER_BY: ({
886
+ readonly updatedAt: "desc";
887
+ } | {
888
+ readonly createdAt: "desc";
889
+ } | {
890
+ readonly id: "asc";
891
+ } | {
892
+ role: "asc";
893
+ })[];
894
+ declare const POST_ORDER_BY: ({
895
+ readonly updatedAt: "desc";
896
+ } | {
897
+ readonly createdAt: "desc";
898
+ } | {
899
+ readonly id: "asc";
900
+ } | {
901
+ index: "asc";
902
+ })[];
903
+
904
+ declare const mimeToExtension: (mimeType?: string) => string;
905
+
906
+ declare const classifyFileType: (mimeType?: string, extension?: string) => "IMAGE" | "AUDIO" | "VIDEO" | "DOCUMENT" | "ARCHIVE" | "OTHER";
907
+
908
+ interface MediaInfo {
909
+ width: number | null;
910
+ height: number | null;
911
+ duration: number | null;
912
+ }
913
+ declare const getMediaInfo: (file: Blob) => Promise<MediaInfo>;
914
+
915
+ declare const formatFileSize: (size: number, decimals?: number) => string;
916
+
917
+ interface BlobFile extends File {
918
+ id: string;
919
+ width: number | null;
920
+ height: number | null;
921
+ duration: number | null;
922
+ }
923
+
924
+ export { ADMIN_ORDER_BY, ADMIN_ROLES, type Admin, type AdminCard, type AdminFull, type AdminRefreshToken, type AdminRole, type AdminSafe, type AdminTranslation, type Alternate, type BaseTranslation, type BlobFile, type DeviceInfo, type ExternalLink, FILE_TYPES, type Faq, type File$1 as File, type FileCard, type FileFull, type FileTranslation, type FileType, type Folder, type FolderFull, type MultiItems, ORDER_BY, POST_ORDER_BY, POST_TYPES, type Post, type PostFull, type PostListCard, type PostTranslation, type PostType, type SeoMetadata, type SingleItem, type TocItem, type Translation, classifyFileType, createAdminCommandRepository, createAdminQueryRepository, createAdminRefreshTokenCommandRepository, createAdminRefreshTokenQueryRepository, createArgon2Service, createCookieService, createCryptoService, createFileCommandRepository, createFileQueryRepository, createFolderCommandRepository, createFolderQueryRepository, createJwtService, createPostCommandRepository, createPostQueryRepository, createSeoMetadataCommandRepository, formatFileSize, getMediaInfo, mimeToExtension };
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import 'next/headers';
5
5
  import { extension, lookup } from 'mime-types';
6
6
  import { ulid } from 'ulid';
7
7
 
8
- // src/infrastructure/jwt/jwt.service.ts
8
+ // src/server/infrastructure/jwt/jwt.service.ts
9
9
  function createJwtService(config) {
10
10
  const { defaultSecret, ...options } = config;
11
11
  function sign({
@@ -195,7 +195,7 @@ function createCookieService(nextCookies, cryptoService) {
195
195
  };
196
196
  }
197
197
 
198
- // src/database/utils/connect.ts
198
+ // src/server/infrastructure/database/utils/connect.ts
199
199
  var ids = (items) => items.map(({ id }) => ({ id }));
200
200
  function connectOne(item) {
201
201
  return item ? { connect: { id: item.id } } : {};
@@ -210,7 +210,7 @@ function updateMany(items) {
210
210
  return { set: ids(items) };
211
211
  }
212
212
 
213
- // src/database/admin/command/create-admin-command-repository.ts
213
+ // src/server/infrastructure/database/admin/command/create-admin-command-repository.ts
214
214
  function createAdminCommandRepository(prisma) {
215
215
  async function create({
216
216
  // ------------------------------------
@@ -291,7 +291,7 @@ function createAdminCommandRepository(prisma) {
291
291
  };
292
292
  }
293
293
 
294
- // src/database/constants.ts
294
+ // src/server/infrastructure/database/constants.ts
295
295
  var ORDER_BY = [
296
296
  { updatedAt: "desc" },
297
297
  { createdAt: "desc" },
@@ -306,14 +306,36 @@ var POST_ORDER_BY = [
306
306
  ...ORDER_BY
307
307
  ];
308
308
 
309
- // src/domain/admin/props.ts
309
+ // src/domain/resources/admin/props.ts
310
310
  var ADMIN_ROLES = {
311
311
  SUPER_ADMIN: "SUPER_ADMIN",
312
312
  ADMIN: "ADMIN",
313
313
  EDITOR: "EDITOR"
314
314
  };
315
315
 
316
- // src/database/admin/include.ts
316
+ // src/domain/resources/file/props.ts
317
+ var FILE_TYPES = {
318
+ IMAGE: "IMAGE",
319
+ AUDIO: "AUDIO",
320
+ VIDEO: "VIDEO",
321
+ DOCUMENT: "DOCUMENT",
322
+ ARCHIVE: "ARCHIVE",
323
+ OTHER: "OTHER"
324
+ };
325
+
326
+ // src/domain/resources/post/props.ts
327
+ var POST_TYPES = {
328
+ TOPIC: "TOPIC",
329
+ CATEGORY: "CATEGORY",
330
+ POST: "POST",
331
+ TAG: "TAG",
332
+ PAGE: "PAGE"
333
+ };
334
+
335
+ // src/domain/resources/constants.ts
336
+ var ROOT_FOLDER_ID = "01ARZ3NDEKTSV4RRFFQ69G5FAV";
337
+
338
+ // src/server/infrastructure/database/admin/include.ts
317
339
  var ADMIN_FULL_INCLUDE = {
318
340
  // ---------------------------
319
341
  // relations: AdminRefreshToken
@@ -333,7 +355,7 @@ var ADMIN_FULL_INCLUDE = {
333
355
  translations: true
334
356
  };
335
357
 
336
- // src/database/utils/create-search.ts
358
+ // src/server/infrastructure/database/utils/create-search.ts
337
359
  function buildContainsOr(fields, value) {
338
360
  return fields.map((field) => ({
339
361
  [field]: { contains: value, mode: "insensitive" }
@@ -365,7 +387,7 @@ function createSearch({
365
387
  return conditions.length > 0 ? { OR: conditions } : {};
366
388
  }
367
389
 
368
- // src/database/utils/create-pagination.ts
390
+ // src/server/infrastructure/database/utils/create-pagination.ts
369
391
  function createPagination(page, pageSize) {
370
392
  if (!page || !pageSize) return {};
371
393
  return {
@@ -374,7 +396,7 @@ function createPagination(page, pageSize) {
374
396
  };
375
397
  }
376
398
 
377
- // src/database/admin/query/create-admin-query-repository.ts
399
+ // src/server/infrastructure/database/admin/query/create-admin-query-repository.ts
378
400
  var OMIT_PASSWORD = { omit: { passwordHash: true } };
379
401
  function buildWhere(params) {
380
402
  if (params.id) return { id: params.id };
@@ -448,7 +470,7 @@ function createAdminQueryRepository(prisma) {
448
470
  };
449
471
  }
450
472
 
451
- // src/database/admin-refresh-token/command/create-admin-refresh-token-command-repository.ts
473
+ // src/server/infrastructure/database/admin-refresh-token/command/create-admin-refresh-token-command-repository.ts
452
474
  function createAdminRefreshTokenCommandRepository(prisma) {
453
475
  async function create({
454
476
  adminId,
@@ -484,7 +506,7 @@ function createAdminRefreshTokenCommandRepository(prisma) {
484
506
  };
485
507
  }
486
508
 
487
- // src/database/admin-refresh-token/query/create-admin-refresh-token-query-repository.ts
509
+ // src/server/infrastructure/database/admin-refresh-token/query/create-admin-refresh-token-query-repository.ts
488
510
  function createAdminRefreshTokenQueryRepository(prisma) {
489
511
  async function findManyByAdminId({
490
512
  adminId
@@ -507,7 +529,7 @@ function createAdminRefreshTokenQueryRepository(prisma) {
507
529
  };
508
530
  }
509
531
 
510
- // src/database/file/include.ts
532
+ // src/server/infrastructure/database/file/include.ts
511
533
  var FILE_FULL_INCLUDE = {
512
534
  // ---------------------------
513
535
  // relations: Folder
@@ -536,53 +558,157 @@ var FILE_FULL_INCLUDE = {
536
558
  // ---------------------------
537
559
  translations: true
538
560
  };
539
-
540
- // src/domain/file/props.ts
541
- var FILE_TYPES = {
542
- IMAGE: "IMAGE",
543
- AUDIO: "AUDIO",
544
- VIDEO: "VIDEO",
545
- DOCUMENT: "DOCUMENT",
546
- ARCHIVE: "ARCHIVE",
547
- OTHER: "OTHER"
561
+ var mimeToExtension = (mimeType) => {
562
+ if (!mimeType) return "unknown";
563
+ return (extension(mimeType) || "unknown").toLowerCase();
548
564
  };
549
-
550
- // src/domain/file/utils/get-file-type.ts
551
- var getFileType = (mimeType, extension2) => {
565
+ var ARCHIVE_MIME = /* @__PURE__ */ new Set([
566
+ "application/zip",
567
+ "application/x-rar-compressed",
568
+ "application/x-7z-compressed",
569
+ "application/gzip",
570
+ "application/x-tar"
571
+ ]);
572
+ var classifyFileType = (mimeType, extension2) => {
552
573
  if (!mimeType && extension2) {
553
- mimeType = lookup(extension2) || "unknown";
554
- }
555
- if (!mimeType) {
556
- return FILE_TYPES.OTHER;
574
+ mimeType = lookup(extension2) || void 0;
557
575
  }
558
- if (mimeType.startsWith("image/")) {
559
- return FILE_TYPES.IMAGE;
560
- }
561
- if (mimeType.startsWith("video/")) {
562
- return FILE_TYPES.VIDEO;
563
- }
564
- if (mimeType.startsWith("audio/")) {
565
- return FILE_TYPES.AUDIO;
566
- }
567
- if (mimeType.startsWith("text/") || mimeType.startsWith("application/")) {
576
+ if (!mimeType) return FILE_TYPES.OTHER;
577
+ if (mimeType.startsWith("image/")) return FILE_TYPES.IMAGE;
578
+ if (mimeType.startsWith("video/")) return FILE_TYPES.VIDEO;
579
+ if (mimeType.startsWith("audio/")) return FILE_TYPES.AUDIO;
580
+ if (ARCHIVE_MIME.has(mimeType)) return FILE_TYPES.ARCHIVE;
581
+ if (mimeType.startsWith("text/") || mimeType === "application/pdf" || mimeType === "application/json" || mimeType === "application/xml") {
568
582
  return FILE_TYPES.DOCUMENT;
569
583
  }
570
- if (mimeType === "application/zip" || mimeType === "application/x-rar-compressed") {
571
- return FILE_TYPES.ARCHIVE;
572
- }
573
- if (mimeType.startsWith("application/x-") || mimeType === "application/octet-stream") {
574
- return FILE_TYPES.OTHER;
575
- }
584
+ if (mimeType.startsWith("application/")) return FILE_TYPES.DOCUMENT;
576
585
  return FILE_TYPES.OTHER;
577
586
  };
578
- var getExtension = (fileType) => {
579
- if (typeof fileType !== "string") {
580
- return "unknown";
587
+
588
+ // src/shared/blob-file/get-media-info/get-audio-info.ts
589
+ function getAudioInfo(file) {
590
+ return new Promise((resolve, reject) => {
591
+ const audio = document.createElement("audio");
592
+ const objectUrl = URL.createObjectURL(file);
593
+ audio.preload = "metadata";
594
+ const cleanup = () => {
595
+ audio.removeEventListener("loadedmetadata", onLoadedMetadata);
596
+ audio.removeEventListener("error", onError);
597
+ URL.revokeObjectURL(objectUrl);
598
+ };
599
+ const onLoadedMetadata = () => {
600
+ const duration = audio.duration;
601
+ cleanup();
602
+ resolve({ duration });
603
+ };
604
+ const onError = () => {
605
+ cleanup();
606
+ reject(new Error("Failed to load audio metadata."));
607
+ };
608
+ audio.addEventListener("loadedmetadata", onLoadedMetadata, { once: true });
609
+ audio.addEventListener("error", onError, { once: true });
610
+ audio.src = objectUrl;
611
+ });
612
+ }
613
+
614
+ // src/shared/blob-file/get-media-info/get-image-info.ts
615
+ function getImageInfo(file) {
616
+ return new Promise((resolve, reject) => {
617
+ const img = new Image();
618
+ const objectUrl = URL.createObjectURL(file);
619
+ const cleanup = () => {
620
+ img.removeEventListener("load", onLoad);
621
+ img.removeEventListener("error", onError);
622
+ URL.revokeObjectURL(objectUrl);
623
+ };
624
+ const onLoad = () => {
625
+ const width = img.naturalWidth;
626
+ const height = img.naturalHeight;
627
+ cleanup();
628
+ resolve({ width, height });
629
+ };
630
+ const onError = () => {
631
+ cleanup();
632
+ reject(new Error("Failed to load image for size detection."));
633
+ };
634
+ img.addEventListener("load", onLoad, { once: true });
635
+ img.addEventListener("error", onError, { once: true });
636
+ img.src = objectUrl;
637
+ });
638
+ }
639
+
640
+ // src/shared/blob-file/get-media-info/get-video-info.ts
641
+ function getVideoInfo(file) {
642
+ return new Promise((resolve, reject) => {
643
+ const video = document.createElement("video");
644
+ const objectUrl = URL.createObjectURL(file);
645
+ video.preload = "metadata";
646
+ const cleanup = () => {
647
+ video.removeEventListener("loadedmetadata", onLoadedMetadata);
648
+ video.removeEventListener("error", onError);
649
+ video.src = "";
650
+ URL.revokeObjectURL(objectUrl);
651
+ };
652
+ const onLoadedMetadata = () => {
653
+ const info = {
654
+ width: video.videoWidth,
655
+ height: video.videoHeight,
656
+ duration: video.duration
657
+ };
658
+ cleanup();
659
+ resolve(info);
660
+ };
661
+ const onError = () => {
662
+ cleanup();
663
+ reject(new Error("Failed to load video metadata."));
664
+ };
665
+ video.addEventListener("loadedmetadata", onLoadedMetadata, { once: true });
666
+ video.addEventListener("error", onError, { once: true });
667
+ video.src = objectUrl;
668
+ });
669
+ }
670
+
671
+ // src/shared/blob-file/get-media-info/get-media-info.ts
672
+ var IMAGE_EXT = /\.(jpe?g|png|gif|webp|bmp|avif)$/i;
673
+ var VIDEO_EXT = /\.(mp4|webm|mov|mkv)$/i;
674
+ var AUDIO_EXT = /\.(mp3|wav|ogg|m4a)$/i;
675
+ var getMediaInfo = async (file) => {
676
+ const fallback = { width: null, height: null, duration: null };
677
+ const mime = file.type || "";
678
+ const name = file instanceof File ? file.name.toLowerCase() : "";
679
+ try {
680
+ if (mime.startsWith("image/") || IMAGE_EXT.test(name)) {
681
+ const { width, height } = await getImageInfo(file);
682
+ return { width, height, duration: null };
683
+ }
684
+ if (mime.startsWith("video/") || VIDEO_EXT.test(name)) {
685
+ const { width, height, duration } = await getVideoInfo(file);
686
+ return { width, height, duration };
687
+ }
688
+ if (mime.startsWith("audio/") || AUDIO_EXT.test(name)) {
689
+ const { duration } = await getAudioInfo(file);
690
+ return { width: null, height: null, duration };
691
+ }
692
+ return fallback;
693
+ } catch {
694
+ return fallback;
695
+ }
696
+ };
697
+
698
+ // src/shared/blob-file/format-file-size.ts
699
+ var formatFileSize = (size, decimals = 2) => {
700
+ const units = ["B", "KB", "MB", "GB", "TB"];
701
+ let value = size;
702
+ let unitIndex = 0;
703
+ while (value >= 1024 && unitIndex < units.length - 1) {
704
+ value /= 1024;
705
+ unitIndex++;
581
706
  }
582
- return (extension(fileType) || "unknown").toLowerCase();
707
+ const display = unitIndex === 0 ? value.toString() : value.toFixed(decimals);
708
+ return `${display} ${units[unitIndex]}`;
583
709
  };
584
710
 
585
- // src/database/file/command/create-file-command-repository.ts
711
+ // src/server/infrastructure/database/file/command/create-file-command-repository.ts
586
712
  function createFileCommandRepository(prisma) {
587
713
  async function create({
588
714
  // meta
@@ -599,7 +725,7 @@ function createFileCommandRepository(prisma) {
599
725
  // rest
600
726
  ...params
601
727
  }) {
602
- const extension2 = getExtension(fileMeta.type);
728
+ const extension2 = mimeToExtension(fileMeta.type);
603
729
  const created = await prisma.file.create({
604
730
  data: {
605
731
  ...params,
@@ -608,7 +734,7 @@ function createFileCommandRepository(prisma) {
608
734
  size: fileMeta.size ?? 0,
609
735
  extension: extension2,
610
736
  mimeType: fileMeta.type || "unknown",
611
- type: getFileType(fileMeta.type, extension2),
737
+ type: classifyFileType(fileMeta.type, extension2),
612
738
  // ------------------------------------------------------------------------
613
739
  // relations
614
740
  // ------------------------------------------------------------------------
@@ -646,7 +772,7 @@ function createFileCommandRepository(prisma) {
646
772
  // rest
647
773
  ...params
648
774
  }) {
649
- const extension2 = getExtension(fileMeta.type);
775
+ const extension2 = mimeToExtension(fileMeta.type);
650
776
  const updated = await prisma.file.update({
651
777
  where: { id: file.id },
652
778
  data: {
@@ -655,7 +781,7 @@ function createFileCommandRepository(prisma) {
655
781
  size: fileMeta.size ?? file.size,
656
782
  extension: fileMeta ? extension2 : file.extension,
657
783
  mimeType: fileMeta.type || file.mimeType,
658
- type: fileMeta.type ? getFileType(fileMeta.type, extension2) : file.type,
784
+ type: fileMeta.type ? classifyFileType(fileMeta.type, extension2) : file.type,
659
785
  // ------------------------------------------------------------------------
660
786
  // relations
661
787
  // ------------------------------------------------------------------------
@@ -712,7 +838,7 @@ function createFileCommandRepository(prisma) {
712
838
  };
713
839
  }
714
840
 
715
- // src/database/utils/build-file-usage.ts
841
+ // src/server/infrastructure/database/utils/build-file-usage.ts
716
842
  function buildFileUsage(isLocked) {
717
843
  const relations = [
718
844
  "adminAsAvatarImage",
@@ -732,10 +858,7 @@ function buildFileUsage(isLocked) {
732
858
  return isLocked ? { OR: condition } : { AND: condition };
733
859
  }
734
860
 
735
- // src/domain/folder/constants/root-folder.ts
736
- var ROOT_FOLDER_ID = "01ARZ3NDEKTSV4RRFFQ69G5FAV";
737
-
738
- // src/database/file/query/create-file-query-repository.ts
861
+ // src/server/infrastructure/database/file/query/create-file-query-repository.ts
739
862
  function createFileQueryRepository(prisma) {
740
863
  async function findListCards({
741
864
  locale,
@@ -801,7 +924,7 @@ function createFileQueryRepository(prisma) {
801
924
  };
802
925
  }
803
926
 
804
- // src/database/folder/command/create-folder-command-repository.ts
927
+ // src/server/infrastructure/database/folder/command/create-folder-command-repository.ts
805
928
  function createFolderCommandRepository(prisma) {
806
929
  async function create({
807
930
  // ------------------------------------
@@ -860,7 +983,7 @@ function createFolderCommandRepository(prisma) {
860
983
  };
861
984
  }
862
985
 
863
- // src/database/folder/include.ts
986
+ // src/server/infrastructure/database/folder/include.ts
864
987
  var FOLDER_FULL_INCLUDE = {
865
988
  // ---------------------------
866
989
  // relations: Folder
@@ -873,7 +996,7 @@ var FOLDER_FULL_INCLUDE = {
873
996
  files: true
874
997
  };
875
998
 
876
- // src/database/folder/query/create-folder-query-repository.ts
999
+ // src/server/infrastructure/database/folder/query/create-folder-query-repository.ts
877
1000
  function buildWhere2(params) {
878
1001
  if (params.id) return { id: params.id };
879
1002
  if (params.key) return { key: params.key };
@@ -1108,7 +1231,7 @@ function createPostCommandRepository(prisma) {
1108
1231
  };
1109
1232
  }
1110
1233
 
1111
- // src/database/post/include.ts
1234
+ // src/server/infrastructure/database/post/include.ts
1112
1235
  var POST_LIST_CARD_INCLUDE = {
1113
1236
  // ---------------------------
1114
1237
  // relations: Post
@@ -1165,7 +1288,7 @@ var POST_FULL_INCLUDE = {
1165
1288
  translations: true
1166
1289
  };
1167
1290
 
1168
- // src/database/post/query/create-post-query-repository.ts
1291
+ // src/server/infrastructure/database/post/query/create-post-query-repository.ts
1169
1292
  function buildWhere3(params) {
1170
1293
  if (params.id) return { id: params.id };
1171
1294
  if (params.type && params.slug)
@@ -1264,7 +1387,7 @@ function createPostQueryRepository(prisma) {
1264
1387
  };
1265
1388
  }
1266
1389
 
1267
- // src/database/seo-metadata/command/create-seo-metadata-command-repository.ts
1390
+ // src/server/infrastructure/database/seo-metadata/command/create-seo-metadata-command-repository.ts
1268
1391
  function createSeoMetadataCommandRepository(prisma) {
1269
1392
  async function upsert({
1270
1393
  // ------------------------------------
@@ -1295,13 +1418,4 @@ function createSeoMetadataCommandRepository(prisma) {
1295
1418
  };
1296
1419
  }
1297
1420
 
1298
- // src/domain/post/props.ts
1299
- var POST_TYPES = {
1300
- TOPIC: "TOPIC",
1301
- CATEGORY: "CATEGORY",
1302
- POST: "POST",
1303
- TAG: "TAG",
1304
- PAGE: "PAGE"
1305
- };
1306
-
1307
- export { ADMIN_ROLES, FILE_TYPES, POST_TYPES, createAdminCommandRepository, createAdminQueryRepository, createAdminRefreshTokenCommandRepository, createAdminRefreshTokenQueryRepository, createArgon2Service, createCookieService, createCryptoService, createFileCommandRepository, createFileQueryRepository, createFolderCommandRepository, createFolderQueryRepository, createJwtService, createPostCommandRepository, createPostQueryRepository, createSeoMetadataCommandRepository };
1421
+ export { ADMIN_ORDER_BY, ADMIN_ROLES, FILE_TYPES, ORDER_BY, POST_ORDER_BY, POST_TYPES, classifyFileType, createAdminCommandRepository, createAdminQueryRepository, createAdminRefreshTokenCommandRepository, createAdminRefreshTokenQueryRepository, createArgon2Service, createCookieService, createCryptoService, createFileCommandRepository, createFileQueryRepository, createFolderCommandRepository, createFolderQueryRepository, createJwtService, createPostCommandRepository, createPostQueryRepository, createSeoMetadataCommandRepository, formatFileSize, getMediaInfo, mimeToExtension };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yimingliao/cms",
3
- "version": "0.0.5",
3
+ "version": "0.0.7",
4
4
  "author": "Yiming Liao",
5
5
  "license": "MIT",
6
6
  "type": "module",