@blinkk/root-cms 2.5.9 → 2.5.10

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
@@ -4,15 +4,15 @@ import {
4
4
  } from "./chunk-T5UK2H24.js";
5
5
  import {
6
6
  getServerVersion
7
- } from "./chunk-SW3UAKP5.js";
7
+ } from "./chunk-7QY6372S.js";
8
8
  import {
9
9
  runCronJobs
10
- } from "./chunk-AFL5KJ4E.js";
10
+ } from "./chunk-PKD2TDSV.js";
11
11
  import {
12
12
  RootCMSClient,
13
13
  parseDocId,
14
14
  unmarshalData
15
- } from "./chunk-5N2KLMQH.js";
15
+ } from "./chunk-YMUZ5H5C.js";
16
16
  import "./chunk-MLKGABMK.js";
17
17
 
18
18
  // core/plugin.ts
@@ -514,6 +514,96 @@ function api(server, options) {
514
514
  res.status(500).json({ success: false, error: err.message || "UNKNOWN" });
515
515
  }
516
516
  });
517
+ server.use(
518
+ "/cms/api/translations.import",
519
+ async (req, res) => {
520
+ await handleTranslationServiceRequest(req, res, "import");
521
+ }
522
+ );
523
+ server.use(
524
+ "/cms/api/translations.export",
525
+ async (req, res) => {
526
+ await handleTranslationServiceRequest(req, res, "export");
527
+ }
528
+ );
529
+ async function handleTranslationServiceRequest(req, res, action) {
530
+ if (req.method !== "POST" || !String(req.get("content-type")).startsWith("application/json")) {
531
+ res.status(400).json({ success: false, error: "BAD_REQUEST" });
532
+ return;
533
+ }
534
+ if (!req.user?.email) {
535
+ res.status(401).json({ success: false, error: "UNAUTHORIZED" });
536
+ return;
537
+ }
538
+ const reqBody = req.body || {};
539
+ const serviceId = String(reqBody.serviceId || "").trim();
540
+ const docId = String(reqBody.docId || "").trim();
541
+ const data = Array.isArray(reqBody.data) ? reqBody.data : [];
542
+ for (const row of data) {
543
+ if (typeof row?.source !== "string" || typeof row?.translations !== "object" || row.translations === null || Array.isArray(row.translations)) {
544
+ res.status(400).json({ success: false, error: "INVALID_DATA_FORMAT" });
545
+ return;
546
+ }
547
+ for (const value of Object.values(row.translations)) {
548
+ if (typeof value !== "string") {
549
+ res.status(400).json({ success: false, error: "INVALID_DATA_FORMAT" });
550
+ return;
551
+ }
552
+ }
553
+ if (row.description !== void 0 && typeof row.description !== "string") {
554
+ res.status(400).json({ success: false, error: "INVALID_DATA_FORMAT" });
555
+ return;
556
+ }
557
+ }
558
+ if (!serviceId || !docId) {
559
+ res.status(400).json({ success: false, error: "MISSING_REQUIRED_FIELD" });
560
+ return;
561
+ }
562
+ const services = options.translations || [];
563
+ const service = services.find((s) => s.id === serviceId);
564
+ if (!service) {
565
+ res.status(404).json({ success: false, error: "SERVICE_NOT_FOUND" });
566
+ return;
567
+ }
568
+ const handler = action === "import" ? service.onImport : service.onExport;
569
+ if (!handler) {
570
+ res.status(400).json({
571
+ success: false,
572
+ error: `SERVICE_DOES_NOT_SUPPORT_${action.toUpperCase()}`
573
+ });
574
+ return;
575
+ }
576
+ let collectionId;
577
+ let slug;
578
+ try {
579
+ const parsed = parseDocId(docId);
580
+ collectionId = parsed.collection;
581
+ slug = parsed.slug;
582
+ } catch (err) {
583
+ console.error(err.stack || err);
584
+ res.status(400).json({ success: false, error: "INVALID_DOC_ID" });
585
+ return;
586
+ }
587
+ try {
588
+ const cmsClient = new RootCMSClient(req.rootConfig);
589
+ const locales = req.rootConfig?.i18n?.locales || [];
590
+ const result = await handler(
591
+ {
592
+ rootConfig: req.rootConfig,
593
+ cmsClient,
594
+ docId,
595
+ collectionId,
596
+ slug,
597
+ locales
598
+ },
599
+ data
600
+ );
601
+ res.status(200).json({ success: true, data: result });
602
+ } catch (err) {
603
+ console.error(err.stack || err);
604
+ res.status(500).json({ success: false, error: err.message || "UNKNOWN" });
605
+ }
606
+ }
517
607
  }
518
608
 
519
609
  // core/sse.ts
@@ -1161,7 +1251,11 @@ function cmsPlugin(options) {
1161
1251
  if (sseData.sseBroadcast) {
1162
1252
  sseBroadcast = sseData.sseBroadcast;
1163
1253
  }
1164
- api(server, { getRenderer, checks: options.checks });
1254
+ api(server, {
1255
+ getRenderer,
1256
+ checks: options.checks,
1257
+ translations: options.translations
1258
+ });
1165
1259
  server.use("/cms", async (req, res) => {
1166
1260
  try {
1167
1261
  if (!req.user) {
package/dist/project.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { S as Schema, C as Collection } from './schema-Bht24XmU.js';
1
+ import { S as Schema, C as Collection } from './schema-D7MOj-YC.js';
2
2
 
3
3
  /**
4
4
  * Loads various files or configurations from the project.
@@ -21,7 +21,14 @@ type StringField = CommonFieldProps & {
21
21
  type: 'string';
22
22
  default?: string;
23
23
  translate?: boolean;
24
- variant?: 'input' | 'textarea';
24
+ /**
25
+ * The UI variant to use for the string field.
26
+ * - `input`: A single-line text input (default).
27
+ * - `textarea`: A multi-line textarea.
28
+ * - `json`: A multi-line textarea that validates and auto-formats JSON on
29
+ * blur. The value is still stored as a string.
30
+ */
31
+ variant?: 'input' | 'textarea' | 'json';
25
32
  /** For textarea variant, the maximum number of rows of text to show. */
26
33
  maxRows?: number;
27
34
  /**