@blinkk/root-cms 3.0.1-beta.3 → 3.0.1-beta.5

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.
@@ -0,0 +1,187 @@
1
+ import {
2
+ SearchIndexService
3
+ } from "./chunk-C245C557.js";
4
+ import {
5
+ RootCMSClient,
6
+ getCmsPlugin
7
+ } from "./chunk-2BSW7SIH.js";
8
+
9
+ // core/cron.ts
10
+ import { Timestamp as Timestamp2 } from "firebase-admin/firestore";
11
+
12
+ // core/versions.ts
13
+ import fs from "fs";
14
+ import path from "path";
15
+ import { Timestamp } from "firebase-admin/firestore";
16
+ import glob from "tiny-glob";
17
+ var DOCUMENT_SAVE_OFFSET = 5 * 60 * 1e3;
18
+ var VersionsService = class {
19
+ constructor(rootConfig) {
20
+ this.rootConfig = rootConfig;
21
+ const cmsPlugin = getCmsPlugin(rootConfig);
22
+ const cmsPluginOptions = cmsPlugin.getConfig();
23
+ const projectId = cmsPluginOptions.id || "default";
24
+ this.projectId = projectId;
25
+ this.db = cmsPlugin.getFirestore();
26
+ }
27
+ /**
28
+ * Saves a version of all documents that have been edited since the last run.
29
+ */
30
+ async saveVersions() {
31
+ const lastRun = await this.getLastRun();
32
+ const lastRunWithOffset = lastRun === 0 ? lastRun : lastRun - DOCUMENT_SAVE_OFFSET;
33
+ const changedDocs = await this.getDocsModifiedAfter(lastRunWithOffset);
34
+ const now = Timestamp.now().toMillis();
35
+ const versions = changedDocs.filter((doc) => {
36
+ const modifiedAt = doc.sys.modifiedAt.toMillis();
37
+ if (modifiedAt > now - DOCUMENT_SAVE_OFFSET) {
38
+ return false;
39
+ }
40
+ const publishedAt = doc.sys.publishedAt?.toMillis?.();
41
+ if (publishedAt && Math.abs(publishedAt - modifiedAt) < 5e3) {
42
+ return false;
43
+ }
44
+ return true;
45
+ });
46
+ if (versions.length > 0) {
47
+ this.saveVersionsToFirestore(versions);
48
+ }
49
+ this.saveLastRun(now);
50
+ }
51
+ async saveVersionsToFirestore(versions) {
52
+ const batch = this.db.batch();
53
+ versions.forEach((version) => {
54
+ if (!version.collection || !version.slug || !version.sys?.modifiedAt) {
55
+ return;
56
+ }
57
+ const modifiedAtMillis = version.sys.modifiedAt.toMillis();
58
+ const versionPath = `Projects/${this.projectId}/Collections/${version.collection}/Drafts/${version.slug}/Versions/${modifiedAtMillis}`;
59
+ console.log(versionPath);
60
+ const versionRef = this.db.doc(versionPath);
61
+ batch.set(versionRef, version);
62
+ });
63
+ await batch.commit();
64
+ console.log(`versions: saved ${versions.length} versions`);
65
+ }
66
+ /**
67
+ * Returns the last time (in millis) saveVersions() was run, or 0 if has
68
+ * never been run.
69
+ */
70
+ async getLastRun() {
71
+ const projectDocRef = this.db.collection("Projects").doc(this.projectId);
72
+ const projectDoc = await projectDocRef.get();
73
+ if (projectDoc.exists) {
74
+ const data = projectDoc.data() || {};
75
+ const ts = data.versionsLastRun;
76
+ if (ts) {
77
+ return ts.toMillis();
78
+ }
79
+ }
80
+ return 0;
81
+ }
82
+ /**
83
+ * Saves {versionLastRun: <timestamp>} to the Projects/<projectId> doc.
84
+ */
85
+ async saveLastRun(millis) {
86
+ const ts = Timestamp.fromMillis(millis);
87
+ const projectDocRef = this.db.collection("Projects").doc(this.projectId);
88
+ await projectDocRef.set({ versionsLastRun: ts }, { merge: true });
89
+ }
90
+ /**
91
+ * Returns a list of all docs that were edited after a certain time.
92
+ */
93
+ async getDocsModifiedAfter(millis) {
94
+ const ts = Timestamp.fromMillis(millis);
95
+ const results = [];
96
+ const collectionIds = await this.listCollections();
97
+ for (const collectionId of collectionIds) {
98
+ const collectionPath = `Projects/${this.projectId}/Collections/${collectionId}/Drafts`;
99
+ const query = this.db.collection(collectionPath).where("sys.modifiedAt", ">=", ts);
100
+ const querySnapshot = await query.get();
101
+ querySnapshot.forEach((doc) => {
102
+ results.push(doc.data());
103
+ });
104
+ }
105
+ return results;
106
+ }
107
+ /**
108
+ * Returns a list of collection ids for the Root project.
109
+ */
110
+ async listCollections() {
111
+ const collectionsDir = path.join(this.rootConfig.rootDir, "collections");
112
+ if (!fs.existsSync(collectionsDir)) {
113
+ return [];
114
+ }
115
+ const collectionIds = [];
116
+ const collectionFileNames = await glob("*.schema.ts", {
117
+ cwd: collectionsDir
118
+ });
119
+ collectionFileNames.forEach((filename) => {
120
+ collectionIds.push(filename.slice(0, -10));
121
+ });
122
+ return collectionIds;
123
+ }
124
+ };
125
+
126
+ // core/cron.ts
127
+ var SEARCH_INDEX_MIN_INTERVAL_MS = 5 * 60 * 1e3;
128
+ async function runCronJobs(rootConfig, options = {}) {
129
+ await Promise.all([
130
+ runCronJob("publishScheduledDocs", runPublishScheduledDocs, rootConfig),
131
+ runCronJob(
132
+ "syncScheduledDataSources",
133
+ runSyncScheduledDataSources,
134
+ rootConfig
135
+ ),
136
+ runCronJob("saveVersions", runSaveVersions, rootConfig),
137
+ runCronJob(
138
+ "incrementalSearchIndex",
139
+ runIncrementalSearchIndex,
140
+ rootConfig,
141
+ options.loadSchema
142
+ )
143
+ ]);
144
+ }
145
+ async function runCronJob(name, fn, ...args) {
146
+ try {
147
+ await fn(...args);
148
+ } catch (err) {
149
+ console.log(`cron failed: ${name}`);
150
+ console.error(String(err.stack || err));
151
+ throw err;
152
+ }
153
+ }
154
+ async function runPublishScheduledDocs(rootConfig) {
155
+ const cmsClient = new RootCMSClient(rootConfig);
156
+ await cmsClient.publishScheduledDocs();
157
+ await cmsClient.publishScheduledReleases();
158
+ }
159
+ async function runSyncScheduledDataSources(rootConfig) {
160
+ const cmsClient = new RootCMSClient(rootConfig);
161
+ await cmsClient.syncScheduledDataSources();
162
+ }
163
+ async function runSaveVersions(rootConfig) {
164
+ const service = new VersionsService(rootConfig);
165
+ await service.saveVersions();
166
+ }
167
+ async function runIncrementalSearchIndex(rootConfig, loadSchema) {
168
+ const service = new SearchIndexService(rootConfig, loadSchema);
169
+ const status = await service.getStatus();
170
+ if (status.lastRun !== null) {
171
+ const elapsed = Date.now() - status.lastRun;
172
+ if (elapsed < SEARCH_INDEX_MIN_INTERVAL_MS) {
173
+ return;
174
+ }
175
+ const hasChanges = await service.hasChangesSince(
176
+ Timestamp2.fromMillis(status.lastRun)
177
+ );
178
+ if (!hasChanges) {
179
+ return;
180
+ }
181
+ }
182
+ await service.rebuildIndex({ force: false });
183
+ }
184
+
185
+ export {
186
+ runCronJobs
187
+ };
@@ -1,10 +1,6 @@
1
1
  import {
2
- RootCMSClient,
3
2
  getCmsPlugin
4
- } from "./chunk-F4SODS5S.js";
5
-
6
- // core/cron.ts
7
- import { Timestamp as Timestamp3 } from "firebase-admin/firestore";
3
+ } from "./chunk-2BSW7SIH.js";
8
4
 
9
5
  // core/search-index.ts
10
6
  import fs from "fs";
@@ -677,8 +673,8 @@ var SearchIndexService = class {
677
673
  async listAllDocs(collectionIds) {
678
674
  const all = [];
679
675
  for (const collectionId of collectionIds) {
680
- const path3 = `Projects/${this.projectId}/Collections/${collectionId}/Drafts`;
681
- const snap = await this.db.collection(path3).get();
676
+ const path2 = `Projects/${this.projectId}/Collections/${collectionId}/Drafts`;
677
+ const snap = await this.db.collection(path2).get();
682
678
  snap.forEach((d) => {
683
679
  const docId = `${collectionId}/${d.id}`;
684
680
  if (!this.isDocIndexable(docId)) {
@@ -700,8 +696,8 @@ var SearchIndexService = class {
700
696
  async listChangedDocs(collectionIds, lastRun) {
701
697
  const all = [];
702
698
  for (const collectionId of collectionIds) {
703
- const path3 = `Projects/${this.projectId}/Collections/${collectionId}/Drafts`;
704
- const q = this.db.collection(path3).where("sys.modifiedAt", ">=", lastRun);
699
+ const path2 = `Projects/${this.projectId}/Collections/${collectionId}/Drafts`;
700
+ const q = this.db.collection(path2).where("sys.modifiedAt", ">=", lastRun);
705
701
  const snap = await q.get();
706
702
  snap.forEach((d) => {
707
703
  const docId = `${collectionId}/${d.id}`;
@@ -725,8 +721,8 @@ var SearchIndexService = class {
725
721
  async hasChangesSince(lastRun, docMap = null) {
726
722
  const collectionIds = await this.listCollectionIds();
727
723
  for (const collectionId of collectionIds) {
728
- const path3 = `Projects/${this.projectId}/Collections/${collectionId}/Drafts`;
729
- const q = this.db.collection(path3).where("sys.modifiedAt", ">=", lastRun).limit(1);
724
+ const path2 = `Projects/${this.projectId}/Collections/${collectionId}/Drafts`;
725
+ const q = this.db.collection(path2).where("sys.modifiedAt", ">=", lastRun).limit(1);
730
726
  const snap = await q.get();
731
727
  if (!snap.empty) {
732
728
  return true;
@@ -739,8 +735,8 @@ var SearchIndexService = class {
739
735
  }
740
736
  const liveIds = /* @__PURE__ */ new Set();
741
737
  for (const collectionId of collectionIds) {
742
- const path3 = `Projects/${this.projectId}/Collections/${collectionId}/Drafts`;
743
- const snap = await this.db.collection(path3).select().get();
738
+ const path2 = `Projects/${this.projectId}/Collections/${collectionId}/Drafts`;
739
+ const snap = await this.db.collection(path2).select().get();
744
740
  snap.forEach((d) => {
745
741
  const docId = `${collectionId}/${d.id}`;
746
742
  if (this.isDocIndexable(docId)) {
@@ -807,8 +803,8 @@ var SearchIndexService = class {
807
803
  );
808
804
  continue;
809
805
  }
810
- const path3 = `Projects/${this.projectId}/Collections/${collectionId}/Drafts`;
811
- const snap = await this.db.collection(path3).get();
806
+ const path2 = `Projects/${this.projectId}/Collections/${collectionId}/Drafts`;
807
+ const snap = await this.db.collection(path2).get();
812
808
  snap.forEach((d) => {
813
809
  const data = d.data() || {};
814
810
  const slug = data.slug || d.id;
@@ -884,8 +880,8 @@ var SearchIndexService = class {
884
880
  }
885
881
  const liveIds = /* @__PURE__ */ new Set();
886
882
  for (const collectionId of collectionIds) {
887
- const path3 = `Projects/${this.projectId}/Collections/${collectionId}/Drafts`;
888
- const snap = await this.db.collection(path3).select().get();
883
+ const path2 = `Projects/${this.projectId}/Collections/${collectionId}/Drafts`;
884
+ const snap = await this.db.collection(path2).select().get();
889
885
  snap.forEach((d) => {
890
886
  const docId = `${collectionId}/${d.id}`;
891
887
  if (this.isDocIndexable(docId)) {
@@ -1001,180 +997,6 @@ var SearchIndexService = class {
1001
997
  }
1002
998
  };
1003
999
 
1004
- // core/versions.ts
1005
- import fs2 from "fs";
1006
- import path2 from "path";
1007
- import { Timestamp as Timestamp2 } from "firebase-admin/firestore";
1008
- import glob2 from "tiny-glob";
1009
- var DOCUMENT_SAVE_OFFSET = 5 * 60 * 1e3;
1010
- var VersionsService = class {
1011
- constructor(rootConfig) {
1012
- this.rootConfig = rootConfig;
1013
- const cmsPlugin = getCmsPlugin(rootConfig);
1014
- const cmsPluginOptions = cmsPlugin.getConfig();
1015
- const projectId = cmsPluginOptions.id || "default";
1016
- this.projectId = projectId;
1017
- this.db = cmsPlugin.getFirestore();
1018
- }
1019
- /**
1020
- * Saves a version of all documents that have been edited since the last run.
1021
- */
1022
- async saveVersions() {
1023
- const lastRun = await this.getLastRun();
1024
- const lastRunWithOffset = lastRun === 0 ? lastRun : lastRun - DOCUMENT_SAVE_OFFSET;
1025
- const changedDocs = await this.getDocsModifiedAfter(lastRunWithOffset);
1026
- const now = Timestamp2.now().toMillis();
1027
- const versions = changedDocs.filter((doc) => {
1028
- const modifiedAt = doc.sys.modifiedAt.toMillis();
1029
- if (modifiedAt > now - DOCUMENT_SAVE_OFFSET) {
1030
- return false;
1031
- }
1032
- const publishedAt = doc.sys.publishedAt?.toMillis?.();
1033
- if (publishedAt && Math.abs(publishedAt - modifiedAt) < 5e3) {
1034
- return false;
1035
- }
1036
- return true;
1037
- });
1038
- if (versions.length > 0) {
1039
- this.saveVersionsToFirestore(versions);
1040
- }
1041
- this.saveLastRun(now);
1042
- }
1043
- async saveVersionsToFirestore(versions) {
1044
- const batch = this.db.batch();
1045
- versions.forEach((version) => {
1046
- if (!version.collection || !version.slug || !version.sys?.modifiedAt) {
1047
- return;
1048
- }
1049
- const modifiedAtMillis = version.sys.modifiedAt.toMillis();
1050
- const versionPath = `Projects/${this.projectId}/Collections/${version.collection}/Drafts/${version.slug}/Versions/${modifiedAtMillis}`;
1051
- console.log(versionPath);
1052
- const versionRef = this.db.doc(versionPath);
1053
- batch.set(versionRef, version);
1054
- });
1055
- await batch.commit();
1056
- console.log(`versions: saved ${versions.length} versions`);
1057
- }
1058
- /**
1059
- * Returns the last time (in millis) saveVersions() was run, or 0 if has
1060
- * never been run.
1061
- */
1062
- async getLastRun() {
1063
- const projectDocRef = this.db.collection("Projects").doc(this.projectId);
1064
- const projectDoc = await projectDocRef.get();
1065
- if (projectDoc.exists) {
1066
- const data = projectDoc.data() || {};
1067
- const ts = data.versionsLastRun;
1068
- if (ts) {
1069
- return ts.toMillis();
1070
- }
1071
- }
1072
- return 0;
1073
- }
1074
- /**
1075
- * Saves {versionLastRun: <timestamp>} to the Projects/<projectId> doc.
1076
- */
1077
- async saveLastRun(millis) {
1078
- const ts = Timestamp2.fromMillis(millis);
1079
- const projectDocRef = this.db.collection("Projects").doc(this.projectId);
1080
- await projectDocRef.set({ versionsLastRun: ts }, { merge: true });
1081
- }
1082
- /**
1083
- * Returns a list of all docs that were edited after a certain time.
1084
- */
1085
- async getDocsModifiedAfter(millis) {
1086
- const ts = Timestamp2.fromMillis(millis);
1087
- const results = [];
1088
- const collectionIds = await this.listCollections();
1089
- for (const collectionId of collectionIds) {
1090
- const collectionPath = `Projects/${this.projectId}/Collections/${collectionId}/Drafts`;
1091
- const query = this.db.collection(collectionPath).where("sys.modifiedAt", ">=", ts);
1092
- const querySnapshot = await query.get();
1093
- querySnapshot.forEach((doc) => {
1094
- results.push(doc.data());
1095
- });
1096
- }
1097
- return results;
1098
- }
1099
- /**
1100
- * Returns a list of collection ids for the Root project.
1101
- */
1102
- async listCollections() {
1103
- const collectionsDir = path2.join(this.rootConfig.rootDir, "collections");
1104
- if (!fs2.existsSync(collectionsDir)) {
1105
- return [];
1106
- }
1107
- const collectionIds = [];
1108
- const collectionFileNames = await glob2("*.schema.ts", {
1109
- cwd: collectionsDir
1110
- });
1111
- collectionFileNames.forEach((filename) => {
1112
- collectionIds.push(filename.slice(0, -10));
1113
- });
1114
- return collectionIds;
1115
- }
1116
- };
1117
-
1118
- // core/cron.ts
1119
- var SEARCH_INDEX_MIN_INTERVAL_MS = 5 * 60 * 1e3;
1120
- async function runCronJobs(rootConfig, options = {}) {
1121
- await Promise.all([
1122
- runCronJob("publishScheduledDocs", runPublishScheduledDocs, rootConfig),
1123
- runCronJob(
1124
- "syncScheduledDataSources",
1125
- runSyncScheduledDataSources,
1126
- rootConfig
1127
- ),
1128
- runCronJob("saveVersions", runSaveVersions, rootConfig),
1129
- runCronJob(
1130
- "incrementalSearchIndex",
1131
- runIncrementalSearchIndex,
1132
- rootConfig,
1133
- options.loadSchema
1134
- )
1135
- ]);
1136
- }
1137
- async function runCronJob(name, fn, ...args) {
1138
- try {
1139
- await fn(...args);
1140
- } catch (err) {
1141
- console.log(`cron failed: ${name}`);
1142
- console.error(String(err.stack || err));
1143
- throw err;
1144
- }
1145
- }
1146
- async function runPublishScheduledDocs(rootConfig) {
1147
- const cmsClient = new RootCMSClient(rootConfig);
1148
- await cmsClient.publishScheduledDocs();
1149
- await cmsClient.publishScheduledReleases();
1150
- }
1151
- async function runSyncScheduledDataSources(rootConfig) {
1152
- const cmsClient = new RootCMSClient(rootConfig);
1153
- await cmsClient.syncScheduledDataSources();
1154
- }
1155
- async function runSaveVersions(rootConfig) {
1156
- const service = new VersionsService(rootConfig);
1157
- await service.saveVersions();
1158
- }
1159
- async function runIncrementalSearchIndex(rootConfig, loadSchema) {
1160
- const service = new SearchIndexService(rootConfig, loadSchema);
1161
- const status = await service.getStatus();
1162
- if (status.lastRun !== null) {
1163
- const elapsed = Date.now() - status.lastRun;
1164
- if (elapsed < SEARCH_INDEX_MIN_INTERVAL_MS) {
1165
- return;
1166
- }
1167
- const hasChanges = await service.hasChangesSince(
1168
- Timestamp3.fromMillis(status.lastRun)
1169
- );
1170
- if (!hasChanges) {
1171
- return;
1172
- }
1173
- }
1174
- await service.rebuildIndex({ force: false });
1175
- }
1176
-
1177
1000
  export {
1178
- SearchIndexService,
1179
- runCronJobs
1001
+ SearchIndexService
1180
1002
  };
package/dist/cli.js CHANGED
@@ -5,8 +5,7 @@ import {
5
5
  RootCMSClient,
6
6
  getCmsPlugin,
7
7
  unmarshalData
8
- } from "./chunk-F4SODS5S.js";
9
- import "./chunk-CRK7N6RR.js";
8
+ } from "./chunk-2BSW7SIH.js";
10
9
  import "./chunk-MLKGABMK.js";
11
10
 
12
11
  // cli/cli.ts
package/dist/client.js CHANGED
@@ -12,8 +12,7 @@ import {
12
12
  translationsForLocale,
13
13
  unmarshalArray,
14
14
  unmarshalData
15
- } from "./chunk-F4SODS5S.js";
16
- import "./chunk-CRK7N6RR.js";
15
+ } from "./chunk-2BSW7SIH.js";
17
16
  import "./chunk-MLKGABMK.js";
18
17
  export {
19
18
  BatchRequest,
package/dist/core.js CHANGED
@@ -16,8 +16,7 @@ import {
16
16
  translationsForLocale,
17
17
  unmarshalArray,
18
18
  unmarshalData
19
- } from "./chunk-F4SODS5S.js";
20
- import "./chunk-CRK7N6RR.js";
19
+ } from "./chunk-2BSW7SIH.js";
21
20
  import {
22
21
  __export
23
22
  } from "./chunk-MLKGABMK.js";
package/dist/functions.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  runCronJobs
3
- } from "./chunk-TRM4MQHU.js";
4
- import "./chunk-F4SODS5S.js";
5
- import "./chunk-CRK7N6RR.js";
3
+ } from "./chunk-BGTUWIV6.js";
4
+ import "./chunk-C245C557.js";
5
+ import "./chunk-2BSW7SIH.js";
6
6
  import "./chunk-MLKGABMK.js";
7
7
 
8
8
  // core/functions.ts
package/dist/plugin.js CHANGED
@@ -12,17 +12,18 @@ import {
12
12
  serializeAiConfig,
13
13
  summarizeDiff,
14
14
  translateString
15
- } from "./chunk-NXEXOHBD.js";
15
+ } from "./chunk-5CZBPART.js";
16
16
  import {
17
- SearchIndexService,
18
17
  runCronJobs
19
- } from "./chunk-TRM4MQHU.js";
18
+ } from "./chunk-BGTUWIV6.js";
19
+ import {
20
+ SearchIndexService
21
+ } from "./chunk-C245C557.js";
20
22
  import {
21
23
  RootCMSClient,
22
24
  parseDocId,
23
25
  unmarshalData
24
- } from "./chunk-F4SODS5S.js";
25
- import "./chunk-CRK7N6RR.js";
26
+ } from "./chunk-2BSW7SIH.js";
26
27
  import "./chunk-MLKGABMK.js";
27
28
 
28
29
  // core/plugin.ts
@@ -546,11 +547,6 @@ function api(server, options) {
546
547
  return;
547
548
  }
548
549
  const body = req.body || {};
549
- const messages = body.messages || [];
550
- if (!Array.isArray(messages) || messages.length === 0) {
551
- res.status(400).json({ success: false, error: "MISSING_MESSAGES" });
552
- return;
553
- }
554
550
  const model = findModel(aiConfig, body.modelId);
555
551
  if (!model) {
556
552
  res.status(400).json({ success: false, error: "UNKNOWN_MODEL" });
@@ -561,10 +557,12 @@ function api(server, options) {
561
557
  const store = new ChatStore(cmsClient, req.user.email);
562
558
  const requestedChatId = typeof body.chatId === "string" ? body.chatId.trim() : "";
563
559
  let chatId = "";
560
+ let storedMessages = [];
564
561
  if (requestedChatId) {
565
562
  const existing = await store.getChat(requestedChatId);
566
563
  if (existing) {
567
564
  chatId = existing.id;
565
+ storedMessages = existing.messages || [];
568
566
  } else {
569
567
  const created = await store.createChat({
570
568
  id: requestedChatId,
@@ -576,6 +574,15 @@ function api(server, options) {
576
574
  const created = await store.createChat({ modelId: model.id });
577
575
  chatId = created.id;
578
576
  }
577
+ let messages;
578
+ if (body.message && typeof body.message === "object") {
579
+ messages = [...storedMessages, body.message];
580
+ } else if (Array.isArray(body.messages) && body.messages.length > 0) {
581
+ messages = body.messages;
582
+ } else {
583
+ res.status(400).json({ success: false, error: "MISSING_MESSAGES" });
584
+ return;
585
+ }
579
586
  try {
580
587
  const streamResponse = await runChatStream({
581
588
  rootConfig: req.rootConfig,
@@ -585,7 +592,9 @@ function api(server, options) {
585
592
  messages,
586
593
  chatId,
587
594
  user: req.user.email,
588
- executionMode
595
+ executionMode,
596
+ loadCollection: (collectionId) => getCollectionSchema(req, collectionId),
597
+ loadAllCollections: async () => (await options.getRenderer(req)).getCollections()
589
598
  });
590
599
  streamResponse.headers.set("x-root-cms-chat-id", chatId);
591
600
  await pipeWebResponse(streamResponse, res);
@@ -628,10 +637,14 @@ function api(server, options) {
628
637
  try {
629
638
  const streamResponse = await runEditObjectStream({
630
639
  rootConfig: req.rootConfig,
640
+ cmsClient: new RootCMSClient(req.rootConfig),
641
+ user: req.user.email,
631
642
  config: aiConfig,
632
643
  model,
633
644
  messages,
634
- editData: body.editData
645
+ editData: body.editData,
646
+ loadCollection: (collectionId) => getCollectionSchema(req, collectionId),
647
+ loadAllCollections: async () => (await options.getRenderer(req)).getCollections()
635
648
  });
636
649
  await pipeWebResponse(streamResponse, res);
637
650
  } catch (err) {
@@ -1442,6 +1455,10 @@ function cmsPlugin(options) {
1442
1455
  * Attaches CMS-specific middleware to the Root.js server.
1443
1456
  */
1444
1457
  configureServer: async (server, serverOptions) => {
1458
+ server.use(
1459
+ ["/cms/api/ai.chat", "/cms/api/ai.edit_object"],
1460
+ bodyParser.json({ limit: "4mb" })
1461
+ );
1445
1462
  server.use(bodyParser.json());
1446
1463
  server.use(
1447
1464
  (err, req, res, next) => {