@blinkk/root-cms 2.4.1 → 2.4.3

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.
package/dist/app.js CHANGED
@@ -83,7 +83,7 @@ function convertOneOfTypes(collection) {
83
83
  // package.json
84
84
  var package_default = {
85
85
  name: "@blinkk/root-cms",
86
- version: "2.4.1",
86
+ version: "2.4.3",
87
87
  author: "s@blinkk.com",
88
88
  license: "MIT",
89
89
  engines: {
@@ -143,7 +143,8 @@ var package_default = {
143
143
  "dev:core": "pnpm build:core --watch",
144
144
  "dev:signin": "pnpm build:signin --watch",
145
145
  "dev:ui": "pnpm build:ui --watch",
146
- test: "pnpm build && firebase emulators:exec 'vitest run'",
146
+ test: "pnpm build && firebase emulators:exec 'vitest run --exclude=**/*.visual.test.tsx'",
147
+ "test:visual": "vitest run --config=vitest.config.visual.ts",
147
148
  "test:watch": "pnpm build && firebase emulators:exec 'vitest'"
148
149
  },
149
150
  dependencies: {
@@ -190,6 +191,7 @@ var package_default = {
190
191
  "@lexical/react": "0.33.1",
191
192
  "@lexical/rich-text": "0.33.1",
192
193
  "@lexical/selection": "0.33.1",
194
+ "@lexical/table": "0.33.1",
193
195
  "@lexical/utils": "0.33.1",
194
196
  "@mantine/core": "4.2.12",
195
197
  "@mantine/hooks": "4.2.12",
@@ -198,6 +200,7 @@ var package_default = {
198
200
  "@mantine/spotlight": "4.2.12",
199
201
  "@preact/compat": "18.3.1",
200
202
  "@tabler/icons-preact": "3.35.0",
203
+ "@testing-library/preact": "3.2.4",
201
204
  "@types/body-parser": "1.19.3",
202
205
  "@types/fnv-plus": "1.3.2",
203
206
  "@types/gapi": "0.0.47",
@@ -206,6 +209,8 @@ var package_default = {
206
209
  "@types/google.accounts": "0.0.14",
207
210
  "@types/jsonwebtoken": "9.0.1",
208
211
  "@types/node": "24.3.1",
212
+ "@vitest/browser": "4.0.10",
213
+ "@vitest/browser-playwright": "4.0.10",
209
214
  concurrently: "7.6.0",
210
215
  esbuild: "0.25.9",
211
216
  firebase: "12.2.1",
@@ -219,6 +224,7 @@ var package_default = {
219
224
  "mdast-util-from-markdown": "2.0.1",
220
225
  "mdast-util-gfm": "3.0.0",
221
226
  "micromark-extension-gfm": "3.0.0",
227
+ playwright: "1.56.1",
222
228
  preact: "10.27.1",
223
229
  "preact-render-to-string": "6.6.1",
224
230
  "preact-router": "4.1.2",
@@ -228,11 +234,11 @@ var package_default = {
228
234
  tsup: "8.5.0",
229
235
  typescript: "5.9.2",
230
236
  vite: "7.1.4",
231
- vitest: "3.2.4",
237
+ vitest: "4.0.10",
232
238
  yjs: "13.6.27"
233
239
  },
234
240
  peerDependencies: {
235
- "@blinkk/root": "2.4.1",
241
+ "@blinkk/root": "2.4.3",
236
242
  "firebase-admin": ">=11",
237
243
  "firebase-functions": ">=4",
238
244
  preact: ">=10",
@@ -492,6 +492,14 @@ interface Action<T = any> {
492
492
  * Metadata for the action.
493
493
  */
494
494
  metadata?: T;
495
+ /**
496
+ * Optional list of quick links to display in the UI.
497
+ */
498
+ links?: {
499
+ label: string;
500
+ url: string;
501
+ target?: string;
502
+ }[];
495
503
  }
496
504
  interface ListActionsOptions {
497
505
  /**
@@ -706,6 +714,11 @@ declare class RootCMSClient {
706
714
  logAction(action: string, options?: {
707
715
  by?: string;
708
716
  metadata?: any;
717
+ links?: {
718
+ label: string;
719
+ url: string;
720
+ target?: string;
721
+ }[];
709
722
  }): Promise<void>;
710
723
  /**
711
724
  * Creates a batch request that is capable of fetching one or more docs,
package/dist/client.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  import '@blinkk/root';
2
2
  import 'firebase-admin/app';
3
3
  import 'firebase-admin/firestore';
4
- export { A as Action, p as ArrayObject, z as BatchRequest, B as BatchRequestOptions, w as BatchRequestQuery, x as BatchRequestQueryOptions, C as BatchResponse, c as DataSource, d as DataSourceData, e as DataSourceMode, b as Doc, D as DocMode, h as GetCountOptions, G as GetDocOptions, H as HttpMethod, k as ListActionsOptions, g as ListDocsOptions, L as LoadTranslationsOptions, a as LocaleTranslations, j as Release, R as RootCMSClient, f as SaveDraftOptions, S as SetDocOptions, i as Translation, y as TranslationsDoc, T as TranslationsMap, U as UserRole, m as getCmsPlugin, l as isRichTextData, q as marshalArray, n as marshalData, o as normalizeData, v as parseDocId, t as toArrayObject, s as translationsForLocale, r as unmarshalArray, u as unmarshalData } from './client-DK623LL2.js';
4
+ export { A as Action, p as ArrayObject, z as BatchRequest, B as BatchRequestOptions, w as BatchRequestQuery, x as BatchRequestQueryOptions, C as BatchResponse, c as DataSource, d as DataSourceData, e as DataSourceMode, b as Doc, D as DocMode, h as GetCountOptions, G as GetDocOptions, H as HttpMethod, k as ListActionsOptions, g as ListDocsOptions, L as LoadTranslationsOptions, a as LocaleTranslations, j as Release, R as RootCMSClient, f as SaveDraftOptions, S as SetDocOptions, i as Translation, y as TranslationsDoc, T as TranslationsMap, U as UserRole, m as getCmsPlugin, l as isRichTextData, q as marshalArray, n as marshalData, o as normalizeData, v as parseDocId, t as toArrayObject, s as translationsForLocale, r as unmarshalArray, u as unmarshalData } from './client-DYO2WWlf.js';
package/dist/client.js CHANGED
@@ -1136,6 +1136,9 @@ var RootCMSClient = class {
1136
1136
  by: options?.by || "system",
1137
1137
  metadata: options?.metadata || {}
1138
1138
  };
1139
+ if (options?.links) {
1140
+ data.links = options.links;
1141
+ }
1139
1142
  const colRef = this.db.collection(`Projects/${this.projectId}/ActionLogs`);
1140
1143
  await colRef.add(data);
1141
1144
  const metaStr = options?.metadata ? stringifyObj(options.metadata) : "";
package/dist/core.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { R as RootCMSClient, D as DocMode, L as LoadTranslationsOptions, T as TranslationsMap, a as LocaleTranslations } from './client-DK623LL2.js';
2
- export { A as Action, p as ArrayObject, z as BatchRequest, B as BatchRequestOptions, w as BatchRequestQuery, x as BatchRequestQueryOptions, C as BatchResponse, c as DataSource, d as DataSourceData, e as DataSourceMode, b as Doc, h as GetCountOptions, G as GetDocOptions, H as HttpMethod, k as ListActionsOptions, g as ListDocsOptions, E as Locale, N as MultiLocaleTranslationsMap, j as Release, f as SaveDraftOptions, S as SetDocOptions, O as SingleLocaleTranslationsMap, F as SourceString, I as TranslatedString, i as Translation, y as TranslationsDoc, J as TranslationsDocMode, M as TranslationsLocaleDocEntry, K as TranslationsLocaleDocHashMap, P as TranslationsManager, U as UserRole, Q as buildTranslationsDbPath, V as buildTranslationsLocaleDocDbPath, m as getCmsPlugin, l as isRichTextData, q as marshalArray, n as marshalData, o as normalizeData, v as parseDocId, t as toArrayObject, s as translationsForLocale, r as unmarshalArray, u as unmarshalData } from './client-DK623LL2.js';
1
+ import { R as RootCMSClient, D as DocMode, L as LoadTranslationsOptions, T as TranslationsMap, a as LocaleTranslations } from './client-DYO2WWlf.js';
2
+ export { A as Action, p as ArrayObject, z as BatchRequest, B as BatchRequestOptions, w as BatchRequestQuery, x as BatchRequestQueryOptions, C as BatchResponse, c as DataSource, d as DataSourceData, e as DataSourceMode, b as Doc, h as GetCountOptions, G as GetDocOptions, H as HttpMethod, k as ListActionsOptions, g as ListDocsOptions, E as Locale, N as MultiLocaleTranslationsMap, j as Release, f as SaveDraftOptions, S as SetDocOptions, O as SingleLocaleTranslationsMap, F as SourceString, I as TranslatedString, i as Translation, y as TranslationsDoc, J as TranslationsDocMode, M as TranslationsLocaleDocEntry, K as TranslationsLocaleDocHashMap, P as TranslationsManager, U as UserRole, Q as buildTranslationsDbPath, V as buildTranslationsLocaleDocDbPath, m as getCmsPlugin, l as isRichTextData, q as marshalArray, n as marshalData, o as normalizeData, v as parseDocId, t as toArrayObject, s as translationsForLocale, r as unmarshalArray, u as unmarshalData } from './client-DYO2WWlf.js';
3
3
  import { Request, RootConfig, Response, RouteParams, GetStaticProps, GetStaticPaths } from '@blinkk/root';
4
4
  import { Query } from 'firebase-admin/firestore';
5
5
  export { s as schema } from './schema-sKTRRRSq.js';
package/dist/core.js CHANGED
@@ -1142,6 +1142,9 @@ var RootCMSClient = class {
1142
1142
  by: options?.by || "system",
1143
1143
  metadata: options?.metadata || {}
1144
1144
  };
1145
+ if (options?.links) {
1146
+ data.links = options.links;
1147
+ }
1145
1148
  const colRef = this.db.collection(`Projects/${this.projectId}/ActionLogs`);
1146
1149
  await colRef.add(data);
1147
1150
  const metaStr = options?.metadata ? stringifyObj(options.metadata) : "";
package/dist/functions.js CHANGED
@@ -1141,6 +1141,9 @@ var RootCMSClient = class {
1141
1141
  by: options?.by || "system",
1142
1142
  metadata: options?.metadata || {}
1143
1143
  };
1144
+ if (options?.links) {
1145
+ data.links = options.links;
1146
+ }
1144
1147
  const colRef = this.db.collection(`Projects/${this.projectId}/ActionLogs`);
1145
1148
  await colRef.add(data);
1146
1149
  const metaStr = options?.metadata ? stringifyObj(options.metadata) : "";
package/dist/plugin.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  import '@blinkk/root';
2
2
  import 'firebase-admin/app';
3
3
  import 'firebase-admin/firestore';
4
- export { Y as CMSAIConfig, W as CMSBuiltInSidebarTool, $ as CMSPlugin, _ as CMSPluginOptions, Z as CMSSidebarTool, X as CMSUser, a0 as cmsPlugin } from './client-DK623LL2.js';
4
+ export { Y as CMSAIConfig, W as CMSBuiltInSidebarTool, $ as CMSPlugin, _ as CMSPluginOptions, Z as CMSSidebarTool, X as CMSUser, a0 as cmsPlugin } from './client-DYO2WWlf.js';
package/dist/plugin.js CHANGED
@@ -517,7 +517,11 @@ var Chat = class {
517
517
  modifiedAt: Timestamp.now()
518
518
  });
519
519
  if (options.mode === "edit") {
520
- return res.output;
520
+ const aiResponse = res.output;
521
+ if (aiResponse?.data && !aiResponse.message) {
522
+ aiResponse.message = "";
523
+ }
524
+ return aiResponse;
521
525
  }
522
526
  return { message: res.text, data: null };
523
527
  }
@@ -1756,6 +1760,9 @@ var RootCMSClient = class {
1756
1760
  by: options?.by || "system",
1757
1761
  metadata: options?.metadata || {}
1758
1762
  };
1763
+ if (options?.links) {
1764
+ data.links = options.links;
1765
+ }
1759
1766
  const colRef = this.db.collection(`Projects/${this.projectId}/ActionLogs`);
1760
1767
  await colRef.add(data);
1761
1768
  const metaStr = options?.metadata ? stringifyObj(options.metadata) : "";
@@ -2444,7 +2451,8 @@ function api(server, options) {
2444
2451
  try {
2445
2452
  await cmsClient.logAction(action, {
2446
2453
  by: req.user?.email,
2447
- metadata
2454
+ metadata,
2455
+ links: reqBody.links
2448
2456
  });
2449
2457
  res.status(200).json({ success: true });
2450
2458
  } catch (err) {
@@ -2552,7 +2560,7 @@ function api(server, options) {
2552
2560
  // package.json
2553
2561
  var package_default = {
2554
2562
  name: "@blinkk/root-cms",
2555
- version: "2.4.1",
2563
+ version: "2.4.3",
2556
2564
  author: "s@blinkk.com",
2557
2565
  license: "MIT",
2558
2566
  engines: {
@@ -2612,7 +2620,8 @@ var package_default = {
2612
2620
  "dev:core": "pnpm build:core --watch",
2613
2621
  "dev:signin": "pnpm build:signin --watch",
2614
2622
  "dev:ui": "pnpm build:ui --watch",
2615
- test: "pnpm build && firebase emulators:exec 'vitest run'",
2623
+ test: "pnpm build && firebase emulators:exec 'vitest run --exclude=**/*.visual.test.tsx'",
2624
+ "test:visual": "vitest run --config=vitest.config.visual.ts",
2616
2625
  "test:watch": "pnpm build && firebase emulators:exec 'vitest'"
2617
2626
  },
2618
2627
  dependencies: {
@@ -2659,6 +2668,7 @@ var package_default = {
2659
2668
  "@lexical/react": "0.33.1",
2660
2669
  "@lexical/rich-text": "0.33.1",
2661
2670
  "@lexical/selection": "0.33.1",
2671
+ "@lexical/table": "0.33.1",
2662
2672
  "@lexical/utils": "0.33.1",
2663
2673
  "@mantine/core": "4.2.12",
2664
2674
  "@mantine/hooks": "4.2.12",
@@ -2667,6 +2677,7 @@ var package_default = {
2667
2677
  "@mantine/spotlight": "4.2.12",
2668
2678
  "@preact/compat": "18.3.1",
2669
2679
  "@tabler/icons-preact": "3.35.0",
2680
+ "@testing-library/preact": "3.2.4",
2670
2681
  "@types/body-parser": "1.19.3",
2671
2682
  "@types/fnv-plus": "1.3.2",
2672
2683
  "@types/gapi": "0.0.47",
@@ -2675,6 +2686,8 @@ var package_default = {
2675
2686
  "@types/google.accounts": "0.0.14",
2676
2687
  "@types/jsonwebtoken": "9.0.1",
2677
2688
  "@types/node": "24.3.1",
2689
+ "@vitest/browser": "4.0.10",
2690
+ "@vitest/browser-playwright": "4.0.10",
2678
2691
  concurrently: "7.6.0",
2679
2692
  esbuild: "0.25.9",
2680
2693
  firebase: "12.2.1",
@@ -2688,6 +2701,7 @@ var package_default = {
2688
2701
  "mdast-util-from-markdown": "2.0.1",
2689
2702
  "mdast-util-gfm": "3.0.0",
2690
2703
  "micromark-extension-gfm": "3.0.0",
2704
+ playwright: "1.56.1",
2691
2705
  preact: "10.27.1",
2692
2706
  "preact-render-to-string": "6.6.1",
2693
2707
  "preact-router": "4.1.2",
@@ -2697,11 +2711,11 @@ var package_default = {
2697
2711
  tsup: "8.5.0",
2698
2712
  typescript: "5.9.2",
2699
2713
  vite: "7.1.4",
2700
- vitest: "3.2.4",
2714
+ vitest: "4.0.10",
2701
2715
  yjs: "13.6.27"
2702
2716
  },
2703
2717
  peerDependencies: {
2704
- "@blinkk/root": "2.4.1",
2718
+ "@blinkk/root": "2.4.3",
2705
2719
  "firebase-admin": ">=11",
2706
2720
  "firebase-functions": ">=4",
2707
2721
  preact: ">=10",
@@ -23,10 +23,13 @@ interface RichTextProps {
23
23
  declare function RichText(props: RichTextProps): preact.JSX.Element;
24
24
  declare namespace RichText {
25
25
  var ParagraphBlock: (props: RichTextParagraphBlockProps) => preact.JSX.Element | null;
26
+ var DelimiterBlock: () => preact.JSX.Element;
26
27
  var HeadingBlock: (props: RichTextHeadingBlockProps) => preact.JSX.Element | null;
28
+ var QuoteBlock: (props: RichTextQuoteBlockProps) => preact.JSX.Element | null;
27
29
  var ListBlock: (props: RichTextListBlockProps) => preact.JSX.Element | null;
28
30
  var ImageBlock: (props: RichTextImageBlockProps) => preact.JSX.Element | null;
29
31
  var HtmlBlock: (props: RichTextHtmlBlockProps) => preact.JSX.Element | null;
32
+ var TableBlock: (props: RichTextTableBlockProps) => preact.JSX.Element | null;
30
33
  }
31
34
  interface RichTextParagraphBlockProps {
32
35
  type: 'paragraph';
@@ -34,6 +37,10 @@ interface RichTextParagraphBlockProps {
34
37
  text?: string;
35
38
  };
36
39
  }
40
+ interface RichTextDelimiterBlockProps {
41
+ type: 'delimiter';
42
+ data?: {};
43
+ }
37
44
  interface RichTextHeadingBlockProps {
38
45
  type: 'heading';
39
46
  data?: {
@@ -41,6 +48,12 @@ interface RichTextHeadingBlockProps {
41
48
  text?: string;
42
49
  };
43
50
  }
51
+ interface RichTextQuoteBlockProps {
52
+ type: 'quote';
53
+ data?: {
54
+ text?: string;
55
+ };
56
+ }
44
57
  interface ListItem {
45
58
  content?: string;
46
59
  items?: ListItem[];
@@ -69,5 +82,16 @@ interface RichTextHtmlBlockProps {
69
82
  html?: string;
70
83
  };
71
84
  }
85
+ interface RichTextTableBlockProps {
86
+ type: 'table';
87
+ data?: {
88
+ rows?: Array<{
89
+ cells: Array<{
90
+ blocks: RichTextBlock[];
91
+ type: 'header' | 'data';
92
+ }>;
93
+ }>;
94
+ };
95
+ }
72
96
 
73
- export { RichText, type RichTextBlock, type RichTextBlockComponent, RichTextContext, type RichTextContextProps, type RichTextData, type RichTextHeadingBlockProps, type RichTextHtmlBlockProps, type RichTextImageBlockProps, type RichTextListBlockProps, type RichTextParagraphBlockProps, type RichTextProps, useRichTextContext };
97
+ export { RichText, type RichTextBlock, type RichTextBlockComponent, RichTextContext, type RichTextContextProps, type RichTextData, type RichTextDelimiterBlockProps, type RichTextHeadingBlockProps, type RichTextHtmlBlockProps, type RichTextImageBlockProps, type RichTextListBlockProps, type RichTextParagraphBlockProps, type RichTextProps, type RichTextQuoteBlockProps, type RichTextTableBlockProps, useRichTextContext };
package/dist/richtext.js CHANGED
@@ -10,11 +10,14 @@ function useRichTextContext() {
10
10
  function RichText(props) {
11
11
  const richTextContext = useRichTextContext();
12
12
  const components = {
13
+ delimiter: RichText.DelimiterBlock,
13
14
  heading: RichText.HeadingBlock,
14
15
  html: RichText.HtmlBlock,
15
16
  image: RichText.ImageBlock,
16
17
  orderedList: RichText.ListBlock,
17
18
  paragraph: RichText.ParagraphBlock,
19
+ quote: RichText.QuoteBlock,
20
+ table: RichText.TableBlock,
18
21
  unorderedList: RichText.ListBlock,
19
22
  ...richTextContext.components,
20
23
  ...props.components
@@ -42,6 +45,9 @@ RichText.ParagraphBlock = (props) => {
42
45
  const t = useTranslations();
43
46
  return /* @__PURE__ */ jsx("p", { dangerouslySetInnerHTML: { __html: t(props.data.text) } });
44
47
  };
48
+ RichText.DelimiterBlock = () => {
49
+ return /* @__PURE__ */ jsx("hr", {});
50
+ };
45
51
  RichText.HeadingBlock = (props) => {
46
52
  if (!props.data?.text) {
47
53
  return null;
@@ -51,6 +57,13 @@ RichText.HeadingBlock = (props) => {
51
57
  const Component = `h${level}`;
52
58
  return /* @__PURE__ */ jsx(Component, { dangerouslySetInnerHTML: { __html: t(props.data.text) } });
53
59
  };
60
+ RichText.QuoteBlock = (props) => {
61
+ if (!props.data?.text) {
62
+ return null;
63
+ }
64
+ const t = useTranslations();
65
+ return /* @__PURE__ */ jsx("blockquote", { dangerouslySetInnerHTML: { __html: t(props.data.text) } });
66
+ };
54
67
  RichText.ListBlock = (props) => {
55
68
  if (!props.data?.items?.length) {
56
69
  return null;
@@ -100,6 +113,24 @@ RichText.HtmlBlock = (props) => {
100
113
  }
101
114
  return /* @__PURE__ */ jsx("div", { dangerouslySetInnerHTML: { __html: html } });
102
115
  };
116
+ RichText.TableBlock = (props) => {
117
+ const rows = props.data?.rows || [];
118
+ const richTextContext = useRichTextContext();
119
+ if (rows.length === 0) {
120
+ return null;
121
+ }
122
+ return /* @__PURE__ */ jsx("table", { children: /* @__PURE__ */ jsx("tbody", { children: rows.map((row, rowIndex) => /* @__PURE__ */ jsx("tr", { children: row.cells.map((cell, cellIndex) => {
123
+ const isHeader = cell.type === "header";
124
+ const Cell = isHeader ? "th" : "td";
125
+ return /* @__PURE__ */ jsx(Cell, { children: /* @__PURE__ */ jsx(
126
+ RichText,
127
+ {
128
+ data: { blocks: cell.blocks, time: 0, version: "" },
129
+ components: richTextContext.components
130
+ }
131
+ ) }, cellIndex);
132
+ }) }, rowIndex)) }) });
133
+ };
103
134
  function toNumber(input) {
104
135
  if (input === void 0) {
105
136
  return 0;