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