@plank-cms/plank 0.19.0 → 0.20.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/admin/assets/index-BrTr5m2J.css +2 -0
- package/dist/admin/assets/index-cDCZafS6.js +223 -0
- package/dist/admin/index.html +2 -2
- package/dist/index.js +2 -2
- package/dist/{server-KVOZGN2H.js → server-JCTD2EIO.js} +137 -32
- package/package.json +4 -4
- package/dist/admin/assets/index-BepYvDmW.js +0 -223
- package/dist/admin/assets/index-FkEexpp5.css +0 -2
package/dist/admin/index.html
CHANGED
|
@@ -12,8 +12,8 @@
|
|
|
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-
|
|
16
|
-
<link rel="stylesheet" crossorigin href="/admin/assets/index-
|
|
15
|
+
<script type="module" crossorigin src="/admin/assets/index-cDCZafS6.js"></script>
|
|
16
|
+
<link rel="stylesheet" crossorigin href="/admin/assets/index-BrTr5m2J.css">
|
|
17
17
|
</head>
|
|
18
18
|
<body>
|
|
19
19
|
<div id="root"></div>
|
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.20.1";
|
|
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-JCTD2EIO.js");
|
|
105
105
|
await startServer();
|
|
106
106
|
}
|
|
107
107
|
|
|
@@ -2164,7 +2164,7 @@ async function setSettings(namespace, values) {
|
|
|
2164
2164
|
}
|
|
2165
2165
|
|
|
2166
2166
|
// ../core/dist/media/providers/local.js
|
|
2167
|
-
import { writeFile, mkdir } from "fs/promises";
|
|
2167
|
+
import { writeFile, mkdir, rm } from "fs/promises";
|
|
2168
2168
|
import { join as join3, extname } from "path";
|
|
2169
2169
|
import { randomBytes as randomBytes3 } from "crypto";
|
|
2170
2170
|
async function uploadsDir() {
|
|
@@ -2200,6 +2200,10 @@ var localProvider = {
|
|
|
2200
2200
|
const dir = await uploadsDir();
|
|
2201
2201
|
await unlink(join3(dir, key));
|
|
2202
2202
|
},
|
|
2203
|
+
async deletePrefix(prefix) {
|
|
2204
|
+
const dir = await uploadsDir();
|
|
2205
|
+
await rm(join3(dir, prefix), { recursive: true, force: true });
|
|
2206
|
+
},
|
|
2203
2207
|
async getUrl(key) {
|
|
2204
2208
|
const base = await publicUrl();
|
|
2205
2209
|
return `${base}/uploads/${key}`;
|
|
@@ -2207,7 +2211,7 @@ var localProvider = {
|
|
|
2207
2211
|
};
|
|
2208
2212
|
|
|
2209
2213
|
// ../core/dist/media/providers/s3.js
|
|
2210
|
-
import { S3Client, PutObjectCommand, DeleteObjectCommand } from "@aws-sdk/client-s3";
|
|
2214
|
+
import { S3Client, PutObjectCommand, DeleteObjectCommand, ListObjectsV2Command, DeleteObjectsCommand } from "@aws-sdk/client-s3";
|
|
2211
2215
|
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
|
|
2212
2216
|
import { extname as extname2 } from "path";
|
|
2213
2217
|
import { randomBytes as randomBytes4 } from "crypto";
|
|
@@ -2237,6 +2241,9 @@ function buildKey(cfg, filename, prefix) {
|
|
|
2237
2241
|
const parts = [cfg.pathPrefix?.replace(/\/$/, ""), prefix, name].filter(Boolean);
|
|
2238
2242
|
return parts.join("/");
|
|
2239
2243
|
}
|
|
2244
|
+
function withPathPrefix(cfg, key) {
|
|
2245
|
+
return [cfg.pathPrefix?.replace(/\/$/, ""), key.replace(/^\//, "")].filter(Boolean).join("/");
|
|
2246
|
+
}
|
|
2240
2247
|
function buildStoredUrl(cfg, key) {
|
|
2241
2248
|
return cfg.publicUrl ? `${cfg.publicUrl.replace(/\/$/, "")}/${key}` : `https://${cfg.bucket}.s3.${cfg.region}.amazonaws.com/${key}`;
|
|
2242
2249
|
}
|
|
@@ -2253,22 +2260,44 @@ var s3Provider = {
|
|
|
2253
2260
|
}));
|
|
2254
2261
|
return { url: buildStoredUrl(cfg, key), key };
|
|
2255
2262
|
},
|
|
2256
|
-
async uploadRaw(buffer,
|
|
2263
|
+
async uploadRaw(buffer, key, mimeType) {
|
|
2257
2264
|
const cfg = await getConfig();
|
|
2258
2265
|
const client = buildClient(cfg);
|
|
2266
|
+
const fullKey = withPathPrefix(cfg, key);
|
|
2259
2267
|
await client.send(new PutObjectCommand({
|
|
2260
2268
|
Bucket: cfg.bucket,
|
|
2261
|
-
Key:
|
|
2269
|
+
Key: fullKey,
|
|
2262
2270
|
Body: buffer,
|
|
2263
2271
|
ContentType: mimeType
|
|
2264
2272
|
}));
|
|
2265
|
-
return { url: buildStoredUrl(cfg,
|
|
2273
|
+
return { url: buildStoredUrl(cfg, fullKey), key: fullKey };
|
|
2266
2274
|
},
|
|
2267
2275
|
async delete(key) {
|
|
2268
2276
|
const cfg = await getConfig();
|
|
2269
2277
|
const client = buildClient(cfg);
|
|
2270
2278
|
await client.send(new DeleteObjectCommand({ Bucket: cfg.bucket, Key: key }));
|
|
2271
2279
|
},
|
|
2280
|
+
async deletePrefix(prefix) {
|
|
2281
|
+
const cfg = await getConfig();
|
|
2282
|
+
const client = buildClient(cfg);
|
|
2283
|
+
const fullPrefix = prefix.endsWith("/") ? prefix : `${prefix}/`;
|
|
2284
|
+
let continuationToken;
|
|
2285
|
+
do {
|
|
2286
|
+
const list = await client.send(new ListObjectsV2Command({
|
|
2287
|
+
Bucket: cfg.bucket,
|
|
2288
|
+
Prefix: fullPrefix,
|
|
2289
|
+
ContinuationToken: continuationToken
|
|
2290
|
+
}));
|
|
2291
|
+
const objects = (list.Contents ?? []).map((o) => o.Key ? { Key: o.Key } : null).filter((o) => o !== null);
|
|
2292
|
+
if (objects.length > 0) {
|
|
2293
|
+
await client.send(new DeleteObjectsCommand({
|
|
2294
|
+
Bucket: cfg.bucket,
|
|
2295
|
+
Delete: { Objects: objects, Quiet: true }
|
|
2296
|
+
}));
|
|
2297
|
+
}
|
|
2298
|
+
continuationToken = list.IsTruncated ? list.NextContinuationToken : void 0;
|
|
2299
|
+
} while (continuationToken);
|
|
2300
|
+
},
|
|
2272
2301
|
async getUrl(key) {
|
|
2273
2302
|
const cfg = await getConfig();
|
|
2274
2303
|
return buildStoredUrl(cfg, key);
|
|
@@ -2284,7 +2313,7 @@ var s3Provider = {
|
|
|
2284
2313
|
};
|
|
2285
2314
|
|
|
2286
2315
|
// ../core/dist/media/providers/r2.js
|
|
2287
|
-
import { S3Client as S3Client2, PutObjectCommand as PutObjectCommand2, DeleteObjectCommand as DeleteObjectCommand2 } from "@aws-sdk/client-s3";
|
|
2316
|
+
import { S3Client as S3Client2, PutObjectCommand as PutObjectCommand2, DeleteObjectCommand as DeleteObjectCommand2, ListObjectsV2Command as ListObjectsV2Command2, DeleteObjectsCommand as DeleteObjectsCommand2 } from "@aws-sdk/client-s3";
|
|
2288
2317
|
import { getSignedUrl as getSignedUrl2 } from "@aws-sdk/s3-request-presigner";
|
|
2289
2318
|
import { extname as extname3 } from "path";
|
|
2290
2319
|
import { randomBytes as randomBytes5 } from "crypto";
|
|
@@ -2317,6 +2346,9 @@ function buildKey2(cfg, filename, prefix) {
|
|
|
2317
2346
|
const parts = [cfg.pathPrefix?.replace(/\/$/, ""), prefix, name].filter(Boolean);
|
|
2318
2347
|
return parts.join("/");
|
|
2319
2348
|
}
|
|
2349
|
+
function withPathPrefix2(cfg, key) {
|
|
2350
|
+
return [cfg.pathPrefix?.replace(/\/$/, ""), key.replace(/^\//, "")].filter(Boolean).join("/");
|
|
2351
|
+
}
|
|
2320
2352
|
function buildStoredUrl2(cfg, key) {
|
|
2321
2353
|
if (!cfg.publicUrl) {
|
|
2322
2354
|
throw new Error("R2 provider requires a public_url configured in Settings > Media.");
|
|
@@ -2336,22 +2368,44 @@ var r2Provider = {
|
|
|
2336
2368
|
}));
|
|
2337
2369
|
return { url: buildStoredUrl2(cfg, key), key };
|
|
2338
2370
|
},
|
|
2339
|
-
async uploadRaw(buffer,
|
|
2371
|
+
async uploadRaw(buffer, key, mimeType) {
|
|
2340
2372
|
const cfg = await getConfig2();
|
|
2341
2373
|
const client = buildClient2(cfg);
|
|
2374
|
+
const fullKey = withPathPrefix2(cfg, key);
|
|
2342
2375
|
await client.send(new PutObjectCommand2({
|
|
2343
2376
|
Bucket: cfg.bucket,
|
|
2344
|
-
Key:
|
|
2377
|
+
Key: fullKey,
|
|
2345
2378
|
Body: buffer,
|
|
2346
2379
|
ContentType: mimeType
|
|
2347
2380
|
}));
|
|
2348
|
-
return { url: buildStoredUrl2(cfg,
|
|
2381
|
+
return { url: buildStoredUrl2(cfg, fullKey), key: fullKey };
|
|
2349
2382
|
},
|
|
2350
2383
|
async delete(key) {
|
|
2351
2384
|
const cfg = await getConfig2();
|
|
2352
2385
|
const client = buildClient2(cfg);
|
|
2353
2386
|
await client.send(new DeleteObjectCommand2({ Bucket: cfg.bucket, Key: key }));
|
|
2354
2387
|
},
|
|
2388
|
+
async deletePrefix(prefix) {
|
|
2389
|
+
const cfg = await getConfig2();
|
|
2390
|
+
const client = buildClient2(cfg);
|
|
2391
|
+
const fullPrefix = prefix.endsWith("/") ? prefix : `${prefix}/`;
|
|
2392
|
+
let continuationToken;
|
|
2393
|
+
do {
|
|
2394
|
+
const list = await client.send(new ListObjectsV2Command2({
|
|
2395
|
+
Bucket: cfg.bucket,
|
|
2396
|
+
Prefix: fullPrefix,
|
|
2397
|
+
ContinuationToken: continuationToken
|
|
2398
|
+
}));
|
|
2399
|
+
const objects = (list.Contents ?? []).map((o) => o.Key ? { Key: o.Key } : null).filter((o) => o !== null);
|
|
2400
|
+
if (objects.length > 0) {
|
|
2401
|
+
await client.send(new DeleteObjectsCommand2({
|
|
2402
|
+
Bucket: cfg.bucket,
|
|
2403
|
+
Delete: { Objects: objects, Quiet: true }
|
|
2404
|
+
}));
|
|
2405
|
+
}
|
|
2406
|
+
continuationToken = list.IsTruncated ? list.NextContinuationToken : void 0;
|
|
2407
|
+
} while (continuationToken);
|
|
2408
|
+
},
|
|
2355
2409
|
async getUrl(key) {
|
|
2356
2410
|
const cfg = await getConfig2();
|
|
2357
2411
|
return buildStoredUrl2(cfg, key);
|
|
@@ -3256,15 +3310,40 @@ var listEntries = async (req, res) => {
|
|
|
3256
3310
|
const quotedSortField = quoteIdentifier(sortField);
|
|
3257
3311
|
const locale = req.query.locale ? String(req.query.locale) : void 0;
|
|
3258
3312
|
const fallbacks = req.query.fallback ? String(req.query.fallback).split(",") : [];
|
|
3313
|
+
const search = req.query.search ? String(req.query.search).trim() : "";
|
|
3314
|
+
const rawSearchFields = req.query.searchFields ? String(req.query.searchFields).split(",") : [];
|
|
3315
|
+
const textLikeTypes = ["string", "uid", "text", "richtext"];
|
|
3316
|
+
const searchFields = rawSearchFields.filter((name) => ct.fields.some((f2) => f2.name === name && textLikeTypes.includes(f2.type)));
|
|
3317
|
+
let mainWhereClause = "";
|
|
3318
|
+
let countWhereClause = "";
|
|
3319
|
+
const mainParams = [limit, offset];
|
|
3320
|
+
const countParams = [];
|
|
3321
|
+
if (search && searchFields.length > 0) {
|
|
3322
|
+
const term = `%${search}%`;
|
|
3323
|
+
mainParams.push(term);
|
|
3324
|
+
countParams.push(term);
|
|
3325
|
+
const mainIdx = mainParams.length;
|
|
3326
|
+
const countIdx = countParams.length;
|
|
3327
|
+
const mainConditions = searchFields.map((name) => {
|
|
3328
|
+
assertSafeIdentifier(name);
|
|
3329
|
+
return `e.${quoteIdentifier(name)}::text ILIKE $${mainIdx}`;
|
|
3330
|
+
});
|
|
3331
|
+
const countConditions = searchFields.map((name) => {
|
|
3332
|
+
return `e.${quoteIdentifier(name)}::text ILIKE $${countIdx}`;
|
|
3333
|
+
});
|
|
3334
|
+
mainWhereClause = `WHERE (${mainConditions.join(" OR ")})`;
|
|
3335
|
+
countWhereClause = `WHERE (${countConditions.join(" OR ")})`;
|
|
3336
|
+
}
|
|
3259
3337
|
const [{ rows }, { rows: countRows }] = await Promise.all([
|
|
3260
3338
|
pool_default.query(`SELECT e.*, u.first_name AS _author_first_name, u.last_name AS _author_last_name, u.avatar_url AS _author_avatar_url,
|
|
3261
3339
|
ed.first_name AS _editor_first_name, ed.last_name AS _editor_last_name, ed.avatar_url AS _editor_avatar_url
|
|
3262
3340
|
FROM ${quotedTableName} e
|
|
3263
3341
|
LEFT JOIN plank_users u ON u.id = e.created_by
|
|
3264
3342
|
LEFT JOIN plank_users ed ON ed.id = e.editor_id
|
|
3343
|
+
${mainWhereClause}
|
|
3265
3344
|
ORDER BY e.${quotedSortField} ${sortDir}
|
|
3266
|
-
LIMIT $1 OFFSET $2`,
|
|
3267
|
-
pool_default.query(`SELECT COUNT(*) as count FROM ${quotedTableName}
|
|
3345
|
+
LIMIT $1 OFFSET $2`, mainParams),
|
|
3346
|
+
pool_default.query(`SELECT COUNT(*) as count FROM ${quotedTableName} e ${countWhereClause}`, countParams)
|
|
3268
3347
|
]);
|
|
3269
3348
|
const provider = await getProvider();
|
|
3270
3349
|
function entryMatchesLocale(row, locale2) {
|
|
@@ -4231,16 +4310,40 @@ function buildDefaultAlt(filename) {
|
|
|
4231
4310
|
const withoutExtension = baseName.replace(/\.[^.]+$/, "").trim();
|
|
4232
4311
|
return withoutExtension || baseName.trim();
|
|
4233
4312
|
}
|
|
4313
|
+
function mimeForHLSFile(filename) {
|
|
4314
|
+
const ext = filename.toLowerCase().split(".").pop();
|
|
4315
|
+
switch (ext) {
|
|
4316
|
+
case "m3u8":
|
|
4317
|
+
return "application/vnd.apple.mpegurl";
|
|
4318
|
+
case "ts":
|
|
4319
|
+
return "video/mp2t";
|
|
4320
|
+
case "m4s":
|
|
4321
|
+
return "video/iso.segment";
|
|
4322
|
+
case "mp4":
|
|
4323
|
+
return "video/mp4";
|
|
4324
|
+
case "aac":
|
|
4325
|
+
return "audio/aac";
|
|
4326
|
+
case "vtt":
|
|
4327
|
+
return "text/vtt";
|
|
4328
|
+
case "key":
|
|
4329
|
+
return "application/octet-stream";
|
|
4330
|
+
default:
|
|
4331
|
+
return null;
|
|
4332
|
+
}
|
|
4333
|
+
}
|
|
4234
4334
|
async function listMedia(req, res) {
|
|
4235
4335
|
const page = Math.max(1, parseInt(req.query.page) || 1);
|
|
4236
4336
|
const limit = Math.min(100, Math.max(1, parseInt(req.query.limit) || 24));
|
|
4237
4337
|
const offset = (page - 1) * limit;
|
|
4238
4338
|
const folderId = req.query.folder_id || null;
|
|
4339
|
+
const search = req.query.search ? String(req.query.search).trim() : null;
|
|
4340
|
+
const searchTerm = search ? `%${search}%` : null;
|
|
4239
4341
|
const { rows } = await pool_default.query(`SELECT *, COUNT(*) OVER() AS total
|
|
4240
4342
|
FROM plank_media
|
|
4241
4343
|
WHERE folder_id IS NOT DISTINCT FROM $3
|
|
4344
|
+
AND ($4::text IS NULL OR filename ILIKE $4 OR alt ILIKE $4 OR caption ILIKE $4)
|
|
4242
4345
|
ORDER BY created_at DESC
|
|
4243
|
-
LIMIT $1 OFFSET $2`, [limit, offset, folderId]);
|
|
4346
|
+
LIMIT $1 OFFSET $2`, [limit, offset, folderId, searchTerm]);
|
|
4244
4347
|
const provider = await getProvider();
|
|
4245
4348
|
const items = await Promise.all(rows.map(async (r2) => ({
|
|
4246
4349
|
id: r2.id,
|
|
@@ -4285,30 +4388,25 @@ async function uploadMedia(req, res) {
|
|
|
4285
4388
|
const prefix = [MEDIA_PREFIX, folderId, bundleId].filter(Boolean).join("/");
|
|
4286
4389
|
const rootDir = m3u8File.originalname.includes("/") ? m3u8File.originalname.split("/")[0] : null;
|
|
4287
4390
|
const stripRoot = (path) => rootDir && path.startsWith(`${rootDir}/`) ? path.slice(rootDir.length + 1) : path;
|
|
4288
|
-
|
|
4391
|
+
const m3u8Mime = mimeForHLSFile(m3u8File.originalname) ?? "application/vnd.apple.mpegurl";
|
|
4392
|
+
const uploaded = await Promise.all(files.map(async (file2) => {
|
|
4289
4393
|
const relativePath = stripRoot(file2.originalname);
|
|
4290
|
-
const
|
|
4291
|
-
|
|
4394
|
+
const relativeKey = `${prefix}/${relativePath}`;
|
|
4395
|
+
const mimeType = mimeForHLSFile(relativePath) ?? file2.mimetype;
|
|
4396
|
+
const result = await provider.uploadRaw(file2.buffer, relativeKey, mimeType);
|
|
4397
|
+
return { file: file2, result };
|
|
4292
4398
|
}));
|
|
4293
|
-
const
|
|
4294
|
-
|
|
4295
|
-
|
|
4399
|
+
const m3u8 = uploaded.find((u) => u.file === m3u8File)?.result;
|
|
4400
|
+
if (!m3u8) {
|
|
4401
|
+
res.status(500).json({ error: "Failed to upload HLS playlist" });
|
|
4402
|
+
return;
|
|
4403
|
+
}
|
|
4296
4404
|
const id2 = createId();
|
|
4297
4405
|
const filename = m3u8File.originalname.split("/").pop() ?? m3u8File.originalname;
|
|
4298
4406
|
const alt2 = buildDefaultAlt(filename);
|
|
4299
4407
|
await pool_default.query(`INSERT INTO plank_media (id, filename, url, provider_key, mime_type, size, alt, folder_id, uploaded_by)
|
|
4300
|
-
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`, [
|
|
4301
|
-
|
|
4302
|
-
filename,
|
|
4303
|
-
m3u8Url,
|
|
4304
|
-
m3u8Key,
|
|
4305
|
-
m3u8File.mimetype,
|
|
4306
|
-
m3u8File.size,
|
|
4307
|
-
alt2,
|
|
4308
|
-
folderId,
|
|
4309
|
-
req.user.id
|
|
4310
|
-
]);
|
|
4311
|
-
res.status(201).json({ id: id2, url: m3u8Url, filename, alt: alt2, caption: null });
|
|
4408
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`, [id2, filename, m3u8.url, m3u8.key, m3u8Mime, m3u8File.size, alt2, folderId, req.user.id]);
|
|
4409
|
+
res.status(201).json({ id: id2, url: m3u8.url, filename, alt: alt2, caption: null });
|
|
4312
4410
|
return;
|
|
4313
4411
|
}
|
|
4314
4412
|
const file = files[0];
|
|
@@ -4345,7 +4443,13 @@ async function deleteMedia(req, res) {
|
|
|
4345
4443
|
return;
|
|
4346
4444
|
}
|
|
4347
4445
|
const provider = await getProvider();
|
|
4348
|
-
|
|
4446
|
+
const key = rows[0].provider_key;
|
|
4447
|
+
if (key.toLowerCase().endsWith(".m3u8")) {
|
|
4448
|
+
const bundlePrefix = key.substring(0, key.lastIndexOf("/"));
|
|
4449
|
+
await provider.deletePrefix(bundlePrefix);
|
|
4450
|
+
} else {
|
|
4451
|
+
await provider.delete(key);
|
|
4452
|
+
}
|
|
4349
4453
|
await pool_default.query("DELETE FROM plank_media WHERE id = $1", [id]);
|
|
4350
4454
|
res.status(204).end();
|
|
4351
4455
|
}
|
|
@@ -5227,7 +5331,8 @@ app.use(helmet({
|
|
|
5227
5331
|
directives: {
|
|
5228
5332
|
...helmet.contentSecurityPolicy.getDefaultDirectives(),
|
|
5229
5333
|
"img-src": ["'self'", "data:", "https:"],
|
|
5230
|
-
"connect-src": ["'self'", "https:"]
|
|
5334
|
+
"connect-src": ["'self'", "https:"],
|
|
5335
|
+
"media-src": ["'self'", "blob:", "https:"]
|
|
5231
5336
|
}
|
|
5232
5337
|
}
|
|
5233
5338
|
}));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plank-cms/plank",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.20.1",
|
|
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/core": "0.
|
|
59
|
-
"@plank-cms/
|
|
60
|
-
"@plank-cms/
|
|
58
|
+
"@plank-cms/core": "0.20.1",
|
|
59
|
+
"@plank-cms/schema": "0.20.1",
|
|
60
|
+
"@plank-cms/db": "0.20.1"
|
|
61
61
|
},
|
|
62
62
|
"scripts": {
|
|
63
63
|
"build": "tsup",
|