@blinkk/root-cms 3.0.2 → 3.0.4

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.
Files changed (161) hide show
  1. package/dist/app.js +5 -5
  2. package/dist/{chunk-2BSW7SIH.js → chunk-N4K6ICFR.js} +4 -4
  3. package/dist/{chunk-BGTUWIV6.js → chunk-PNLLZXVY.js} +4 -4
  4. package/dist/{chunk-3HARN4U6.js → chunk-RLZFZT42.js} +176 -83
  5. package/dist/{chunk-C245C557.js → chunk-RXWDB3K4.js} +3 -3
  6. package/dist/{chunk-XLX37FRL.js → chunk-TEKMLYXS.js} +3 -4
  7. package/dist/cli/cli.d.ts +12 -0
  8. package/dist/cli/docs.d.ts +49 -0
  9. package/dist/cli/export.d.ts +11 -0
  10. package/dist/cli/generate-types.d.ts +6 -0
  11. package/dist/cli/import.d.ts +13 -0
  12. package/dist/cli/init-firebase.d.ts +7 -0
  13. package/dist/cli/utils.d.ts +27 -0
  14. package/dist/cli.js +10 -10
  15. package/dist/client.js +1 -1
  16. package/dist/core/ai-tools.d.ts +156 -0
  17. package/dist/core/ai.d.ts +330 -0
  18. package/dist/core/api.d.ts +21 -0
  19. package/dist/core/app.d.ts +16 -0
  20. package/dist/core/checks-translations.d.ts +13 -0
  21. package/dist/core/checks.d.ts +48 -0
  22. package/dist/core/client.d.ts +715 -0
  23. package/dist/core/core.d.ts +5 -0
  24. package/dist/core/cron.d.ts +19 -0
  25. package/dist/core/csv.d.ts +5 -0
  26. package/dist/core/functions.d.ts +9 -0
  27. package/dist/core/plugin.d.ts +357 -0
  28. package/dist/{project.d.ts → core/project.d.ts} +8 -12
  29. package/dist/core/richtext.d.ts +101 -0
  30. package/dist/{core.d.ts → core/route.d.ts} +13 -66
  31. package/dist/core/runtime.d.ts +46 -0
  32. package/dist/{schema-Db_xODoi.d.ts → core/schema.d.ts} +47 -100
  33. package/dist/core/search-extract.d.ts +70 -0
  34. package/dist/core/search-index.d.ts +182 -0
  35. package/dist/core/search-query.d.ts +68 -0
  36. package/dist/core/security.d.ts +6 -0
  37. package/dist/core/server-version.d.ts +5 -0
  38. package/dist/core/services-notifications.d.ts +57 -0
  39. package/dist/core/services.d.ts +44 -0
  40. package/dist/core/sse.d.ts +10 -0
  41. package/dist/core/translations-manager.d.ts +187 -0
  42. package/dist/core/translations.d.ts +83 -0
  43. package/dist/core/url-safety.d.ts +19 -0
  44. package/dist/core/validation.d.ts +30 -0
  45. package/dist/core/values.d.ts +9 -0
  46. package/dist/core/versions.d.ts +48 -0
  47. package/dist/core.js +1 -1
  48. package/dist/edit-M4PN4SGX.js +7 -0
  49. package/dist/functions.js +4 -4
  50. package/dist/{generate-types-SPV7I3A5.js → generate-types-JWIG4QVI.js} +1 -1
  51. package/dist/plugin.js +128 -133
  52. package/dist/shared/marshal.d.ts +68 -0
  53. package/dist/shared/objects.d.ts +9 -0
  54. package/dist/shared/richtext.d.ts +74 -0
  55. package/dist/shared/safe-json.d.ts +11 -0
  56. package/dist/shared/sanitize.d.ts +12 -0
  57. package/dist/shared/slug.d.ts +19 -0
  58. package/dist/shared/sse.d.ts +16 -0
  59. package/dist/shared/strings.d.ts +23 -0
  60. package/dist/ui/AIPage-YI3RFK5F.js +1 -0
  61. package/dist/ui/AssetsPage-4JNAOFYF.js +1 -0
  62. package/dist/ui/CollectionPage-JWHH5G55.js +1 -0
  63. package/dist/ui/ComparePage-YZE3EMU4.js +1 -0
  64. package/dist/ui/DataPage-VRCQSZZG.js +1 -0
  65. package/dist/ui/DataSourcePage-WMSPBZ3W.js +1 -0
  66. package/dist/ui/DocTranslationsPage-RY2LOZBX.js +1 -0
  67. package/dist/ui/DocumentPage-EEGTJMIW.js +1 -0
  68. package/dist/ui/EditDataSourcePage-LLCX6K4J.js +1 -0
  69. package/dist/ui/EditReleasePage-WQYXXMZQ.js +1 -0
  70. package/dist/ui/ImageEditorDialog-4H665KK2.js +81 -0
  71. package/dist/ui/ImageEditorDialog-4H665KK2.js.LEGAL.txt +17 -0
  72. package/dist/ui/LogsPage-IP2DKEYR.js +1 -0
  73. package/dist/ui/NewDataSourcePage-RDYJC4DH.js +1 -0
  74. package/dist/ui/NewReleasePage-DGMFU2JN.js +1 -0
  75. package/dist/ui/NotFoundPage-WDZ2K7EF.js +1 -0
  76. package/dist/ui/ProjectPage-HYJOQUWR.js +1 -0
  77. package/dist/ui/ReleasePage-2KSF23TK.js +1 -0
  78. package/dist/ui/ReleasesPage-NZIBBXU4.js +1 -0
  79. package/dist/ui/SettingsPage-36XFWV62.js +1 -0
  80. package/dist/ui/SidebarToolsPage-5C6YBWJ7.js +1 -0
  81. package/dist/ui/TaskPage-SPIFPGPP.js +1 -0
  82. package/dist/ui/TasksPage-ZOXRPBQV.js +1 -0
  83. package/dist/ui/TranslationsArbPage-UHANA7JD.js +2 -0
  84. package/dist/ui/TranslationsEditPage-PQY6W5YG.js +1 -0
  85. package/dist/ui/TranslationsPage-V2PQFCN5.js +162 -0
  86. package/dist/ui/ai-tools-5E5ELLZX.js +1 -0
  87. package/dist/ui/chunk-3IYZCUPI.js +1 -0
  88. package/dist/ui/chunk-4KE2SZKH.js +1 -0
  89. package/dist/ui/chunk-4W73RW5I.js +1 -0
  90. package/dist/ui/chunk-54DVDYU6.js +1 -0
  91. package/dist/ui/chunk-5MV6XVGA.js +1 -0
  92. package/dist/ui/chunk-62UWGWON.js +1 -0
  93. package/dist/ui/chunk-767BAQ53.js +1 -0
  94. package/dist/ui/chunk-AFWBSIPL.js +1 -0
  95. package/dist/ui/chunk-AL3TN2KI.js +1 -0
  96. package/dist/ui/chunk-BZIRGB4W.js +1 -0
  97. package/dist/ui/chunk-C5NH23G4.js +3 -0
  98. package/dist/ui/chunk-CGCKJFL4.js +1 -0
  99. package/dist/ui/chunk-DEGMKEHP.js +1 -0
  100. package/dist/ui/chunk-DTMZLUNY.js +15 -0
  101. package/dist/ui/chunk-DTMZLUNY.js.LEGAL.txt +237 -0
  102. package/dist/ui/chunk-DUJYIOLE.js +5 -0
  103. package/dist/ui/chunk-E2RCCK2T.js +1 -0
  104. package/dist/ui/chunk-EGEB6N4J.js +22 -0
  105. package/dist/ui/chunk-EGEB6N4J.js.LEGAL.txt +1059 -0
  106. package/dist/ui/chunk-FBJURT7Z.js +1 -0
  107. package/dist/ui/chunk-GXSAEPU3.js +1 -0
  108. package/dist/ui/chunk-HHMG665Z.js +1 -0
  109. package/dist/ui/chunk-HKINZLMW.js +84 -0
  110. package/dist/ui/chunk-HLMBCVRX.js +1 -0
  111. package/dist/ui/chunk-HRGYNHZ3.js +1 -0
  112. package/dist/ui/chunk-I6ICVKEC.js +1 -0
  113. package/dist/ui/chunk-JDW4UORS.js +1 -0
  114. package/dist/ui/chunk-JHBAMPGB.js +1 -0
  115. package/dist/ui/chunk-JT5L6GPZ.js +141 -0
  116. package/dist/ui/chunk-JT5L6GPZ.js.LEGAL.txt +106 -0
  117. package/dist/ui/chunk-JYFLU7DM.js +19 -0
  118. package/dist/ui/chunk-JZFTZ4X4.js +87 -0
  119. package/dist/ui/chunk-JZFTZ4X4.js.LEGAL.txt +9 -0
  120. package/dist/ui/chunk-KFAZBEPV.js +1 -0
  121. package/dist/ui/chunk-KKEWCXVV.js +1 -0
  122. package/dist/ui/chunk-KUCVLANF.js +1 -0
  123. package/dist/ui/chunk-KYDOSLTO.js +1 -0
  124. package/dist/ui/chunk-L4RHGQUG.js +1 -0
  125. package/dist/ui/chunk-MDUBCXU2.js +1 -0
  126. package/dist/ui/chunk-NXQVLOTK.js +1 -0
  127. package/dist/ui/chunk-NZHF733K.js +7 -0
  128. package/dist/ui/chunk-NZHF733K.js.LEGAL.txt +146 -0
  129. package/dist/ui/chunk-ONTGW2VA.js +1 -0
  130. package/dist/ui/chunk-ORXEMIQC.js +1 -0
  131. package/dist/ui/chunk-P3NETZZP.js +1 -0
  132. package/dist/ui/chunk-PHBMVORG.js +1 -0
  133. package/dist/ui/chunk-PJA7YP4A.js +1 -0
  134. package/dist/ui/chunk-PVAE643M.js +1 -0
  135. package/dist/ui/chunk-PWKJDYE2.js +1 -0
  136. package/dist/ui/chunk-RSVO46S3.js +1 -0
  137. package/dist/ui/chunk-SKEP5WYH.js +10 -0
  138. package/dist/ui/chunk-SKEP5WYH.js.LEGAL.txt +176 -0
  139. package/dist/ui/chunk-SQRKKWRG.js +3 -0
  140. package/dist/ui/chunk-TJBVMFNQ.js +1 -0
  141. package/dist/ui/chunk-V7S4IAGB.js +1 -0
  142. package/dist/ui/chunk-VMT7JFAM.js +1 -0
  143. package/dist/ui/chunk-W3BJ2EZX.js +1 -0
  144. package/dist/ui/chunk-W3HIZQ4Z.js +1 -0
  145. package/dist/ui/chunk-X2WHBGTP.js +1 -0
  146. package/dist/ui/chunk-XOQ3KDSR.js +3 -0
  147. package/dist/ui/chunk-YDO2EDVY.js +1 -0
  148. package/dist/ui/chunk-YFA6U2CV.js +1 -0
  149. package/dist/ui/gcs-L33FIRZU.js +1 -0
  150. package/dist/ui/prerender-Q4YSDCPB.js +1 -0
  151. package/dist/ui/signin.js +1 -1
  152. package/dist/ui/ui.css +1 -1
  153. package/dist/ui/ui.js +1 -630
  154. package/dist/ui/ui.js.LEGAL.txt +19 -732
  155. package/package.json +20 -20
  156. package/dist/client-1puwLgNx.d.ts +0 -1552
  157. package/dist/client.d.ts +0 -5
  158. package/dist/edit-MT4B37QK.js +0 -7
  159. package/dist/functions.d.ts +0 -13
  160. package/dist/plugin.d.ts +0 -5
  161. package/dist/richtext.d.ts +0 -104
@@ -1,1552 +0,0 @@
1
- import { RootConfig, Plugin, Request } from '@blinkk/root';
2
- import { App } from 'firebase-admin/app';
3
- import { Firestore, WriteBatch, Timestamp, Query } from 'firebase-admin/firestore';
4
- import { C as Collection } from './schema-Db_xODoi.js';
5
-
6
- /**
7
- * Provider type for an AI model. Use `openai-compatible` for any OpenAI-style
8
- * endpoint (e.g. local Ollama, vLLM, OpenRouter).
9
- */
10
- type AiProvider = 'openai' | 'openai-compatible' | 'anthropic' | 'google';
11
- /**
12
- * Configuration for a single chat model.
13
- *
14
- * Inspired by Ollama's `Modelfile` and LiteLLM's model config: each entry maps
15
- * a CMS-facing id to a provider, model id and credentials.
16
- */
17
- interface AiModelConfig {
18
- /** Stable id used by the CMS UI and stored alongside chat history. */
19
- id: string;
20
- /** Optional human-readable label rendered in the model picker. */
21
- label?: string;
22
- /** Optional description shown under the label. */
23
- description?: string;
24
- /** AI provider/family to route requests to. */
25
- provider: AiProvider;
26
- /**
27
- * Provider-specific model id (e.g. `gpt-4o`, `claude-opus-4-5`,
28
- * `gemini-2.5-pro`). Defaults to `id` if omitted.
29
- */
30
- modelId?: string;
31
- /** API key for the provider. */
32
- apiKey?: string;
33
- /** Override the provider's base URL (required for `openai-compatible`). */
34
- baseURL?: string;
35
- /** Custom headers to send with each request. */
36
- headers?: Record<string, string>;
37
- /** Capabilities advertised to the UI. */
38
- capabilities?: {
39
- /** Whether the model can call tools. Defaults to `true`. */
40
- tools?: boolean;
41
- /** Whether the model can stream reasoning/thinking. Defaults to `false`. */
42
- reasoning?: boolean;
43
- /** Whether the model accepts image attachments. Defaults to `false`. */
44
- attachments?: boolean;
45
- };
46
- }
47
- /**
48
- * Full AI config registered on the cms plugin.
49
- */
50
- interface AiConfig {
51
- /** Models exposed in the model picker. The first entry is the default. */
52
- models: AiModelConfig[];
53
- /** Id of the default model. Defaults to the first model in `models`. */
54
- defaultModel?: string;
55
- /**
56
- * Image generation models. Used by the image generator and any other
57
- * features that produce images. Only the `openai` and `google` providers
58
- * support image generation.
59
- */
60
- imageModels?: AiModelConfig[];
61
- /** Id of the default image model. Defaults to the first entry in `imageModels`. */
62
- defaultImageModel?: string;
63
- /**
64
- * Optional system prompt prepended to every conversation. If a `ROOT.md`
65
- * file exists at the project root, its contents are appended to this
66
- * prompt automatically.
67
- */
68
- systemPrompt?: string;
69
- /** Maximum tool-loop steps before stopping. Defaults to 10. */
70
- maxSteps?: number;
71
- }
72
-
73
- /** The result status of a check. */
74
- type CheckStatus = 'success' | 'warning' | 'error';
75
- /** Result returned by a check function after execution. */
76
- interface CheckResult {
77
- /** Whether the check succeeded, warned, or failed. */
78
- status: CheckStatus;
79
- /** A message describing the result. Supports markdown. */
80
- message: string;
81
- /** Optional metadata to include with the result. */
82
- metadata?: Record<string, any>;
83
- }
84
- /** Context passed to a check function during execution. */
85
- interface CheckContext {
86
- /** The Root.js config. */
87
- rootConfig: RootConfig;
88
- /** The Root CMS client for accessing the database. */
89
- cmsClient: RootCMSClient;
90
- /** The document ID, e.g. `Pages/index`. */
91
- docId: string;
92
- /** The collection ID, e.g. `Pages`. */
93
- collectionId: string;
94
- /** The slug, e.g. `index`. */
95
- slug: string;
96
- /** The collection schema. */
97
- collectionSchema: Collection | null;
98
- }
99
- /** Configuration for defining a CMS check. */
100
- interface CMSCheck {
101
- /** Unique ID for the check. */
102
- id: string;
103
- /** Human-readable label displayed in the UI. */
104
- label: string;
105
- /** Optional description explaining what the check does. */
106
- description?: string;
107
- /**
108
- * Optional list of collection IDs to restrict this check to. When set, the
109
- * check is only shown and runnable for documents belonging to one of the
110
- * listed collections. When omitted, the check applies to all collections.
111
- */
112
- collections?: string[];
113
- /**
114
- * Function that runs the check on the server-side and returns a result.
115
- */
116
- run: (ctx: CheckContext) => Promise<CheckResult>;
117
- }
118
-
119
- /**
120
- * Base shape for a service registered with the CMS plugin.
121
- *
122
- * Services are extension points that let plugins provide capabilities
123
- * (e.g. email delivery, cache, translations) that root-cms can call into.
124
- * Every service shares the same identifying fields — `id`, `label`, optional
125
- * `icon` — and is registered via the `services` option on `cmsPlugin()`.
126
- *
127
- * Concrete service interfaces (e.g. `CMSEmailService`,
128
- * `CMSTranslationService`) extend this base and add the handler functions
129
- * specific to their capability.
130
- */
131
- interface CMSService {
132
- /** Unique ID for the service (e.g. `'sendgrid'`, `'crowdin'`). */
133
- id: string;
134
- /** Human-readable label displayed in the UI (e.g. "SendGrid"). */
135
- label: string;
136
- /**
137
- * Optional icon URL displayed in the UI next to the label. Similar to the
138
- * sidebar tools `icon` option, this should be a URL to an image.
139
- */
140
- icon?: string;
141
- }
142
- /**
143
- * Base context passed to service handler functions. Concrete services may
144
- * extend this with additional fields specific to the call site (e.g. the
145
- * translation context adds `docId`, `collectionId`, etc.).
146
- */
147
- interface CMSServiceContext {
148
- /** The Root.js config. */
149
- rootConfig: RootConfig;
150
- /** The Root CMS client for accessing the database. */
151
- cmsClient: RootCMSClient;
152
- /**
153
- * Email of the user that triggered the action, if any. Some service calls
154
- * are initiated by the system rather than a user, in which case this is
155
- * undefined.
156
- */
157
- user?: {
158
- email: string;
159
- };
160
- }
161
-
162
- /** Result returned by a notification service `onAction` handler. */
163
- interface NotificationResult {
164
- /**
165
- * Delivery status.
166
- * - `'success'`: the notification was delivered.
167
- * - `'error'`: delivery failed; `message` should describe why.
168
- * - `'info'` (default): the service handled the action but did not
169
- * deliver a notification (e.g. the action was filtered out).
170
- */
171
- status?: 'success' | 'info' | 'error';
172
- /** Optional human-readable message describing the result. */
173
- message?: string;
174
- }
175
- /** Context passed to notification service handler functions. */
176
- interface NotificationServiceContext extends CMSServiceContext {
177
- }
178
- /**
179
- * Configuration for defining a CMS notification service.
180
- *
181
- * Notification services react to actions in the CMS (publishes, schema
182
- * changes, comments, etc.) and dispatch them to an external channel.
183
- * Initially this is intended for email, with Slack, webhooks, and other
184
- * transports planned.
185
- *
186
- * Multiple notification services may be registered; each independently
187
- * decides whether and how to handle a given action.
188
- *
189
- * Example:
190
- * ```ts
191
- * cmsPlugin({
192
- * services: {
193
- * notifications: [
194
- * {
195
- * id: 'sendgrid',
196
- * label: 'SendGrid',
197
- * onAction: async (ctx, action) => {
198
- * if (action.action === 'doc.publish') {
199
- * await sendgrid.send({ ... });
200
- * }
201
- * },
202
- * },
203
- * ],
204
- * },
205
- * });
206
- * ```
207
- */
208
- interface CMSNotificationService extends CMSService {
209
- /**
210
- * Async function called when an action occurs in the CMS. Receives the
211
- * action and may dispatch a notification (e.g. send email, post to Slack)
212
- * via the service's underlying transport. Can optionally return a
213
- * `NotificationResult` describing delivery status.
214
- */
215
- onAction?: (ctx: NotificationServiceContext, action: Action) => Promise<void | NotificationResult>;
216
- }
217
-
218
- /** A row of translation data keyed by locale. */
219
- interface TranslationRow {
220
- /** The source string. */
221
- source: string;
222
- /** Map of locale code to translated string. */
223
- translations: Record<string, string>;
224
- /** Optional translator notes/context for the source string. */
225
- description?: string;
226
- }
227
- /** Context passed to translation service import/export functions. */
228
- interface TranslationServiceContext extends CMSServiceContext {
229
- /** The document ID, e.g. `Pages/index`. */
230
- docId: string;
231
- /** The collection ID, e.g. `Pages`. */
232
- collectionId: string;
233
- /** The slug, e.g. `index`. */
234
- slug: string;
235
- /** The locales configured for the project. */
236
- locales: string[];
237
- /** The email of the user performing the action. */
238
- user: {
239
- email: string;
240
- };
241
- }
242
- /** Result returned by an onExport handler. */
243
- interface TranslationExportResult {
244
- /** Optional title displayed in the notification after export. */
245
- title?: string;
246
- /** Optional message displayed in the notification after export. */
247
- message?: string;
248
- /** Optional link displayed in the notification (e.g. to the translation service). */
249
- link?: {
250
- /** The URL to link to. */
251
- url: string;
252
- /** Optional label for the link. Defaults to "Open". */
253
- label?: string;
254
- };
255
- /**
256
- * Notification status controlling the color of the notification.
257
- * - `'success'`: green
258
- * - `'error'`: red
259
- * - `'info'` (default): neutral
260
- */
261
- status?: 'success' | 'info' | 'error';
262
- }
263
- /** Result returned by an onImport handler when no rows are imported. */
264
- interface TranslationImportResult {
265
- /** Optional title displayed in the notification after import. */
266
- title?: string;
267
- /** Optional message displayed in the notification after import. */
268
- message?: string;
269
- /** Optional link displayed in the notification (e.g. to the translation service). */
270
- link?: {
271
- /** The URL to link to. */
272
- url: string;
273
- /** Optional label for the link. Defaults to "Open". */
274
- label?: string;
275
- };
276
- /**
277
- * Notification status controlling the color of the notification.
278
- * - `'success'`: green
279
- * - `'error'`: red
280
- * - `'info'` (default): neutral
281
- */
282
- status?: 'success' | 'info' | 'error';
283
- }
284
- /** Configuration for defining a CMS translation service. */
285
- interface CMSTranslationService extends CMSService {
286
- /**
287
- * Async function to import translations from the service. Should return an
288
- * array of translation rows that will be merged into the CMS translations
289
- * database, or a `TranslationImportResult` object to display a notification
290
- * without importing any rows.
291
- */
292
- onImport?: (ctx: TranslationServiceContext, data: TranslationRow[]) => Promise<TranslationRow[] | TranslationImportResult>;
293
- /**
294
- * Async function to export translations to the service. Receives the
295
- * current translation rows for the document. Can optionally return an object
296
- * with a `message` to display in the success notification.
297
- */
298
- onExport?: (ctx: TranslationServiceContext, data: TranslationRow[]) => Promise<void | TranslationExportResult>;
299
- }
300
-
301
- interface TranslationsCheckOptions {
302
- /**
303
- * Optional list of collection IDs to restrict this check to. When set, the
304
- * check is only shown and runnable for documents in these collections.
305
- */
306
- collections?: string[];
307
- }
308
- /**
309
- * A first-party CMS check that verifies all translatable strings in a document
310
- * have translations for each of the document's enabled locales.
311
- */
312
- declare function translationsCheck(options?: TranslationsCheckOptions): CMSCheck;
313
-
314
- /**
315
- * Built-in sidebar tools that can be toggled on/off in the CMS UI.
316
- */
317
- type CMSBuiltInSidebarTool = 'home' | 'content' | 'releases' | 'data' | 'assets' | 'translations' | 'ai' | 'settings';
318
- interface CMSUser {
319
- email: string;
320
- }
321
- /**
322
- * @deprecated The `experiments.ai` flag is now used only as a sidebar toggle.
323
- * Configure chat models on the top-level `ai` plugin option instead.
324
- */
325
- interface CMSAIConfig {
326
- /** Custom API endpoint for chat prompts. */
327
- endpoint?: string;
328
- /** Gen AI model to use. */
329
- model?: string;
330
- }
331
- /**
332
- * Filters applied to the spotlight / global search indexer. By default every
333
- * collection and every doc is indexed. Use these options to scope the index to
334
- * a subset of the project's content.
335
- *
336
- * Doc ids use the `<collectionId>/<slug>` format (e.g. `Pages/about`), which
337
- * matches the format used elsewhere in the CMS.
338
- */
339
- interface CMSSearchIndexConfig {
340
- /**
341
- * Collections to include in the search index. If specified, only these
342
- * collections are indexed. If unset, all collections are indexed (subject to
343
- * `excludeCollections`).
344
- */
345
- includeCollections?: string[];
346
- /**
347
- * Collections to exclude from the search index. Applied after
348
- * `includeCollections`.
349
- */
350
- excludeCollections?: string[];
351
- /**
352
- * Doc ids to include in the search index. If specified, only these docs are
353
- * indexed (within collections that pass the collection filter). Format:
354
- * `<collectionId>/<slug>`.
355
- */
356
- includeDocIds?: string[];
357
- /**
358
- * Doc ids to exclude from the search index. Applied after `includeDocIds`.
359
- * Format: `<collectionId>/<slug>`.
360
- */
361
- excludeDocIds?: string[];
362
- }
363
- interface CMSSidebarTool {
364
- /** URL for the sidebar icon image. */
365
- icon?: string;
366
- /** Label. */
367
- label?: string;
368
- /** Iframe URL to render for the tool. */
369
- iframeUrl?: string;
370
- /**
371
- * CMS URL that should be opened when the tool is selected. The url must start
372
- * with `/cms/`. Use this to create shortcuts to CMS pages instead of
373
- * rendering the tool inside an iframe.
374
- */
375
- cmsUrl?: string;
376
- /**
377
- * External URL that should open in a new tab when the tool is selected.
378
- */
379
- externalUrl?: string;
380
- }
381
- type CMSPluginOptions = {
382
- /**
383
- * The ID of the project. Data will be stored under the namespace
384
- * `Projects/${id}` in firestore.
385
- */
386
- id?: string;
387
- /**
388
- * The name of the project. Used in the header of the CMS to help identify
389
- * the project.
390
- */
391
- name?: string;
392
- /**
393
- * Firebase config object, which can be obtained in the Firebase Console by
394
- * going to "Project Settings".
395
- */
396
- firebaseConfig: {
397
- [key: string]: string | undefined;
398
- apiKey: string;
399
- authDomain: string;
400
- projectId: string;
401
- storageBucket: string;
402
- databaseId?: string;
403
- };
404
- /**
405
- * GAPI credentials. Include if using Google Drive and Google Sheets features.
406
- * See: https://developers.google.com/sheets/api/quickstart/js
407
- */
408
- gapi?: {
409
- /** https://developers.google.com/sheets/api/quickstart/js#create_an_api_key */
410
- apiKey: string;
411
- /** https://developers.google.com/sheets/api/quickstart/js#authorize_credentials_for_a_web_application */
412
- clientId: string;
413
- };
414
- /**
415
- * Secret value(s) used for signing the user authentication cookie.
416
- * @deprecated This is now handled directly by root's sessionMiddleware under
417
- * `server.sessionCookieSecret` in root.config.ts.
418
- */
419
- cookieSecret?: string | string[];
420
- /** Function called to check if a user should have access to the CMS. */
421
- isUserAuthorized?: (req: Request, user: CMSUser) => boolean | Promise<boolean>;
422
- /**
423
- * Function to call to check if login is required for a particular request.
424
- */
425
- isLoginRequired?: (req: Request) => boolean;
426
- /**
427
- * By default, iframing the CMS is disallowed. Setting this value will allow
428
- * iframes from the specified origins. Example:
429
- * ```
430
- * allowedIframeOrigins: ['https://app.example.com']
431
- * ```
432
- */
433
- allowedIframeOrigins?: string[];
434
- /**
435
- * URL to GCI service for transforming uploaded GCS images to a Google App
436
- * Engine Images API serving URL.
437
- *
438
- * Setting this to `true` uses the default hosted service at
439
- * https://services.rootjs.dev.
440
- *
441
- * To set up GCI:
442
- *
443
- * - Create a GCS bucket with fine-grained permissions
444
- * - Share owner access to the bucket with the service account returned in
445
- * https://services.rootjs.dev/_/service_account
446
- *
447
- * To disable GCI, leave this value empty or set to `false`, which which will
448
- * serve images directly from GCS instead.
449
- */
450
- gci?: string | boolean;
451
- /**
452
- * Customization options for the CMS sidebar.
453
- */
454
- sidebar?: {
455
- /**
456
- * Sidebar tools, a map of the sidebar id to config options. The sidebar
457
- * tool is url-mapped to `/cms/tools/:id` and displays the tool in an
458
- * iframe.
459
- */
460
- tools?: Record<string, CMSSidebarTool>;
461
- /**
462
- * Hide specific built-in sidebar tools. Hiding a tool also removes its
463
- * surfaces from the CMS home page. The underlying routes remain
464
- * accessible via direct URL.
465
- */
466
- hiddenBuiltInTools?: CMSBuiltInSidebarTool[];
467
- };
468
- /**
469
- * URL for a custom favicon used by the CMS UI.
470
- */
471
- favicon?: string;
472
- /**
473
- * Enables minimal branding mode in the CMS header. This hides the Root CMS
474
- * logo and displays the project name on the top-right.
475
- */
476
- minimalBranding?: boolean;
477
- /**
478
- * Callback when an action occurs.
479
- */
480
- onAction?: (action: Action) => any;
481
- /**
482
- * Configures the Root CMS AI chat (`/cms/ai`). Provide one or more models
483
- * — the CMS proxies user requests directly to the configured providers.
484
- *
485
- * The shape mirrors open source tools like Ollama and LiteLLM: each entry
486
- * declares the provider, model id and credentials. Keys live on the server,
487
- * never on the client.
488
- *
489
- * Example:
490
- * ```ts
491
- * cmsPlugin({
492
- * ai: {
493
- * models: [
494
- * {
495
- * id: 'gpt-5.5',
496
- * label: 'GPT-5.5',
497
- * provider: 'openai',
498
- * apiKey: process.env.OPENAI_API_KEY,
499
- * capabilities: {tools: true, reasoning: true, attachments: true},
500
- * },
501
- * {
502
- * id: 'claude-opus-4-7',
503
- * label: 'Claude Opus 4.7',
504
- * provider: 'anthropic',
505
- * apiKey: process.env.ANTHROPIC_API_KEY,
506
- * capabilities: {tools: true, reasoning: true, attachments: true},
507
- * },
508
- * {
509
- * id: 'gemini-3.1-pro',
510
- * label: 'Gemini 3.1 Pro',
511
- * provider: 'gemini',
512
- * apiKey: process.env.GEMINI_API_KEY,
513
- * capabilities: {tools: true, reasoning: true, attachments: true},
514
- * },
515
- * {
516
- * id: 'llama3-local',
517
- * label: 'Llama 3 (local)',
518
- * provider: 'openai-compatible',
519
- * baseURL: 'http://localhost:11434/v1',
520
- * },
521
- * ],
522
- * defaultModel: 'gpt-4o',
523
- * },
524
- * });
525
- * ```
526
- *
527
- * For project-specific guidance (conventions, patterns, naming rules, etc.),
528
- * drop a `ROOT.md` file at the project root. Its contents are appended to
529
- * the system prompt for every chat — similar to `AGENTS.md` / `CLAUDE.md`.
530
- */
531
- ai?: AiConfig;
532
- /**
533
- * Experimental config options. Note: these are subject to change at any time.
534
- */
535
- experiments?: {
536
- /**
537
- * @deprecated Use the top-level `ai` config instead. Setting this to
538
- * `true` keeps the AI chat icon visible in the sidebar.
539
- */
540
- ai?: boolean | CMSAIConfig;
541
- /**
542
- * Enables the v2 `TranslationsManager`.
543
- */
544
- v2TranslationsManager?: boolean;
545
- /**
546
- * Enables the task manager (sidebar entry, home page card, and
547
- * `/cms/tasks` routes).
548
- */
549
- taskManager?: boolean;
550
- };
551
- /**
552
- * Adjust console output verbosity. Default is `'info'`.
553
- */
554
- logLevel?: 'info' | 'warn' | 'error' | 'silent' | 'debug';
555
- /**
556
- * Whether to enable/disable file watching in dev (e.g. for generating
557
- * `root-cms.d.ts`). Defaults to `true`.
558
- */
559
- watch?: boolean;
560
- /** Options associated with the preview. */
561
- preview?: {
562
- /**
563
- * Whether to send messages to the preview iframe, handle messages from
564
- * the preview iframe, enable both (`true`), or disable messages entirely
565
- * (`false`). If unspecified, the default is `false`.
566
- */
567
- channel: boolean | 'to-preview' | 'from-preview';
568
- };
569
- /**
570
- * Checks that can be run on-demand from the CMS UI to validate document
571
- * content. Each check defines a server-side function that returns a
572
- * success/warning/error result with a markdown message.
573
- *
574
- * Example:
575
- * ```ts
576
- * cmsPlugin({
577
- * checks: [
578
- * {
579
- * id: 'my-check',
580
- * label: 'My Check',
581
- * run: async (ctx) => {
582
- * return {status: 'success', message: 'All good!'};
583
- * },
584
- * },
585
- * ],
586
- * });
587
- * ```
588
- *
589
- * NOTE: The checks feature is considered a "beta" feature, its interface
590
- * may change from version to version as we add new features.
591
- */
592
- checks?: CMSCheck[];
593
- /**
594
- * Translation services that appear in the Localization modal's Import and
595
- * Export menus. Each service defines server-side import/export functions
596
- * that integrate with an external translation platform (e.g. Crowdin).
597
- *
598
- * Example:
599
- * ```ts
600
- * cmsPlugin({
601
- * translations: [
602
- * {
603
- * id: 'crowdin',
604
- * label: 'Crowdin',
605
- * onImport: async (ctx, data) => { ... },
606
- * onExport: async (ctx, data) => { ... },
607
- * },
608
- * ],
609
- * });
610
- * ```
611
- */
612
- translations?: CMSTranslationService[];
613
- /**
614
- * Notification services that react to CMS actions and dispatch them to
615
- * external channels (email, Slack, webhooks, etc.). Each service defines
616
- * an optional server-side `onAction` handler.
617
- *
618
- * Example:
619
- * ```ts
620
- * cmsPlugin({
621
- * notifications: [
622
- * {
623
- * id: 'sendgrid',
624
- * label: 'SendGrid',
625
- * onAction: async (ctx, action) => {
626
- * if (action.action === 'doc.publish') {
627
- * await sendgrid.send({ ... });
628
- * }
629
- * },
630
- * },
631
- * ],
632
- * });
633
- * ```
634
- */
635
- notifications?: CMSNotificationService[];
636
- /**
637
- * Configuration for the spotlight / global search indexer. Use this to
638
- * include or exclude specific collections or docs from being indexed.
639
- */
640
- searchIndex?: CMSSearchIndexConfig;
641
- /**
642
- * Default UI variant for `oneOf` fields. Individual fields can still
643
- * override this by setting their own `variant`. Defaults to `'dropdown'`.
644
- */
645
- defaultOneOfVariant?: 'dropdown' | 'picker';
646
- };
647
- type CMSPlugin = Plugin & {
648
- name: 'root-cms';
649
- getConfig: () => CMSPluginOptions;
650
- getFirebaseApp: () => App;
651
- getFirestore: (options?: {
652
- databaseId?: string;
653
- }) => Firestore;
654
- };
655
- declare function cmsPlugin(options: CMSPluginOptions): CMSPlugin;
656
-
657
- type Locale = string;
658
- type SourceString = string;
659
- type TranslatedString = string;
660
- type TranslationsDocMode = 'draft' | 'published';
661
- interface TranslationsLocaleDocHashMap {
662
- /**
663
- * A hash map of a source string's hash fingerprint to the source string and
664
- * translated string.
665
- */
666
- [hash: string]: TranslationsLocaleDocEntry;
667
- }
668
- interface TranslationsLocaleDocEntry {
669
- source: SourceString;
670
- translation: TranslatedString;
671
- }
672
- interface TranslationsDbPathOptions {
673
- project: string;
674
- mode: TranslationsDocMode;
675
- }
676
- type TranslationsLocaleDocDbPathOptions = TranslationsDbPathOptions & {
677
- id: string;
678
- locale: string;
679
- };
680
- /**
681
- * A translations map containing translations for multiple locales.
682
- *
683
- * Example:
684
- * ```
685
- * {
686
- * "one": {"es": "uno", "fr": "un"},
687
- * "two": {"es": "dos", "fr": "deux"}
688
- * }
689
- * ```
690
- */
691
- interface MultiLocaleTranslationsMap {
692
- [source: SourceString]: {
693
- [locale: Locale]: TranslatedString;
694
- };
695
- }
696
- /**
697
- * A translations map containing translations for a single locale.
698
- *
699
- * Example:
700
- * ```
701
- * {
702
- * "one": "uno",
703
- * "two": "dos"
704
- * }
705
- * ```
706
- */
707
- interface SingleLocaleTranslationsMap {
708
- [source: SourceString]: TranslatedString;
709
- }
710
- declare class TranslationsManager {
711
- cmsClient: RootCMSClient;
712
- constructor(cmsClient: RootCMSClient);
713
- /**
714
- * Saves draft translations for a translations doc id.
715
- *
716
- * Example:
717
- * ```
718
- * const strings = {
719
- * 'one': {es: 'uno', fr: 'un'},
720
- * 'two': {es: 'dos', fr: 'deux'},
721
- * };
722
- * await tm.saveTranslations('Pages/index', strings);
723
- * ```
724
- */
725
- saveTranslations(id: string, strings: MultiLocaleTranslationsMap, options?: {
726
- tags?: string[];
727
- modifiedBy?: string;
728
- }): Promise<void>;
729
- /**
730
- * Publishes a translations doc.
731
- */
732
- publishTranslations(id: string, options?: {
733
- batch?: WriteBatch;
734
- publishedBy?: string;
735
- }): Promise<void>;
736
- /**
737
- * Fetches translations from one or more translations docs in the translations
738
- * manager.
739
- *
740
- * Example:
741
- * ```
742
- * await tm.loadTranslations();
743
- * // =>
744
- * // {
745
- * // "one": {"es": "uno", "fr": "un"},
746
- * // "two": {"es": "dos", "fr": "deux"}
747
- * // }
748
- * ```
749
- *
750
- * To load a specific set of translations docs by id:
751
- * ```
752
- * const translationsToLoad = ['Global/strings', 'Global/header', 'Global/footer', 'Pages/index'];
753
- * await tm.loadTranslations({ids: translationsToLoad});
754
- * // =>
755
- * // {
756
- * // "one": {"es": "uno", "fr": "un"},
757
- * // "two": {"es": "dos", "fr": "deux"}
758
- * // }
759
- * ```
760
- *
761
- * To load a subset of locales (more performant):
762
- * ```
763
- * await tm.loadTranslations({locales: ['es']});
764
- * // =>
765
- * // {
766
- * // "one": {"es": "uno"},
767
- * // "two": {"es": "dos"}
768
- * // }
769
- * ```
770
- */
771
- loadTranslations(options?: {
772
- ids?: string[];
773
- tags?: string[];
774
- locales?: Locale[];
775
- mode?: TranslationsDocMode;
776
- }): Promise<MultiLocaleTranslationsMap>;
777
- /**
778
- * Fetches translations for a given locale, with optional fallbacks.
779
- * The return value is a map of source string to translated string.
780
- *
781
- * Example:
782
- * ```
783
- * await translationsDoc.loadTranslationsForLocale('es');
784
- * // =>
785
- * // {
786
- * // "one": "uno",
787
- * // "two": "dos",
788
- * // }
789
- * ```
790
- */
791
- loadTranslationsForLocale(locale: Locale, options?: {
792
- mode?: TranslationsDocMode;
793
- fallbackLocales?: Locale[];
794
- }): Promise<SingleLocaleTranslationsMap>;
795
- /**
796
- * Converts a multi-locale translations map to a flat single-locale map,
797
- * with optional support for fallback locales.
798
- *
799
- * ```
800
- * const multiLocaleStrings = {
801
- * 'one': {es: 'uno', fr: 'un'},
802
- * 'two': {es: 'dos', fr: 'deux'}
803
- * };
804
- * translationsDoc.toSingleLocaleMap(multiLocaleStrings, ['es']);
805
- * // =>
806
- * // {
807
- * // "one": "uno",
808
- * // "two": "dos",
809
- * // }
810
- * ```
811
- */
812
- private toSingleLocaleMap;
813
- /**
814
- * Converts a multi-locale translations map to a single-locale hashed version,
815
- * used for storage in in the DB.
816
- *
817
- * ```
818
- * const multiLocaleStrings = {
819
- * 'one': {es: 'uno', fr: 'un'},
820
- * 'two': {es: 'dos', fr: 'deux'}
821
- * };
822
- * translationsDoc.toLocaleDocHashMap(multiLocaleStrings, 'es');
823
- * // =>
824
- * // {
825
- * // "<hash1>": {"source": "one", "translation": "uno"},
826
- * // "<hash2>": {"source": "two", "translation": "dos"},
827
- * // }
828
- * ```
829
- *
830
- * One reason for using hashes is because the DB has limits on the number of
831
- * chars that can be used as the "key" in a object map.
832
- */
833
- private toLocaleDocHashMap;
834
- /**
835
- * Import translations from the v1 system to the TranslationsManager.
836
- */
837
- importTranslationsFromV1(): Promise<void>;
838
- }
839
- declare function buildTranslationsDbPath(options: TranslationsDbPathOptions): string;
840
- declare function buildTranslationsLocaleDocDbPath(options: TranslationsLocaleDocDbPathOptions): string;
841
-
842
- interface Doc<Fields = any> {
843
- /** The id of the doc, e.g. "Pages/foo-bar". */
844
- id: string;
845
- /** The collection id of the doc, e.g. "Pages". */
846
- collection: string;
847
- /** The slug of the doc, e.g. "foo-bar". */
848
- slug: string;
849
- sys: {
850
- createdAt: number;
851
- createdBy: string;
852
- modifiedAt: number;
853
- modifiedBy: string;
854
- firstPublishedAt?: number;
855
- firstPublishedBy?: string;
856
- publishedAt?: number;
857
- publishedBy?: string;
858
- publishingLocked: {
859
- lockedAt: string;
860
- lockedBy: string;
861
- reason: string;
862
- until?: Timestamp;
863
- };
864
- locales?: string[];
865
- };
866
- fields: Fields;
867
- }
868
- type DocMode = 'draft' | 'published';
869
- type UserRole = 'ADMIN' | 'EDITOR' | 'CONTRIBUTOR' | 'VIEWER';
870
- type HttpMethod = 'GET' | 'POST';
871
- type CronUnit = 'minutes' | 'hours' | 'days';
872
- interface DataSourceCron {
873
- enabled: boolean;
874
- interval: number;
875
- unit: CronUnit;
876
- autoPublish?: boolean;
877
- }
878
- interface DataSource {
879
- id: string;
880
- description?: string;
881
- type: 'http' | 'gsheet';
882
- url: string;
883
- /**
884
- * Currently only used by gsheet. `array` returns the sheet as an array of
885
- * arrays, `map` returns the sheet as an array of objects.
886
- */
887
- dataFormat?: 'array' | 'map';
888
- /**
889
- * Options for HTTP requests.
890
- */
891
- httpOptions?: {
892
- method: HttpMethod;
893
- headers?: Record<string, string>;
894
- body?: string;
895
- };
896
- cron?: DataSourceCron;
897
- createdAt: Timestamp;
898
- createdBy: string;
899
- syncedAt?: Timestamp;
900
- syncedBy?: string;
901
- publishedAt?: Timestamp;
902
- publishedBy?: string;
903
- archivedAt?: Timestamp;
904
- archivedBy?: string;
905
- }
906
- interface DataSourceData<T = any> {
907
- dataSource: DataSource;
908
- data: T;
909
- /** Optional list of column headers (for gsheet sources). */
910
- headers?: string[];
911
- }
912
- type DataSourceMode = 'draft' | 'published';
913
- interface GetDocOptions {
914
- /** Mode, either "draft" or "published". */
915
- mode: DocMode;
916
- }
917
- interface SetDocOptions {
918
- /** Mode, either "draft" or "published". */
919
- mode: DocMode;
920
- }
921
- interface SaveDraftOptions {
922
- /**
923
- * Locales to enable.
924
- */
925
- locales?: string[];
926
- /**
927
- * Email of user modifying the doc. If blank, defaults to `root-cms-client`.
928
- */
929
- modifiedBy?: string;
930
- /**
931
- * Whether to validate fieldsData against the collection schema before saving.
932
- * If validation fails, an error will be thrown with details about the validation errors.
933
- */
934
- validate?: boolean;
935
- }
936
- interface UpdateDraftOptions {
937
- /**
938
- * Whether to validate the updated field against the collection schema.
939
- * If validation fails, an error will be thrown with details about the validation errors.
940
- */
941
- validate?: boolean;
942
- }
943
- interface ListDocsOptions {
944
- mode: DocMode;
945
- offset?: number;
946
- limit?: number;
947
- orderBy?: string;
948
- orderByDirection?: 'asc' | 'desc';
949
- query?: (query: Query) => Query;
950
- /**
951
- * Whether to fetch the "raw" version of the doc (for use in conjunction with
952
- * `setRawDoc()`).
953
- */
954
- raw?: boolean;
955
- }
956
- interface GetCountOptions {
957
- mode: DocMode;
958
- query?: (query: Query) => Query;
959
- }
960
- interface Translation {
961
- [locale: string]: string;
962
- source: string;
963
- }
964
- interface TranslationsMap {
965
- [hash: string]: Translation;
966
- }
967
- interface LocaleTranslations {
968
- [source: string]: string;
969
- }
970
- interface LoadTranslationsOptions {
971
- tags?: string[];
972
- }
973
- interface Release {
974
- id: string;
975
- description?: string;
976
- docIds?: string[];
977
- dataSourceIds?: string[];
978
- createdAt?: Timestamp;
979
- createdBy?: string;
980
- scheduledAt?: Timestamp;
981
- scheduledBy?: string;
982
- publishedAt?: Timestamp;
983
- publishedBy?: string;
984
- }
985
- interface Action<T = any> {
986
- /**
987
- * The name of the action.
988
- */
989
- action: string;
990
- /**
991
- * The user's email that performed the action (or "system").
992
- */
993
- by?: string;
994
- /**
995
- * Timestamp when the action occurred.
996
- */
997
- timestamp: Timestamp;
998
- /**
999
- * Metadata for the action.
1000
- */
1001
- metadata?: T;
1002
- /**
1003
- * Optional list of quick links to display in the UI.
1004
- */
1005
- links?: {
1006
- label: string;
1007
- url: string;
1008
- target?: string;
1009
- }[];
1010
- }
1011
- interface ListActionsOptions {
1012
- /**
1013
- * Filter by a specific action. Defaults to all actions.
1014
- */
1015
- action?: string;
1016
- /**
1017
- * Filter by a specific user. Defaults to all users.
1018
- */
1019
- by?: string;
1020
- /**
1021
- * Max number of actions to return. Defaults to 100.
1022
- */
1023
- limit?: number;
1024
- }
1025
- declare class RootCMSClient {
1026
- readonly rootConfig: RootConfig;
1027
- readonly cmsPlugin: CMSPlugin;
1028
- readonly projectId: string;
1029
- readonly app: App;
1030
- readonly db: Firestore;
1031
- constructor(rootConfig: RootConfig);
1032
- /**
1033
- * Converts a doc mode to the Firestore collection name.
1034
- */
1035
- private getModeCollection;
1036
- /**
1037
- * Retrieves doc data from Root.js CMS.
1038
- */
1039
- getDoc<Fields = any>(collectionId: string, slug: string, options: GetDocOptions): Promise<Doc<Fields> | null>;
1040
- /**
1041
- * Retrieves raw doc data as stored in the database. Only use this if you know
1042
- * what you are doing.
1043
- */
1044
- getRawDoc(collectionId: string, slug: string, options: GetDocOptions): Promise<any | null>;
1045
- /**
1046
- * Firestore path for a collection.
1047
- */
1048
- dbCollectionDocsPath(collectionId: string, options: {
1049
- mode: 'draft' | 'published';
1050
- }): string;
1051
- /**
1052
- * Firestore path for a content doc.
1053
- */
1054
- dbDocPath(collectionId: string, slug: string, options: {
1055
- mode: 'draft' | 'published';
1056
- }): string;
1057
- /**
1058
- * Firestore doc ref for a content doc.
1059
- */
1060
- dbDocRef(collectionId: string, slug: string, options: {
1061
- mode: 'draft' | 'published';
1062
- }): FirebaseFirestore.DocumentReference<FirebaseFirestore.DocumentData, FirebaseFirestore.DocumentData>;
1063
- /**
1064
- * Returns a collection's schema definition as defined in
1065
- * `/collections/<id>.schema.ts`.
1066
- */
1067
- getCollection(collectionId: string): Promise<Collection | null>;
1068
- /**
1069
- * Saves draft data to a doc.
1070
- *
1071
- * Note: this saves data to the "fields" attr of the draft doc. If you need to
1072
- * modify the sys-level attributes of the doc, use `setRawDoc()`.
1073
- */
1074
- saveDraftData(docId: string, fieldsData: any, options?: SaveDraftOptions): Promise<void>;
1075
- /**
1076
- * Updates a specific field path in a draft doc.
1077
- *
1078
- * This allows partial updates to nested fields without replacing the entire document.
1079
- * For example: `updateDraftData('Pages/home', 'hero.title', 'New Title')`
1080
- *
1081
- * @param docId - The document ID (e.g., 'Pages/home')
1082
- * @param path - JSON path to the field (e.g., 'hero.title' or 'content.0.text')
1083
- * @param fieldValue - The value to set at the specified path
1084
- * @param options - Update options including validation
1085
- */
1086
- updateDraftData(docId: string, path: string, fieldValue: any, options?: UpdateDraftOptions): Promise<void>;
1087
- /**
1088
- * Sets the raw document data directly in Firestore.
1089
- *
1090
- * CAUTION Prefer using `saveDraftData('Pages/foo', data)` in most cases.
1091
- * Only use this method if you need to manipulate system-level (sys) fields
1092
- * directly or if you're implementing low-level data operations.
1093
- *
1094
- * ## Validation & Normalization
1095
- *
1096
- * This method automatically validates and normalizes `sys` fields to prevent
1097
- * data integrity issues that can cause runtime errors like
1098
- * "e.toMillis is not a function".
1099
- *
1100
- * ### Timestamp Fields (auto-converted)
1101
- * The following fields accept multiple formats and are automatically converted
1102
- * to Firestore Timestamp objects:
1103
- * - `sys.createdAt`
1104
- * - `sys.modifiedAt`
1105
- * - `sys.publishedAt`
1106
- * - `sys.firstPublishedAt`
1107
- *
1108
- * Accepted formats:
1109
- * - Firestore `Timestamp` object (unchanged)
1110
- * - `number` - Interpreted as milliseconds since epoch, converted to Timestamp
1111
- * - `Date` object - Converted to Timestamp
1112
- *
1113
- * ### Required Fields (auto-populated with defaults if missing)
1114
- * - `sys.createdAt` - Defaults to current time if not provided
1115
- * - `sys.modifiedAt` - Defaults to current time if not provided
1116
- * - `sys.createdBy` - Defaults to 'root-cms-client' if not provided
1117
- * - `sys.modifiedBy` - Defaults to 'root-cms-client' if not provided
1118
- * - `sys.locales` - Defaults to ['en'] if not provided
1119
- *
1120
- * ### Optional Fields (validated if present)
1121
- * - `sys.publishedBy` - String identifier
1122
- * - `sys.firstPublishedBy` - String identifier
1123
- * - `sys.publishingLocked` - Object with optional `until` Timestamp
1124
- *
1125
- * ### Document Identity
1126
- * The `id`, `collection`, and `slug` fields are always set to match the
1127
- * provided parameters, overwriting any existing values to prevent data
1128
- * inconsistencies.
1129
- *
1130
- * @param collectionId - The collection ID (e.g., 'Pages')
1131
- * @param slug - The document slug (e.g., 'home')
1132
- * @param data - The complete document data including sys and fields
1133
- * @param options - Options specifying mode ('draft' or 'published')
1134
- *
1135
- * @throws {Error} If sys fields are invalid or missing required fields
1136
- * @throws {Error} If timestamp fields have invalid types
1137
- *
1138
- * @example
1139
- * ```typescript
1140
- * // Minimal example - sys fields use defaults
1141
- * await client.setRawDoc('Pages', 'home', {
1142
- * sys: {}, // All sys fields will be auto-populated with defaults
1143
- * fields: {
1144
- * title: 'Home Page'
1145
- * }
1146
- * }, { mode: 'draft' });
1147
- *
1148
- * // Full example - with number timestamps (auto-converted)
1149
- * await client.setRawDoc('Pages', 'home', {
1150
- * id: 'Pages/home',
1151
- * collection: 'Pages',
1152
- * slug: 'home',
1153
- * sys: {
1154
- * createdAt: Date.now(), // Auto-converted to Timestamp.
1155
- * createdBy: 'user@example.com',
1156
- * modifiedAt: Date.now(), // Auto-converted to Timestamp.
1157
- * modifiedBy: 'user@example.com',
1158
- * locales: ['en', 'es']
1159
- * },
1160
- * fields: {
1161
- * title: 'Home Page'
1162
- * }
1163
- * }, { mode: 'draft' });
1164
- * ```
1165
- */
1166
- setRawDoc(collectionId: string, slug: string, data: any, options: SetDocOptions): Promise<void>;
1167
- /**
1168
- * Lists docs from a Root.js CMS collection.
1169
- */
1170
- listDocs<T>(collectionId: string, options: ListDocsOptions): Promise<{
1171
- docs: T[];
1172
- }>;
1173
- /**
1174
- * Returns the number of docs in a Root.js CMS collection.
1175
- */
1176
- getDocsCount(collectionId: string, options: GetCountOptions): Promise<number>;
1177
- /**
1178
- * Batch publishes a set of docs by id.
1179
- */
1180
- publishDocs(docIds: string[], options?: {
1181
- publishedBy: string;
1182
- batch?: WriteBatch;
1183
- releaseId?: string;
1184
- }): Promise<any[]>;
1185
- /**
1186
- * Batch unpublishes a set of docs by id.
1187
- */
1188
- unpublishDocs(docIds: string[], options?: {
1189
- unpublishedBy?: string;
1190
- batch?: WriteBatch;
1191
- }): Promise<any[]>;
1192
- /**
1193
- * Publishes scheduled docs.
1194
- */
1195
- publishScheduledDocs(): Promise<any[]>;
1196
- /**
1197
- * Publishes docs in scheduled releases.
1198
- */
1199
- publishScheduledReleases(): Promise<void>;
1200
- /**
1201
- * Syncs data sources that have cron scheduling enabled and are due for sync.
1202
- */
1203
- syncScheduledDataSources(): Promise<void>;
1204
- /**
1205
- * Checks if a doc is currently "locked" for publishing.
1206
- */
1207
- testPublishingLocked(doc: Doc): boolean;
1208
- /**
1209
- * Returns a `TranslationsManager` object for managing translations.
1210
- *
1211
- * To get translations:
1212
- * ```
1213
- * await tm.loadTranslations({
1214
- * ids: ['Global/strings', 'Pages/index'],
1215
- * locales: ['es'],
1216
- * });
1217
- * ```
1218
- *
1219
- * NOTE: The `TranslationsManager` is a v2 feature that will eventually
1220
- * replace the v1 translations system.
1221
- */
1222
- getTranslationsManager(): TranslationsManager;
1223
- /**
1224
- * Loads translations saved in the translations collection, optionally
1225
- * filtered by tag.
1226
- *
1227
- * Returns a map like:
1228
- * ```
1229
- * {
1230
- * "<hash>": {"source": "Hello", "es": "Hola", "fr": "Bonjour"},
1231
- * }
1232
- * ```
1233
- */
1234
- loadTranslations(options?: LoadTranslationsOptions): Promise<TranslationsMap>;
1235
- /**
1236
- * Saves a map of translations, e.g.:
1237
- * ```
1238
- * await client.saveTranslations({
1239
- * "Hello": {"es": "Hola", "fr": "Bonjour"},
1240
- * });
1241
- * ```
1242
- */
1243
- saveTranslations(translations: {
1244
- [source: string]: {
1245
- [locale: string]: string;
1246
- };
1247
- }, tags?: string[]): Promise<void>;
1248
- /**
1249
- * Returns the "key" used for a translation as stored in the db. Translations
1250
- * are stored under `Projects/<project id>/Translations/<sha1 hash>`.
1251
- */
1252
- getTranslationKey(source: string): string;
1253
- /**
1254
- * Cleans a string that's used for translations. Performs the following:
1255
- * - Removes any leading/trailing whitespace
1256
- * - Removes spaces at the end of any line
1257
- */
1258
- normalizeString(str: string): string;
1259
- /**
1260
- * Loads translations for a particular locale.
1261
- *
1262
- * Returns a map like:
1263
- * ```
1264
- * {
1265
- * "Hello": "Bonjour",
1266
- * }
1267
- * ```
1268
- */
1269
- loadTranslationsForLocale(locale: string, options?: LoadTranslationsOptions): Promise<LocaleTranslations>;
1270
- /**
1271
- * Firestore path for a translations file.
1272
- */
1273
- dbTranslationsPath(translationsId: string, options: {
1274
- mode: 'draft' | 'published';
1275
- }): string;
1276
- /**
1277
- * Firestore doc ref for a translations file.
1278
- */
1279
- dbTranslationsRef(translationsId: string, options: {
1280
- mode: 'draft' | 'published';
1281
- }): FirebaseFirestore.DocumentReference<FirebaseFirestore.DocumentData, FirebaseFirestore.DocumentData>;
1282
- /**
1283
- * Returns a data source configuration object.
1284
- */
1285
- getDataSource(dataSourceId: string): Promise<DataSource | null>;
1286
- /**
1287
- * Archives a data source. Archived data sources cannot be synced or published.
1288
- */
1289
- archiveDataSource(dataSourceId: string, options?: {
1290
- archivedBy?: string;
1291
- }): Promise<void>;
1292
- /**
1293
- * Unarchives a data source.
1294
- */
1295
- unarchiveDataSource(dataSourceId: string): Promise<void>;
1296
- /**
1297
- * Syncs a data source to draft state.
1298
- */
1299
- syncDataSource(dataSourceId: string, options?: {
1300
- syncedBy?: string;
1301
- }): Promise<void>;
1302
- publishDataSource(dataSourceId: string, options?: {
1303
- publishedBy?: string;
1304
- }): Promise<void>;
1305
- /**
1306
- * Unpublishes a data source. Removes the `publishedAt`/`publishedBy`
1307
- * metadata from the DataSource doc and deletes the `Data/published` doc.
1308
- */
1309
- unpublishDataSource(dataSourceId: string): Promise<void>;
1310
- publishDataSources(dataSourceIds: string[], options?: {
1311
- publishedBy: string;
1312
- batch?: WriteBatch;
1313
- commitBatch?: boolean;
1314
- }): Promise<void>;
1315
- private fetchData;
1316
- private fetchHttpData;
1317
- /**
1318
- * Fetches data from a Google Sheet using the Google Sheets API v4.
1319
- *
1320
- * ## Setup
1321
- *
1322
- * For the server-side service account to access the Google Sheet:
1323
- *
1324
- * 1. **Enable the Google Sheets API** in the Google Cloud Console for the
1325
- * project associated with the service account.
1326
- * https://console.cloud.google.com/apis/library/sheets.googleapis.com
1327
- *
1328
- * 2. **Share the Google Sheet** with the service account's email address
1329
- * (e.g. `my-service-account@my-project.iam.gserviceaccount.com`).
1330
- * Open the sheet in Google Sheets, click "Share", and add the service
1331
- * account email as a Viewer.
1332
- *
1333
- * - For **App Engine**: the service account email is typically
1334
- * `<project-id>@appspot.gserviceaccount.com`.
1335
- * - For **Cloud Run**: check the service account configured for the
1336
- * Cloud Run service in the Google Cloud Console.
1337
- * - For **local development**: use the service account email from the
1338
- * JSON key file specified in `GOOGLE_APPLICATION_CREDENTIALS`.
1339
- */
1340
- private fetchGsheetData;
1341
- /**
1342
- * Fetches data from a data source.
1343
- */
1344
- getFromDataSource<T = any>(dataSourceId: string, options?: {
1345
- mode?: 'draft' | 'published';
1346
- }): Promise<DataSourceData<T> | null>;
1347
- /**
1348
- * Firestore path for a datasource data.
1349
- */
1350
- dbDataSourceDataPath(dataSourceId: string, options: {
1351
- mode: 'draft' | 'published';
1352
- }): string;
1353
- /**
1354
- * Firestore doc ref for a datasource data.
1355
- */
1356
- dbDataSourceDataRef(dataSourceId: string, options: {
1357
- mode: 'draft' | 'published';
1358
- }): FirebaseFirestore.DocumentReference<FirebaseFirestore.DocumentData, FirebaseFirestore.DocumentData>;
1359
- /**
1360
- * Gets the user's role from the project's ACL.
1361
- */
1362
- getUserRole(email: string): Promise<UserRole | null>;
1363
- /**
1364
- * Verifies user exists in the ACL list.
1365
- */
1366
- userExistsInAcl(email: string): Promise<boolean>;
1367
- /**
1368
- * Lists action logs from the database.
1369
- */
1370
- listActions(options?: ListActionsOptions): Promise<Action[]>;
1371
- logAction(action: string, options?: {
1372
- by?: string;
1373
- metadata?: any;
1374
- links?: {
1375
- label: string;
1376
- url: string;
1377
- target?: string;
1378
- }[];
1379
- }): Promise<void>;
1380
- /**
1381
- * Creates a batch request that is capable of fetching one or more docs,
1382
- * corresponding translations, and dataSources.
1383
- */
1384
- createBatchRequest(options: BatchRequestOptions): BatchRequest;
1385
- }
1386
- /**
1387
- * Returns true if the `data` is a rich text data object.
1388
- */
1389
- declare function isRichTextData(data: any): boolean;
1390
- declare function getCmsPlugin(rootConfig: RootConfig): CMSPlugin;
1391
- /**
1392
- * Walks the data tree and converts any array of objects into "array objects"
1393
- * for storage in firestore.
1394
- */
1395
- declare function marshalData(data: any): any;
1396
- /**
1397
- * Walks the data tree and converts any Timestamp objects to millis and any
1398
- * _array maps to normal arrays.
1399
- *
1400
- * E.g.:
1401
- *
1402
- * normalizeData({
1403
- * sys: {modifiedAt: Timestamp(123)},
1404
- * fields: {
1405
- * _array: ['asdf'],
1406
- * asdf: {title: 'hello'}
1407
- * }
1408
- * })
1409
- * // => {sys: {modifiedAt: 123}, fields: {foo: [{title: 'hello'}]}}
1410
- */
1411
- declare function unmarshalData(data: any): any;
1412
- /** @deprecated Use `unmarshalData()` instead. */
1413
- declare function normalizeData(data: any): any;
1414
- interface ArrayObject {
1415
- [key: string]: any;
1416
- _array: string[];
1417
- }
1418
- /**
1419
- * Serializes an array into an `ArrayObject`, e.g.:
1420
- *
1421
- * ```
1422
- * marshalArray([1, 2, 3])
1423
- * // => {a: 1, b: 2, c: 3, _array: ['a', 'b', 'c']}
1424
- * ```
1425
- *
1426
- * This database storage method makes it easier to update a single field in a
1427
- * deeply nested array object.
1428
- */
1429
- declare function toArrayObject(arr: any[]): ArrayObject;
1430
- declare const marshalArray: typeof toArrayObject;
1431
- /**
1432
- * Converts an `ArrayObject` to a normal array.
1433
- */
1434
- declare function unmarshalArray(arrObject: ArrayObject): any[];
1435
- /**
1436
- * Converts a translations map from `loadTranslations()` to a map of source to
1437
- * translated string for a particular locale.
1438
- *
1439
- * Returns a map like:
1440
- * ```
1441
- * {
1442
- * "Hello": "Bonjour",
1443
- * }
1444
- * ```
1445
- */
1446
- declare function translationsForLocale(translationsMap: TranslationsMap, locale: string): LocaleTranslations;
1447
- /**
1448
- * Parses a docId (e.g. `Pages/foo`) and returns the `collection` and `slug`.
1449
- */
1450
- declare function parseDocId(docId: string): {
1451
- collection: string;
1452
- slug: string;
1453
- };
1454
- interface BatchRequestOptions {
1455
- mode: 'draft' | 'published';
1456
- /**
1457
- * Whether to automatically fetch translations for the docs retrieved in the
1458
- * request.
1459
- */
1460
- translate?: boolean;
1461
- }
1462
- interface BatchRequestQuery {
1463
- queryId: string;
1464
- collectionId: string;
1465
- queryOptions?: BatchRequestQueryOptions;
1466
- }
1467
- interface BatchRequestQueryOptions {
1468
- offset?: number;
1469
- limit?: number;
1470
- orderBy?: string;
1471
- orderByDirection?: 'asc' | 'desc';
1472
- query?: (query: Query) => Query;
1473
- }
1474
- interface TranslationsDoc {
1475
- id: string;
1476
- sys: {
1477
- modifiedAt: Timestamp;
1478
- modifiedBy: string;
1479
- publishedAt?: Timestamp;
1480
- publishedBy?: string;
1481
- linkedSheet?: {
1482
- spreadsheetId: string;
1483
- gid: number;
1484
- linkedAt: Timestamp;
1485
- linkedBy: string;
1486
- };
1487
- tags?: string[];
1488
- };
1489
- strings: TranslationsMap;
1490
- }
1491
- declare class BatchRequest {
1492
- cmsClient: RootCMSClient;
1493
- private options;
1494
- private db;
1495
- private docIds;
1496
- private dataSourceIds;
1497
- private queries;
1498
- private translationsIds;
1499
- constructor(cmsClient: RootCMSClient, options: BatchRequestOptions);
1500
- /**
1501
- * Adds a doc to the batch request.
1502
- */
1503
- addDoc(docId: string): void;
1504
- /**
1505
- * Adds a data source to the batch request.
1506
- */
1507
- addDataSource(dataSourceId: string): void;
1508
- /**
1509
- * Adds a collection-based query to the batch request.
1510
- */
1511
- addQuery(queryId: string, collectionId: string, queryOptions?: BatchRequestQueryOptions): void;
1512
- /**
1513
- * Adds a translation file to the request.
1514
- */
1515
- addTranslations(translationsId: string): void;
1516
- /**
1517
- * Fetches data from the DB.
1518
- */
1519
- fetch(): Promise<BatchResponse>;
1520
- private fetchDocs;
1521
- private fetchQueries;
1522
- private fetchDataSources;
1523
- private fetchTranslations;
1524
- }
1525
- declare class BatchResponse {
1526
- docs: Record<string, Doc>;
1527
- queries: Record<string, Doc[]>;
1528
- dataSources: Record<string, DataSourceData>;
1529
- translations: Record<string, TranslationsDoc>;
1530
- /**
1531
- * Returns a map of translations for a given locale or locale fallbacks.
1532
- *
1533
- * The input is either a single locale (e.g. "de") or an array of locales
1534
- * representing the fallback tree, e.g. ["en-CA", "en-GB", "en"].
1535
- *
1536
- * TODO(stevenle): support the locale fallback tree.
1537
- *
1538
- * The returned value is a flat map of source string to translated string,
1539
- * e.g.:
1540
- * {"<source>": "<translation>"}
1541
- */
1542
- getTranslations(locale: string): LocaleTranslations;
1543
- /**
1544
- * Merges the strings from all translations files retrieved in the request.
1545
- * The returned value is a map of string to translations, e.g.:
1546
- *
1547
- * {"<hash>": {"source": "<source>", "<locale>": "<translation>"}}
1548
- */
1549
- private getTranslationsMap;
1550
- }
1551
-
1552
- 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 CMSSearchIndexConfig as a0, type CMSSidebarTool as a1, type CMSPluginOptions as a2, type CMSPlugin as a3, cmsPlugin as a4, type AiConfig as a5, type AiModelConfig as a6, type AiProvider as a7, type CMSCheck as a8, type CheckResult as a9, type CheckContext as aa, type CheckStatus as ab, translationsCheck as ac, type TranslationsCheckOptions as ad, type CMSService as ae, type CMSServiceContext as af, type CMSNotificationService as ag, type NotificationResult as ah, type NotificationServiceContext as ai, type CMSTranslationService as aj, type TranslationExportResult as ak, type TranslationImportResult as al, type TranslationRow as am, type TranslationServiceContext as an, 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 };