@blinkk/root-cms 2.5.8 → 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/app.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getServerVersion
3
- } from "./chunk-4YTAYZTP.js";
3
+ } from "./chunk-7QY6372S.js";
4
4
  import {
5
5
  getCollectionSchema,
6
6
  getProjectSchemas
@@ -128,6 +128,13 @@ async function renderApp(req, res, options) {
128
128
  label: c.label,
129
129
  description: c.description,
130
130
  collections: c.collections
131
+ })),
132
+ translations: (cmsConfig.translations || []).map((t) => ({
133
+ id: t.id,
134
+ label: t.label,
135
+ icon: t.icon,
136
+ hasImport: isFunction(t.onImport),
137
+ hasExport: isFunction(t.onExport)
131
138
  }))
132
139
  };
133
140
  const projectName = cmsConfig.name || cmsConfig.id || "";
@@ -158,6 +165,9 @@ function serializeCollection(collection) {
158
165
  sortOptions: collection.sortOptions
159
166
  };
160
167
  }
168
+ function isFunction(value) {
169
+ return typeof value === "function";
170
+ }
161
171
  function SignIn(props) {
162
172
  return /* @__PURE__ */ jsxs("html", { children: [
163
173
  /* @__PURE__ */ jsxs("head", { children: [
@@ -1,7 +1,7 @@
1
1
  // package.json
2
2
  var package_default = {
3
3
  name: "@blinkk/root-cms",
4
- version: "2.5.8",
4
+ version: "2.5.10",
5
5
  author: "s@blinkk.com",
6
6
  license: "MIT",
7
7
  engines: {
@@ -169,7 +169,7 @@ var package_default = {
169
169
  yjs: "13.6.27"
170
170
  },
171
171
  peerDependencies: {
172
- "@blinkk/root": "2.5.8",
172
+ "@blinkk/root": "2.5.10",
173
173
  "firebase-admin": ">=11",
174
174
  "firebase-functions": ">=4",
175
175
  preact: ">=10",
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  RootCMSClient,
3
3
  getCmsPlugin
4
- } from "./chunk-5N2KLMQH.js";
4
+ } from "./chunk-YMUZ5H5C.js";
5
5
 
6
6
  // core/versions.ts
7
7
  import path from "path";
@@ -109,6 +109,11 @@ var VersionsService = class {
109
109
  async function runCronJobs(rootConfig) {
110
110
  await Promise.all([
111
111
  runCronJob("publishScheduledDocs", runPublishScheduledDocs, rootConfig),
112
+ runCronJob(
113
+ "syncScheduledDataSources",
114
+ runSyncScheduledDataSources,
115
+ rootConfig
116
+ ),
112
117
  runCronJob("saveVersions", runSaveVersions, rootConfig)
113
118
  ]);
114
119
  }
@@ -126,6 +131,10 @@ async function runPublishScheduledDocs(rootConfig) {
126
131
  await cmsClient.publishScheduledDocs();
127
132
  await cmsClient.publishScheduledReleases();
128
133
  }
134
+ async function runSyncScheduledDataSources(rootConfig) {
135
+ const cmsClient = new RootCMSClient(rootConfig);
136
+ await cmsClient.syncScheduledDataSources();
137
+ }
129
138
  async function runSaveVersions(rootConfig) {
130
139
  const service = new VersionsService(rootConfig);
131
140
  await service.saveVersions();
@@ -1288,6 +1288,69 @@ ${errorMessages}`);
1288
1288
  });
1289
1289
  }
1290
1290
  }
1291
+ /**
1292
+ * Syncs data sources that have cron scheduling enabled and are due for sync.
1293
+ */
1294
+ async syncScheduledDataSources() {
1295
+ const dataSourcesPath = `Projects/${this.projectId}/DataSources`;
1296
+ const query = this.db.collection(dataSourcesPath).where("cron.enabled", "==", true);
1297
+ const querySnapshot = await query.get();
1298
+ const now = Date.now();
1299
+ for (const snapshot of querySnapshot.docs) {
1300
+ const dataSource = snapshot.data();
1301
+ const cron = dataSource.cron;
1302
+ if (!cron || !cron.enabled || cron.interval == null || !cron.unit) {
1303
+ continue;
1304
+ }
1305
+ const interval = Number(cron.interval);
1306
+ if (!Number.isFinite(interval) || interval <= 0 || !Number.isInteger(interval)) {
1307
+ continue;
1308
+ }
1309
+ let intervalMs = interval;
1310
+ switch (cron.unit) {
1311
+ case "minutes":
1312
+ intervalMs *= 60 * 1e3;
1313
+ break;
1314
+ case "hours":
1315
+ intervalMs *= 60 * 60 * 1e3;
1316
+ break;
1317
+ case "days":
1318
+ intervalMs *= 24 * 60 * 60 * 1e3;
1319
+ break;
1320
+ default:
1321
+ continue;
1322
+ }
1323
+ let lastSyncMs = dataSource.syncedAt ? dataSource.syncedAt.toMillis() : 0;
1324
+ if (lastSyncMs > now) {
1325
+ lastSyncMs = now;
1326
+ }
1327
+ if (now - lastSyncMs < intervalMs) {
1328
+ continue;
1329
+ }
1330
+ try {
1331
+ console.log(`cron: syncing data source: ${dataSource.id}`);
1332
+ await this.syncDataSource(dataSource.id, { syncedBy: "cron" });
1333
+ if (cron.autoPublish) {
1334
+ console.log(`cron: auto-publishing data source: ${dataSource.id}`);
1335
+ await this.publishDataSource(dataSource.id, {
1336
+ publishedBy: "cron"
1337
+ });
1338
+ }
1339
+ await this.logAction("datasource.cron_sync", {
1340
+ by: "cron",
1341
+ metadata: {
1342
+ datasourceId: dataSource.id,
1343
+ autoPublish: cron.autoPublish || false
1344
+ }
1345
+ });
1346
+ } catch (err) {
1347
+ console.error(
1348
+ `cron: failed to sync data source ${dataSource.id}:`,
1349
+ String(err)
1350
+ );
1351
+ }
1352
+ }
1353
+ }
1291
1354
  /**
1292
1355
  * Checks if a doc is currently "locked" for publishing.
1293
1356
  */
@@ -1450,7 +1513,7 @@ ${errorMessages}`);
1450
1513
  if (!dataSource) {
1451
1514
  throw new Error(`data source not found: ${dataSourceId}`);
1452
1515
  }
1453
- const data = await this.fetchData(dataSource);
1516
+ const result = await this.fetchData(dataSource);
1454
1517
  const dataSourceDocRef = this.db.doc(
1455
1518
  `Projects/${this.projectId}/DataSources/${dataSourceId}`
1456
1519
  );
@@ -1466,7 +1529,8 @@ ${errorMessages}`);
1466
1529
  const batch = this.db.batch();
1467
1530
  batch.set(dataDocRef, {
1468
1531
  dataSource: updatedDataSource,
1469
- data
1532
+ data: result.data,
1533
+ ...result.headers ? { headers: result.headers } : {}
1470
1534
  });
1471
1535
  batch.update(dataSourceDocRef, {
1472
1536
  syncedAt: Timestamp2.now(),
@@ -1554,7 +1618,10 @@ ${errorMessages}`);
1554
1618
  }
1555
1619
  async fetchData(dataSource) {
1556
1620
  if (dataSource.type === "http") {
1557
- return await this.fetchHttpData(dataSource);
1621
+ return { data: await this.fetchHttpData(dataSource) };
1622
+ }
1623
+ if (dataSource.type === "gsheet") {
1624
+ return await this.fetchGsheetData(dataSource);
1558
1625
  }
1559
1626
  throw new Error(`unsupported data source: ${dataSource.type}`);
1560
1627
  }
@@ -1578,6 +1645,98 @@ ${errorMessages}`);
1578
1645
  }
1579
1646
  return res.text();
1580
1647
  }
1648
+ /**
1649
+ * Fetches data from a Google Sheet using the Google Sheets API v4.
1650
+ *
1651
+ * ## Setup
1652
+ *
1653
+ * For the server-side service account to access the Google Sheet:
1654
+ *
1655
+ * 1. **Enable the Google Sheets API** in the Google Cloud Console for the
1656
+ * project associated with the service account.
1657
+ * https://console.cloud.google.com/apis/library/sheets.googleapis.com
1658
+ *
1659
+ * 2. **Share the Google Sheet** with the service account's email address
1660
+ * (e.g. `my-service-account@my-project.iam.gserviceaccount.com`).
1661
+ * Open the sheet in Google Sheets, click "Share", and add the service
1662
+ * account email as a Viewer.
1663
+ *
1664
+ * - For **App Engine**: the service account email is typically
1665
+ * `<project-id>@appspot.gserviceaccount.com`.
1666
+ * - For **Cloud Run**: check the service account configured for the
1667
+ * Cloud Run service in the Google Cloud Console.
1668
+ * - For **local development**: use the service account email from the
1669
+ * JSON key file specified in `GOOGLE_APPLICATION_CREDENTIALS`.
1670
+ */
1671
+ async fetchGsheetData(dataSource) {
1672
+ const gsheetId = parseSpreadsheetUrl(dataSource.url);
1673
+ if (!gsheetId?.spreadsheetId) {
1674
+ throw new Error(`failed to parse google sheet url: ${dataSource.url}`);
1675
+ }
1676
+ const credential = this.app.options.credential;
1677
+ if (!credential) {
1678
+ throw new Error(
1679
+ "firebase credential not available. ensure the firebase admin app is initialized with a service account."
1680
+ );
1681
+ }
1682
+ const { access_token } = await credential.getAccessToken();
1683
+ let sheetTitle = "Sheet1";
1684
+ const metaUrl = `https://sheets.googleapis.com/v4/spreadsheets/${encodeURIComponent(
1685
+ gsheetId.spreadsheetId
1686
+ )}?fields=sheets.properties`;
1687
+ const metaRes = await fetch(metaUrl, {
1688
+ headers: { Authorization: `Bearer ${access_token}` }
1689
+ });
1690
+ if (metaRes.status !== 200) {
1691
+ const err = await metaRes.text();
1692
+ throw new Error(`failed to fetch spreadsheet metadata: ${err}`);
1693
+ }
1694
+ const meta = await metaRes.json();
1695
+ const sheets = meta.sheets || [];
1696
+ if (gsheetId.gid !== void 0) {
1697
+ const sheet = sheets.find((s) => s.properties?.sheetId === gsheetId.gid);
1698
+ if (sheet?.properties?.title) {
1699
+ sheetTitle = sheet.properties.title;
1700
+ } else if (gsheetId.gid !== 0) {
1701
+ throw new Error(
1702
+ `sheet with gid ${gsheetId.gid} not found in spreadsheet`
1703
+ );
1704
+ }
1705
+ }
1706
+ const range = encodeURIComponent(sheetTitle);
1707
+ const valuesUrl = `https://sheets.googleapis.com/v4/spreadsheets/${encodeURIComponent(
1708
+ gsheetId.spreadsheetId
1709
+ )}/values/${range}`;
1710
+ const valuesRes = await fetch(valuesUrl, {
1711
+ headers: { Authorization: `Bearer ${access_token}` }
1712
+ });
1713
+ if (valuesRes.status !== 200) {
1714
+ const err = await valuesRes.text();
1715
+ throw new Error(`failed to fetch sheet values: ${err}`);
1716
+ }
1717
+ const valuesData = await valuesRes.json();
1718
+ const values = valuesData.values || [];
1719
+ if (values.length === 0) {
1720
+ return { data: [], headers: [] };
1721
+ }
1722
+ const headers = values[0];
1723
+ const rows = values.slice(1);
1724
+ const dataFormat = dataSource.dataFormat || "map";
1725
+ if (dataFormat === "array") {
1726
+ return { data: [headers, ...rows], headers };
1727
+ }
1728
+ const mapData = rows.map((row) => {
1729
+ const item = {};
1730
+ row.forEach((val, i) => {
1731
+ const key = headers[i];
1732
+ if (key) {
1733
+ item[key] = String(val || "");
1734
+ }
1735
+ });
1736
+ return item;
1737
+ });
1738
+ return { data: mapData, headers };
1739
+ }
1581
1740
  /**
1582
1741
  * Fetches data from a data source.
1583
1742
  */
@@ -1887,6 +2046,30 @@ function unmarshalArray(arrObject) {
1887
2046
  function isObject(data) {
1888
2047
  return typeof data === "object" && !Array.isArray(data) && data !== null;
1889
2048
  }
2049
+ function parseSpreadsheetUrl(url) {
2050
+ if (!url.startsWith("https://docs.google.com/spreadsheets/d/")) {
2051
+ return null;
2052
+ }
2053
+ const parts = url.split("/");
2054
+ const dIndex = parts.indexOf("d");
2055
+ if (dIndex === -1 || dIndex + 1 >= parts.length) {
2056
+ return null;
2057
+ }
2058
+ const spreadsheetId = parts[dIndex + 1];
2059
+ if (!spreadsheetId) {
2060
+ return null;
2061
+ }
2062
+ let gid = 0;
2063
+ const hashIndex = url.indexOf("#");
2064
+ if (hashIndex !== -1) {
2065
+ const hash = url.slice(hashIndex);
2066
+ const gidMatch = hash.match(/gid=(\d+)/);
2067
+ if (gidMatch && gidMatch[1]) {
2068
+ gid = parseInt(gidMatch[1]);
2069
+ }
2070
+ }
2071
+ return { spreadsheetId, gid };
2072
+ }
1890
2073
  function randString(len) {
1891
2074
  const result = [];
1892
2075
  const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
package/dist/cli.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  RootCMSClient,
6
6
  getCmsPlugin,
7
7
  unmarshalData
8
- } from "./chunk-5N2KLMQH.js";
8
+ } from "./chunk-YMUZ5H5C.js";
9
9
  import "./chunk-MLKGABMK.js";
10
10
 
11
11
  // cli/cli.ts
@@ -1,7 +1,7 @@
1
1
  import { RootConfig, Plugin, Request } from '@blinkk/root';
2
2
  import { App } from 'firebase-admin/app';
3
3
  import { Firestore, WriteBatch, Timestamp, Query } from 'firebase-admin/firestore';
4
- import { C as Collection } from './schema-Bht24XmU.js';
4
+ import { C as Collection } from './schema-D7MOj-YC.js';
5
5
 
6
6
  /**
7
7
  * Supported Root AI models. Defaults to 'gemini-3-flash-preview'.
@@ -54,11 +54,81 @@ interface CMSCheck {
54
54
  run: (ctx: CheckContext) => Promise<CheckResult>;
55
55
  }
56
56
 
57
+ /** A row of translation data keyed by locale. */
58
+ interface TranslationRow {
59
+ /** The source string. */
60
+ source: string;
61
+ /** Map of locale code to translated string. */
62
+ translations: Record<string, string>;
63
+ /** Optional translator notes/context for the source string. */
64
+ description?: string;
65
+ }
66
+ /** Context passed to translation service import/export functions. */
67
+ interface TranslationServiceContext {
68
+ /** The Root.js config. */
69
+ rootConfig: RootConfig;
70
+ /** The Root CMS client for accessing the database. */
71
+ cmsClient: RootCMSClient;
72
+ /** The document ID, e.g. `Pages/index`. */
73
+ docId: string;
74
+ /** The collection ID, e.g. `Pages`. */
75
+ collectionId: string;
76
+ /** The slug, e.g. `index`. */
77
+ slug: string;
78
+ /** The locales configured for the project. */
79
+ locales: string[];
80
+ }
81
+ /** Result returned by an onExport handler. */
82
+ interface TranslationExportResult {
83
+ /** Optional title displayed in the notification after export. */
84
+ title?: string;
85
+ /** Optional message displayed in the notification after export. */
86
+ message?: string;
87
+ /** Optional link displayed in the notification (e.g. to the translation service). */
88
+ link?: {
89
+ /** The URL to link to. */
90
+ url: string;
91
+ /** Optional label for the link. Defaults to "Open". */
92
+ label?: string;
93
+ };
94
+ }
95
+ /** Configuration for defining a CMS translation service. */
96
+ interface CMSTranslationService {
97
+ /** Unique ID for the translation service. */
98
+ id: string;
99
+ /** Human-readable label displayed in the UI (e.g. "Crowdin"). */
100
+ label: string;
101
+ /**
102
+ * Optional icon URL displayed in the UI next to the label. Similar to the
103
+ * sidebar tools `icon` option, this should be a URL to an image.
104
+ */
105
+ icon?: string;
106
+ /**
107
+ * Async function to import translations from the service. Should return an
108
+ * array of translation rows that will be merged into the CMS translations
109
+ * database.
110
+ */
111
+ onImport?: (ctx: TranslationServiceContext, data: TranslationRow[]) => Promise<TranslationRow[]>;
112
+ /**
113
+ * Async function to export translations to the service. Receives the
114
+ * current translation rows for the document. Can optionally return an object
115
+ * with a `message` to display in the success notification.
116
+ */
117
+ onExport?: (ctx: TranslationServiceContext, data: TranslationRow[]) => Promise<void | TranslationExportResult>;
118
+ }
119
+
120
+ interface TranslationsCheckOptions {
121
+ /**
122
+ * Optional list of collection IDs to restrict this check to. When set, the
123
+ * check is only shown and runnable for documents in these collections.
124
+ */
125
+ collections?: string[];
126
+ }
57
127
  /**
58
128
  * A first-party CMS check that verifies all translatable strings in a document
59
129
  * have translations for each of the document's enabled locales.
60
130
  */
61
- declare function translationsCheck(): CMSCheck;
131
+ declare function translationsCheck(options?: TranslationsCheckOptions): CMSCheck;
62
132
 
63
133
  /**
64
134
  * Built-in sidebar tools that can be toggled on/off in the CMS UI.
@@ -244,6 +314,26 @@ type CMSPluginOptions = {
244
314
  * may change from version to version as we add new features.
245
315
  */
246
316
  checks?: CMSCheck[];
317
+ /**
318
+ * Translation services that appear in the Localization modal's Import and
319
+ * Export menus. Each service defines server-side import/export functions
320
+ * that integrate with an external translation platform (e.g. Crowdin).
321
+ *
322
+ * Example:
323
+ * ```ts
324
+ * cmsPlugin({
325
+ * translations: [
326
+ * {
327
+ * id: 'crowdin',
328
+ * label: 'Crowdin',
329
+ * onImport: async (ctx, data) => { ... },
330
+ * onExport: async (ctx, data) => { ... },
331
+ * },
332
+ * ],
333
+ * });
334
+ * ```
335
+ */
336
+ translations?: CMSTranslationService[];
247
337
  };
248
338
  type CMSPlugin = Plugin & {
249
339
  name: 'root-cms';
@@ -469,6 +559,13 @@ interface Doc<Fields = any> {
469
559
  type DocMode = 'draft' | 'published';
470
560
  type UserRole = 'ADMIN' | 'EDITOR' | 'CONTRIBUTOR' | 'VIEWER';
471
561
  type HttpMethod = 'GET' | 'POST';
562
+ type CronUnit = 'minutes' | 'hours' | 'days';
563
+ interface DataSourceCron {
564
+ enabled: boolean;
565
+ interval: number;
566
+ unit: CronUnit;
567
+ autoPublish?: boolean;
568
+ }
472
569
  interface DataSource {
473
570
  id: string;
474
571
  description?: string;
@@ -487,6 +584,7 @@ interface DataSource {
487
584
  headers?: Record<string, string>;
488
585
  body?: string;
489
586
  };
587
+ cron?: DataSourceCron;
490
588
  createdAt: Timestamp;
491
589
  createdBy: string;
492
590
  syncedAt?: Timestamp;
@@ -788,6 +886,10 @@ declare class RootCMSClient {
788
886
  * Publishes docs in scheduled releases.
789
887
  */
790
888
  publishScheduledReleases(): Promise<void>;
889
+ /**
890
+ * Syncs data sources that have cron scheduling enabled and are due for sync.
891
+ */
892
+ syncScheduledDataSources(): Promise<void>;
791
893
  /**
792
894
  * Checks if a doc is currently "locked" for publishing.
793
895
  */
@@ -886,6 +988,30 @@ declare class RootCMSClient {
886
988
  }): Promise<void>;
887
989
  private fetchData;
888
990
  private fetchHttpData;
991
+ /**
992
+ * Fetches data from a Google Sheet using the Google Sheets API v4.
993
+ *
994
+ * ## Setup
995
+ *
996
+ * For the server-side service account to access the Google Sheet:
997
+ *
998
+ * 1. **Enable the Google Sheets API** in the Google Cloud Console for the
999
+ * project associated with the service account.
1000
+ * https://console.cloud.google.com/apis/library/sheets.googleapis.com
1001
+ *
1002
+ * 2. **Share the Google Sheet** with the service account's email address
1003
+ * (e.g. `my-service-account@my-project.iam.gserviceaccount.com`).
1004
+ * Open the sheet in Google Sheets, click "Share", and add the service
1005
+ * account email as a Viewer.
1006
+ *
1007
+ * - For **App Engine**: the service account email is typically
1008
+ * `<project-id>@appspot.gserviceaccount.com`.
1009
+ * - For **Cloud Run**: check the service account configured for the
1010
+ * Cloud Run service in the Google Cloud Console.
1011
+ * - For **local development**: use the service account email from the
1012
+ * JSON key file specified in `GOOGLE_APPLICATION_CREDENTIALS`.
1013
+ */
1014
+ private fetchGsheetData;
889
1015
  /**
890
1016
  * Fetches data from a data source.
891
1017
  */
@@ -1097,4 +1223,4 @@ declare class BatchResponse {
1097
1223
  private getTranslationsMap;
1098
1224
  }
1099
1225
 
1100
- export { type CMSPluginOptions as $, type Action as A, type BatchRequestOptions as B, BatchRequest as C, type DocMode as D, BatchResponse as E, type Locale as F, type GetDocOptions as G, type HttpMethod as H, type SourceString as I, type TranslatedString as J, type TranslationsDocMode as K, type LoadTranslationsOptions as L, type TranslationsLocaleDocHashMap as M, type TranslationsLocaleDocEntry as N, type MultiLocaleTranslationsMap as O, type SingleLocaleTranslationsMap as P, TranslationsManager as Q, RootCMSClient as R, type SetDocOptions as S, type TranslationsMap as T, type UserRole as U, buildTranslationsDbPath as V, buildTranslationsLocaleDocDbPath as W, type CMSBuiltInSidebarTool as X, type CMSUser as Y, type CMSAIConfig as Z, type CMSSidebarTool as _, type LocaleTranslations as a, type CMSPlugin as a0, cmsPlugin as a1, type CMSCheck as a2, type CheckResult as a3, type CheckContext as a4, type CheckStatus as a5, translationsCheck as a6, type Doc as b, type DataSource as c, type DataSourceData as d, type DataSourceMode as e, type SaveDraftOptions as f, type UpdateDraftOptions as g, type ListDocsOptions as h, type GetCountOptions as i, type Translation as j, type Release as k, type ListActionsOptions as l, isRichTextData as m, getCmsPlugin as n, marshalData as o, normalizeData as p, type ArrayObject as q, marshalArray as r, unmarshalArray as s, toArrayObject as t, unmarshalData as u, translationsForLocale as v, parseDocId as w, type BatchRequestQuery as x, type BatchRequestQueryOptions as y, type TranslationsDoc as z };
1226
+ export { type CMSAIConfig as $, type Action as A, type BatchRequestOptions as B, type CronUnit as C, type DocMode as D, type TranslationsDoc as E, BatchRequest as F, type GetDocOptions as G, type HttpMethod as H, BatchResponse as I, type Locale as J, type SourceString as K, type LoadTranslationsOptions as L, type TranslatedString as M, type TranslationsDocMode as N, type TranslationsLocaleDocHashMap as O, type TranslationsLocaleDocEntry as P, type MultiLocaleTranslationsMap as Q, RootCMSClient as R, type SetDocOptions as S, type TranslationsMap as T, type UserRole as U, type SingleLocaleTranslationsMap as V, TranslationsManager as W, buildTranslationsDbPath as X, buildTranslationsLocaleDocDbPath as Y, type CMSBuiltInSidebarTool as Z, type CMSUser as _, type LocaleTranslations as a, type CMSSidebarTool as a0, type CMSPluginOptions as a1, type CMSPlugin as a2, cmsPlugin as a3, type CMSCheck as a4, type CheckResult as a5, type CheckContext as a6, type CheckStatus as a7, translationsCheck as a8, type TranslationsCheckOptions as a9, type CMSTranslationService as aa, type TranslationExportResult as ab, type TranslationRow as ac, type TranslationServiceContext as ad, type Doc as b, type DataSourceCron as c, type DataSource as d, type DataSourceData as e, type DataSourceMode as f, type SaveDraftOptions as g, type UpdateDraftOptions as h, type ListDocsOptions as i, type GetCountOptions as j, type Translation as k, type Release as l, type ListActionsOptions as m, isRichTextData as n, getCmsPlugin as o, marshalData as p, normalizeData as q, type ArrayObject as r, marshalArray as s, toArrayObject as t, unmarshalData as u, unmarshalArray as v, translationsForLocale as w, parseDocId as x, type BatchRequestQuery as y, type BatchRequestQueryOptions as z };
package/dist/client.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import '@blinkk/root';
2
2
  import 'firebase-admin/app';
3
3
  import 'firebase-admin/firestore';
4
- export { A as Action, q as ArrayObject, C as BatchRequest, B as BatchRequestOptions, x as BatchRequestQuery, y as BatchRequestQueryOptions, E as BatchResponse, c as DataSource, d as DataSourceData, e as DataSourceMode, b as Doc, D as DocMode, i as GetCountOptions, G as GetDocOptions, H as HttpMethod, l as ListActionsOptions, h as ListDocsOptions, L as LoadTranslationsOptions, a as LocaleTranslations, k as Release, R as RootCMSClient, f as SaveDraftOptions, S as SetDocOptions, j as Translation, z as TranslationsDoc, T as TranslationsMap, g as UpdateDraftOptions, U as UserRole, n as getCmsPlugin, m as isRichTextData, r as marshalArray, o as marshalData, p as normalizeData, w as parseDocId, t as toArrayObject, v as translationsForLocale, s as unmarshalArray, u as unmarshalData } from './client-B3U47cNR.js';
5
- import './schema-Bht24XmU.js';
4
+ export { A as Action, r as ArrayObject, F as BatchRequest, B as BatchRequestOptions, y as BatchRequestQuery, z as BatchRequestQueryOptions, I as BatchResponse, C as CronUnit, d as DataSource, c as DataSourceCron, e as DataSourceData, f as DataSourceMode, b as Doc, D as DocMode, j as GetCountOptions, G as GetDocOptions, H as HttpMethod, m as ListActionsOptions, i as ListDocsOptions, L as LoadTranslationsOptions, a as LocaleTranslations, l as Release, R as RootCMSClient, g as SaveDraftOptions, S as SetDocOptions, k as Translation, E as TranslationsDoc, T as TranslationsMap, h as UpdateDraftOptions, U as UserRole, o as getCmsPlugin, n as isRichTextData, s as marshalArray, p as marshalData, q as normalizeData, x as parseDocId, t as toArrayObject, w as translationsForLocale, v as unmarshalArray, u as unmarshalData } from './client-CFCGhGA0.js';
5
+ import './schema-D7MOj-YC.js';
package/dist/client.js CHANGED
@@ -12,7 +12,7 @@ import {
12
12
  translationsForLocale,
13
13
  unmarshalArray,
14
14
  unmarshalData
15
- } from "./chunk-5N2KLMQH.js";
15
+ } from "./chunk-YMUZ5H5C.js";
16
16
  import "./chunk-MLKGABMK.js";
17
17
  export {
18
18
  BatchRequest,
package/dist/core.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- import { R as RootCMSClient, D as DocMode, L as LoadTranslationsOptions, T as TranslationsMap, a as LocaleTranslations } from './client-B3U47cNR.js';
2
- export { A as Action, q as ArrayObject, C as BatchRequest, B as BatchRequestOptions, x as BatchRequestQuery, y as BatchRequestQueryOptions, E as BatchResponse, c as DataSource, d as DataSourceData, e as DataSourceMode, b as Doc, i as GetCountOptions, G as GetDocOptions, H as HttpMethod, l as ListActionsOptions, h as ListDocsOptions, F as Locale, O as MultiLocaleTranslationsMap, k as Release, f as SaveDraftOptions, S as SetDocOptions, P as SingleLocaleTranslationsMap, I as SourceString, J as TranslatedString, j as Translation, z as TranslationsDoc, K as TranslationsDocMode, N as TranslationsLocaleDocEntry, M as TranslationsLocaleDocHashMap, Q as TranslationsManager, g as UpdateDraftOptions, U as UserRole, V as buildTranslationsDbPath, W as buildTranslationsLocaleDocDbPath, n as getCmsPlugin, m as isRichTextData, r as marshalArray, o as marshalData, p as normalizeData, w as parseDocId, t as toArrayObject, v as translationsForLocale, s as unmarshalArray, u as unmarshalData } from './client-B3U47cNR.js';
1
+ import { R as RootCMSClient, D as DocMode, L as LoadTranslationsOptions, T as TranslationsMap, a as LocaleTranslations } from './client-CFCGhGA0.js';
2
+ export { A as Action, r as ArrayObject, F as BatchRequest, B as BatchRequestOptions, y as BatchRequestQuery, z as BatchRequestQueryOptions, I as BatchResponse, C as CronUnit, d as DataSource, c as DataSourceCron, e as DataSourceData, f as DataSourceMode, b as Doc, j as GetCountOptions, G as GetDocOptions, H as HttpMethod, m as ListActionsOptions, i as ListDocsOptions, J as Locale, Q as MultiLocaleTranslationsMap, l as Release, g as SaveDraftOptions, S as SetDocOptions, V as SingleLocaleTranslationsMap, K as SourceString, M as TranslatedString, k as Translation, E as TranslationsDoc, N as TranslationsDocMode, P as TranslationsLocaleDocEntry, O as TranslationsLocaleDocHashMap, W as TranslationsManager, h as UpdateDraftOptions, U as UserRole, X as buildTranslationsDbPath, Y as buildTranslationsLocaleDocDbPath, o as getCmsPlugin, n as isRichTextData, s as marshalArray, p as marshalData, q as normalizeData, x as parseDocId, t as toArrayObject, w as translationsForLocale, v as unmarshalArray, u as unmarshalData } from './client-CFCGhGA0.js';
3
3
  import { Request, RootConfig, Response, RouteParams, GetStaticProps, GetStaticPaths } from '@blinkk/root';
4
4
  import { Query } from 'firebase-admin/firestore';
5
- export { s as schema } from './schema-Bht24XmU.js';
5
+ export { s as schema } from './schema-D7MOj-YC.js';
6
6
  import 'firebase-admin/app';
7
7
 
8
8
  /**
package/dist/core.js CHANGED
@@ -16,7 +16,7 @@ import {
16
16
  translationsForLocale,
17
17
  unmarshalArray,
18
18
  unmarshalData
19
- } from "./chunk-5N2KLMQH.js";
19
+ } from "./chunk-YMUZ5H5C.js";
20
20
  import {
21
21
  __export
22
22
  } from "./chunk-MLKGABMK.js";
@@ -86,7 +86,6 @@ function createRoute(options) {
86
86
  const ctx = req.handlerContext;
87
87
  const slug = getSlug(ctx.params);
88
88
  if (slug.includes(".") || slug.includes("--")) {
89
- res.setHeader("cache-control", "private");
90
89
  return ctx.render404();
91
90
  }
92
91
  const mode = await getMode(req);
@@ -122,7 +121,6 @@ function createRoute(options) {
122
121
  await options.notFoundHook(req, res);
123
122
  return;
124
123
  }
125
- res.setHeader("cache-control", "private");
126
124
  return ctx.render404();
127
125
  }
128
126
  const hl = getFirstQueryParam(req, "hl");
@@ -184,7 +182,6 @@ function createRoute(options) {
184
182
  await options.notFoundHook(req, res);
185
183
  return;
186
184
  }
187
- res.setHeader("cache-control", "private");
188
185
  return ctx.render404();
189
186
  }
190
187
  }
package/dist/functions.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  runCronJobs
3
- } from "./chunk-AFL5KJ4E.js";
4
- import "./chunk-5N2KLMQH.js";
3
+ } from "./chunk-PKD2TDSV.js";
4
+ import "./chunk-YMUZ5H5C.js";
5
5
  import "./chunk-MLKGABMK.js";
6
6
 
7
7
  // core/functions.ts
package/dist/plugin.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import '@blinkk/root';
2
2
  import 'firebase-admin/app';
3
3
  import 'firebase-admin/firestore';
4
- export { Z as CMSAIConfig, X as CMSBuiltInSidebarTool, a2 as CMSCheck, a0 as CMSPlugin, $ as CMSPluginOptions, _ as CMSSidebarTool, Y as CMSUser, a4 as CheckContext, a3 as CheckResult, a5 as CheckStatus, a1 as cmsPlugin, a6 as translationsCheck } from './client-B3U47cNR.js';
5
- import './schema-Bht24XmU.js';
4
+ export { $ as CMSAIConfig, Z as CMSBuiltInSidebarTool, a4 as CMSCheck, a2 as CMSPlugin, a1 as CMSPluginOptions, a0 as CMSSidebarTool, aa as CMSTranslationService, _ as CMSUser, a6 as CheckContext, a5 as CheckResult, a7 as CheckStatus, ab as TranslationExportResult, ac as TranslationRow, ad as TranslationServiceContext, a9 as TranslationsCheckOptions, a3 as cmsPlugin, a8 as translationsCheck } from './client-CFCGhGA0.js';
5
+ import './schema-D7MOj-YC.js';