@yimingliao/cms 0.0.75 → 0.0.76

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.
@@ -468,6 +468,29 @@ var jsonArrayToUi = (data) => {
468
468
  }
469
469
  };
470
470
 
471
+ // src/shared/utils/ensure-array.ts
472
+ function ensureArray(value) {
473
+ if (value == null) return [];
474
+ return Array.isArray(value) ? value : [value];
475
+ }
476
+
477
+ // src/shared/utils/format-date-time.ts
478
+ var dateTimeFormatter = new Intl.DateTimeFormat(void 0, {
479
+ year: "numeric",
480
+ month: "numeric",
481
+ day: "numeric",
482
+ hour: "2-digit",
483
+ minute: "2-digit"
484
+ });
485
+ function formatDateTime(input) {
486
+ if (!input) return "";
487
+ const date = typeof input === "string" ? new Date(input) : input;
488
+ if (Number.isNaN(date.getTime())) {
489
+ return "";
490
+ }
491
+ return dateTimeFormatter.format(date);
492
+ }
493
+
471
494
  // src/shared/units.ts
472
495
  var SIZE = {
473
496
  BYTE: 1,
@@ -478,4 +501,4 @@ var SIZE = {
478
501
  PB: 1024 ** 5
479
502
  };
480
503
 
481
- export { FILE_TYPES, OG_TYPE_ARRAY, SIZE, TWITTER_CARD_ARRAY, classifyFileType, createBuildArticleMetadata, createBuildTranslations, createBuildWebsiteMetadata, datetimeToDb, datetimeToUi, findTranslation, formatFileSize, getMediaInfo, jsonArrayToDb, jsonArrayToUi, mimeToExtension, result, serializeJsonLd };
504
+ export { FILE_TYPES, OG_TYPE_ARRAY, SIZE, TWITTER_CARD_ARRAY, classifyFileType, createBuildArticleMetadata, createBuildTranslations, createBuildWebsiteMetadata, datetimeToDb, datetimeToUi, ensureArray, findTranslation, formatDateTime, formatFileSize, getMediaInfo, jsonArrayToDb, jsonArrayToUi, mimeToExtension, result, serializeJsonLd };
@@ -1,4 +1,4 @@
1
- import { mimeToExtension } from './chunk-N2PRNBP2.js';
1
+ import { mimeToExtension } from './chunk-OAENV763.js';
2
2
  import path from 'path/posix';
3
3
  import { ulid } from 'ulid';
4
4
 
@@ -1,5 +1,6 @@
1
- import { R as Result } from '../types-DHlRoJwv.js';
1
+ import { R as Result, S as SuccessResult, a as ErrorResult, E as ErrorDetail } from '../types-DHlRoJwv.js';
2
2
  import { Logger } from 'logry';
3
+ import * as react_jsx_runtime from 'react/jsx-runtime';
3
4
 
4
5
  interface FetchContext {
5
6
  input: string;
@@ -27,4 +28,14 @@ declare function createResponseInterceptor({ logger }: {
27
28
  logger: Logger;
28
29
  }): ResponseInterceptor;
29
30
 
30
- export { createRequestInterceptor, createResponseInterceptor, createSmartFetch };
31
+ type ShowToastOption = boolean | {
32
+ success?: boolean;
33
+ error?: boolean;
34
+ };
35
+ declare const handleToast: (result: SuccessResult | ErrorResult, showToast?: ShowToastOption) => void;
36
+
37
+ declare const shouldShowToast: (type: "success" | "error", showToast?: ShowToastOption) => boolean;
38
+
39
+ declare const createErrorDisplay: (errors: ErrorDetail[]) => react_jsx_runtime.JSX.Element;
40
+
41
+ export { type ShowToastOption, createErrorDisplay, createRequestInterceptor, createResponseInterceptor, createSmartFetch, handleToast, shouldShowToast };
@@ -1,4 +1,7 @@
1
- // src/client/infrastructure/smart-fetch/smart-fetch.ts
1
+ import { toast } from 'sonner';
2
+ import { jsx, jsxs } from 'react/jsx-runtime';
3
+
4
+ // src/client/infrastructure/fetch/smart-fetch.ts
2
5
  function createSmartFetch({
3
6
  requestInterceptor,
4
7
  responseInterceptor,
@@ -22,7 +25,7 @@ function createSmartFetch({
22
25
  return smartFetch;
23
26
  }
24
27
 
25
- // src/client/infrastructure/smart-fetch/request-interceptor.ts
28
+ // src/client/infrastructure/fetch/request-interceptor.ts
26
29
  function createRequestInterceptor({ baseUrl }) {
27
30
  const requestInterceptor = (ctx) => {
28
31
  const normalizedBase = baseUrl.replace(/\/+$/, "");
@@ -43,7 +46,7 @@ function createRequestInterceptor({ baseUrl }) {
43
46
  return requestInterceptor;
44
47
  }
45
48
 
46
- // src/client/infrastructure/smart-fetch/response-interceptor.ts
49
+ // src/client/infrastructure/fetch/response-interceptor.ts
47
50
  function createResponseInterceptor({ logger }) {
48
51
  const responseInterceptor = async (response, ctx) => {
49
52
  const duration = Date.now() - (ctx.meta.startTime ?? 0);
@@ -64,5 +67,59 @@ function createResponseInterceptor({ logger }) {
64
67
  };
65
68
  return responseInterceptor;
66
69
  }
70
+ function ErrorDisplay({ errors }) {
71
+ return /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2", children: errors.map((error, index) => {
72
+ let field = error.field ?? "";
73
+ if (field.startsWith("translations")) field = field.slice(15);
74
+ if (field.includes(".") && !Number.isNaN(Number(field.at(-1)))) {
75
+ const [f, i] = field.split(".");
76
+ field = `${f} ${Number(i) + 1}`;
77
+ }
78
+ return /* @__PURE__ */ jsxs("p", { children: [
79
+ /* @__PURE__ */ jsxs("span", { className: "font-bold", children: [
80
+ "(",
81
+ index + 1,
82
+ ")"
83
+ ] }),
84
+ "\xA0",
85
+ /* @__PURE__ */ jsx("span", { className: "font-bold underline underline-offset-2", children: field }),
86
+ "\xA0",
87
+ /* @__PURE__ */ jsx("span", { children: error.message })
88
+ ] }, index);
89
+ }) });
90
+ }
91
+ var createErrorDisplay = (errors) => ErrorDisplay({ errors });
92
+
93
+ // src/client/infrastructure/toast/should-show-toast.ts
94
+ var shouldShowToast = (type, showToast) => {
95
+ if (showToast === void 0) return false;
96
+ if (typeof showToast === "boolean") return showToast;
97
+ return !!showToast[type];
98
+ };
99
+
100
+ // src/client/infrastructure/toast/handle-toast.ts
101
+ var handleToast = (result, showToast) => {
102
+ const normalizedShowToast = typeof showToast === "object" ? {
103
+ success: showToast.success ?? true,
104
+ error: showToast.error ?? true
105
+ } : showToast ?? true;
106
+ if (result.success) {
107
+ const { message } = result;
108
+ if (shouldShowToast("success", normalizedShowToast) && message) {
109
+ toast.success(message);
110
+ }
111
+ } else {
112
+ const { message, errors } = result;
113
+ if (shouldShowToast("error", normalizedShowToast)) {
114
+ if (errors && errors.length > 0) {
115
+ toast.error(createErrorDisplay(errors));
116
+ } else if (message) {
117
+ toast.error(message);
118
+ } else {
119
+ toast.error("Unknown Error");
120
+ }
121
+ }
122
+ }
123
+ };
67
124
 
68
- export { createRequestInterceptor, createResponseInterceptor, createSmartFetch };
125
+ export { createErrorDisplay, createRequestInterceptor, createResponseInterceptor, createSmartFetch, handleToast, shouldShowToast };
package/dist/index.d.ts CHANGED
@@ -96,6 +96,10 @@ declare const jsonArrayToDb: (data?: unknown) => unknown[];
96
96
 
97
97
  declare const jsonArrayToUi: (data?: unknown[]) => string;
98
98
 
99
+ declare function ensureArray<T>(value: T | T[] | null | undefined): T[];
100
+
101
+ declare function formatDateTime(input?: string | Date): string;
102
+
99
103
  declare const SIZE: {
100
104
  readonly BYTE: 1;
101
105
  readonly KB: 1024;
@@ -106,4 +110,4 @@ declare const SIZE: {
106
110
  };
107
111
  type SizeUnit = keyof typeof SIZE;
108
112
 
109
- export { BaseTranslation, ErrorDetail, ErrorResult, type ErrorResultParams, FileCard, FileFull, Folder, FolderFull, OG_TYPE_ARRAY, type OgType, PostFull, ROOT_FOLDER, ROOT_FOLDER_ID, ROOT_FOLDER_NAME, SIMPLE_UPLOAD_FOLDER_KEY, SIMPLE_UPLOAD_FOLDER_NAME, SIZE, type SizeUnit, SuccessResult, type SuccessResultParams, TWITTER_CARD_ARRAY, type TwitterCard, classifyFileType, createBuildArticleMetadata, createBuildTranslations, createBuildWebsiteMetadata, datetimeToDb, datetimeToUi, findTranslation, formatFileSize, getMediaInfo, isFileLocked, isFolderLocked, jsonArrayToDb, jsonArrayToUi, mimeToExtension, result, serializeJsonLd };
113
+ export { BaseTranslation, ErrorDetail, ErrorResult, type ErrorResultParams, FileCard, FileFull, Folder, FolderFull, OG_TYPE_ARRAY, type OgType, PostFull, ROOT_FOLDER, ROOT_FOLDER_ID, ROOT_FOLDER_NAME, SIMPLE_UPLOAD_FOLDER_KEY, SIMPLE_UPLOAD_FOLDER_NAME, SIZE, type SizeUnit, SuccessResult, type SuccessResultParams, TWITTER_CARD_ARRAY, type TwitterCard, classifyFileType, createBuildArticleMetadata, createBuildTranslations, createBuildWebsiteMetadata, datetimeToDb, datetimeToUi, ensureArray, findTranslation, formatDateTime, formatFileSize, getMediaInfo, isFileLocked, isFolderLocked, jsonArrayToDb, jsonArrayToUi, mimeToExtension, result, serializeJsonLd };
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-N2PRNBP2.js';
2
+ export { FILE_TYPES, OG_TYPE_ARRAY, SIZE, TWITTER_CARD_ARRAY, classifyFileType, createBuildArticleMetadata, createBuildTranslations, createBuildWebsiteMetadata, datetimeToDb, datetimeToUi, ensureArray, findTranslation, formatDateTime, formatFileSize, getMediaInfo, jsonArrayToDb, jsonArrayToUi, mimeToExtension, result, serializeJsonLd } from './chunk-OAENV763.js';
@@ -1,5 +1,5 @@
1
1
  import { ADMIN_ROLES, isFileLocked, isFolderLocked, ROOT_FOLDER_ID, ROOT_FOLDER } from '../chunk-FUAJWL2N.js';
2
- import { SIZE, result, datetimeToDb, jsonArrayToDb, mimeToExtension, classifyFileType, TWITTER_CARD_ARRAY, OG_TYPE_ARRAY } from '../chunk-N2PRNBP2.js';
2
+ import { SIZE, result, datetimeToDb, jsonArrayToDb, mimeToExtension, classifyFileType, TWITTER_CARD_ARRAY, OG_TYPE_ARRAY } from '../chunk-OAENV763.js';
3
3
  import jwt from 'jsonwebtoken';
4
4
  import argon2 from 'argon2';
5
5
  import crypto, { timingSafeEqual } from 'crypto';
@@ -1,5 +1,5 @@
1
- import { createObjectKey } from '../../chunk-3J5YR2NA.js';
2
- import '../../chunk-N2PRNBP2.js';
1
+ import { createObjectKey } from '../../chunk-XWXG67I4.js';
2
+ import '../../chunk-OAENV763.js';
3
3
  import { PutObjectCommand, DeleteObjectCommand, CopyObjectCommand } from '@aws-sdk/client-s3';
4
4
 
5
5
  function createR2Service({
@@ -1,5 +1,5 @@
1
- import { createObjectKey } from '../../chunk-3J5YR2NA.js';
2
- import '../../chunk-N2PRNBP2.js';
1
+ import { createObjectKey } from '../../chunk-XWXG67I4.js';
2
+ import '../../chunk-OAENV763.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.75",
3
+ "version": "0.0.76",
4
4
  "author": "Yiming Liao",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -44,12 +44,14 @@
44
44
  },
45
45
  "dependencies": {
46
46
  "@keyv/redis": "^5.1.6",
47
+ "@types/react": "^19.2.14",
47
48
  "argon2": "^0.44.0",
48
49
  "jsonwebtoken": "^9.0.3",
49
50
  "keyv": "^5.6.0",
50
51
  "logry": "^2.1.6",
51
52
  "mime-types": "^3.0.2",
52
53
  "nodemailer": "^8.0.1",
54
+ "sonner": "^2.0.7",
53
55
  "ulid": "^3.0.2"
54
56
  },
55
57
  "devDependencies": {
@@ -73,6 +75,7 @@
73
75
  "knip": "^5.86.0",
74
76
  "next": "^16.1.6",
75
77
  "prisma": "6.5.0",
78
+ "react": "^19.2.4",
76
79
  "tsup": "^8.5.1",
77
80
  "typescript": "^5.9.3",
78
81
  "typescript-eslint": "^8.56.1",