@blinkk/root-cms 3.0.1-alpha.0 → 3.0.1-beta.2

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/plugin.js CHANGED
@@ -1,18 +1,27 @@
1
1
  import {
2
- ChatClient,
3
- summarizeDiff
4
- } from "./chunk-T5UK2H24.js";
5
- import {
6
- getServerVersion
7
- } from "./chunk-N4Z3O53K.js";
2
+ ChatStore,
3
+ findModel,
4
+ generateAltText,
5
+ generateImage,
6
+ generatePublishMessage,
7
+ getAiConfig,
8
+ getServerVersion,
9
+ runChatStream,
10
+ runEditObjectStream,
11
+ serializeAiConfig,
12
+ summarizeDiff,
13
+ translateString
14
+ } from "./chunk-ATPWU3CU.js";
8
15
  import {
16
+ SearchIndexService,
9
17
  runCronJobs
10
- } from "./chunk-H6ZKML2S.js";
18
+ } from "./chunk-TRM4MQHU.js";
11
19
  import {
12
20
  RootCMSClient,
13
21
  parseDocId,
14
22
  unmarshalData
15
- } from "./chunk-YMUZ5H5C.js";
23
+ } from "./chunk-F4SODS5S.js";
24
+ import "./chunk-CRK7N6RR.js";
16
25
  import "./chunk-MLKGABMK.js";
17
26
 
18
27
  // core/plugin.ts
@@ -109,6 +118,31 @@ function isRecord(value) {
109
118
  function isDocVersion(value) {
110
119
  return value === "draft" || value === "published";
111
120
  }
121
+ async function pipeWebResponse(webResponse, res) {
122
+ res.status(webResponse.status);
123
+ webResponse.headers.forEach((value, key) => {
124
+ res.setHeader(key, value);
125
+ });
126
+ res.setHeader("X-Accel-Buffering", "no");
127
+ if (!webResponse.body) {
128
+ res.end();
129
+ return;
130
+ }
131
+ const reader = webResponse.body.getReader();
132
+ try {
133
+ let done = false;
134
+ while (!done) {
135
+ const next = await reader.read();
136
+ done = next.done;
137
+ if (next.value) {
138
+ res.write(next.value);
139
+ }
140
+ }
141
+ } finally {
142
+ reader.releaseLock();
143
+ res.end();
144
+ }
145
+ }
112
146
  function api(server, options) {
113
147
  async function getCollectionSchema(req, collectionId) {
114
148
  if (req.viteServer) {
@@ -160,13 +194,96 @@ function api(server, options) {
160
194
  });
161
195
  server.use("/cms/api/cron.run", async (req, res) => {
162
196
  try {
163
- await runCronJobs(req.rootConfig);
197
+ await runCronJobs(req.rootConfig, {
198
+ loadSchema: (collectionId) => getCollectionSchema(req, collectionId)
199
+ });
164
200
  res.status(200).json({ success: true });
165
201
  } catch (err) {
166
202
  console.error(err);
167
203
  res.status(500).json({ success: false });
168
204
  }
169
205
  });
206
+ const searchRebuildJobs = /* @__PURE__ */ new Map();
207
+ server.use("/cms/api/search.query", async (req, res) => {
208
+ if (req.method !== "POST" || !String(req.get("content-type")).startsWith("application/json")) {
209
+ res.status(400).json({ success: false, error: "BAD_REQUEST" });
210
+ return;
211
+ }
212
+ if (!req.user?.email) {
213
+ res.status(401).json({ success: false, error: "UNAUTHORIZED" });
214
+ return;
215
+ }
216
+ const body = req.body || {};
217
+ const q = typeof body.q === "string" ? body.q : "";
218
+ const limit = typeof body.limit === "number" ? body.limit : 25;
219
+ try {
220
+ const service = new SearchIndexService(req.rootConfig);
221
+ const result = await service.search(q, { limit });
222
+ res.setHeader("Cache-Control", "no-store");
223
+ res.status(200).json({ success: true, ...result });
224
+ } catch (err) {
225
+ console.error(err.stack || err);
226
+ res.status(500).json({ success: false, error: "UNKNOWN" });
227
+ }
228
+ });
229
+ server.use("/cms/api/search.status", async (req, res) => {
230
+ if (!req.user?.email) {
231
+ res.status(401).json({ success: false, error: "UNAUTHORIZED" });
232
+ return;
233
+ }
234
+ try {
235
+ const cmsClient = new RootCMSClient(req.rootConfig);
236
+ const service = new SearchIndexService(req.rootConfig);
237
+ const status = await service.getStatus();
238
+ const running = searchRebuildJobs.has(cmsClient.projectId);
239
+ res.setHeader("Cache-Control", "no-store");
240
+ res.status(200).json({ success: true, status, running });
241
+ } catch (err) {
242
+ console.error(err.stack || err);
243
+ res.status(500).json({ success: false, error: "UNKNOWN" });
244
+ }
245
+ });
246
+ server.use("/cms/api/search.rebuild", async (req, res) => {
247
+ if (req.method !== "POST") {
248
+ res.status(400).json({ success: false, error: "BAD_REQUEST" });
249
+ return;
250
+ }
251
+ if (!req.user?.email) {
252
+ res.status(401).json({ success: false, error: "UNAUTHORIZED" });
253
+ return;
254
+ }
255
+ const cmsClient = new RootCMSClient(req.rootConfig);
256
+ try {
257
+ const role = await cmsClient.getUserRole(req.user.email);
258
+ if (role !== "ADMIN") {
259
+ res.status(403).json({ success: false, error: "FORBIDDEN" });
260
+ return;
261
+ }
262
+ } catch (err) {
263
+ console.error(err.stack || err);
264
+ res.status(500).json({ success: false, error: "UNKNOWN" });
265
+ return;
266
+ }
267
+ const body = req.body || {};
268
+ const force = !!body.force;
269
+ const projectId = cmsClient.projectId;
270
+ if (searchRebuildJobs.has(projectId)) {
271
+ res.status(202).json({ success: true, alreadyRunning: true });
272
+ return;
273
+ }
274
+ const service = new SearchIndexService(
275
+ req.rootConfig,
276
+ (collectionId) => getCollectionSchema(req, collectionId)
277
+ );
278
+ const job = service.rebuildIndex({ force }).catch((err) => {
279
+ console.error("search.rebuild failed:", err.stack || err);
280
+ throw err;
281
+ }).finally(() => {
282
+ searchRebuildJobs.delete(projectId);
283
+ });
284
+ searchRebuildJobs.set(projectId, job);
285
+ res.status(202).json({ success: true, started: true, force });
286
+ });
170
287
  server.use("/cms/api/csv.download", (req, res) => {
171
288
  if (req.method !== "POST" || !String(req.get("content-type")).startsWith("application/json")) {
172
289
  res.status(400).json({ success: false, error: "BAD_REQUEST" });
@@ -258,39 +375,6 @@ function api(server, options) {
258
375
  res.status(500).json({ success: false, error: "UNKNOWN" });
259
376
  }
260
377
  });
261
- server.use("/cms/api/ai.chat", async (req, res) => {
262
- if (req.method !== "POST" || !String(req.get("content-type")).startsWith("application/json")) {
263
- res.status(400).json({ success: false, error: "BAD_REQUEST" });
264
- return;
265
- }
266
- if (!req.user?.email) {
267
- res.status(401).json({ success: false, error: "UNAUTHORIZED" });
268
- return;
269
- }
270
- const reqBody = req.body || {};
271
- if (!reqBody.prompt) {
272
- res.status(400).json({ success: false, error: "MISSING_PROMPT" });
273
- return;
274
- }
275
- const prompt = reqBody.prompt;
276
- try {
277
- const cmsClient = new RootCMSClient(req.rootConfig);
278
- const chatClient = new ChatClient(cmsClient, req.user.email);
279
- const chat = await chatClient.getOrCreateChat(reqBody.chatId);
280
- const apiResponse = {
281
- success: true,
282
- chatId: chat.id,
283
- response: await chat.sendPrompt(prompt, {
284
- mode: reqBody.options?.mode || "chat",
285
- editData: reqBody.options?.editData
286
- })
287
- };
288
- res.status(200).json(apiResponse);
289
- } catch (err) {
290
- console.error(err.stack || err);
291
- res.status(500).json({ success: false, error: "UNKNOWN" });
292
- }
293
- });
294
378
  server.use("/cms/api/ai.diff", async (req, res) => {
295
379
  if (req.method !== "POST" || !String(req.get("content-type")).startsWith("application/json")) {
296
380
  res.status(400).json({ success: false, error: "BAD_REQUEST" });
@@ -322,35 +406,14 @@ function api(server, options) {
322
406
  res.status(200).json({ success: true, summary: "" });
323
407
  return;
324
408
  }
325
- const summary = await summarizeDiff(cmsClient, {
409
+ const summary = await summarizeDiff(req.rootConfig, {
326
410
  before: diffPayload.before,
327
411
  after: diffPayload.after
328
412
  });
329
413
  res.status(200).json({ success: true, summary });
330
414
  } catch (err) {
331
415
  console.error(err.stack || err);
332
- res.status(500).json({ success: false, error: "UNKNOWN" });
333
- }
334
- });
335
- server.use("/cms/api/ai.list_chats", async (req, res) => {
336
- if (req.method !== "POST" || !String(req.get("content-type")).startsWith("application/json")) {
337
- res.status(400).json({ success: false, error: "BAD_REQUEST" });
338
- return;
339
- }
340
- if (!req.user?.email) {
341
- res.status(401).json({ success: false, error: "UNAUTHORIZED" });
342
- return;
343
- }
344
- const reqBody = req.body || {};
345
- const limit = reqBody.limit;
346
- try {
347
- const cmsClient = new RootCMSClient(req.rootConfig);
348
- const chatClient = new ChatClient(cmsClient, req.user.email);
349
- const chats = await chatClient.listChats({ limit });
350
- res.status(200).json({ success: true, chats });
351
- } catch (err) {
352
- console.error(err.stack || err);
353
- res.status(500).json({ success: false, error: "UNKNOWN" });
416
+ res.status(500).json({ success: false, error: err.message || "UNKNOWN" });
354
417
  }
355
418
  });
356
419
  server.use(
@@ -372,13 +435,11 @@ function api(server, options) {
372
435
  return;
373
436
  }
374
437
  try {
375
- const cmsClient = new RootCMSClient(req.rootConfig);
376
- const { generateImage } = await import("./ai-OZY3JXDH.js");
377
- const imageUrl = await generateImage(cmsClient, {
438
+ const result = await generateImage(req.rootConfig, {
378
439
  prompt,
379
440
  aspectRatio
380
441
  });
381
- res.status(200).json({ success: true, image: imageUrl });
442
+ res.status(200).json({ success: true, image: result.imageUrl });
382
443
  } catch (err) {
383
444
  console.error(err.stack || err);
384
445
  res.status(500).json({ success: false, error: err.message || "UNKNOWN" });
@@ -408,28 +469,259 @@ function api(server, options) {
408
469
  }
409
470
  try {
410
471
  const cmsClient = new RootCMSClient(req.rootConfig);
411
- const beforeVersion = "published";
412
- const afterVersion = "draft";
413
472
  const diffPayload = await buildDocDiffPayload(cmsClient, docId, {
414
- beforeVersion,
415
- afterVersion
473
+ beforeVersion: "published",
474
+ afterVersion: "draft"
416
475
  });
417
476
  if (!diffPayload.before && !diffPayload.after) {
418
477
  res.status(200).json({ success: true, message: "Initial version" });
419
478
  return;
420
479
  }
421
- const { generatePublishMessage } = await import("./ai-OZY3JXDH.js");
422
- const message = await generatePublishMessage(cmsClient, {
480
+ const message = await generatePublishMessage(req.rootConfig, {
423
481
  before: diffPayload.before,
424
482
  after: diffPayload.after
425
483
  });
426
484
  res.status(200).json({ success: true, message });
485
+ } catch (err) {
486
+ console.error(err.stack || err);
487
+ res.status(500).json({ success: false, error: err.message || "UNKNOWN" });
488
+ }
489
+ }
490
+ );
491
+ server.use(
492
+ "/cms/api/ai.generate_alt_text",
493
+ async (req, res) => {
494
+ if (req.method !== "POST" || !String(req.get("content-type")).startsWith("application/json")) {
495
+ res.status(400).json({ success: false, error: "BAD_REQUEST" });
496
+ return;
497
+ }
498
+ if (!req.user?.email) {
499
+ res.status(401).json({ success: false, error: "UNAUTHORIZED" });
500
+ return;
501
+ }
502
+ const reqBody = req.body || {};
503
+ const imageUrl = typeof reqBody.imageUrl === "string" ? reqBody.imageUrl.trim() : "";
504
+ if (!imageUrl) {
505
+ res.status(400).json({
506
+ success: false,
507
+ error: "MISSING_REQUIRED_FIELD",
508
+ field: "imageUrl"
509
+ });
510
+ return;
511
+ }
512
+ try {
513
+ const altText = await generateAltText(req.rootConfig, { imageUrl });
514
+ res.status(200).json({ success: true, altText });
515
+ } catch (err) {
516
+ console.error(err.stack || err);
517
+ res.status(500).json({ success: false, error: err.message || "UNKNOWN" });
518
+ }
519
+ }
520
+ );
521
+ server.use("/cms/api/ai.config", async (req, res) => {
522
+ if (!req.user?.email) {
523
+ res.status(401).json({ success: false, error: "UNAUTHORIZED" });
524
+ return;
525
+ }
526
+ const aiConfig = getAiConfig(req.rootConfig);
527
+ if (!aiConfig) {
528
+ res.status(200).json({ success: true, enabled: false });
529
+ return;
530
+ }
531
+ res.status(200).json({ success: true, enabled: true, ...serializeAiConfig(aiConfig) });
532
+ });
533
+ server.use("/cms/api/ai.chat", async (req, res) => {
534
+ if (req.method !== "POST") {
535
+ res.status(400).json({ success: false, error: "BAD_REQUEST" });
536
+ return;
537
+ }
538
+ if (!req.user?.email) {
539
+ res.status(401).json({ success: false, error: "UNAUTHORIZED" });
540
+ return;
541
+ }
542
+ const aiConfig = getAiConfig(req.rootConfig);
543
+ if (!aiConfig) {
544
+ res.status(404).json({ success: false, error: "AI_NOT_CONFIGURED" });
545
+ return;
546
+ }
547
+ const body = req.body || {};
548
+ const messages = body.messages || [];
549
+ if (!Array.isArray(messages) || messages.length === 0) {
550
+ res.status(400).json({ success: false, error: "MISSING_MESSAGES" });
551
+ return;
552
+ }
553
+ const model = findModel(aiConfig, body.modelId);
554
+ if (!model) {
555
+ res.status(400).json({ success: false, error: "UNKNOWN_MODEL" });
556
+ return;
557
+ }
558
+ const cmsClient = new RootCMSClient(req.rootConfig);
559
+ const store = new ChatStore(cmsClient, req.user.email);
560
+ const requestedChatId = typeof body.chatId === "string" ? body.chatId.trim() : "";
561
+ let chatId = "";
562
+ if (requestedChatId) {
563
+ const existing = await store.getChat(requestedChatId);
564
+ if (existing) {
565
+ chatId = existing.id;
566
+ } else {
567
+ const created = await store.createChat({
568
+ id: requestedChatId,
569
+ modelId: model.id
570
+ });
571
+ chatId = created.id;
572
+ }
573
+ } else {
574
+ const created = await store.createChat({ modelId: model.id });
575
+ chatId = created.id;
576
+ }
577
+ try {
578
+ const streamResponse = await runChatStream({
579
+ rootConfig: req.rootConfig,
580
+ cmsClient,
581
+ config: aiConfig,
582
+ model,
583
+ messages,
584
+ chatId,
585
+ user: req.user.email
586
+ });
587
+ streamResponse.headers.set("x-root-cms-chat-id", chatId);
588
+ await pipeWebResponse(streamResponse, res);
589
+ } catch (err) {
590
+ console.error(err.stack || err);
591
+ if (!res.headersSent) {
592
+ res.status(500).json({ success: false, error: err.message || "UNKNOWN" });
593
+ } else {
594
+ res.end();
595
+ }
596
+ }
597
+ });
598
+ server.use(
599
+ "/cms/api/ai.edit_object",
600
+ async (req, res) => {
601
+ if (req.method !== "POST") {
602
+ res.status(400).json({ success: false, error: "BAD_REQUEST" });
603
+ return;
604
+ }
605
+ if (!req.user?.email) {
606
+ res.status(401).json({ success: false, error: "UNAUTHORIZED" });
607
+ return;
608
+ }
609
+ const aiConfig = getAiConfig(req.rootConfig);
610
+ if (!aiConfig) {
611
+ res.status(404).json({ success: false, error: "AI_NOT_CONFIGURED" });
612
+ return;
613
+ }
614
+ const body = req.body || {};
615
+ const messages = body.messages || [];
616
+ if (!Array.isArray(messages) || messages.length === 0) {
617
+ res.status(400).json({ success: false, error: "MISSING_MESSAGES" });
618
+ return;
619
+ }
620
+ const model = findModel(aiConfig, body.modelId);
621
+ if (!model) {
622
+ res.status(400).json({ success: false, error: "UNKNOWN_MODEL" });
623
+ return;
624
+ }
625
+ try {
626
+ const streamResponse = await runEditObjectStream({
627
+ rootConfig: req.rootConfig,
628
+ config: aiConfig,
629
+ model,
630
+ messages,
631
+ editData: body.editData
632
+ });
633
+ await pipeWebResponse(streamResponse, res);
634
+ } catch (err) {
635
+ console.error(err.stack || err);
636
+ if (!res.headersSent) {
637
+ res.status(500).json({ success: false, error: err.message || "UNKNOWN" });
638
+ } else {
639
+ res.end();
640
+ }
641
+ }
642
+ }
643
+ );
644
+ server.use(
645
+ "/cms/api/ai.chats.list",
646
+ async (req, res) => {
647
+ if (!req.user?.email) {
648
+ res.status(401).json({ success: false, error: "UNAUTHORIZED" });
649
+ return;
650
+ }
651
+ const cmsClient = new RootCMSClient(req.rootConfig);
652
+ const store = new ChatStore(cmsClient, req.user.email);
653
+ try {
654
+ const chats = await store.listChats({ limit: req.body?.limit });
655
+ res.status(200).json({
656
+ success: true,
657
+ chats: chats.map((c) => ({
658
+ id: c.id,
659
+ title: c.title,
660
+ modelId: c.modelId,
661
+ createdAt: c.createdAt.toMillis(),
662
+ modifiedAt: c.modifiedAt.toMillis()
663
+ }))
664
+ });
427
665
  } catch (err) {
428
666
  console.error(err.stack || err);
429
667
  res.status(500).json({ success: false, error: "UNKNOWN" });
430
668
  }
431
669
  }
432
670
  );
671
+ server.use(
672
+ "/cms/api/ai.chats.get",
673
+ async (req, res) => {
674
+ if (!req.user?.email) {
675
+ res.status(401).json({ success: false, error: "UNAUTHORIZED" });
676
+ return;
677
+ }
678
+ const id = String(req.body?.id || "").trim();
679
+ if (!id) {
680
+ res.status(400).json({ success: false, error: "MISSING_ID" });
681
+ return;
682
+ }
683
+ const cmsClient = new RootCMSClient(req.rootConfig);
684
+ const store = new ChatStore(cmsClient, req.user.email);
685
+ const chat = await store.getChat(id);
686
+ if (!chat) {
687
+ res.status(404).json({ success: false, error: "NOT_FOUND" });
688
+ return;
689
+ }
690
+ res.status(200).json({
691
+ success: true,
692
+ chat: {
693
+ id: chat.id,
694
+ title: chat.title,
695
+ modelId: chat.modelId,
696
+ messages: chat.messages,
697
+ createdAt: chat.createdAt.toMillis(),
698
+ modifiedAt: chat.modifiedAt.toMillis()
699
+ }
700
+ });
701
+ }
702
+ );
703
+ server.use(
704
+ "/cms/api/ai.chats.delete",
705
+ async (req, res) => {
706
+ if (req.method !== "POST") {
707
+ res.status(400).json({ success: false, error: "BAD_REQUEST" });
708
+ return;
709
+ }
710
+ if (!req.user?.email) {
711
+ res.status(401).json({ success: false, error: "UNAUTHORIZED" });
712
+ return;
713
+ }
714
+ const id = String(req.body?.id || "").trim();
715
+ if (!id) {
716
+ res.status(400).json({ success: false, error: "MISSING_ID" });
717
+ return;
718
+ }
719
+ const cmsClient = new RootCMSClient(req.rootConfig);
720
+ const store = new ChatStore(cmsClient, req.user.email);
721
+ await store.deleteChat(id);
722
+ res.status(200).json({ success: true });
723
+ }
724
+ );
433
725
  server.use("/cms/api/ai.translate", async (req, res) => {
434
726
  if (req.method !== "POST" || !String(req.get("content-type")).startsWith("application/json")) {
435
727
  res.status(400).json({ success: false, error: "BAD_REQUEST" });
@@ -449,9 +741,7 @@ function api(server, options) {
449
741
  return;
450
742
  }
451
743
  try {
452
- const cmsClient = new RootCMSClient(req.rootConfig);
453
- const { translateString } = await import("./ai-OZY3JXDH.js");
454
- const translations = await translateString(cmsClient, {
744
+ const translations = await translateString(req.rootConfig, {
455
745
  sourceText,
456
746
  targetLocales,
457
747
  description,
@@ -1294,7 +1584,7 @@ function cmsPlugin(options) {
1294
1584
  if (process.env.NODE_ENV === "development" && options.watch !== false) {
1295
1585
  plugin.onFileChange = (eventName, filepath) => {
1296
1586
  if (filepath.endsWith(".schema.ts")) {
1297
- import("./generate-types-MHWSSOWV.js").then((generateTypesModule) => {
1587
+ import("./generate-types-SPV7I3A5.js").then((generateTypesModule) => {
1298
1588
  const generateTypes = generateTypesModule.generateTypes;
1299
1589
  generateTypes();
1300
1590
  });
package/dist/project.d.ts CHANGED
@@ -1,10 +1,10 @@
1
- import { S as Schema, C as Collection } from './schema-D7MOj-YC.js';
1
+ import { S as Schema, C as Collection } from './schema-Db_xODoi.js';
2
2
 
3
3
  /**
4
4
  * Loads various files or configurations from the project.
5
5
  *
6
6
  * NOTE: This file needs to be loaded through vite's ssrLoadModule so that
7
- * `import.meta.glob()` calls are resolved.
7
+ * virtual modules are resolved.
8
8
  */
9
9
 
10
10
  interface SchemaModule {
@@ -27,5 +27,18 @@ declare function resolveOneOfPatterns(schemaObj: Schema): Schema;
27
27
  * `/collections/<id>.schema.ts`.
28
28
  */
29
29
  declare function getCollectionSchema(collectionId: string): Collection | null;
30
+ /**
31
+ * Converts all `oneof` field type definitions into a map keyed by the type
32
+ * name. The field definitions are replaced with an array of type names.
33
+ *
34
+ * String references (used for self-referencing schemas) are resolved from the
35
+ * project's schema modules. SchemaPatterns are resolved by matching file paths.
36
+ *
37
+ * Schemas pulled in via SchemaPattern or string-name reference are always
38
+ * deep-cloned before being walked. The walk rewrites `oneof` fields in place,
39
+ * and skipping the clone would mutate the shared entries in `SCHEMA_MODULES`
40
+ * and corrupt subsequent calls (e.g. when building multiple collections).
41
+ */
42
+ declare function convertOneOfTypes(collection: Collection, schemaModules?: Record<string, SchemaModule>): Collection;
30
43
 
31
- export { SCHEMA_MODULES, type SchemaModule, getCollectionSchema, getProjectSchemas, resolveOneOfPatterns };
44
+ export { SCHEMA_MODULES, type SchemaModule, convertOneOfTypes, getCollectionSchema, getProjectSchemas, resolveOneOfPatterns };
package/dist/project.js CHANGED
@@ -1,12 +1,14 @@
1
1
  import {
2
2
  SCHEMA_MODULES,
3
+ convertOneOfTypes,
3
4
  getCollectionSchema,
4
5
  getProjectSchemas,
5
6
  resolveOneOfPatterns
6
- } from "./chunk-MSJGHSR6.js";
7
+ } from "./chunk-MAZA5B27.js";
7
8
  import "./chunk-MLKGABMK.js";
8
9
  export {
9
10
  SCHEMA_MODULES,
11
+ convertOneOfTypes,
10
12
  getCollectionSchema,
11
13
  getProjectSchemas,
12
14
  resolveOneOfPatterns
@@ -7,25 +7,36 @@ interface RichTextBlock {
7
7
  }
8
8
  interface RichTextData {
9
9
  [key: string]: any;
10
- blocks: any[];
10
+ blocks: RichTextBlock[];
11
11
  }
12
- type RichTextBlockComponent = FunctionalComponent<any>;
12
+ type RichTextComponent = FunctionalComponent<any>;
13
+ type RichTextBlockComponent = RichTextComponent;
14
+ type RichTextInlineComponent = RichTextComponent;
15
+ type RichTextComponentMap = Record<string, RichTextComponent>;
13
16
  interface RichTextContextProps {
14
- components?: Record<string, RichTextBlockComponent>;
17
+ /**
18
+ * Rich text components override for both inline and block level components.
19
+ */
20
+ components?: RichTextComponentMap;
21
+ /**
22
+ * Translator function override.
23
+ */
24
+ t?: (msg: string, params?: Record<string, string | number>) => string;
15
25
  }
16
26
  declare const RichTextContext: preact.Context<RichTextContextProps>;
17
27
  declare function useRichTextContext(): RichTextContextProps;
18
28
  interface RichTextProps {
19
- data: RichTextData;
29
+ data: RichTextData | undefined;
20
30
  components?: Record<string, RichTextBlockComponent>;
31
+ /** @deprecated */
32
+ translate?: boolean;
21
33
  }
22
34
  /** Renders data from the "richtext" field. */
23
- declare function RichText(props: RichTextProps): preact.JSX.Element;
35
+ declare function RichText(props: RichTextProps): preact.JSX.Element | null;
24
36
  declare namespace RichText {
37
+ var Block: (props: RichTextBlock) => preact.JSX.Element | null;
25
38
  var ParagraphBlock: (props: RichTextParagraphBlockProps) => preact.JSX.Element | null;
26
- var DelimiterBlock: () => preact.JSX.Element;
27
39
  var HeadingBlock: (props: RichTextHeadingBlockProps) => preact.JSX.Element | null;
28
- var QuoteBlock: (props: RichTextQuoteBlockProps) => preact.JSX.Element | null;
29
40
  var ListBlock: (props: RichTextListBlockProps) => preact.JSX.Element | null;
30
41
  var ImageBlock: (props: RichTextImageBlockProps) => preact.JSX.Element | null;
31
42
  var HtmlBlock: (props: RichTextHtmlBlockProps) => preact.JSX.Element | null;
@@ -35,12 +46,9 @@ interface RichTextParagraphBlockProps {
35
46
  type: 'paragraph';
36
47
  data?: {
37
48
  text?: string;
49
+ components?: Record<string, any>;
38
50
  };
39
51
  }
40
- interface RichTextDelimiterBlockProps {
41
- type: 'delimiter';
42
- data?: {};
43
- }
44
52
  interface RichTextHeadingBlockProps {
45
53
  type: 'heading';
46
54
  data?: {
@@ -48,15 +56,10 @@ interface RichTextHeadingBlockProps {
48
56
  text?: string;
49
57
  };
50
58
  }
51
- interface RichTextQuoteBlockProps {
52
- type: 'quote';
53
- data?: {
54
- text?: string;
55
- };
56
- }
57
59
  interface ListItem {
58
60
  content?: string;
59
61
  items?: ListItem[];
62
+ components?: Record<string, any>;
60
63
  }
61
64
  interface RichTextListBlockProps {
62
65
  type: 'orderedList' | 'unorderedList';
@@ -68,6 +71,8 @@ interface RichTextListBlockProps {
68
71
  interface RichTextImageBlockProps {
69
72
  type: 'image';
70
73
  data?: {
74
+ /** The caption entered into the CMS Image field. */
75
+ caption?: string;
71
76
  file?: {
72
77
  url: string;
73
78
  width: string | number;
@@ -93,5 +98,7 @@ interface RichTextTableBlockProps {
93
98
  }>;
94
99
  };
95
100
  }
101
+ /** Returns whether the rich text value is truthy. */
102
+ declare function testContent(data: RichTextData): boolean;
96
103
 
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 };
104
+ export { RichText, type RichTextBlock, type RichTextBlockComponent, type RichTextComponent, type RichTextComponentMap, RichTextContext, type RichTextContextProps, type RichTextData, type RichTextHeadingBlockProps, type RichTextHtmlBlockProps, type RichTextImageBlockProps, type RichTextInlineComponent, type RichTextListBlockProps, type RichTextParagraphBlockProps, type RichTextProps, type RichTextTableBlockProps, testContent, useRichTextContext };