@bobbykim/manguito-cms-cli 0.2.1 → 0.3.0
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/index.js +375 -97
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -7530,13 +7530,13 @@ var require_bcrypt = __commonJS({
|
|
|
7530
7530
|
throw Error("Illegal callback: " + typeof callback);
|
|
7531
7531
|
_async(callback);
|
|
7532
7532
|
} else
|
|
7533
|
-
return new Promise(function(
|
|
7533
|
+
return new Promise(function(resolve10, reject) {
|
|
7534
7534
|
_async(function(err, res) {
|
|
7535
7535
|
if (err) {
|
|
7536
7536
|
reject(err);
|
|
7537
7537
|
return;
|
|
7538
7538
|
}
|
|
7539
|
-
|
|
7539
|
+
resolve10(res);
|
|
7540
7540
|
});
|
|
7541
7541
|
});
|
|
7542
7542
|
};
|
|
@@ -7565,13 +7565,13 @@ var require_bcrypt = __commonJS({
|
|
|
7565
7565
|
throw Error("Illegal callback: " + typeof callback);
|
|
7566
7566
|
_async(callback);
|
|
7567
7567
|
} else
|
|
7568
|
-
return new Promise(function(
|
|
7568
|
+
return new Promise(function(resolve10, reject) {
|
|
7569
7569
|
_async(function(err, res) {
|
|
7570
7570
|
if (err) {
|
|
7571
7571
|
reject(err);
|
|
7572
7572
|
return;
|
|
7573
7573
|
}
|
|
7574
|
-
|
|
7574
|
+
resolve10(res);
|
|
7575
7575
|
});
|
|
7576
7576
|
});
|
|
7577
7577
|
};
|
|
@@ -7616,13 +7616,13 @@ var require_bcrypt = __commonJS({
|
|
|
7616
7616
|
throw Error("Illegal callback: " + typeof callback);
|
|
7617
7617
|
_async(callback);
|
|
7618
7618
|
} else
|
|
7619
|
-
return new Promise(function(
|
|
7619
|
+
return new Promise(function(resolve10, reject) {
|
|
7620
7620
|
_async(function(err, res) {
|
|
7621
7621
|
if (err) {
|
|
7622
7622
|
reject(err);
|
|
7623
7623
|
return;
|
|
7624
7624
|
}
|
|
7625
|
-
|
|
7625
|
+
resolve10(res);
|
|
7626
7626
|
});
|
|
7627
7627
|
});
|
|
7628
7628
|
};
|
|
@@ -12343,7 +12343,7 @@ var require_dist2 = __commonJS({
|
|
|
12343
12343
|
function parse4(stream, callback) {
|
|
12344
12344
|
const parser = new parser_1.Parser();
|
|
12345
12345
|
stream.on("data", (buffer) => parser.parse(buffer, callback));
|
|
12346
|
-
return new Promise((
|
|
12346
|
+
return new Promise((resolve10) => stream.on("end", () => resolve10()));
|
|
12347
12347
|
}
|
|
12348
12348
|
}
|
|
12349
12349
|
});
|
|
@@ -13112,12 +13112,12 @@ var require_client = __commonJS({
|
|
|
13112
13112
|
this._connect(callback);
|
|
13113
13113
|
return;
|
|
13114
13114
|
}
|
|
13115
|
-
return new this._Promise((
|
|
13115
|
+
return new this._Promise((resolve10, reject) => {
|
|
13116
13116
|
this._connect((error51) => {
|
|
13117
13117
|
if (error51) {
|
|
13118
13118
|
reject(error51);
|
|
13119
13119
|
} else {
|
|
13120
|
-
|
|
13120
|
+
resolve10(this);
|
|
13121
13121
|
}
|
|
13122
13122
|
});
|
|
13123
13123
|
});
|
|
@@ -13464,8 +13464,8 @@ var require_client = __commonJS({
|
|
|
13464
13464
|
} else {
|
|
13465
13465
|
query = new Query2(config3, values, callback);
|
|
13466
13466
|
if (!query.callback) {
|
|
13467
|
-
result = new this._Promise((
|
|
13468
|
-
query.callback = (err, res) => err ? reject(err) :
|
|
13467
|
+
result = new this._Promise((resolve10, reject) => {
|
|
13468
|
+
query.callback = (err, res) => err ? reject(err) : resolve10(res);
|
|
13469
13469
|
}).catch((err) => {
|
|
13470
13470
|
Error.captureStackTrace(err);
|
|
13471
13471
|
throw err;
|
|
@@ -13549,8 +13549,8 @@ var require_client = __commonJS({
|
|
|
13549
13549
|
if (cb) {
|
|
13550
13550
|
this.connection.once("end", cb);
|
|
13551
13551
|
} else {
|
|
13552
|
-
return new this._Promise((
|
|
13553
|
-
this.connection.once("end",
|
|
13552
|
+
return new this._Promise((resolve10) => {
|
|
13553
|
+
this.connection.once("end", resolve10);
|
|
13554
13554
|
});
|
|
13555
13555
|
}
|
|
13556
13556
|
}
|
|
@@ -13600,8 +13600,8 @@ var require_pg_pool = __commonJS({
|
|
|
13600
13600
|
const cb = function(err, client) {
|
|
13601
13601
|
err ? rej(err) : res(client);
|
|
13602
13602
|
};
|
|
13603
|
-
const result = new Promise2(function(
|
|
13604
|
-
res =
|
|
13603
|
+
const result = new Promise2(function(resolve10, reject) {
|
|
13604
|
+
res = resolve10;
|
|
13605
13605
|
rej = reject;
|
|
13606
13606
|
}).catch((err) => {
|
|
13607
13607
|
Error.captureStackTrace(err);
|
|
@@ -13662,7 +13662,7 @@ var require_pg_pool = __commonJS({
|
|
|
13662
13662
|
if (typeof Promise2.try === "function") {
|
|
13663
13663
|
return Promise2.try(f);
|
|
13664
13664
|
}
|
|
13665
|
-
return new Promise2((
|
|
13665
|
+
return new Promise2((resolve10) => resolve10(f()));
|
|
13666
13666
|
}
|
|
13667
13667
|
_isFull() {
|
|
13668
13668
|
return this._clients.length >= this.options.max;
|
|
@@ -14056,8 +14056,8 @@ var require_query2 = __commonJS({
|
|
|
14056
14056
|
NativeQuery.prototype._getPromise = function() {
|
|
14057
14057
|
if (this._promise) return this._promise;
|
|
14058
14058
|
this._promise = new Promise(
|
|
14059
|
-
function(
|
|
14060
|
-
this._once("end",
|
|
14059
|
+
function(resolve10, reject) {
|
|
14060
|
+
this._once("end", resolve10);
|
|
14061
14061
|
this._once("error", reject);
|
|
14062
14062
|
}.bind(this)
|
|
14063
14063
|
);
|
|
@@ -14236,12 +14236,12 @@ var require_client2 = __commonJS({
|
|
|
14236
14236
|
this._connect(callback);
|
|
14237
14237
|
return;
|
|
14238
14238
|
}
|
|
14239
|
-
return new this._Promise((
|
|
14239
|
+
return new this._Promise((resolve10, reject) => {
|
|
14240
14240
|
this._connect((error51) => {
|
|
14241
14241
|
if (error51) {
|
|
14242
14242
|
reject(error51);
|
|
14243
14243
|
} else {
|
|
14244
|
-
|
|
14244
|
+
resolve10(this);
|
|
14245
14245
|
}
|
|
14246
14246
|
});
|
|
14247
14247
|
});
|
|
@@ -14265,8 +14265,8 @@ var require_client2 = __commonJS({
|
|
|
14265
14265
|
query = new NativeQuery(config3, values, callback);
|
|
14266
14266
|
if (!query.callback) {
|
|
14267
14267
|
let resolveOut, rejectOut;
|
|
14268
|
-
result = new this._Promise((
|
|
14269
|
-
resolveOut =
|
|
14268
|
+
result = new this._Promise((resolve10, reject) => {
|
|
14269
|
+
resolveOut = resolve10;
|
|
14270
14270
|
rejectOut = reject;
|
|
14271
14271
|
}).catch((err) => {
|
|
14272
14272
|
Error.captureStackTrace(err);
|
|
@@ -14329,8 +14329,8 @@ var require_client2 = __commonJS({
|
|
|
14329
14329
|
}
|
|
14330
14330
|
let result;
|
|
14331
14331
|
if (!cb) {
|
|
14332
|
-
result = new this._Promise(function(
|
|
14333
|
-
cb = (err) => err ? reject(err) :
|
|
14332
|
+
result = new this._Promise(function(resolve10, reject) {
|
|
14333
|
+
cb = (err) => err ? reject(err) : resolve10();
|
|
14334
14334
|
});
|
|
14335
14335
|
}
|
|
14336
14336
|
this.native.end(function() {
|
|
@@ -14478,7 +14478,7 @@ import { Command } from "commander";
|
|
|
14478
14478
|
// src/commands/build.ts
|
|
14479
14479
|
init_esm_shims();
|
|
14480
14480
|
import { mkdirSync, statSync as statSync2, existsSync as existsSync3, readdirSync as readdirSync2, writeFileSync } from "fs";
|
|
14481
|
-
import { resolve as resolve3, join as
|
|
14481
|
+
import { resolve as resolve3, join as join7, dirname } from "path";
|
|
14482
14482
|
import { createRequire } from "module";
|
|
14483
14483
|
import { build as viteBuild } from "vite";
|
|
14484
14484
|
import { build as tsupBuild } from "tsup";
|
|
@@ -29155,6 +29155,10 @@ var RawBooleanFieldSchema = RawFieldBase.extend({
|
|
|
29155
29155
|
var RawDateFieldSchema = RawFieldBase.extend({
|
|
29156
29156
|
type: external_exports.literal("date")
|
|
29157
29157
|
});
|
|
29158
|
+
var RawProgrammaticFieldSchema = RawFieldBase.extend({
|
|
29159
|
+
type: external_exports.literal("programmatic"),
|
|
29160
|
+
required: external_exports.boolean().optional()
|
|
29161
|
+
});
|
|
29158
29162
|
var RawImageFieldSchema = RawFieldBase.extend({
|
|
29159
29163
|
type: external_exports.literal("image"),
|
|
29160
29164
|
max_size: maxSizeString.optional(),
|
|
@@ -29201,7 +29205,8 @@ var RawNonEnumFieldSchema = external_exports.discriminatedUnion("type", [
|
|
|
29201
29205
|
RawVideoFieldSchema,
|
|
29202
29206
|
RawFileFieldSchema,
|
|
29203
29207
|
RawParagraphFieldSchema,
|
|
29204
|
-
RawReferenceFieldSchema
|
|
29208
|
+
RawReferenceFieldSchema,
|
|
29209
|
+
RawProgrammaticFieldSchema
|
|
29205
29210
|
]);
|
|
29206
29211
|
var RawFieldSchema = external_exports.union([RawNonEnumFieldSchema, RawEnumFieldSchema]);
|
|
29207
29212
|
var RawTabSchema = external_exports.object({
|
|
@@ -29786,7 +29791,14 @@ var fieldTypeRegistry = {
|
|
|
29786
29791
|
db_column,
|
|
29787
29792
|
ui_component: { component: "typeahead-select", ref: raw2.target, rel: raw2.rel }
|
|
29788
29793
|
};
|
|
29789
|
-
}
|
|
29794
|
+
},
|
|
29795
|
+
// ── Programmatic — computed at read time, no column ─────────────────────────
|
|
29796
|
+
// Inert marker: the value is produced by a user resolver in the api layer.
|
|
29797
|
+
programmatic: () => ({
|
|
29798
|
+
validation: { required: false },
|
|
29799
|
+
db_column: null,
|
|
29800
|
+
ui_component: { component: "computed-display" }
|
|
29801
|
+
})
|
|
29790
29802
|
};
|
|
29791
29803
|
var CONTENT_SYSTEM_FIELDS = [
|
|
29792
29804
|
{ name: "id", db_type: "uuid", primary_key: true, default: "gen_random_uuid()", nullable: false },
|
|
@@ -29867,8 +29879,9 @@ function buildParsedField(rawField, order, sourceFile, ownerTableName) {
|
|
|
29867
29879
|
}]
|
|
29868
29880
|
};
|
|
29869
29881
|
}
|
|
29870
|
-
const { name, label
|
|
29882
|
+
const { name, label } = rawField;
|
|
29871
29883
|
const { validation, db_column, ui_component } = build(rawField, { ownerTableName });
|
|
29884
|
+
const required2 = validation.required;
|
|
29872
29885
|
return {
|
|
29873
29886
|
ok: true,
|
|
29874
29887
|
value: {
|
|
@@ -31220,7 +31233,7 @@ function sql(strings, ...params) {
|
|
|
31220
31233
|
return new SQL([new StringChunk(str2)]);
|
|
31221
31234
|
}
|
|
31222
31235
|
sql2.raw = raw2;
|
|
31223
|
-
function
|
|
31236
|
+
function join13(chunks, separator) {
|
|
31224
31237
|
const result = [];
|
|
31225
31238
|
for (const [i, chunk] of chunks.entries()) {
|
|
31226
31239
|
if (i > 0 && separator !== void 0) {
|
|
@@ -31230,7 +31243,7 @@ function sql(strings, ...params) {
|
|
|
31230
31243
|
}
|
|
31231
31244
|
return new SQL(result);
|
|
31232
31245
|
}
|
|
31233
|
-
sql2.join =
|
|
31246
|
+
sql2.join = join13;
|
|
31234
31247
|
function identifier(value) {
|
|
31235
31248
|
return new Name(value);
|
|
31236
31249
|
}
|
|
@@ -34912,7 +34925,7 @@ var PgSelectQueryBuilderBase = class extends TypedQueryBuilder {
|
|
|
34912
34925
|
const baseTableName = this.tableName;
|
|
34913
34926
|
const tableName = getTableLikeName(table);
|
|
34914
34927
|
for (const item of extractUsedTable(table)) this.usedTables.add(item);
|
|
34915
|
-
if (typeof tableName === "string" && this.config.joins?.some((
|
|
34928
|
+
if (typeof tableName === "string" && this.config.joins?.some((join13) => join13.alias === tableName)) {
|
|
34916
34929
|
throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
34917
34930
|
}
|
|
34918
34931
|
if (!this.isPartialSelect) {
|
|
@@ -36136,7 +36149,7 @@ var PgUpdateBase = class extends QueryPromise {
|
|
|
36136
36149
|
createJoin(joinType) {
|
|
36137
36150
|
return (table, on) => {
|
|
36138
36151
|
const tableName = getTableLikeName(table);
|
|
36139
|
-
if (typeof tableName === "string" && this.config.joins.some((
|
|
36152
|
+
if (typeof tableName === "string" && this.config.joins.some((join13) => join13.alias === tableName)) {
|
|
36140
36153
|
throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
36141
36154
|
}
|
|
36142
36155
|
if (typeof on === "function") {
|
|
@@ -36232,10 +36245,10 @@ var PgUpdateBase = class extends QueryPromise {
|
|
|
36232
36245
|
const fromFields = this.getTableLikeFields(this.config.from);
|
|
36233
36246
|
fields[tableName] = fromFields;
|
|
36234
36247
|
}
|
|
36235
|
-
for (const
|
|
36236
|
-
const tableName2 = getTableLikeName(
|
|
36237
|
-
if (typeof tableName2 === "string" && !is(
|
|
36238
|
-
const fromFields = this.getTableLikeFields(
|
|
36248
|
+
for (const join13 of this.config.joins) {
|
|
36249
|
+
const tableName2 = getTableLikeName(join13.table);
|
|
36250
|
+
if (typeof tableName2 === "string" && !is(join13.table, SQL)) {
|
|
36251
|
+
const fromFields = this.getTableLikeFields(join13.table);
|
|
36239
36252
|
fields[tableName2] = fromFields;
|
|
36240
36253
|
}
|
|
36241
36254
|
}
|
|
@@ -44162,7 +44175,8 @@ var COMPONENT_NAME = {
|
|
|
44162
44175
|
"file-upload": "MediaUpload",
|
|
44163
44176
|
select: "EnumSelect",
|
|
44164
44177
|
"typeahead-select": "ReferenceSelect",
|
|
44165
|
-
"paragraph-embed": "ParagraphEmbed"
|
|
44178
|
+
"paragraph-embed": "ParagraphEmbed",
|
|
44179
|
+
"computed-display": "ComputedDisplay"
|
|
44166
44180
|
};
|
|
44167
44181
|
var COMPONENT_IMPORT = {
|
|
44168
44182
|
TextInput: `${ADMIN_PKG}/src/components/fields/TextInput.vue`,
|
|
@@ -44173,7 +44187,8 @@ var COMPONENT_IMPORT = {
|
|
|
44173
44187
|
MediaUpload: `${ADMIN_PKG}/src/components/fields/MediaUpload.vue`,
|
|
44174
44188
|
EnumSelect: `${ADMIN_PKG}/src/components/fields/EnumSelect.vue`,
|
|
44175
44189
|
ReferenceSelect: `${ADMIN_PKG}/src/components/fields/ReferenceSelect.vue`,
|
|
44176
|
-
ParagraphEmbed: `${ADMIN_PKG}/src/components/fields/ParagraphEmbed.vue
|
|
44190
|
+
ParagraphEmbed: `${ADMIN_PKG}/src/components/fields/ParagraphEmbed.vue`,
|
|
44191
|
+
ComputedDisplay: `${ADMIN_PKG}/src/components/fields/ComputedDisplay.vue`
|
|
44177
44192
|
};
|
|
44178
44193
|
function esc2(s) {
|
|
44179
44194
|
return s.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
@@ -44220,6 +44235,9 @@ function renderField(field, indent) {
|
|
|
44220
44235
|
const compName = COMPONENT_NAME[field.ui_component.component];
|
|
44221
44236
|
const fieldObj = buildFieldObject(field);
|
|
44222
44237
|
const attr = indent + " ";
|
|
44238
|
+
if (field.ui_component.component === "computed-display") {
|
|
44239
|
+
return [`${indent}<${compName}`, `${attr}:field="${fieldObj}"`, `${indent}/>`].join("\n");
|
|
44240
|
+
}
|
|
44223
44241
|
const lines = [`${indent}<${compName}`];
|
|
44224
44242
|
lines.push(`${attr}:field="${fieldObj}"`);
|
|
44225
44243
|
if (field.ui_component.component === "paragraph-embed") {
|
|
@@ -44327,6 +44345,7 @@ async function generateServerEntries(options, targetDir) {
|
|
|
44327
44345
|
function appSetup() {
|
|
44328
44346
|
return `import config from '../../manguito.config.js'
|
|
44329
44347
|
import { schemaRegistry } from './schema-registry.js'
|
|
44348
|
+
import { programmaticResolvers } from './programmatic-registry.js'
|
|
44330
44349
|
import { createCmsApp } from '@bobbykim/manguito-cms-api'
|
|
44331
44350
|
import { createPostgresAdapter } from '@bobbykim/manguito-cms-db'
|
|
44332
44351
|
|
|
@@ -44339,6 +44358,7 @@ const { app } = createCmsApp({
|
|
|
44339
44358
|
db: dbAdapter.getDb(),
|
|
44340
44359
|
storage: config.storage,
|
|
44341
44360
|
prefix: config.api.prefix,
|
|
44361
|
+
resolvers: programmaticResolvers,
|
|
44342
44362
|
...(config.api.media ? { media: config.api.media } : {}),
|
|
44343
44363
|
...(config.api.rateLimit ? { rateLimit: config.api.rateLimit } : {}),
|
|
44344
44364
|
...(config.server.cors ? { cors: config.server.cors } : {}),
|
|
@@ -44499,6 +44519,34 @@ export default handle(app)
|
|
|
44499
44519
|
`;
|
|
44500
44520
|
}
|
|
44501
44521
|
|
|
44522
|
+
// src/codegen/programmatic-registry.ts
|
|
44523
|
+
init_esm_shims();
|
|
44524
|
+
import { writeFile as writeFile5 } from "fs/promises";
|
|
44525
|
+
import { join as join6, relative } from "path";
|
|
44526
|
+
function importSpecifier(targetDir, file2) {
|
|
44527
|
+
let rel = relative(targetDir, file2).replace(/\\/g, "/");
|
|
44528
|
+
if (!rel.startsWith(".")) rel = `./${rel}`;
|
|
44529
|
+
return rel.replace(/\.ts$/, ".js");
|
|
44530
|
+
}
|
|
44531
|
+
async function generateProgrammaticRegistry(files, targetDir) {
|
|
44532
|
+
const sorted = [...files].sort();
|
|
44533
|
+
const imports = sorted.map((file2, i) => `import def${i} from '${importSpecifier(targetDir, file2)}'`).join("\n");
|
|
44534
|
+
const defs = sorted.map((_f, i) => `def${i}`);
|
|
44535
|
+
const entries = defs.map((d2) => ` [\`\${${d2}.schema}::\${${d2}.field}\`, ${d2}] as const`).join(",\n");
|
|
44536
|
+
const typeImport = "import type { ProgrammaticFieldDefinition } from '@bobbykim/manguito-cms-core'";
|
|
44537
|
+
const body = sorted.length === 0 ? `${typeImport}
|
|
44538
|
+
|
|
44539
|
+
export const programmaticResolvers = new Map<string, ProgrammaticFieldDefinition>()
|
|
44540
|
+
` : `${typeImport}
|
|
44541
|
+
${imports}
|
|
44542
|
+
|
|
44543
|
+
export const programmaticResolvers = new Map<string, ProgrammaticFieldDefinition>([
|
|
44544
|
+
${entries},
|
|
44545
|
+
])
|
|
44546
|
+
`;
|
|
44547
|
+
await writeFile5(join6(targetDir, "programmatic-registry.ts"), body, "utf8");
|
|
44548
|
+
}
|
|
44549
|
+
|
|
44502
44550
|
// src/utils/config.ts
|
|
44503
44551
|
init_esm_shims();
|
|
44504
44552
|
import { existsSync } from "fs";
|
|
@@ -44676,10 +44724,13 @@ async function runBuild(options, deps) {
|
|
|
44676
44724
|
);
|
|
44677
44725
|
const generatedDir = resolve3(cwd, "dist/generated");
|
|
44678
44726
|
mkdirSync(generatedDir, { recursive: true });
|
|
44679
|
-
writeFileSync(
|
|
44727
|
+
writeFileSync(join7(generatedDir, "schema.ts"), generateSchemaFile(registry2), "utf8");
|
|
44680
44728
|
await generateSchemaRegistry(registry2, generatedDir);
|
|
44681
44729
|
await generateRoutes2(registry2, generatedDir);
|
|
44682
|
-
await generateForms(registry2,
|
|
44730
|
+
await generateForms(registry2, join7(generatedDir, "forms"));
|
|
44731
|
+
const programmaticDir = resolve3(cwd, config3.programmatic.dir);
|
|
44732
|
+
const resolverFiles = existsSync3(programmaticDir) ? walkFiles(programmaticDir).filter((f) => /\.(ts|mjs|js)$/.test(f)) : [];
|
|
44733
|
+
await generateProgrammaticRegistry(resolverFiles, generatedDir);
|
|
44683
44734
|
await generateServerEntries(
|
|
44684
44735
|
{ adminPrefix: config3.admin.prefix, apiPrefix: config3.api.prefix },
|
|
44685
44736
|
generatedDir
|
|
@@ -44743,14 +44794,14 @@ async function needsRebuild(cwd) {
|
|
|
44743
44794
|
);
|
|
44744
44795
|
}
|
|
44745
44796
|
function resolveAdminRoot(cwd) {
|
|
44746
|
-
const cwdRequire = createRequire(
|
|
44797
|
+
const cwdRequire = createRequire(join7(cwd, "package.json"));
|
|
44747
44798
|
const adminPkgJson = cwdRequire.resolve("@bobbykim/manguito-cms-admin/package.json");
|
|
44748
44799
|
return dirname(adminPkgJson);
|
|
44749
44800
|
}
|
|
44750
44801
|
function walkFiles(dir) {
|
|
44751
44802
|
const files = [];
|
|
44752
44803
|
for (const entry of readdirSync2(dir, { withFileTypes: true })) {
|
|
44753
|
-
const full =
|
|
44804
|
+
const full = join7(dir, entry.name);
|
|
44754
44805
|
if (entry.isDirectory()) {
|
|
44755
44806
|
files.push(...walkFiles(full));
|
|
44756
44807
|
} else {
|
|
@@ -44763,10 +44814,11 @@ function walkFiles(dir) {
|
|
|
44763
44814
|
// src/commands/dev.ts
|
|
44764
44815
|
init_esm_shims();
|
|
44765
44816
|
import { createServer as createHttpServer } from "http";
|
|
44766
|
-
import {
|
|
44767
|
-
import {
|
|
44817
|
+
import { existsSync as existsSync5 } from "fs";
|
|
44818
|
+
import { resolve as resolve6, join as join11, dirname as dirname2, extname as extname3 } from "path";
|
|
44819
|
+
import { mkdir as mkdir2, writeFile as writeFile8, watch, readFile } from "fs/promises";
|
|
44768
44820
|
import { createRequire as createRequire2 } from "module";
|
|
44769
|
-
import { createServer as createViteServer } from "vite";
|
|
44821
|
+
import { createServer as createViteServer, searchForWorkspaceRoot } from "vite";
|
|
44770
44822
|
|
|
44771
44823
|
// ../api/dist/index.mjs
|
|
44772
44824
|
init_esm_shims();
|
|
@@ -48074,6 +48126,138 @@ function buildRolesRegistry(roles2) {
|
|
|
48074
48126
|
validateRoles(roles2);
|
|
48075
48127
|
return Object.fromEntries(roles2.map((r) => [r.name, r]));
|
|
48076
48128
|
}
|
|
48129
|
+
var DEFAULT_TIMEOUT_MS = 5e3;
|
|
48130
|
+
var LIST_CONCURRENCY = 10;
|
|
48131
|
+
function resolverKey(schema, field) {
|
|
48132
|
+
return `${schema}::${field}`;
|
|
48133
|
+
}
|
|
48134
|
+
function validateResolverBindings(registry2, resolvers) {
|
|
48135
|
+
const declared = /* @__PURE__ */ new Set();
|
|
48136
|
+
const schemas = [
|
|
48137
|
+
...Object.values(registry2.content_types),
|
|
48138
|
+
...Object.values(registry2.taxonomy_types)
|
|
48139
|
+
];
|
|
48140
|
+
for (const schema of schemas) {
|
|
48141
|
+
for (const field of schema.fields) {
|
|
48142
|
+
if (field.field_type === "programmatic") {
|
|
48143
|
+
declared.add(resolverKey(schema.name, field.name));
|
|
48144
|
+
}
|
|
48145
|
+
}
|
|
48146
|
+
}
|
|
48147
|
+
const missing = [];
|
|
48148
|
+
for (const key of declared) if (!resolvers.has(key)) missing.push(key);
|
|
48149
|
+
const orphans = [];
|
|
48150
|
+
for (const key of resolvers.keys()) if (!declared.has(key)) orphans.push(key);
|
|
48151
|
+
if (missing.length === 0 && orphans.length === 0) return;
|
|
48152
|
+
const lines = ["\u2717 Programmatic field resolver bindings are invalid."];
|
|
48153
|
+
if (missing.length > 0) {
|
|
48154
|
+
lines.push("", ' Declared as `type: "programmatic"` but no resolver found:');
|
|
48155
|
+
for (const k of missing) lines.push(` - ${k} (add a programmaticField in src/programmatic)`);
|
|
48156
|
+
}
|
|
48157
|
+
if (orphans.length > 0) {
|
|
48158
|
+
lines.push("", " Resolver has no matching programmatic field in the schema:");
|
|
48159
|
+
for (const k of orphans) lines.push(` - ${k}`);
|
|
48160
|
+
}
|
|
48161
|
+
lines.push("", "Exiting.");
|
|
48162
|
+
throw new Error(lines.join("\n"));
|
|
48163
|
+
}
|
|
48164
|
+
function buildContext(row) {
|
|
48165
|
+
return {
|
|
48166
|
+
get: (name) => row[name],
|
|
48167
|
+
record: row
|
|
48168
|
+
};
|
|
48169
|
+
}
|
|
48170
|
+
async function withTimeout(p2, ms2) {
|
|
48171
|
+
let timer;
|
|
48172
|
+
const timeout = new Promise((_, reject) => {
|
|
48173
|
+
timer = setTimeout(() => reject(new Error("resolver timeout")), ms2);
|
|
48174
|
+
});
|
|
48175
|
+
try {
|
|
48176
|
+
return await Promise.race([p2, timeout]);
|
|
48177
|
+
} finally {
|
|
48178
|
+
clearTimeout(timer);
|
|
48179
|
+
}
|
|
48180
|
+
}
|
|
48181
|
+
async function runOne(def, row, onError) {
|
|
48182
|
+
const fallback = def.fallback ?? null;
|
|
48183
|
+
try {
|
|
48184
|
+
const result = await withTimeout(
|
|
48185
|
+
Promise.resolve(def.resolve(buildContext(row))),
|
|
48186
|
+
def.timeout ?? DEFAULT_TIMEOUT_MS
|
|
48187
|
+
);
|
|
48188
|
+
return { value: result === void 0 ? null : result, failed: false };
|
|
48189
|
+
} catch (err) {
|
|
48190
|
+
onError(
|
|
48191
|
+
`\u26A0 programmatic field ${resolverKey(def.schema, def.field)} failed: ${err instanceof Error ? err.message : String(err)}`
|
|
48192
|
+
);
|
|
48193
|
+
return { value: fallback, failed: true };
|
|
48194
|
+
}
|
|
48195
|
+
}
|
|
48196
|
+
async function runPool(items, limit, fn) {
|
|
48197
|
+
let i = 0;
|
|
48198
|
+
async function worker() {
|
|
48199
|
+
while (i < items.length) {
|
|
48200
|
+
const idx = i++;
|
|
48201
|
+
await fn(items[idx]);
|
|
48202
|
+
}
|
|
48203
|
+
}
|
|
48204
|
+
const workers = Array.from({ length: Math.min(limit, items.length) }, worker);
|
|
48205
|
+
await Promise.all(workers);
|
|
48206
|
+
}
|
|
48207
|
+
function createProgrammaticResolver(resolvers, options) {
|
|
48208
|
+
const onError = options?.onError ?? ((message) => {
|
|
48209
|
+
process.stderr.write(message + "\n");
|
|
48210
|
+
});
|
|
48211
|
+
const bySchema = /* @__PURE__ */ new Map();
|
|
48212
|
+
for (const def of resolvers.values()) {
|
|
48213
|
+
const arr = bySchema.get(def.schema) ?? [];
|
|
48214
|
+
arr.push(def);
|
|
48215
|
+
bySchema.set(def.schema, arr);
|
|
48216
|
+
}
|
|
48217
|
+
const cache = /* @__PURE__ */ new Map();
|
|
48218
|
+
async function resolveField(def, row) {
|
|
48219
|
+
const itemId = row["id"] !== void 0 ? String(row["id"]) : "";
|
|
48220
|
+
if (def.cache && itemId) {
|
|
48221
|
+
const key = `${resolverKey(def.schema, def.field)}::${itemId}`;
|
|
48222
|
+
const now = Date.now();
|
|
48223
|
+
const hit = cache.get(key);
|
|
48224
|
+
if (hit && hit.expires > now) return hit.value;
|
|
48225
|
+
const { value: value2, failed } = await runOne(def, row, onError);
|
|
48226
|
+
if (!failed) cache.set(key, { value: value2, expires: now + def.cache.ttl * 1e3 });
|
|
48227
|
+
return value2;
|
|
48228
|
+
}
|
|
48229
|
+
const { value } = await runOne(def, row, onError);
|
|
48230
|
+
return value;
|
|
48231
|
+
}
|
|
48232
|
+
async function resolveItem(schema, row) {
|
|
48233
|
+
const defs = bySchema.get(schema);
|
|
48234
|
+
if (!defs || defs.length === 0) return { ...row };
|
|
48235
|
+
const out = { ...row };
|
|
48236
|
+
await Promise.all(
|
|
48237
|
+
defs.map(async (def) => {
|
|
48238
|
+
out[def.field] = await resolveField(def, row);
|
|
48239
|
+
})
|
|
48240
|
+
);
|
|
48241
|
+
return out;
|
|
48242
|
+
}
|
|
48243
|
+
async function resolveList(schema, rows) {
|
|
48244
|
+
const defs = (bySchema.get(schema) ?? []).filter((d2) => d2.on_list === true);
|
|
48245
|
+
if (defs.length === 0) return rows.map((r) => ({ ...r }));
|
|
48246
|
+
const out = rows.map((r) => ({ ...r }));
|
|
48247
|
+
const tasks = [];
|
|
48248
|
+
for (let i = 0; i < rows.length; i++) {
|
|
48249
|
+
for (const def of defs) tasks.push({ rowIndex: i, def });
|
|
48250
|
+
}
|
|
48251
|
+
await runPool(tasks, LIST_CONCURRENCY, async ({ rowIndex, def }) => {
|
|
48252
|
+
out[rowIndex][def.field] = await resolveField(def, rows[rowIndex]);
|
|
48253
|
+
});
|
|
48254
|
+
return out;
|
|
48255
|
+
}
|
|
48256
|
+
function hasSchema(schema) {
|
|
48257
|
+
return bySchema.has(schema);
|
|
48258
|
+
}
|
|
48259
|
+
return { resolveItem, resolveList, hasSchema };
|
|
48260
|
+
}
|
|
48077
48261
|
var SORTABLE_FIELDS = /* @__PURE__ */ new Set(["title", "created_at", "updated_at"]);
|
|
48078
48262
|
var RELATION_FIELD_TYPES = /* @__PURE__ */ new Set([
|
|
48079
48263
|
"paragraph",
|
|
@@ -48122,7 +48306,7 @@ function parseFilters(url2, validFields) {
|
|
|
48122
48306
|
function isPublished(item) {
|
|
48123
48307
|
return item["published"] === true;
|
|
48124
48308
|
}
|
|
48125
|
-
function registerPublicContentRoutes(app, registry2, repos, listRateLimit) {
|
|
48309
|
+
function registerPublicContentRoutes(app, registry2, repos, listRateLimit, resolver) {
|
|
48126
48310
|
function registerListRoute(path4, handler) {
|
|
48127
48311
|
if (listRateLimit) {
|
|
48128
48312
|
app.get(path4, listRateLimit, handler);
|
|
@@ -48149,13 +48333,13 @@ function registerPublicContentRoutes(app, registry2, repos, listRateLimit) {
|
|
|
48149
48333
|
const basePath = contentType.default_base_path;
|
|
48150
48334
|
const repo = repos[typeName];
|
|
48151
48335
|
if (!repo) continue;
|
|
48152
|
-
const schemaFieldNames = /* @__PURE__ */ new Set([
|
|
48153
|
-
...contentType.fields.map((f) => f.name),
|
|
48154
|
-
...contentType.system_fields.map((f) => f.name)
|
|
48155
|
-
]);
|
|
48156
48336
|
const relationFieldNames = new Set(
|
|
48157
48337
|
contentType.fields.filter((f) => RELATION_FIELD_TYPES.has(f.field_type)).map((f) => f.name)
|
|
48158
48338
|
);
|
|
48339
|
+
const filterableFieldNames = /* @__PURE__ */ new Set([
|
|
48340
|
+
...contentType.fields.filter((f) => f.field_type !== "programmatic").map((f) => f.name),
|
|
48341
|
+
...contentType.system_fields.map((f) => f.name)
|
|
48342
|
+
]);
|
|
48159
48343
|
if (contentType.only_one) {
|
|
48160
48344
|
app.get(`/api/${basePath}`, async (c) => {
|
|
48161
48345
|
const result = await repo.findMany({ published_only: true, page: 1, per_page: 1 });
|
|
@@ -48165,7 +48349,9 @@ function registerPublicContentRoutes(app, registry2, repos, listRateLimit) {
|
|
|
48165
48349
|
404
|
|
48166
48350
|
);
|
|
48167
48351
|
}
|
|
48168
|
-
|
|
48352
|
+
let data = result.data[0];
|
|
48353
|
+
if (resolver?.hasSchema(typeName)) data = await resolver.resolveItem(typeName, data);
|
|
48354
|
+
return c.json({ ok: true, data });
|
|
48169
48355
|
});
|
|
48170
48356
|
} else {
|
|
48171
48357
|
registerListRoute(`/api/${basePath}`, async (c) => {
|
|
@@ -48208,7 +48394,7 @@ function registerPublicContentRoutes(app, registry2, repos, listRateLimit) {
|
|
|
48208
48394
|
400
|
|
48209
48395
|
);
|
|
48210
48396
|
}
|
|
48211
|
-
const filtersResult = parseFilters(c.req.url,
|
|
48397
|
+
const filtersResult = parseFilters(c.req.url, filterableFieldNames);
|
|
48212
48398
|
if (!filtersResult.ok) {
|
|
48213
48399
|
return c.json(
|
|
48214
48400
|
{
|
|
@@ -48245,6 +48431,10 @@ function registerPublicContentRoutes(app, registry2, repos, listRateLimit) {
|
|
|
48245
48431
|
filters: filtersResult.filters,
|
|
48246
48432
|
include
|
|
48247
48433
|
});
|
|
48434
|
+
if (resolver?.hasSchema(typeName)) {
|
|
48435
|
+
const resolved = await resolver.resolveList(typeName, result.data);
|
|
48436
|
+
return c.json({ ...result, data: resolved });
|
|
48437
|
+
}
|
|
48248
48438
|
return c.json(result);
|
|
48249
48439
|
});
|
|
48250
48440
|
app.get(`/api/${basePath}/:slug`, async (c) => {
|
|
@@ -48274,7 +48464,9 @@ function registerPublicContentRoutes(app, registry2, repos, listRateLimit) {
|
|
|
48274
48464
|
404
|
|
48275
48465
|
);
|
|
48276
48466
|
}
|
|
48277
|
-
|
|
48467
|
+
let data = item;
|
|
48468
|
+
if (resolver?.hasSchema(typeName)) data = await resolver.resolveItem(typeName, data);
|
|
48469
|
+
return c.json({ ok: true, data });
|
|
48278
48470
|
});
|
|
48279
48471
|
}
|
|
48280
48472
|
}
|
|
@@ -48300,6 +48492,10 @@ function registerPublicContentRoutes(app, registry2, repos, listRateLimit) {
|
|
|
48300
48492
|
page: pagination.page,
|
|
48301
48493
|
per_page: pagination.per_page
|
|
48302
48494
|
});
|
|
48495
|
+
if (resolver?.hasSchema(typeName)) {
|
|
48496
|
+
const resolved = await resolver.resolveList(typeName, result.data);
|
|
48497
|
+
return c.json({ ...result, data: resolved });
|
|
48498
|
+
}
|
|
48303
48499
|
return c.json(result);
|
|
48304
48500
|
});
|
|
48305
48501
|
app.get(`/api/taxonomy/${typeName}/:id`, async (c) => {
|
|
@@ -48314,7 +48510,9 @@ function registerPublicContentRoutes(app, registry2, repos, listRateLimit) {
|
|
|
48314
48510
|
404
|
|
48315
48511
|
);
|
|
48316
48512
|
}
|
|
48317
|
-
|
|
48513
|
+
let data = item;
|
|
48514
|
+
if (resolver?.hasSchema(typeName)) data = await resolver.resolveItem(typeName, data);
|
|
48515
|
+
return c.json({ ok: true, data });
|
|
48318
48516
|
});
|
|
48319
48517
|
}
|
|
48320
48518
|
}
|
|
@@ -50238,7 +50436,7 @@ function registerUserRoutes(app, db, requirePermission, requireHierarchy) {
|
|
|
50238
50436
|
}
|
|
50239
50437
|
var API_VERSION = (() => {
|
|
50240
50438
|
try {
|
|
50241
|
-
return "0.
|
|
50439
|
+
return "0.2.0";
|
|
50242
50440
|
} catch {
|
|
50243
50441
|
return "0.0.0";
|
|
50244
50442
|
}
|
|
@@ -50641,6 +50839,9 @@ function createCmsApp(options) {
|
|
|
50641
50839
|
const cmsName = options.name ?? "Manguito CMS";
|
|
50642
50840
|
const maxFileSize = media?.max_file_size;
|
|
50643
50841
|
const rolesRegistry = buildRolesRegistry(registry2.roles.roles);
|
|
50842
|
+
const resolverMap = options.resolvers ?? /* @__PURE__ */ new Map();
|
|
50843
|
+
validateResolverBindings(registry2, resolverMap);
|
|
50844
|
+
const programmaticResolver = createProgrammaticResolver(resolverMap);
|
|
50644
50845
|
const app = new Hono2();
|
|
50645
50846
|
const uploadOrigins = storage.getUploadOrigins?.() ?? [];
|
|
50646
50847
|
app.use("*", createSecurityHeadersMiddleware({ connectSrc: uploadOrigins }));
|
|
@@ -50725,7 +50926,7 @@ function createCmsApp(options) {
|
|
|
50725
50926
|
paths: {}
|
|
50726
50927
|
})
|
|
50727
50928
|
);
|
|
50728
|
-
registerPublicContentRoutes(app, registry2, publicRepos, listRateLimit);
|
|
50929
|
+
registerPublicContentRoutes(app, registry2, publicRepos, listRateLimit, programmaticResolver);
|
|
50729
50930
|
registerPublicMediaRoutes(app, mediaRepo, listRateLimit);
|
|
50730
50931
|
registerConfigRoute(
|
|
50731
50932
|
app,
|
|
@@ -50750,12 +50951,12 @@ function createCmsApp(options) {
|
|
|
50750
50951
|
|
|
50751
50952
|
// src/codegen/drizzle-config.ts
|
|
50752
50953
|
init_esm_shims();
|
|
50753
|
-
import { writeFile as
|
|
50754
|
-
import { join as
|
|
50954
|
+
import { writeFile as writeFile6 } from "fs/promises";
|
|
50955
|
+
import { join as join8, relative as relative2, resolve as resolve4 } from "path";
|
|
50755
50956
|
async function generateDrizzleConfig(config3, targetDir) {
|
|
50756
50957
|
const migrationsFolder = config3.migrations?.folder ?? "./migrations";
|
|
50757
50958
|
const migrationsTable = config3.migrations?.table ?? "__manguito_migrations";
|
|
50758
|
-
const outPath =
|
|
50959
|
+
const outPath = relative2(resolve4(targetDir), resolve4(migrationsFolder)).replace(/\\/g, "/");
|
|
50759
50960
|
const content = [
|
|
50760
50961
|
`import { defineConfig } from 'drizzle-kit'`,
|
|
50761
50962
|
``,
|
|
@@ -50773,13 +50974,13 @@ async function generateDrizzleConfig(config3, targetDir) {
|
|
|
50773
50974
|
` tablesFilter: ['!${migrationsTable}'],`,
|
|
50774
50975
|
`})`
|
|
50775
50976
|
].join("\n");
|
|
50776
|
-
await
|
|
50977
|
+
await writeFile6(join8(targetDir, "drizzle.config.ts"), content, "utf8");
|
|
50777
50978
|
}
|
|
50778
50979
|
|
|
50779
50980
|
// src/codegen/nav.ts
|
|
50780
50981
|
init_esm_shims();
|
|
50781
|
-
import { writeFile as
|
|
50782
|
-
import { join as
|
|
50982
|
+
import { writeFile as writeFile7 } from "fs/promises";
|
|
50983
|
+
import { join as join9 } from "path";
|
|
50783
50984
|
function schemaBasePath(name) {
|
|
50784
50985
|
const segment = name.includes("--") ? name.slice(name.indexOf("--") + 2) : name;
|
|
50785
50986
|
return segment.replace(/_/g, "-");
|
|
@@ -50797,7 +50998,7 @@ async function generateNav(registry2, targetDir) {
|
|
|
50797
50998
|
})).sort((a2, b2) => a2.label.localeCompare(b2.label));
|
|
50798
50999
|
const content = `export const nav = ${JSON.stringify({ contentTypes, taxonomyTypes }, null, 2)}
|
|
50799
51000
|
`;
|
|
50800
|
-
await
|
|
51001
|
+
await writeFile7(join9(targetDir, "nav.ts"), content, "utf8");
|
|
50801
51002
|
}
|
|
50802
51003
|
|
|
50803
51004
|
// src/utils/db.ts
|
|
@@ -50828,6 +51029,49 @@ function createPromptAdapter() {
|
|
|
50828
51029
|
};
|
|
50829
51030
|
}
|
|
50830
51031
|
|
|
51032
|
+
// src/utils/programmatic-loader.ts
|
|
51033
|
+
init_esm_shims();
|
|
51034
|
+
import { existsSync as existsSync4 } from "fs";
|
|
51035
|
+
import { readdir } from "fs/promises";
|
|
51036
|
+
import { resolve as resolve5, join as join10, extname as extname2 } from "path";
|
|
51037
|
+
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
51038
|
+
var RESOLVER_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".mjs", ".js"]);
|
|
51039
|
+
function isProgrammaticFieldDefinition(v2) {
|
|
51040
|
+
return v2 !== null && typeof v2 === "object" && v2.__manguito_programmatic === true && typeof v2.schema === "string" && typeof v2.field === "string" && typeof v2.resolve === "function";
|
|
51041
|
+
}
|
|
51042
|
+
async function walkTsFiles(dir) {
|
|
51043
|
+
const out = [];
|
|
51044
|
+
for (const entry of await readdir(dir, { withFileTypes: true })) {
|
|
51045
|
+
const full = join10(dir, entry.name);
|
|
51046
|
+
if (entry.isDirectory()) {
|
|
51047
|
+
out.push(...await walkTsFiles(full));
|
|
51048
|
+
} else if (RESOLVER_EXTENSIONS.has(extname2(entry.name))) {
|
|
51049
|
+
out.push(full);
|
|
51050
|
+
}
|
|
51051
|
+
}
|
|
51052
|
+
return out;
|
|
51053
|
+
}
|
|
51054
|
+
async function loadProgrammaticResolvers(cwd, dir) {
|
|
51055
|
+
const abs = resolve5(cwd, dir);
|
|
51056
|
+
const map2 = /* @__PURE__ */ new Map();
|
|
51057
|
+
if (!existsSync4(abs)) return map2;
|
|
51058
|
+
for (const file2 of (await walkTsFiles(abs)).sort()) {
|
|
51059
|
+
const mod = await import(pathToFileURL2(file2).href);
|
|
51060
|
+
const def = mod.default;
|
|
51061
|
+
if (!isProgrammaticFieldDefinition(def)) {
|
|
51062
|
+
throw new Error(
|
|
51063
|
+
`\u2717 ${file2} does not default-export a programmaticField(). Each resolver file must \`export default programmaticField({ schema, field }, resolver)\`.`
|
|
51064
|
+
);
|
|
51065
|
+
}
|
|
51066
|
+
const key = resolverKey(def.schema, def.field);
|
|
51067
|
+
if (map2.has(key)) {
|
|
51068
|
+
throw new Error(`\u2717 Duplicate programmatic resolver for ${key} (found again in ${file2}).`);
|
|
51069
|
+
}
|
|
51070
|
+
map2.set(key, def);
|
|
51071
|
+
}
|
|
51072
|
+
return map2;
|
|
51073
|
+
}
|
|
51074
|
+
|
|
50831
51075
|
// src/commands/dev.ts
|
|
50832
51076
|
var UPLOAD_MIME_MAP = {
|
|
50833
51077
|
jpg: "image/jpeg",
|
|
@@ -50855,13 +51099,13 @@ async function runDev(options, deps) {
|
|
|
50855
51099
|
printSuccess("Config loaded");
|
|
50856
51100
|
const db = await connectDb(config3);
|
|
50857
51101
|
printSuccess("Database connected");
|
|
50858
|
-
const manguitoDir =
|
|
51102
|
+
const manguitoDir = resolve6(cwd, ".manguito");
|
|
50859
51103
|
await mkdir2(manguitoDir, { recursive: true });
|
|
50860
|
-
const drizzleConfigPath =
|
|
51104
|
+
const drizzleConfigPath = resolve6(manguitoDir, "drizzle.config.ts");
|
|
50861
51105
|
const needsSeed = !await db.tableExists("users");
|
|
50862
51106
|
const bootstrapRegistry = await parseAllSchemas(cwd, config3);
|
|
50863
51107
|
await generateDrizzleConfig(config3, manguitoDir);
|
|
50864
|
-
await
|
|
51108
|
+
await writeFile8(join11(manguitoDir, "schema.ts"), generateSchemaFile(bootstrapRegistry), "utf8");
|
|
50865
51109
|
await runDevMigration(drizzleConfigPath);
|
|
50866
51110
|
printSuccess(needsSeed ? "Schema tables created" : "Schema tables up to date");
|
|
50867
51111
|
if (needsSeed) {
|
|
@@ -50907,13 +51151,15 @@ async function runDev(options, deps) {
|
|
|
50907
51151
|
);
|
|
50908
51152
|
await generateSchemaRegistry(registry2, manguitoDir);
|
|
50909
51153
|
await generateRoutes2(registry2, manguitoDir);
|
|
50910
|
-
await generateForms(registry2,
|
|
51154
|
+
await generateForms(registry2, join11(manguitoDir, "forms"));
|
|
50911
51155
|
await generateNav(registry2, manguitoDir);
|
|
51156
|
+
const resolverMap = await loadProgrammaticResolvers(cwd, config3.programmatic.dir);
|
|
50912
51157
|
const adapter = createCmsApp({
|
|
50913
51158
|
name: config3.name,
|
|
50914
51159
|
registry: registry2,
|
|
50915
51160
|
db: db.getDb(),
|
|
50916
51161
|
storage: config3.storage,
|
|
51162
|
+
resolvers: resolverMap,
|
|
50917
51163
|
...config3.api.prefix ? { prefix: config3.api.prefix } : {},
|
|
50918
51164
|
...config3.api.media?.max_file_size ? { media: { max_file_size: config3.api.media.max_file_size } } : {},
|
|
50919
51165
|
...config3.api.rateLimit ? { rateLimit: config3.api.rateLimit } : {},
|
|
@@ -50922,7 +51168,15 @@ async function runDev(options, deps) {
|
|
|
50922
51168
|
let honoFetch = (req) => adapter.app.fetch(req);
|
|
50923
51169
|
const vite = await createViteServer({
|
|
50924
51170
|
root: resolveAdminRoot2(cwd),
|
|
50925
|
-
server: {
|
|
51171
|
+
server: {
|
|
51172
|
+
middlewareMode: true,
|
|
51173
|
+
// The admin package (Vite root) lives deep in node_modules/.pnpm, so Vite's
|
|
51174
|
+
// default file-serving allow list does not cover sibling deps like the
|
|
51175
|
+
// @fontsource font files. Allow the project root (covers cwd/node_modules
|
|
51176
|
+
// in installed projects) and the workspace root (covers hoisted deps +
|
|
51177
|
+
// packages/admin in the monorepo).
|
|
51178
|
+
fs: { allow: [searchForWorkspaceRoot(cwd), cwd] }
|
|
51179
|
+
},
|
|
50926
51180
|
appType: "spa",
|
|
50927
51181
|
logLevel: "warn"
|
|
50928
51182
|
});
|
|
@@ -50937,8 +51191,8 @@ async function runDev(options, deps) {
|
|
|
50937
51191
|
}
|
|
50938
51192
|
if (url2.startsWith("/uploads/")) {
|
|
50939
51193
|
const relativePath = (url2.slice("/uploads/".length).split("?")[0] ?? "").replace(/\.\./g, "");
|
|
50940
|
-
const uploadsDir =
|
|
50941
|
-
const filePath =
|
|
51194
|
+
const uploadsDir = resolve6(cwd, "uploads");
|
|
51195
|
+
const filePath = resolve6(uploadsDir, relativePath);
|
|
50942
51196
|
if (!filePath.startsWith(uploadsDir + "/") && filePath !== uploadsDir) {
|
|
50943
51197
|
res.statusCode = 403;
|
|
50944
51198
|
res.end("Forbidden");
|
|
@@ -50946,7 +51200,7 @@ async function runDev(options, deps) {
|
|
|
50946
51200
|
}
|
|
50947
51201
|
try {
|
|
50948
51202
|
const data = await readFile(filePath);
|
|
50949
|
-
const ext =
|
|
51203
|
+
const ext = extname3(filePath).slice(1).toLowerCase();
|
|
50950
51204
|
const mime = UPLOAD_MIME_MAP[ext] ?? "application/octet-stream";
|
|
50951
51205
|
res.setHeader("Content-Type", mime);
|
|
50952
51206
|
res.setHeader("X-Content-Type-Options", "nosniff");
|
|
@@ -50979,7 +51233,7 @@ async function runDev(options, deps) {
|
|
|
50979
51233
|
printSuccess(`Dev server running at http://localhost:${port}`);
|
|
50980
51234
|
printSuccess(`Admin panel at http://localhost:${port}${config3.admin.prefix}`);
|
|
50981
51235
|
});
|
|
50982
|
-
const schemasDir =
|
|
51236
|
+
const schemasDir = resolve6(cwd, config3.schema.base_path);
|
|
50983
51237
|
const watcher = watch(schemasDir, { recursive: true });
|
|
50984
51238
|
void (async () => {
|
|
50985
51239
|
for await (const event of watcher) {
|
|
@@ -50992,14 +51246,36 @@ async function runDev(options, deps) {
|
|
|
50992
51246
|
db,
|
|
50993
51247
|
updateFetch: (fetch2) => {
|
|
50994
51248
|
honoFetch = fetch2;
|
|
50995
|
-
}
|
|
51249
|
+
},
|
|
51250
|
+
getResolvers: () => loadProgrammaticResolvers(cwd, config3.programmatic.dir)
|
|
50996
51251
|
});
|
|
50997
51252
|
}
|
|
50998
51253
|
}
|
|
50999
51254
|
})();
|
|
51255
|
+
const programmaticDir = resolve6(cwd, config3.programmatic.dir);
|
|
51256
|
+
if (existsSync5(programmaticDir)) {
|
|
51257
|
+
const progWatcher = watch(programmaticDir, { recursive: true });
|
|
51258
|
+
void (async () => {
|
|
51259
|
+
for await (const event of progWatcher) {
|
|
51260
|
+
if (event.filename && /\.(ts|mjs|js)$/.test(event.filename)) {
|
|
51261
|
+
await onSchemaFileChange({
|
|
51262
|
+
cwd,
|
|
51263
|
+
config: config3,
|
|
51264
|
+
manguitoDir,
|
|
51265
|
+
drizzleConfigPath,
|
|
51266
|
+
db,
|
|
51267
|
+
updateFetch: (fetch2) => {
|
|
51268
|
+
honoFetch = fetch2;
|
|
51269
|
+
},
|
|
51270
|
+
getResolvers: () => loadProgrammaticResolvers(cwd, config3.programmatic.dir)
|
|
51271
|
+
});
|
|
51272
|
+
}
|
|
51273
|
+
}
|
|
51274
|
+
})();
|
|
51275
|
+
}
|
|
51000
51276
|
}
|
|
51001
51277
|
async function onSchemaFileChange(args) {
|
|
51002
|
-
const { cwd, config: config3, manguitoDir, drizzleConfigPath, db, updateFetch } = args;
|
|
51278
|
+
const { cwd, config: config3, manguitoDir, drizzleConfigPath, db, updateFetch, getResolvers } = args;
|
|
51003
51279
|
let registry2;
|
|
51004
51280
|
try {
|
|
51005
51281
|
registry2 = await parseAllSchemas(cwd, config3);
|
|
@@ -51008,10 +51284,10 @@ async function onSchemaFileChange(args) {
|
|
|
51008
51284
|
return;
|
|
51009
51285
|
}
|
|
51010
51286
|
await generateDrizzleConfig(config3, manguitoDir);
|
|
51011
|
-
await
|
|
51287
|
+
await writeFile8(join11(manguitoDir, "schema.ts"), generateSchemaFile(registry2), "utf8");
|
|
51012
51288
|
await generateSchemaRegistry(registry2, manguitoDir);
|
|
51013
51289
|
await generateRoutes2(registry2, manguitoDir);
|
|
51014
|
-
await generateForms(registry2,
|
|
51290
|
+
await generateForms(registry2, join11(manguitoDir, "forms"));
|
|
51015
51291
|
await generateNav(registry2, manguitoDir);
|
|
51016
51292
|
try {
|
|
51017
51293
|
await runDevMigration(drizzleConfigPath);
|
|
@@ -51020,11 +51296,13 @@ async function onSchemaFileChange(args) {
|
|
|
51020
51296
|
`);
|
|
51021
51297
|
return;
|
|
51022
51298
|
}
|
|
51299
|
+
const resolverMap = await getResolvers();
|
|
51023
51300
|
const newAdapter = createCmsApp({
|
|
51024
51301
|
name: config3.name,
|
|
51025
51302
|
registry: registry2,
|
|
51026
51303
|
db: db.getDb(),
|
|
51027
51304
|
storage: config3.storage,
|
|
51305
|
+
resolvers: resolverMap,
|
|
51028
51306
|
...config3.api.prefix ? { prefix: config3.api.prefix } : {},
|
|
51029
51307
|
...config3.api.media?.max_file_size ? { media: { max_file_size: config3.api.media.max_file_size } } : {},
|
|
51030
51308
|
...config3.api.rateLimit ? { rateLimit: config3.api.rateLimit } : {},
|
|
@@ -51048,7 +51326,7 @@ async function parseAllSchemas(cwd, config3) {
|
|
|
51048
51326
|
}
|
|
51049
51327
|
parsedSchemas.push(parseResult.schema);
|
|
51050
51328
|
}
|
|
51051
|
-
const rolesPath =
|
|
51329
|
+
const rolesPath = resolve6(cwd, config3.schema.base_path, "roles.json");
|
|
51052
51330
|
const rolesLoad = loadSchemaFile(rolesPath);
|
|
51053
51331
|
if (!rolesLoad.ok) {
|
|
51054
51332
|
printGuidedError("Could not read roles.json.");
|
|
@@ -51059,7 +51337,7 @@ async function parseAllSchemas(cwd, config3) {
|
|
|
51059
51337
|
printGuidedError("roles.json parse errors \u2014 run `manguito validate` for details.");
|
|
51060
51338
|
process.exit(1);
|
|
51061
51339
|
}
|
|
51062
|
-
const routesPath =
|
|
51340
|
+
const routesPath = resolve6(cwd, config3.schema.base_path, "routes.json");
|
|
51063
51341
|
const routesLoad = loadSchemaFile(routesPath);
|
|
51064
51342
|
if (!routesLoad.ok) {
|
|
51065
51343
|
printGuidedError("Could not read routes.json.");
|
|
@@ -51073,7 +51351,7 @@ async function parseAllSchemas(cwd, config3) {
|
|
|
51073
51351
|
return buildSchemaRegistry(parsedSchemas, routesResult.value, rolesResult.value);
|
|
51074
51352
|
}
|
|
51075
51353
|
function resolveAdminRoot2(cwd) {
|
|
51076
|
-
const cwdRequire = createRequire2(
|
|
51354
|
+
const cwdRequire = createRequire2(join11(cwd, "package.json"));
|
|
51077
51355
|
const adminPkgJson = cwdRequire.resolve("@bobbykim/manguito-cms-admin/package.json");
|
|
51078
51356
|
return dirname2(adminPkgJson);
|
|
51079
51357
|
}
|
|
@@ -51119,8 +51397,8 @@ async function bridgeToHono(req, res, honoFetch) {
|
|
|
51119
51397
|
|
|
51120
51398
|
// src/commands/start.ts
|
|
51121
51399
|
init_esm_shims();
|
|
51122
|
-
import { resolve as
|
|
51123
|
-
import { pathToFileURL as
|
|
51400
|
+
import { resolve as resolve7 } from "path";
|
|
51401
|
+
import { pathToFileURL as pathToFileURL3 } from "url";
|
|
51124
51402
|
function registerStart(program2) {
|
|
51125
51403
|
program2.command("start").description("Start the production server from dist/").option("--env <path>", "path to .env file to load").action(async (options) => {
|
|
51126
51404
|
await runStart(options, { cwd: process.cwd() });
|
|
@@ -51132,7 +51410,7 @@ async function runStart(options, deps) {
|
|
|
51132
51410
|
const config3 = await resolveConfig(cwd);
|
|
51133
51411
|
const db = await connectDb(config3);
|
|
51134
51412
|
const migrationsTable = config3.migrations?.table ?? "__manguito_migrations";
|
|
51135
|
-
const migrationsFolder = config3.migrations?.folder ?
|
|
51413
|
+
const migrationsFolder = config3.migrations?.folder ? resolve7(cwd, config3.migrations.folder) : resolve7(cwd, "./migrations");
|
|
51136
51414
|
const trackingTableExists = await db.tableExists(migrationsTable);
|
|
51137
51415
|
if (!trackingTableExists) {
|
|
51138
51416
|
printGuidedError(
|
|
@@ -51167,7 +51445,7 @@ async function runStart(options, deps) {
|
|
|
51167
51445
|
} else {
|
|
51168
51446
|
allErrors.push(...walkResult.errors);
|
|
51169
51447
|
}
|
|
51170
|
-
const rolesPath =
|
|
51448
|
+
const rolesPath = resolve7(cwd, config3.schema.base_path, "roles.json");
|
|
51171
51449
|
const rolesLoad = loadSchemaFile(rolesPath);
|
|
51172
51450
|
let parsedRoles = null;
|
|
51173
51451
|
if (rolesLoad.ok) {
|
|
@@ -51180,7 +51458,7 @@ async function runStart(options, deps) {
|
|
|
51180
51458
|
} else {
|
|
51181
51459
|
allErrors.push(...rolesLoad.errors);
|
|
51182
51460
|
}
|
|
51183
|
-
const routesPath =
|
|
51461
|
+
const routesPath = resolve7(cwd, config3.schema.base_path, "routes.json");
|
|
51184
51462
|
const routesLoad = loadSchemaFile(routesPath);
|
|
51185
51463
|
let parsedRoutes = null;
|
|
51186
51464
|
if (routesLoad.ok) {
|
|
@@ -51202,7 +51480,7 @@ async function runStart(options, deps) {
|
|
|
51202
51480
|
}
|
|
51203
51481
|
const registry2 = buildSchemaRegistry(parsedSchemas, parsedRoutes, parsedRoles);
|
|
51204
51482
|
await seedSystemTables(db.getDb(), registry2);
|
|
51205
|
-
const serverUrl =
|
|
51483
|
+
const serverUrl = pathToFileURL3(resolve7(cwd, "dist/server.js")).href;
|
|
51206
51484
|
await (deps.loadServer ? deps.loadServer(serverUrl) : import(serverUrl));
|
|
51207
51485
|
const port = Number(process.env["PORT"] ?? 3e3);
|
|
51208
51486
|
printSuccess(`Server running at http://localhost:${port}`);
|
|
@@ -51211,7 +51489,7 @@ async function runStart(options, deps) {
|
|
|
51211
51489
|
|
|
51212
51490
|
// src/commands/migrate.ts
|
|
51213
51491
|
init_esm_shims();
|
|
51214
|
-
import { resolve as
|
|
51492
|
+
import { resolve as resolve8, join as join12 } from "path";
|
|
51215
51493
|
import { readFile as readFile2 } from "fs/promises";
|
|
51216
51494
|
function registerMigrate(program2) {
|
|
51217
51495
|
program2.command("migrate").description("Apply pending database migrations").option("--env <path>", "path to .env file to load").option("--status", "show migration state without applying").option("--dry-run", "preview migrations without writing").option("--force", "skip destructive-change confirmation prompt").action(async (options) => {
|
|
@@ -51229,8 +51507,8 @@ function buildDeps(options, cwd) {
|
|
|
51229
51507
|
buildRunner: async () => runBuild(options.env ? { env: options.env } : {}, { cwd }),
|
|
51230
51508
|
needsRebuild: () => needsRebuild(cwd),
|
|
51231
51509
|
db: createPostgresAdapter(),
|
|
51232
|
-
migrationsFolder:
|
|
51233
|
-
configPath:
|
|
51510
|
+
migrationsFolder: resolve8(cwd, "./migrations"),
|
|
51511
|
+
configPath: resolve8(cwd, "dist/generated/drizzle.config.ts"),
|
|
51234
51512
|
prompt: createPromptAdapter()
|
|
51235
51513
|
};
|
|
51236
51514
|
}
|
|
@@ -51245,7 +51523,7 @@ async function runMigrate(options, deps) {
|
|
|
51245
51523
|
}
|
|
51246
51524
|
const config4 = await resolveConfig(process.cwd());
|
|
51247
51525
|
const migrationsTable2 = config4.migrations?.table ?? "__manguito_migrations";
|
|
51248
|
-
const migrationsFolder2 = config4.migrations?.folder ?
|
|
51526
|
+
const migrationsFolder2 = config4.migrations?.folder ? resolve8(process.cwd(), config4.migrations.folder) : deps.migrationsFolder;
|
|
51249
51527
|
const status = await getMigrationStatus(deps.db.getDb(), { migrationsTable: migrationsTable2, migrationsFolder: migrationsFolder2 });
|
|
51250
51528
|
if (status.applied.length === 0 && status.pending.length === 0) {
|
|
51251
51529
|
process.stdout.write(
|
|
@@ -51277,7 +51555,7 @@ async function runMigrate(options, deps) {
|
|
|
51277
51555
|
loadEnvFile(options.env);
|
|
51278
51556
|
const cwd = process.cwd();
|
|
51279
51557
|
const config3 = await resolveConfig(cwd);
|
|
51280
|
-
const migrationsFolder = config3.migrations?.folder ?
|
|
51558
|
+
const migrationsFolder = config3.migrations?.folder ? resolve8(cwd, config3.migrations.folder) : deps.migrationsFolder;
|
|
51281
51559
|
const migrationsTable = config3.migrations?.table ?? "__manguito_migrations";
|
|
51282
51560
|
try {
|
|
51283
51561
|
await deps.db.connect();
|
|
@@ -51297,10 +51575,10 @@ async function runMigrate(options, deps) {
|
|
|
51297
51575
|
}
|
|
51298
51576
|
}
|
|
51299
51577
|
printSuccess("Build complete");
|
|
51300
|
-
const generatedDir =
|
|
51578
|
+
const generatedDir = resolve8(cwd, "dist/generated");
|
|
51301
51579
|
await generateDrizzleConfig(config3, generatedDir);
|
|
51302
51580
|
const newFileNames = await generateMigration(deps.configPath, migrationsFolder);
|
|
51303
|
-
const newFilePaths = newFileNames.map((f) =>
|
|
51581
|
+
const newFilePaths = newFileNames.map((f) => join12(migrationsFolder, f));
|
|
51304
51582
|
printSuccess(
|
|
51305
51583
|
newFileNames.length === 0 ? "No new migration files generated" : `Generated ${newFileNames.length} migration file${newFileNames.length !== 1 ? "s" : ""}: ${newFileNames.join(", ")}`
|
|
51306
51584
|
);
|
|
@@ -51370,7 +51648,7 @@ async function runMigrate(options, deps) {
|
|
|
51370
51648
|
} else {
|
|
51371
51649
|
allErrors.push(...walkResult.errors);
|
|
51372
51650
|
}
|
|
51373
|
-
const rolesPath =
|
|
51651
|
+
const rolesPath = resolve8(cwd, config3.schema.base_path, "roles.json");
|
|
51374
51652
|
const rolesLoad = loadSchemaFile(rolesPath);
|
|
51375
51653
|
let parsedRoles = null;
|
|
51376
51654
|
if (rolesLoad.ok) {
|
|
@@ -51383,7 +51661,7 @@ async function runMigrate(options, deps) {
|
|
|
51383
51661
|
} else {
|
|
51384
51662
|
allErrors.push(...rolesLoad.errors);
|
|
51385
51663
|
}
|
|
51386
|
-
const routesPath =
|
|
51664
|
+
const routesPath = resolve8(cwd, config3.schema.base_path, "routes.json");
|
|
51387
51665
|
const routesLoad = loadSchemaFile(routesPath);
|
|
51388
51666
|
let parsedRoutes = null;
|
|
51389
51667
|
if (routesLoad.ok) {
|
|
@@ -51415,7 +51693,7 @@ async function runMigrate(options, deps) {
|
|
|
51415
51693
|
|
|
51416
51694
|
// src/commands/validate.ts
|
|
51417
51695
|
init_esm_shims();
|
|
51418
|
-
import { resolve as
|
|
51696
|
+
import { resolve as resolve9 } from "path";
|
|
51419
51697
|
function registerValidate(program2) {
|
|
51420
51698
|
program2.command("validate").description("Parse and validate all schemas, config, roles, and routes").option("--env <path>", "path to .env file to load").action(async (options) => {
|
|
51421
51699
|
await runValidate(options, { cwd: process.cwd() });
|
|
@@ -51440,7 +51718,7 @@ async function runValidate(options, deps) {
|
|
|
51440
51718
|
}
|
|
51441
51719
|
}
|
|
51442
51720
|
}
|
|
51443
|
-
const rolesPath =
|
|
51721
|
+
const rolesPath = resolve9(cwd, config3.schema.base_path, "roles.json");
|
|
51444
51722
|
const rolesLoadResult = loadSchemaFile(rolesPath);
|
|
51445
51723
|
let parsedRoles = null;
|
|
51446
51724
|
if (!rolesLoadResult.ok) {
|
|
@@ -51453,7 +51731,7 @@ async function runValidate(options, deps) {
|
|
|
51453
51731
|
parsedRoles = rolesParseResult.value;
|
|
51454
51732
|
}
|
|
51455
51733
|
}
|
|
51456
|
-
const routesPath =
|
|
51734
|
+
const routesPath = resolve9(cwd, config3.schema.base_path, "routes.json");
|
|
51457
51735
|
const routesLoadResult = loadSchemaFile(routesPath);
|
|
51458
51736
|
let parsedRoutesDef = null;
|
|
51459
51737
|
if (!routesLoadResult.ok) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bobbykim/manguito-cms-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Bobby Kim <bobby.sihun.kim@gmail.com>",
|
|
6
6
|
"homepage": "https://github.com/bobbykim89/manguito-cms",
|
|
@@ -29,10 +29,10 @@
|
|
|
29
29
|
"tsup": "^8.5.1",
|
|
30
30
|
"typescript": "^6.0.3",
|
|
31
31
|
"vite": "^8.1.3",
|
|
32
|
-
"@bobbykim/manguito-cms-
|
|
33
|
-
"@bobbykim/manguito-cms-
|
|
34
|
-
"@bobbykim/manguito-cms-db": "0.1.
|
|
35
|
-
"@bobbykim/manguito-cms-api": "0.
|
|
32
|
+
"@bobbykim/manguito-cms-core": "0.2.0",
|
|
33
|
+
"@bobbykim/manguito-cms-admin": "0.3.0",
|
|
34
|
+
"@bobbykim/manguito-cms-db": "0.1.2",
|
|
35
|
+
"@bobbykim/manguito-cms-api": "0.2.0"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@types/node": "^25.9.5",
|