@yimingliao/cms 0.0.250 → 0.0.252

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.
@@ -4,15 +4,20 @@ import { ThemeProvider as ThemeProvider$1 } from 'next-themes';
4
4
 
5
5
  function ThemeProvider({
6
6
  children,
7
+ defaultTheme = "system",
8
+ enableSystem = true,
9
+ disableTransitionOnChange = true,
10
+ storageKey = "cms-theme",
7
11
  ...props
8
12
  }) {
9
13
  return /* @__PURE__ */ jsx(
10
14
  ThemeProvider$1,
11
15
  {
12
16
  attribute: "class",
13
- defaultTheme: "system",
14
- enableSystem: true,
15
- disableTransitionOnChange: true,
17
+ defaultTheme,
18
+ enableSystem,
19
+ disableTransitionOnChange,
20
+ storageKey,
16
21
  ...props,
17
22
  children
18
23
  }
@@ -5,18 +5,27 @@ import 'mime-types';
5
5
  import { cn } from '../../../../applications/cms/shadcn/utils.js';
6
6
  import 'next/navigation';
7
7
 
8
+ const FIGURE_OEMBED_PATTERN = /<figure\b[^>]*\bclass=(["'])[^"']*\bmedia\b[^"']*\1[^>]*>\s*<oembed\b[^>]*\burl=(["'])(.*?)\2[^>]*>\s*<\/oembed>\s*<\/figure>/gi;
9
+ const YOUTUBE_VIDEO_ID_PATTERN = /^[\w-]{11}$/;
10
+ const HTML_ESCAPE_MAP = {
11
+ '"': "&quot;",
12
+ "&": "&amp;",
13
+ "<": "&lt;",
14
+ ">": "&gt;"
15
+ };
8
16
  function HtmlDisplay({
9
17
  html = "",
10
- textOnly,
18
+ textOnly = false,
11
19
  className = "",
12
20
  ...props
13
21
  }) {
14
- const content = textOnly ? normalizeHtmlText(html) : html ?? "";
22
+ const content = textOnly ? toPlainText(html) : normalizeHtml(html ?? "");
15
23
  return /* @__PURE__ */ jsx(
16
24
  "div",
17
25
  {
18
26
  className: cn(
19
27
  className,
28
+ "w-full",
20
29
  "ck ck-content"
21
30
  // CKEditor styles prefix: .ck (ckeditor.css)
22
31
  ),
@@ -25,9 +34,94 @@ function HtmlDisplay({
25
34
  }
26
35
  );
27
36
  }
28
- function normalizeHtmlText(html) {
37
+ function toPlainText(html) {
29
38
  if (!html) return "";
30
- return html.replace(/<\/(p|div|li|h[1-6]|tr|td)>/gi, " ").replace(/<br\s*\/?>/gi, " ").replace(/<[^>]+>/g, " ").replace(/\r?\n|\r/g, " ").replace(/\s{2,}/g, " ").trim();
39
+ return removeMediaContent(html).replace(/<\/(p|div|li|h[1-6]|tr|td)>/gi, " ").replace(/<br\s*\/?>/gi, " ").replace(/<[^>]+>/g, " ").replace(/\r?\n|\r/g, " ").replace(/\s{2,}/g, " ").replace(/\s+([,。!?;:、])/g, "$1").trim();
40
+ }
41
+ function normalizeHtml(html) {
42
+ if (!html) return "";
43
+ return html.replace(
44
+ FIGURE_OEMBED_PATTERN,
45
+ (figureHtml, _classQuote, _urlQuote, rawUrl) => {
46
+ const embedHtml = createEmbedHtml(rawUrl);
47
+ return embedHtml ?? createEmbedFallbackHtml(rawUrl, figureHtml);
48
+ }
49
+ );
50
+ }
51
+ function removeMediaContent(html) {
52
+ return html.replace(FIGURE_OEMBED_PATTERN, " ").replace(/<iframe\b[^>]*>[\s\S]*?<\/iframe>/gi, " ").replace(/<video\b[^>]*>[\s\S]*?<\/video>/gi, " ").replace(/<picture\b[^>]*>[\s\S]*?<\/picture>/gi, " ").replace(/<img\b[^>]*>/gi, " ").replace(/<source\b[^>]*>/gi, " ");
53
+ }
54
+ function createEmbedHtml(rawUrl) {
55
+ const embedUrl = getYouTubeEmbedUrl(rawUrl);
56
+ if (!embedUrl) return null;
57
+ return `<iframe
58
+ src="${escapeHtmlAttribute(embedUrl)}"
59
+ title="Embedded media"
60
+ frameborder="0"
61
+ loading="lazy"
62
+ referrerpolicy="strict-origin-when-cross-origin"
63
+ allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
64
+ allowfullscreen
65
+ class="media"
66
+ style="display: block; width: 100%; aspect-ratio: 16 / 9; border: 0;"
67
+ ></iframe>`.trim();
68
+ }
69
+ function createEmbedFallbackHtml(rawUrl, fallbackHtml) {
70
+ const safeUrl = getSafeExternalUrl(rawUrl);
71
+ if (!safeUrl) return fallbackHtml;
72
+ return `<figure class="media">
73
+ <a
74
+ href="${escapeHtmlAttribute(safeUrl)}"
75
+ target="_blank"
76
+ rel="noreferrer noopener"
77
+ >
78
+ ${escapeHtmlText(safeUrl)}
79
+ </a>
80
+ </figure>`.trim();
81
+ }
82
+ function getYouTubeEmbedUrl(rawUrl) {
83
+ const url = safeParseUrl(rawUrl);
84
+ if (!url) return null;
85
+ const hostname = url.hostname.toLowerCase().replace(/^www\./, "");
86
+ let videoId = "";
87
+ if (hostname === "youtu.be") {
88
+ videoId = url.pathname.split("/").filter(Boolean)[0] ?? "";
89
+ } else if (hostname === "youtube.com" || hostname === "m.youtube.com") {
90
+ if (url.pathname === "/watch") {
91
+ videoId = url.searchParams.get("v") ?? "";
92
+ } else if (url.pathname.startsWith("/embed/")) {
93
+ videoId = url.pathname.split("/")[2] ?? "";
94
+ } else if (url.pathname.startsWith("/shorts/")) {
95
+ videoId = url.pathname.split("/")[2] ?? "";
96
+ }
97
+ }
98
+ if (!YOUTUBE_VIDEO_ID_PATTERN.test(videoId)) return null;
99
+ return `https://www.youtube-nocookie.com/embed/${videoId}`;
100
+ }
101
+ function getSafeExternalUrl(rawUrl) {
102
+ const url = safeParseUrl(rawUrl);
103
+ if (!url) return null;
104
+ if (url.protocol !== "http:" && url.protocol !== "https:") return null;
105
+ return url.toString();
106
+ }
107
+ function safeParseUrl(rawUrl) {
108
+ try {
109
+ return new URL(rawUrl);
110
+ } catch {
111
+ return null;
112
+ }
113
+ }
114
+ function escapeHtmlAttribute(value) {
115
+ return value.replaceAll(
116
+ /["&<>]/g,
117
+ (character) => HTML_ESCAPE_MAP[character] ?? character
118
+ );
119
+ }
120
+ function escapeHtmlText(value) {
121
+ return value.replaceAll(
122
+ /[&<>]/g,
123
+ (character) => HTML_ESCAPE_MAP[character] ?? character
124
+ );
31
125
  }
32
126
 
33
127
  export { HtmlDisplay };
@@ -16,7 +16,7 @@ const POST_LIST_CARD_INCLUDE = {
16
16
  // ---------------------------
17
17
  // relations: File
18
18
  // ---------------------------
19
- coverImage: true,
19
+ coverImage: { include: { translations: true } },
20
20
  // ---------------------------
21
21
  // translation
22
22
  // ---------------------------
@@ -1,8 +1,8 @@
1
+ import type { PostListCard } from "../../../../../domain";
1
2
  import type { PageIdentity } from "../get-page-identity";
2
3
  import type { createMapCategoryItem } from "./map-category-item";
3
4
  import type { createMapPostItem } from "./map-post-item";
4
5
  import type { CategoryItem, EntityType, ListMode, PostItem } from "./types";
5
- import type { PostListCard } from "@yimingliao/cms";
6
6
  export declare function createResolveTopicItemList({ mapCategoryItem, mapPostItem, }: {
7
7
  mapCategoryItem: ReturnType<typeof createMapCategoryItem>;
8
8
  mapPostItem: ReturnType<typeof createMapPostItem>;
@@ -1 +1 @@
1
- {"version":3,"file":"resolve-topic-item-list.d.ts","sourceRoot":"","sources":["../../../../../../../../src/client/applications/web/structured-data/resolve-topic-item-list/resolve-topic-item-list.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AACjE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC5E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAEpD,wBAAgB,0BAA0B,CAAC,EACzC,eAAe,EACf,WAAW,GACZ,EAAE;IACD,eAAe,EAAE,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAC;IAC1D,WAAW,EAAE,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC;CACnD,IACsC,iEAMlC;IACD,QAAQ,EAAE,QAAQ,CAAC;IACnB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,YAAY,EAAE,YAAY,CAAC;IAC3B,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;CACtB;;;EAqBF"}
1
+ {"version":3,"file":"resolve-topic-item-list.d.ts","sourceRoot":"","sources":["../../../../../../../../src/client/applications/web/structured-data/resolve-topic-item-list/resolve-topic-item-list.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AACjE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAE5E,wBAAgB,0BAA0B,CAAC,EACzC,eAAe,EACf,WAAW,GACZ,EAAE;IACD,eAAe,EAAE,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAC;IAC1D,WAAW,EAAE,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC;CACnD,IACsC,iEAMlC;IACD,QAAQ,EAAE,QAAQ,CAAC;IACnB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,YAAY,EAAE,YAAY,CAAC;IAC3B,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;CACtB;;;EAqBF"}
@@ -1,4 +1,4 @@
1
1
  import { ThemeProvider as NextThemesProvider } from "next-themes";
2
2
  import * as React from "react";
3
- export declare function ThemeProvider({ children, ...props }: React.ComponentProps<typeof NextThemesProvider>): import("react/jsx-runtime").JSX.Element;
3
+ export declare function ThemeProvider({ children, defaultTheme, enableSystem, disableTransitionOnChange, storageKey, ...props }: React.ComponentProps<typeof NextThemesProvider>): import("react/jsx-runtime").JSX.Element;
4
4
  //# sourceMappingURL=theme.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../../../../../src/client/infrastructure/contexts/theme.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,IAAI,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,wBAAgB,aAAa,CAAC,EAC5B,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,kBAAkB,CAAC,2CAYjD"}
1
+ {"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../../../../../src/client/infrastructure/contexts/theme.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,IAAI,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,wBAAgB,aAAa,CAAC,EAC5B,QAAQ,EACR,YAAuB,EACvB,YAAmB,EACnB,yBAAgC,EAChC,UAAwB,EACxB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,kBAAkB,CAAC,2CAajD"}
@@ -3,6 +3,9 @@ interface HtmlDisplayProps extends HTMLAttributes<HTMLDivElement> {
3
3
  html?: string | null;
4
4
  textOnly?: boolean;
5
5
  }
6
+ /**
7
+ * Render CMS HTML content with CKEditor-compatible media transforms.
8
+ */
6
9
  export declare function HtmlDisplay({ html, textOnly, className, ...props }: HtmlDisplayProps): import("react/jsx-runtime").JSX.Element;
7
10
  export {};
8
11
  //# sourceMappingURL=html-display.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"html-display.d.ts","sourceRoot":"","sources":["../../../../../../../../src/client/interfaces/components/ui/display/html-display.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAG5C,UAAU,gBAAiB,SAAQ,cAAc,CAAC,cAAc,CAAC;IAC/D,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,wBAAgB,WAAW,CAAC,EAC1B,IAAS,EACT,QAAQ,EACR,SAAc,EACd,GAAG,KAAK,EACT,EAAE,gBAAgB,2CAalB"}
1
+ {"version":3,"file":"html-display.d.ts","sourceRoot":"","sources":["../../../../../../../../src/client/interfaces/components/ui/display/html-display.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAa5C,UAAU,gBAAiB,SAAQ,cAAc,CAAC,cAAc,CAAC;IAC/D,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,EAC1B,IAAS,EACT,QAAgB,EAChB,SAAc,EACd,GAAG,KAAK,EACT,EAAE,gBAAgB,2CAclB"}
@@ -1,6 +1,6 @@
1
1
  import type { Post } from "./base";
2
2
  import type { PostTranslation } from "./translation";
3
- import type { File } from "../file";
3
+ import type { FileCard } from "../file";
4
4
  export type PostListCard = Post & {
5
5
  topic: (Post & {
6
6
  translations: PostTranslation[];
@@ -11,7 +11,7 @@ export type PostListCard = Post & {
11
11
  tags: (Post & {
12
12
  translations: PostTranslation[];
13
13
  })[];
14
- coverImage: File | null;
14
+ coverImage: FileCard | null;
15
15
  translations: PostTranslation[];
16
16
  };
17
17
  //# sourceMappingURL=card.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"card.d.ts","sourceRoot":"","sources":["../../../../../../src/domain/resources/post/card.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AACnC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAEpC,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG;IAIhC,KAAK,EAAE,CAAC,IAAI,GAAG;QAAE,YAAY,EAAE,eAAe,EAAE,CAAA;KAAE,CAAC,GAAG,IAAI,CAAC;IAC3D,YAAY,EAAE,IAAI,EAAE,CAAC;IACrB,QAAQ,EAAE,IAAI,EAAE,CAAC;IACjB,WAAW,EAAE,IAAI,EAAE,CAAC;IACpB,IAAI,EAAE,CAAC,IAAI,GAAG;QAAE,YAAY,EAAE,eAAe,EAAE,CAAA;KAAE,CAAC,EAAE,CAAC;IAKrD,UAAU,EAAE,IAAI,GAAG,IAAI,CAAC;IAKxB,YAAY,EAAE,eAAe,EAAE,CAAC;CACjC,CAAC"}
1
+ {"version":3,"file":"card.d.ts","sourceRoot":"","sources":["../../../../../../src/domain/resources/post/card.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AACnC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAExC,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG;IAIhC,KAAK,EAAE,CAAC,IAAI,GAAG;QAAE,YAAY,EAAE,eAAe,EAAE,CAAA;KAAE,CAAC,GAAG,IAAI,CAAC;IAC3D,YAAY,EAAE,IAAI,EAAE,CAAC;IACrB,QAAQ,EAAE,IAAI,EAAE,CAAC;IACjB,WAAW,EAAE,IAAI,EAAE,CAAC;IACpB,IAAI,EAAE,CAAC,IAAI,GAAG;QAAE,YAAY,EAAE,eAAe,EAAE,CAAA;KAAE,CAAC,EAAE,CAAC;IAKrD,UAAU,EAAE,QAAQ,GAAG,IAAI,CAAC;IAK5B,YAAY,EAAE,eAAe,EAAE,CAAC;CACjC,CAAC"}
@@ -12,7 +12,11 @@ export declare const POST_LIST_CARD_INCLUDE: {
12
12
  translations: true;
13
13
  };
14
14
  };
15
- coverImage: true;
15
+ coverImage: {
16
+ include: {
17
+ translations: true;
18
+ };
19
+ };
16
20
  translations: true;
17
21
  };
18
22
  export declare const POST_FULL_INCLUDE: {
@@ -46,7 +50,11 @@ export declare const POST_FULL_INCLUDE: {
46
50
  translations: true;
47
51
  };
48
52
  };
49
- coverImage: true;
53
+ coverImage: {
54
+ include: {
55
+ translations: true;
56
+ };
57
+ };
50
58
  translations: true;
51
59
  };
52
60
  };
@@ -65,7 +73,11 @@ export declare const POST_FULL_INCLUDE: {
65
73
  translations: true;
66
74
  };
67
75
  };
68
- coverImage: true;
76
+ coverImage: {
77
+ include: {
78
+ translations: true;
79
+ };
80
+ };
69
81
  translations: true;
70
82
  };
71
83
  };
@@ -84,7 +96,11 @@ export declare const POST_FULL_INCLUDE: {
84
96
  translations: true;
85
97
  };
86
98
  };
87
- coverImage: true;
99
+ coverImage: {
100
+ include: {
101
+ translations: true;
102
+ };
103
+ };
88
104
  translations: true;
89
105
  };
90
106
  };
@@ -103,7 +119,11 @@ export declare const POST_FULL_INCLUDE: {
103
119
  translations: true;
104
120
  };
105
121
  };
106
- coverImage: true;
122
+ coverImage: {
123
+ include: {
124
+ translations: true;
125
+ };
126
+ };
107
127
  translations: true;
108
128
  };
109
129
  };
@@ -122,7 +142,11 @@ export declare const POST_FULL_INCLUDE: {
122
142
  translations: true;
123
143
  };
124
144
  };
125
- coverImage: true;
145
+ coverImage: {
146
+ include: {
147
+ translations: true;
148
+ };
149
+ };
126
150
  translations: true;
127
151
  };
128
152
  };
@@ -141,7 +165,11 @@ export declare const POST_FULL_INCLUDE: {
141
165
  translations: true;
142
166
  };
143
167
  };
144
- coverImage: true;
168
+ coverImage: {
169
+ include: {
170
+ translations: true;
171
+ };
172
+ };
145
173
  translations: true;
146
174
  };
147
175
  };
@@ -160,7 +188,11 @@ export declare const POST_FULL_INCLUDE: {
160
188
  translations: true;
161
189
  };
162
190
  };
163
- coverImage: true;
191
+ coverImage: {
192
+ include: {
193
+ translations: true;
194
+ };
195
+ };
164
196
  translations: true;
165
197
  };
166
198
  };
@@ -179,7 +211,11 @@ export declare const POST_FULL_INCLUDE: {
179
211
  translations: true;
180
212
  };
181
213
  };
182
- coverImage: true;
214
+ coverImage: {
215
+ include: {
216
+ translations: true;
217
+ };
218
+ };
183
219
  translations: true;
184
220
  };
185
221
  };
@@ -1 +1 @@
1
- {"version":3,"file":"include.d.ts","sourceRoot":"","sources":["../../../../../../../src/server/infrastructure/database/post/include.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;CAmBL,CAAC;AAE/B,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgDA,CAAC"}
1
+ {"version":3,"file":"include.d.ts","sourceRoot":"","sources":["../../../../../../../src/server/infrastructure/database/post/include.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;CAmBL,CAAC;AAE/B,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgDA,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yimingliao/cms",
3
- "version": "0.0.250",
3
+ "version": "0.0.252",
4
4
  "author": "Yiming Liao",
5
5
  "license": "MIT",
6
6
  "type": "module",