@blinkk/root-cms 2.0.10 → 2.1.1
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 +84 -19
- package/dist/cli.js +16 -5
- package/dist/core.d.ts +1 -2
- package/dist/core.js +18 -14
- package/dist/plugin.js +102 -26
- package/dist/project.d.ts +14 -4
- package/dist/project.js +68 -8
- package/dist/{schema-KpQGOA1Z.d.ts → schema-UCmjggdA.d.ts} +39 -9
- package/dist/ui/ui.css +1 -1
- package/dist/ui/ui.js +98 -98
- package/package.json +3 -3
package/dist/app.js
CHANGED
|
@@ -7,7 +7,7 @@ import { render as renderToString } from "preact-render-to-string";
|
|
|
7
7
|
// package.json
|
|
8
8
|
var package_default = {
|
|
9
9
|
name: "@blinkk/root-cms",
|
|
10
|
-
version: "2.
|
|
10
|
+
version: "2.1.1",
|
|
11
11
|
author: "s@blinkk.com",
|
|
12
12
|
license: "MIT",
|
|
13
13
|
engines: {
|
|
@@ -154,7 +154,7 @@ var package_default = {
|
|
|
154
154
|
yjs: "13.6.27"
|
|
155
155
|
},
|
|
156
156
|
peerDependencies: {
|
|
157
|
-
"@blinkk/root": "2.
|
|
157
|
+
"@blinkk/root": "2.1.1",
|
|
158
158
|
"firebase-admin": ">=11",
|
|
159
159
|
"firebase-functions": ">=4",
|
|
160
160
|
preact: ">=10",
|
|
@@ -168,16 +168,18 @@ var package_default = {
|
|
|
168
168
|
};
|
|
169
169
|
|
|
170
170
|
// core/project.ts
|
|
171
|
-
var
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
171
|
+
var SCHEMA_MODULES = import.meta.glob(
|
|
172
|
+
[
|
|
173
|
+
"/**/*.schema.ts",
|
|
174
|
+
"!/appengine/**/*.schema.ts",
|
|
175
|
+
"!/functions/**/*.schema.ts",
|
|
176
|
+
"!/gae/**/*.schema.ts"
|
|
177
|
+
],
|
|
178
|
+
{ eager: true }
|
|
179
|
+
);
|
|
180
|
+
async function getProjectSchemas() {
|
|
176
181
|
const schemas = {};
|
|
177
182
|
for (const fileId in SCHEMA_MODULES) {
|
|
178
|
-
if (IGNORED_SCHEMA_FOLDERS.some((prefix) => fileId.startsWith(prefix))) {
|
|
179
|
-
continue;
|
|
180
|
-
}
|
|
181
183
|
const schemaModule = SCHEMA_MODULES[fileId];
|
|
182
184
|
if (schemaModule.default) {
|
|
183
185
|
schemas[fileId] = schemaModule.default;
|
|
@@ -185,6 +187,62 @@ function getProjectSchemas() {
|
|
|
185
187
|
}
|
|
186
188
|
return schemas;
|
|
187
189
|
}
|
|
190
|
+
async function getCollectionSchema(collectionId) {
|
|
191
|
+
if (!testValidCollectionId(collectionId)) {
|
|
192
|
+
throw new Error(`invalid collection id: ${collectionId}`);
|
|
193
|
+
}
|
|
194
|
+
const fileId = `/collections/${collectionId}.schema.ts`;
|
|
195
|
+
const module = SCHEMA_MODULES[fileId];
|
|
196
|
+
if (!module.default) {
|
|
197
|
+
console.warn(`collection schema not exported in: ${fileId}`);
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
const collection = module.default;
|
|
201
|
+
collection.id = collectionId;
|
|
202
|
+
return convertOneOfTypes(collection);
|
|
203
|
+
}
|
|
204
|
+
function testValidCollectionId(id) {
|
|
205
|
+
return /^[A-Za-z0-9_-]+$/.test(id);
|
|
206
|
+
}
|
|
207
|
+
function convertOneOfTypes(collection) {
|
|
208
|
+
const clone = structuredClone(collection);
|
|
209
|
+
const types = clone.types || {};
|
|
210
|
+
function handleOneOfField(field) {
|
|
211
|
+
const names = [];
|
|
212
|
+
(field.types || []).forEach((sub) => {
|
|
213
|
+
if (typeof sub === "string") {
|
|
214
|
+
names.push(sub);
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
if (sub.name) {
|
|
218
|
+
names.push(sub.name);
|
|
219
|
+
if (!types[sub.name]) {
|
|
220
|
+
types[sub.name] = sub;
|
|
221
|
+
if (sub.fields) {
|
|
222
|
+
walk(sub);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
field.types = names;
|
|
228
|
+
}
|
|
229
|
+
function handleField(field) {
|
|
230
|
+
if (field.type === "oneof") {
|
|
231
|
+
handleOneOfField(field);
|
|
232
|
+
} else if (field.type === "object") {
|
|
233
|
+
walk(field);
|
|
234
|
+
} else if (field.type === "array" && field.of) {
|
|
235
|
+
handleField(field.of);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
function walk(schema) {
|
|
239
|
+
const fields = schema?.fields || [];
|
|
240
|
+
fields.forEach(handleField);
|
|
241
|
+
}
|
|
242
|
+
walk(clone);
|
|
243
|
+
clone.types = types;
|
|
244
|
+
return clone;
|
|
245
|
+
}
|
|
188
246
|
|
|
189
247
|
// core/app.tsx
|
|
190
248
|
import { jsx, jsxs } from "preact/jsx-runtime";
|
|
@@ -259,9 +317,11 @@ function App(props) {
|
|
|
259
317
|
}
|
|
260
318
|
async function renderApp(req, res, options) {
|
|
261
319
|
const collections = {};
|
|
262
|
-
Object.entries(getCollections()).forEach(
|
|
263
|
-
|
|
264
|
-
|
|
320
|
+
Object.entries(await getCollections()).forEach(
|
|
321
|
+
([collectionId, collection]) => {
|
|
322
|
+
collections[collectionId] = serializeCollection(collection);
|
|
323
|
+
}
|
|
324
|
+
);
|
|
265
325
|
const rootConfig = options.rootConfig || {};
|
|
266
326
|
const cmsConfig = options.cmsConfig || {};
|
|
267
327
|
let gci = cmsConfig.gci;
|
|
@@ -324,7 +384,8 @@ function serializeCollection(collection) {
|
|
|
324
384
|
preview: collection.preview,
|
|
325
385
|
slugRegex: collection.slugRegex,
|
|
326
386
|
autolock: collection.autolock,
|
|
327
|
-
autolockReason: collection.autolockReason
|
|
387
|
+
autolockReason: collection.autolockReason,
|
|
388
|
+
sortOptions: collection.sortOptions
|
|
328
389
|
};
|
|
329
390
|
}
|
|
330
391
|
function SignIn(props) {
|
|
@@ -407,18 +468,21 @@ ${mainHtml}`;
|
|
|
407
468
|
res.status(403);
|
|
408
469
|
res.send(html);
|
|
409
470
|
}
|
|
410
|
-
function getCollections() {
|
|
471
|
+
async function getCollections() {
|
|
411
472
|
const collections = {};
|
|
412
|
-
const schemas = getProjectSchemas();
|
|
473
|
+
const schemas = await getProjectSchemas();
|
|
413
474
|
Object.entries(schemas).forEach(([fileId, schema]) => {
|
|
414
475
|
if (fileId.startsWith("/collections/")) {
|
|
415
|
-
const collectionId =
|
|
416
|
-
collections[collectionId] = {
|
|
476
|
+
const collectionId = toCollectionId(fileId);
|
|
477
|
+
collections[collectionId] = { id: collectionId, ...schema };
|
|
417
478
|
}
|
|
418
479
|
});
|
|
419
480
|
return collections;
|
|
420
481
|
}
|
|
421
|
-
function
|
|
482
|
+
async function getCollection(collectionId) {
|
|
483
|
+
return getCollectionSchema(collectionId);
|
|
484
|
+
}
|
|
485
|
+
function toCollectionId(fileId) {
|
|
422
486
|
return path.basename(fileId).split(".")[0];
|
|
423
487
|
}
|
|
424
488
|
function generateNonce() {
|
|
@@ -461,6 +525,7 @@ function cachebust(req, url) {
|
|
|
461
525
|
return `${url}?c=${value}`;
|
|
462
526
|
}
|
|
463
527
|
export {
|
|
528
|
+
getCollection,
|
|
464
529
|
getCollections,
|
|
465
530
|
renderApp,
|
|
466
531
|
renderSignIn
|
package/dist/cli.js
CHANGED
|
@@ -17,7 +17,7 @@ async function generateTypes() {
|
|
|
17
17
|
rootConfig,
|
|
18
18
|
modulePath
|
|
19
19
|
);
|
|
20
|
-
const schemas = project.getProjectSchemas();
|
|
20
|
+
const schemas = await project.getProjectSchemas();
|
|
21
21
|
const outputPath = path.resolve(rootDir, "root-cms.d.ts");
|
|
22
22
|
await generateSchemaDts(outputPath, schemas);
|
|
23
23
|
console.log("saved root-cms.d.ts!");
|
|
@@ -231,12 +231,19 @@ function fieldType(field, options) {
|
|
|
231
231
|
if (field.types && Array.isArray(field.types)) {
|
|
232
232
|
const unionTypes = [];
|
|
233
233
|
field.types.forEach((schema) => {
|
|
234
|
-
|
|
234
|
+
let typeName;
|
|
235
|
+
if (typeof schema === "string") {
|
|
236
|
+
typeName = schema;
|
|
235
237
|
return;
|
|
238
|
+
} else {
|
|
239
|
+
typeName = schema.name;
|
|
236
240
|
}
|
|
237
|
-
|
|
241
|
+
if (!typeName) {
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
const cleanName = alphanumeric(typeName);
|
|
238
245
|
const oneOfTypeId = `${cleanName}Fields`;
|
|
239
|
-
if (!options.oneOfTypes[oneOfTypeId]) {
|
|
246
|
+
if (typeof schema === "object" && !options.oneOfTypes[oneOfTypeId]) {
|
|
240
247
|
const oneOfTypeInterface = dom.create.interface(
|
|
241
248
|
oneOfTypeId,
|
|
242
249
|
dom.DeclarationFlags.Export
|
|
@@ -252,7 +259,7 @@ function fieldType(field, options) {
|
|
|
252
259
|
}
|
|
253
260
|
const oneOfOption = dom.create.namedTypeReference("RootCMSOneOfOption");
|
|
254
261
|
oneOfOption.typeArguments = [
|
|
255
|
-
dom.type.stringLiteral(
|
|
262
|
+
dom.type.stringLiteral(typeName),
|
|
256
263
|
dom.create.namedTypeReference(oneOfTypeId)
|
|
257
264
|
];
|
|
258
265
|
unionTypes.push(oneOfOption);
|
|
@@ -267,6 +274,10 @@ function fieldType(field, options) {
|
|
|
267
274
|
const referenceType = dom.create.namedTypeReference("RootCMSReference");
|
|
268
275
|
return referenceType;
|
|
269
276
|
}
|
|
277
|
+
if (field.type === "references") {
|
|
278
|
+
const referenceType = dom.create.namedTypeReference("RootCMSReference");
|
|
279
|
+
return dom.type.array(referenceType);
|
|
280
|
+
}
|
|
270
281
|
if (field.type === "richtext") {
|
|
271
282
|
const richtextType = dom.create.namedTypeReference("RootCMSRichText");
|
|
272
283
|
return richtextType;
|
package/dist/core.d.ts
CHANGED
|
@@ -2,9 +2,8 @@ import { L as LoadTranslationsOptions, T as TranslationsMap, a as LocaleTranslat
|
|
|
2
2
|
export { A as Action, p as ArrayObject, z as BatchRequest, B as BatchRequestOptions, w as BatchRequestQuery, x as BatchRequestQueryOptions, C as BatchResponse, c as DataSource, d as DataSourceData, e as DataSourceMode, D as Doc, b as DocMode, h as GetCountOptions, G as GetDocOptions, H as HttpMethod, j as ListActionsOptions, g as ListDocsOptions, E as Locale, N as MultiLocaleTranslationsMap, R as Release, k as RootCMSClient, f as SaveDraftOptions, S as SetDocOptions, O as SingleLocaleTranslationsMap, F as SourceString, I as TranslatedString, i as Translation, y as TranslationsDoc, J as TranslationsDocMode, M as TranslationsLocaleDocEntry, K as TranslationsLocaleDocHashMap, P as TranslationsManager, U as UserRole, Q as buildTranslationsDbPath, V as buildTranslationsLocaleDocDbPath, m as getCmsPlugin, l as isRichTextData, q as marshalArray, n as marshalData, o as normalizeData, v as parseDocId, t as toArrayObject, s as translationsForLocale, r as unmarshalArray, u as unmarshalData } from './client-Vr32ZRmC.js';
|
|
3
3
|
import { RootConfig } from '@blinkk/root';
|
|
4
4
|
import { Query } from 'firebase-admin/firestore';
|
|
5
|
-
export { s as schema } from './schema-
|
|
5
|
+
export { s as schema } from './schema-UCmjggdA.js';
|
|
6
6
|
import 'firebase-admin/app';
|
|
7
|
-
import 'preact';
|
|
8
7
|
|
|
9
8
|
/** @deprecated Use client.ts instead. */
|
|
10
9
|
|
package/dist/core.js
CHANGED
|
@@ -1700,51 +1700,55 @@ __export(schema_exports, {
|
|
|
1700
1700
|
object: () => object,
|
|
1701
1701
|
oneOf: () => oneOf,
|
|
1702
1702
|
reference: () => reference,
|
|
1703
|
+
references: () => references,
|
|
1703
1704
|
richtext: () => richtext,
|
|
1704
1705
|
select: () => select,
|
|
1705
1706
|
string: () => string
|
|
1706
1707
|
});
|
|
1707
1708
|
function string(field) {
|
|
1708
|
-
return {
|
|
1709
|
+
return { type: "string", ...field };
|
|
1709
1710
|
}
|
|
1710
1711
|
function number(field) {
|
|
1711
|
-
return {
|
|
1712
|
+
return { type: "number", ...field };
|
|
1712
1713
|
}
|
|
1713
1714
|
function date(field) {
|
|
1714
|
-
return {
|
|
1715
|
+
return { type: "date", ...field };
|
|
1715
1716
|
}
|
|
1716
1717
|
function datetime(field) {
|
|
1717
|
-
return {
|
|
1718
|
+
return { type: "datetime", ...field };
|
|
1718
1719
|
}
|
|
1719
1720
|
function boolean(field) {
|
|
1720
|
-
return {
|
|
1721
|
+
return { type: "boolean", ...field };
|
|
1721
1722
|
}
|
|
1722
1723
|
function select(field) {
|
|
1723
|
-
return {
|
|
1724
|
+
return { type: "select", ...field };
|
|
1724
1725
|
}
|
|
1725
1726
|
function multiselect(field) {
|
|
1726
|
-
return {
|
|
1727
|
+
return { type: "multiselect", ...field };
|
|
1727
1728
|
}
|
|
1728
1729
|
function image(field) {
|
|
1729
|
-
return {
|
|
1730
|
+
return { type: "image", ...field };
|
|
1730
1731
|
}
|
|
1731
1732
|
function file(field) {
|
|
1732
|
-
return {
|
|
1733
|
+
return { type: "file", ...field };
|
|
1733
1734
|
}
|
|
1734
1735
|
function object(field) {
|
|
1735
|
-
return {
|
|
1736
|
+
return { type: "object", ...field };
|
|
1736
1737
|
}
|
|
1737
1738
|
function array(field) {
|
|
1738
|
-
return {
|
|
1739
|
+
return { type: "array", ...field };
|
|
1739
1740
|
}
|
|
1740
1741
|
function oneOf(field) {
|
|
1741
|
-
return {
|
|
1742
|
+
return { type: "oneof", ...field };
|
|
1742
1743
|
}
|
|
1743
1744
|
function richtext(field) {
|
|
1744
|
-
return {
|
|
1745
|
+
return { type: "richtext", ...field };
|
|
1745
1746
|
}
|
|
1746
1747
|
function reference(field) {
|
|
1747
|
-
return {
|
|
1748
|
+
return { type: "reference", ...field };
|
|
1749
|
+
}
|
|
1750
|
+
function references(field) {
|
|
1751
|
+
return { ...field, type: "references" };
|
|
1748
1752
|
}
|
|
1749
1753
|
function defineSchema(schema) {
|
|
1750
1754
|
return schema;
|
package/dist/plugin.js
CHANGED
|
@@ -51,21 +51,21 @@ __export(generate_types_exports, {
|
|
|
51
51
|
generateSchemaDts: () => generateSchemaDts,
|
|
52
52
|
generateTypes: () => generateTypes
|
|
53
53
|
});
|
|
54
|
-
import { promises as
|
|
55
|
-
import
|
|
54
|
+
import { promises as fs3 } from "node:fs";
|
|
55
|
+
import path4 from "node:path";
|
|
56
56
|
import { fileURLToPath } from "node:url";
|
|
57
57
|
import { loadRootConfig, viteSsrLoadModule } from "@blinkk/root/node";
|
|
58
58
|
import * as dom from "dts-dom";
|
|
59
59
|
async function generateTypes() {
|
|
60
60
|
const rootDir = process.cwd();
|
|
61
61
|
const rootConfig = await loadRootConfig(rootDir, { command: "root-cms" });
|
|
62
|
-
const modulePath =
|
|
62
|
+
const modulePath = path4.resolve(__dirname, "./project.js");
|
|
63
63
|
const project = await viteSsrLoadModule(
|
|
64
64
|
rootConfig,
|
|
65
65
|
modulePath
|
|
66
66
|
);
|
|
67
|
-
const schemas = project.getProjectSchemas();
|
|
68
|
-
const outputPath =
|
|
67
|
+
const schemas = await project.getProjectSchemas();
|
|
68
|
+
const outputPath = path4.resolve(rootDir, "root-cms.d.ts");
|
|
69
69
|
await generateSchemaDts(outputPath, schemas);
|
|
70
70
|
console.log("saved root-cms.d.ts!");
|
|
71
71
|
}
|
|
@@ -76,7 +76,7 @@ async function generateSchemaDts(outputPath, schemas) {
|
|
|
76
76
|
dtsFormatter.addSchemaFile(fileId, schema);
|
|
77
77
|
}
|
|
78
78
|
const output = dtsFormatter.toString();
|
|
79
|
-
await
|
|
79
|
+
await fs3.writeFile(outputPath, output, "utf-8");
|
|
80
80
|
}
|
|
81
81
|
function fieldProperty(field, options) {
|
|
82
82
|
const prop = dom.create.property(
|
|
@@ -129,12 +129,19 @@ function fieldType(field, options) {
|
|
|
129
129
|
if (field.types && Array.isArray(field.types)) {
|
|
130
130
|
const unionTypes = [];
|
|
131
131
|
field.types.forEach((schema) => {
|
|
132
|
-
|
|
132
|
+
let typeName;
|
|
133
|
+
if (typeof schema === "string") {
|
|
134
|
+
typeName = schema;
|
|
135
|
+
return;
|
|
136
|
+
} else {
|
|
137
|
+
typeName = schema.name;
|
|
138
|
+
}
|
|
139
|
+
if (!typeName) {
|
|
133
140
|
return;
|
|
134
141
|
}
|
|
135
|
-
const cleanName = alphanumeric(
|
|
142
|
+
const cleanName = alphanumeric(typeName);
|
|
136
143
|
const oneOfTypeId = `${cleanName}Fields`;
|
|
137
|
-
if (!options.oneOfTypes[oneOfTypeId]) {
|
|
144
|
+
if (typeof schema === "object" && !options.oneOfTypes[oneOfTypeId]) {
|
|
138
145
|
const oneOfTypeInterface = dom.create.interface(
|
|
139
146
|
oneOfTypeId,
|
|
140
147
|
dom.DeclarationFlags.Export
|
|
@@ -150,7 +157,7 @@ function fieldType(field, options) {
|
|
|
150
157
|
}
|
|
151
158
|
const oneOfOption = dom.create.namedTypeReference("RootCMSOneOfOption");
|
|
152
159
|
oneOfOption.typeArguments = [
|
|
153
|
-
dom.type.stringLiteral(
|
|
160
|
+
dom.type.stringLiteral(typeName),
|
|
154
161
|
dom.create.namedTypeReference(oneOfTypeId)
|
|
155
162
|
];
|
|
156
163
|
unionTypes.push(oneOfOption);
|
|
@@ -165,6 +172,10 @@ function fieldType(field, options) {
|
|
|
165
172
|
const referenceType = dom.create.namedTypeReference("RootCMSReference");
|
|
166
173
|
return referenceType;
|
|
167
174
|
}
|
|
175
|
+
if (field.type === "references") {
|
|
176
|
+
const referenceType = dom.create.namedTypeReference("RootCMSReference");
|
|
177
|
+
return dom.type.array(referenceType);
|
|
178
|
+
}
|
|
168
179
|
if (field.type === "richtext") {
|
|
169
180
|
const richtextType = dom.create.namedTypeReference("RootCMSRichText");
|
|
170
181
|
return richtextType;
|
|
@@ -190,7 +201,7 @@ var __dirname, TEMPLATE, DtsFormatter;
|
|
|
190
201
|
var init_generate_types = __esm({
|
|
191
202
|
"cli/generate-types.ts"() {
|
|
192
203
|
"use strict";
|
|
193
|
-
__dirname =
|
|
204
|
+
__dirname = path4.dirname(fileURLToPath(import.meta.url));
|
|
194
205
|
TEMPLATE = `/* eslint-disable */
|
|
195
206
|
/** Root.js CMS types. This file is autogenerated. */
|
|
196
207
|
|
|
@@ -264,7 +275,7 @@ export interface RootCMSDoc<Fields extends {}> {
|
|
|
264
275
|
/** Adds the types for a `.schema.ts` file to the `.d.ts` file. */
|
|
265
276
|
addSchemaFile(fileId, schema) {
|
|
266
277
|
const jsdoc = `Generated from \`${fileId}\`.`;
|
|
267
|
-
const typeId = alphanumeric(
|
|
278
|
+
const typeId = alphanumeric(path4.parse(fileId).name.split(".")[0]);
|
|
268
279
|
const oneOfTypes = {};
|
|
269
280
|
const fieldsTypeId = `${typeId}Fields`;
|
|
270
281
|
const fieldsType = dom.create.interface(
|
|
@@ -344,9 +355,10 @@ export interface RootCMSDoc<Fields extends {}> {
|
|
|
344
355
|
});
|
|
345
356
|
|
|
346
357
|
// core/plugin.ts
|
|
347
|
-
import { promises as
|
|
348
|
-
import
|
|
358
|
+
import { promises as fs4 } from "node:fs";
|
|
359
|
+
import path5 from "node:path";
|
|
349
360
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
361
|
+
import { viteSsrLoadModule as viteSsrLoadModule2 } from "@blinkk/root/node";
|
|
350
362
|
import bodyParser from "body-parser";
|
|
351
363
|
import {
|
|
352
364
|
applicationDefault,
|
|
@@ -359,6 +371,8 @@ import * as jsonwebtoken from "jsonwebtoken";
|
|
|
359
371
|
import sirv from "sirv";
|
|
360
372
|
|
|
361
373
|
// core/api.ts
|
|
374
|
+
import { promises as fs2 } from "node:fs";
|
|
375
|
+
import path3 from "node:path";
|
|
362
376
|
import { multipartMiddleware } from "@blinkk/root/middleware";
|
|
363
377
|
|
|
364
378
|
// core/ai.ts
|
|
@@ -2192,21 +2206,48 @@ function csvToArray(csvString) {
|
|
|
2192
2206
|
}
|
|
2193
2207
|
|
|
2194
2208
|
// core/api.ts
|
|
2209
|
+
function testValidCollectionId(id) {
|
|
2210
|
+
return /^[A-Za-z0-9_-]+$/.test(id);
|
|
2211
|
+
}
|
|
2195
2212
|
function api(server, options) {
|
|
2213
|
+
async function getCollectionSchema(req, collectionId) {
|
|
2214
|
+
if (req.viteServer) {
|
|
2215
|
+
const app = await options.getRenderer(req);
|
|
2216
|
+
return await app.getCollection(collectionId);
|
|
2217
|
+
}
|
|
2218
|
+
try {
|
|
2219
|
+
const schemaPath = path3.join(
|
|
2220
|
+
req.rootConfig.rootDir,
|
|
2221
|
+
"dist",
|
|
2222
|
+
"collections",
|
|
2223
|
+
`${collectionId}.schema.json`
|
|
2224
|
+
);
|
|
2225
|
+
const contents = await fs2.readFile(schemaPath, "utf8");
|
|
2226
|
+
return JSON.parse(contents);
|
|
2227
|
+
} catch (err) {
|
|
2228
|
+
if (err && err.code === "ENOENT") {
|
|
2229
|
+
return null;
|
|
2230
|
+
}
|
|
2231
|
+
throw err;
|
|
2232
|
+
}
|
|
2233
|
+
}
|
|
2196
2234
|
server.use("/cms/api/collection.get", async (req, res) => {
|
|
2197
2235
|
if (req.method !== "POST" || !String(req.get("content-type")).startsWith("application/json")) {
|
|
2198
2236
|
res.status(400).json({ success: false, error: "BAD_REQUEST" });
|
|
2199
2237
|
return;
|
|
2200
2238
|
}
|
|
2201
2239
|
const reqBody = req.body || {};
|
|
2202
|
-
|
|
2240
|
+
const collectionId = String(reqBody.collectionId || "");
|
|
2241
|
+
if (!collectionId) {
|
|
2203
2242
|
res.status(400).json({ success: false, error: "MISSING_COLLECTION_ID" });
|
|
2204
2243
|
return;
|
|
2205
2244
|
}
|
|
2245
|
+
if (!testValidCollectionId(collectionId)) {
|
|
2246
|
+
res.status(400).json({ success: false, error: "INVALID_COLLECTION_ID" });
|
|
2247
|
+
return;
|
|
2248
|
+
}
|
|
2206
2249
|
try {
|
|
2207
|
-
const
|
|
2208
|
-
const collections = app.getCollections();
|
|
2209
|
-
const collection = collections[reqBody.collectionId];
|
|
2250
|
+
const collection = await getCollectionSchema(req, collectionId);
|
|
2210
2251
|
if (!collection) {
|
|
2211
2252
|
res.status(404).json({ success: false, error: "NOT_FOUND" });
|
|
2212
2253
|
return;
|
|
@@ -2373,7 +2414,31 @@ function api(server, options) {
|
|
|
2373
2414
|
}
|
|
2374
2415
|
|
|
2375
2416
|
// core/plugin.ts
|
|
2376
|
-
var __dirname2 =
|
|
2417
|
+
var __dirname2 = path5.dirname(fileURLToPath2(import.meta.url));
|
|
2418
|
+
async function writeCollectionSchemasToJson(rootConfig) {
|
|
2419
|
+
const modulePath = path5.resolve(__dirname2, "./project.js");
|
|
2420
|
+
const project = await viteSsrLoadModule2(
|
|
2421
|
+
rootConfig,
|
|
2422
|
+
modulePath
|
|
2423
|
+
);
|
|
2424
|
+
const outDir = path5.join(rootConfig.rootDir, "dist", "collections");
|
|
2425
|
+
await fs4.mkdir(outDir, { recursive: true });
|
|
2426
|
+
const fileIds = Object.keys(project.SCHEMA_MODULES);
|
|
2427
|
+
for (const fileId of fileIds) {
|
|
2428
|
+
if (!fileId.startsWith("/collections/")) {
|
|
2429
|
+
continue;
|
|
2430
|
+
}
|
|
2431
|
+
const collectionId = path5.basename(fileId).split(".")[0];
|
|
2432
|
+
const schema = await project.getCollectionSchema(collectionId);
|
|
2433
|
+
if (!schema) {
|
|
2434
|
+
console.warn(`collection is missing a default export: ${fileId}`);
|
|
2435
|
+
continue;
|
|
2436
|
+
}
|
|
2437
|
+
const jsonPath = path5.join(outDir, `${collectionId}.schema.json`);
|
|
2438
|
+
const data = JSON.stringify(schema, null, 2);
|
|
2439
|
+
await fs4.writeFile(jsonPath, data, "utf-8");
|
|
2440
|
+
}
|
|
2441
|
+
}
|
|
2377
2442
|
var SESSION_COOKIE_AUTH = "root-cms-auth";
|
|
2378
2443
|
var NONCONF_STATIC_PATHS = [
|
|
2379
2444
|
"/cms/static/signin.css",
|
|
@@ -2574,12 +2639,23 @@ function cmsPlugin(options) {
|
|
|
2574
2639
|
const databaseId = firebaseConfig.databaseId || "(default)";
|
|
2575
2640
|
return getFirestore(app, databaseId);
|
|
2576
2641
|
},
|
|
2642
|
+
hooks: {
|
|
2643
|
+
/**
|
|
2644
|
+
* Saves collection schema files from `collections/*.schema.ts` to
|
|
2645
|
+
* `dist/collections/*.schema.json` for prod builds.
|
|
2646
|
+
*/
|
|
2647
|
+
preBuild: async (rootConfig) => {
|
|
2648
|
+
await writeCollectionSchemasToJson(rootConfig);
|
|
2649
|
+
}
|
|
2650
|
+
},
|
|
2577
2651
|
/**
|
|
2578
2652
|
* A map of ssr files to include when running `root build`.
|
|
2579
2653
|
*/
|
|
2580
|
-
ssrInput: () =>
|
|
2581
|
-
|
|
2582
|
-
|
|
2654
|
+
ssrInput: () => {
|
|
2655
|
+
return {
|
|
2656
|
+
cms: path5.resolve(__dirname2, "./app.js")
|
|
2657
|
+
};
|
|
2658
|
+
},
|
|
2583
2659
|
/**
|
|
2584
2660
|
* Attaches CMS-specific middleware to the Root.js server.
|
|
2585
2661
|
*/
|
|
@@ -2587,13 +2663,13 @@ function cmsPlugin(options) {
|
|
|
2587
2663
|
server.use(bodyParser.json());
|
|
2588
2664
|
async function getRenderer(req) {
|
|
2589
2665
|
if (serverOptions.type === "dev") {
|
|
2590
|
-
const appFilePath =
|
|
2666
|
+
const appFilePath = path5.resolve(__dirname2, "./app.js");
|
|
2591
2667
|
const app3 = await req.viteServer.ssrLoadModule(
|
|
2592
2668
|
appFilePath
|
|
2593
2669
|
);
|
|
2594
2670
|
return app3;
|
|
2595
2671
|
}
|
|
2596
|
-
const appImportPath =
|
|
2672
|
+
const appImportPath = path5.resolve(
|
|
2597
2673
|
req.rootConfig.rootDir,
|
|
2598
2674
|
"dist/server/cms.js"
|
|
2599
2675
|
);
|
|
@@ -2665,7 +2741,7 @@ function cmsPlugin(options) {
|
|
|
2665
2741
|
}
|
|
2666
2742
|
next();
|
|
2667
2743
|
});
|
|
2668
|
-
const staticDir =
|
|
2744
|
+
const staticDir = path5.resolve(__dirname2, "ui");
|
|
2669
2745
|
server.use("/cms/static", sirv(staticDir, { dev: false }));
|
|
2670
2746
|
api(server, { getRenderer });
|
|
2671
2747
|
server.use("/cms", async (req, res) => {
|
|
@@ -2699,7 +2775,7 @@ function cmsPlugin(options) {
|
|
|
2699
2775
|
return plugin;
|
|
2700
2776
|
}
|
|
2701
2777
|
function fileExists(filepath) {
|
|
2702
|
-
return
|
|
2778
|
+
return fs4.access(filepath).then(() => true).catch(() => false);
|
|
2703
2779
|
}
|
|
2704
2780
|
export {
|
|
2705
2781
|
cmsPlugin
|
package/dist/project.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { S as Schema } from './schema-
|
|
2
|
-
import 'preact';
|
|
1
|
+
import { S as Schema, C as Collection } from './schema-UCmjggdA.js';
|
|
3
2
|
|
|
4
3
|
/**
|
|
5
4
|
* Loads various files or configurations from the project.
|
|
@@ -11,6 +10,17 @@ import 'preact';
|
|
|
11
10
|
interface SchemaModule {
|
|
12
11
|
default: Schema;
|
|
13
12
|
}
|
|
14
|
-
declare
|
|
13
|
+
declare const SCHEMA_MODULES: Record<string, SchemaModule>;
|
|
14
|
+
/**
|
|
15
|
+
* Returns a map of all `schema.ts` files defined in the project as
|
|
16
|
+
* fileId => schema. This is used by `generate-types.ts` to build the
|
|
17
|
+
* `root-cms.d.ts` file.
|
|
18
|
+
*/
|
|
19
|
+
declare function getProjectSchemas(): Promise<Record<string, Schema>>;
|
|
20
|
+
/**
|
|
21
|
+
* Returns a collection's schema definition as defined in
|
|
22
|
+
* `/collections/<id>.schema.ts`.
|
|
23
|
+
*/
|
|
24
|
+
declare function getCollectionSchema(collectionId: string): Promise<Collection | null>;
|
|
15
25
|
|
|
16
|
-
export { type SchemaModule, getProjectSchemas };
|
|
26
|
+
export { SCHEMA_MODULES, type SchemaModule, getCollectionSchema, getProjectSchemas };
|
package/dist/project.js
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
// core/project.ts
|
|
2
|
-
var
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
var SCHEMA_MODULES = import.meta.glob(
|
|
3
|
+
[
|
|
4
|
+
"/**/*.schema.ts",
|
|
5
|
+
"!/appengine/**/*.schema.ts",
|
|
6
|
+
"!/functions/**/*.schema.ts",
|
|
7
|
+
"!/gae/**/*.schema.ts"
|
|
8
|
+
],
|
|
9
|
+
{ eager: true }
|
|
10
|
+
);
|
|
11
|
+
async function getProjectSchemas() {
|
|
7
12
|
const schemas = {};
|
|
8
13
|
for (const fileId in SCHEMA_MODULES) {
|
|
9
|
-
if (IGNORED_SCHEMA_FOLDERS.some((prefix) => fileId.startsWith(prefix))) {
|
|
10
|
-
continue;
|
|
11
|
-
}
|
|
12
14
|
const schemaModule = SCHEMA_MODULES[fileId];
|
|
13
15
|
if (schemaModule.default) {
|
|
14
16
|
schemas[fileId] = schemaModule.default;
|
|
@@ -16,6 +18,64 @@ function getProjectSchemas() {
|
|
|
16
18
|
}
|
|
17
19
|
return schemas;
|
|
18
20
|
}
|
|
21
|
+
async function getCollectionSchema(collectionId) {
|
|
22
|
+
if (!testValidCollectionId(collectionId)) {
|
|
23
|
+
throw new Error(`invalid collection id: ${collectionId}`);
|
|
24
|
+
}
|
|
25
|
+
const fileId = `/collections/${collectionId}.schema.ts`;
|
|
26
|
+
const module = SCHEMA_MODULES[fileId];
|
|
27
|
+
if (!module.default) {
|
|
28
|
+
console.warn(`collection schema not exported in: ${fileId}`);
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
const collection = module.default;
|
|
32
|
+
collection.id = collectionId;
|
|
33
|
+
return convertOneOfTypes(collection);
|
|
34
|
+
}
|
|
35
|
+
function testValidCollectionId(id) {
|
|
36
|
+
return /^[A-Za-z0-9_-]+$/.test(id);
|
|
37
|
+
}
|
|
38
|
+
function convertOneOfTypes(collection) {
|
|
39
|
+
const clone = structuredClone(collection);
|
|
40
|
+
const types = clone.types || {};
|
|
41
|
+
function handleOneOfField(field) {
|
|
42
|
+
const names = [];
|
|
43
|
+
(field.types || []).forEach((sub) => {
|
|
44
|
+
if (typeof sub === "string") {
|
|
45
|
+
names.push(sub);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
if (sub.name) {
|
|
49
|
+
names.push(sub.name);
|
|
50
|
+
if (!types[sub.name]) {
|
|
51
|
+
types[sub.name] = sub;
|
|
52
|
+
if (sub.fields) {
|
|
53
|
+
walk(sub);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
field.types = names;
|
|
59
|
+
}
|
|
60
|
+
function handleField(field) {
|
|
61
|
+
if (field.type === "oneof") {
|
|
62
|
+
handleOneOfField(field);
|
|
63
|
+
} else if (field.type === "object") {
|
|
64
|
+
walk(field);
|
|
65
|
+
} else if (field.type === "array" && field.of) {
|
|
66
|
+
handleField(field.of);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function walk(schema) {
|
|
70
|
+
const fields = schema?.fields || [];
|
|
71
|
+
fields.forEach(handleField);
|
|
72
|
+
}
|
|
73
|
+
walk(clone);
|
|
74
|
+
clone.types = types;
|
|
75
|
+
return clone;
|
|
76
|
+
}
|
|
19
77
|
export {
|
|
78
|
+
SCHEMA_MODULES,
|
|
79
|
+
getCollectionSchema,
|
|
20
80
|
getProjectSchemas
|
|
21
81
|
};
|