@plank-cms/plank 0.24.2 → 0.25.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/admin/index.html
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
href="https://fonts.googleapis.com/css2?family=Google+Sans:ital,opsz,wght@0,17..18,400..700;1,17..18,400..700&display=swap"
|
|
13
13
|
rel="stylesheet"
|
|
14
14
|
/>
|
|
15
|
-
<script type="module" crossorigin src="/admin/assets/index-
|
|
15
|
+
<script type="module" crossorigin src="/admin/assets/index-BlWGZ3Y_.js"></script>
|
|
16
16
|
<link rel="stylesheet" crossorigin href="/admin/assets/index-BSi0iXTe.css">
|
|
17
17
|
</head>
|
|
18
18
|
<body>
|
package/dist/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import { randomBytes } from "crypto";
|
|
|
7
7
|
import { resolve, join } from "path";
|
|
8
8
|
import fs from "fs-extra";
|
|
9
9
|
import { execa } from "execa";
|
|
10
|
-
var PACKAGE_VERSION = "0.
|
|
10
|
+
var PACKAGE_VERSION = "0.25.0";
|
|
11
11
|
function generateSecret() {
|
|
12
12
|
return randomBytes(32).toString("hex");
|
|
13
13
|
}
|
|
@@ -101,7 +101,7 @@ import { dirname, join as join2, resolve as resolve2 } from "path";
|
|
|
101
101
|
async function start() {
|
|
102
102
|
config({ path: resolve2(process.cwd(), ".env") });
|
|
103
103
|
process.env.PLANK_ADMIN_DIST = join2(dirname(fileURLToPath(import.meta.url)), "admin");
|
|
104
|
-
const { start: startServer } = await import("./server-
|
|
104
|
+
const { start: startServer } = await import("./server-ESNIHORP.js");
|
|
105
105
|
await startServer();
|
|
106
106
|
}
|
|
107
107
|
|
|
@@ -204,6 +204,7 @@ function rowToContentType(row) {
|
|
|
204
204
|
name: row.name,
|
|
205
205
|
slug: row.slug,
|
|
206
206
|
kind: row.kind,
|
|
207
|
+
previewEnabled: row.preview_enabled,
|
|
207
208
|
tableName: row.table_name,
|
|
208
209
|
fields: row.fields,
|
|
209
210
|
isDefault: row.is_default,
|
|
@@ -220,16 +221,24 @@ async function findContentTypeBySlug(slug) {
|
|
|
220
221
|
return rows[0] ? rowToContentType(rows[0]) : null;
|
|
221
222
|
}
|
|
222
223
|
async function saveContentType(contentType) {
|
|
223
|
-
const { rows } = await pool_default.query(`INSERT INTO plank_content_types (id, name, slug, kind, table_name, fields)
|
|
224
|
-
VALUES ($1, $2, $3, $4, $5, $6)
|
|
225
|
-
RETURNING *`, [
|
|
224
|
+
const { rows } = await pool_default.query(`INSERT INTO plank_content_types (id, name, slug, kind, preview_enabled, table_name, fields)
|
|
225
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
|
226
|
+
RETURNING *`, [
|
|
227
|
+
createId(),
|
|
228
|
+
contentType.name,
|
|
229
|
+
contentType.slug,
|
|
230
|
+
contentType.kind ?? "collection",
|
|
231
|
+
contentType.previewEnabled ?? true,
|
|
232
|
+
contentType.tableName,
|
|
233
|
+
JSON.stringify(contentType.fields)
|
|
234
|
+
]);
|
|
226
235
|
return rowToContentType(rows[0]);
|
|
227
236
|
}
|
|
228
237
|
async function updateContentType(slug, contentType) {
|
|
229
238
|
const { rows } = await pool_default.query(`UPDATE plank_content_types
|
|
230
|
-
SET name = $1, fields = $2, updated_at = NOW()
|
|
231
|
-
WHERE slug = $
|
|
232
|
-
RETURNING *`, [contentType.name, JSON.stringify(contentType.fields), slug]);
|
|
239
|
+
SET name = $1, fields = $2, preview_enabled = $3, updated_at = NOW()
|
|
240
|
+
WHERE slug = $4
|
|
241
|
+
RETURNING *`, [contentType.name, JSON.stringify(contentType.fields), contentType.previewEnabled ?? true, slug]);
|
|
233
242
|
return rowToContentType(rows[0]);
|
|
234
243
|
}
|
|
235
244
|
async function setDefaultContentType(slug) {
|
|
@@ -2977,6 +2986,7 @@ var ContentTypeSchema = z2.object({
|
|
|
2977
2986
|
name: z2.string().min(1),
|
|
2978
2987
|
slug: z2.string().regex(/^[a-z][a-z0-9-]*$/, "Slug must be lowercase with hyphens"),
|
|
2979
2988
|
tableName: z2.string().regex(/^[a-z][a-z0-9_]*$/, "Table name must be lowercase with underscores"),
|
|
2989
|
+
previewEnabled: z2.boolean().default(true),
|
|
2980
2990
|
fields: z2.array(FieldSchema)
|
|
2981
2991
|
});
|
|
2982
2992
|
var CreateContentTypeSchema = ContentTypeSchema.extend({
|
|
@@ -3224,6 +3234,73 @@ async function triggerWebhooks(event, payload) {
|
|
|
3224
3234
|
signal: AbortSignal.timeout(1e4)
|
|
3225
3235
|
})));
|
|
3226
3236
|
}
|
|
3237
|
+
async function triggerPreviewSyncWebhook(params) {
|
|
3238
|
+
const settings = await getSettings("preview");
|
|
3239
|
+
const enabled = String(settings.enabled ?? "false").toLowerCase() === "true";
|
|
3240
|
+
const syncUrl = settings.sync_url?.trim();
|
|
3241
|
+
if (!enabled || !syncUrl)
|
|
3242
|
+
return;
|
|
3243
|
+
let parsedSyncUrl;
|
|
3244
|
+
try {
|
|
3245
|
+
parsedSyncUrl = new URL(syncUrl);
|
|
3246
|
+
} catch {
|
|
3247
|
+
return;
|
|
3248
|
+
}
|
|
3249
|
+
const slugField = settings.slug_field?.trim() || "slug";
|
|
3250
|
+
const slugValue = params.entry[slugField];
|
|
3251
|
+
const slug = typeof slugValue === "string" && slugValue.trim() ? slugValue.trim() : null;
|
|
3252
|
+
const previewUrl = resolvePreviewUrlFromSettings(settings, {
|
|
3253
|
+
contentType: params.contentType,
|
|
3254
|
+
entry: params.entry
|
|
3255
|
+
});
|
|
3256
|
+
const payload = {
|
|
3257
|
+
event: "preview.sync",
|
|
3258
|
+
content_type: params.contentType,
|
|
3259
|
+
entry_id: params.entry.id ? String(params.entry.id) : "",
|
|
3260
|
+
status: typeof params.entry.status === "string" ? params.entry.status : null,
|
|
3261
|
+
slug,
|
|
3262
|
+
preview_url: previewUrl,
|
|
3263
|
+
triggered_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
3264
|
+
};
|
|
3265
|
+
if (!payload.entry_id)
|
|
3266
|
+
return;
|
|
3267
|
+
try {
|
|
3268
|
+
await fetch(parsedSyncUrl, {
|
|
3269
|
+
method: "POST",
|
|
3270
|
+
headers: { "Content-Type": "application/json" },
|
|
3271
|
+
body: JSON.stringify(payload),
|
|
3272
|
+
signal: AbortSignal.timeout(1e4)
|
|
3273
|
+
});
|
|
3274
|
+
} catch {
|
|
3275
|
+
}
|
|
3276
|
+
}
|
|
3277
|
+
function resolvePreviewUrlFromSettings(settings, params) {
|
|
3278
|
+
const template = settings.url_template?.trim();
|
|
3279
|
+
if (!template)
|
|
3280
|
+
return null;
|
|
3281
|
+
const slugField = settings.slug_field?.trim() || "slug";
|
|
3282
|
+
const slugValue = params.entry[slugField];
|
|
3283
|
+
const resolved = template.replace(/\{(contentType|entryId|slug|status)\}/g, (_match, key) => {
|
|
3284
|
+
if (key === "contentType")
|
|
3285
|
+
return encodeURIComponent(params.contentType);
|
|
3286
|
+
if (key === "entryId")
|
|
3287
|
+
return params.entry.id ? encodeURIComponent(String(params.entry.id)) : "";
|
|
3288
|
+
if (key === "slug") {
|
|
3289
|
+
return typeof slugValue === "string" && slugValue.trim() ? encodeURIComponent(slugValue.trim()) : "";
|
|
3290
|
+
}
|
|
3291
|
+
if (key === "status") {
|
|
3292
|
+
return typeof params.entry.status === "string" ? encodeURIComponent(params.entry.status) : "";
|
|
3293
|
+
}
|
|
3294
|
+
return "";
|
|
3295
|
+
});
|
|
3296
|
+
if (/\{[^}]+\}/.test(resolved))
|
|
3297
|
+
return null;
|
|
3298
|
+
try {
|
|
3299
|
+
return new URL(resolved).toString();
|
|
3300
|
+
} catch {
|
|
3301
|
+
return null;
|
|
3302
|
+
}
|
|
3303
|
+
}
|
|
3227
3304
|
|
|
3228
3305
|
// ../core/dist/controllers/entries.js
|
|
3229
3306
|
function resolveLocalizedRow(row, ct, locale, fallbacks = []) {
|
|
@@ -3561,6 +3638,9 @@ var createEntry = async (req, res) => {
|
|
|
3561
3638
|
}));
|
|
3562
3639
|
res.status(201).json(normalizeNavigationFields(rows[0], ct.fields));
|
|
3563
3640
|
triggerWebhooks("entry.created", { content_type: req.params.slug, entry_id: rows[0].id });
|
|
3641
|
+
if (ct.previewEnabled !== false) {
|
|
3642
|
+
triggerPreviewSyncWebhook({ contentType: req.params.slug, entry: rows[0] });
|
|
3643
|
+
}
|
|
3564
3644
|
};
|
|
3565
3645
|
var getSingleEntry = async (req, res) => {
|
|
3566
3646
|
const ct = await findContentTypeBySlug(req.params.slug);
|
|
@@ -3654,6 +3734,9 @@ var updateEntry = async (req, res) => {
|
|
|
3654
3734
|
}));
|
|
3655
3735
|
res.json(normalizeNavigationFields(rows[0], ct.fields));
|
|
3656
3736
|
triggerWebhooks("entry.updated", { content_type: req.params.slug, entry_id: req.params.id });
|
|
3737
|
+
if (ct.previewEnabled !== false) {
|
|
3738
|
+
triggerPreviewSyncWebhook({ contentType: req.params.slug, entry: rows[0] });
|
|
3739
|
+
}
|
|
3657
3740
|
};
|
|
3658
3741
|
var SNAPSHOT_EXCLUDED = [
|
|
3659
3742
|
"'id'",
|
|
@@ -4789,6 +4872,7 @@ async function getClientSettings(_req, res) {
|
|
|
4789
4872
|
locales: settings.locales ?? '["en"]',
|
|
4790
4873
|
default_locale: settings.default_locale ?? "en",
|
|
4791
4874
|
preview_enabled: previewSettings.enabled ?? "false",
|
|
4875
|
+
preview_sync_url: previewSettings.sync_url ?? "",
|
|
4792
4876
|
preview_url_template: previewSettings.url_template ?? "",
|
|
4793
4877
|
preview_slug_field: previewSettings.slug_field ?? "slug"
|
|
4794
4878
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plank-cms/plank",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.0",
|
|
4
4
|
"description": "Self-hosted headless CMS. Deploy in minutes on your own infrastructure.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -55,9 +55,9 @@
|
|
|
55
55
|
"devDependencies": {
|
|
56
56
|
"@types/fs-extra": "^11.0.4",
|
|
57
57
|
"tsup": "^8.5.0",
|
|
58
|
-
"@plank-cms/
|
|
59
|
-
"@plank-cms/
|
|
60
|
-
"@plank-cms/
|
|
58
|
+
"@plank-cms/schema": "0.25.0",
|
|
59
|
+
"@plank-cms/core": "0.25.0",
|
|
60
|
+
"@plank-cms/db": "0.25.0"
|
|
61
61
|
},
|
|
62
62
|
"scripts": {
|
|
63
63
|
"build": "tsup",
|