emdash 0.1.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/{apply-kC39ev1Z.mjs → apply-Bqoekfbe.mjs} +57 -10
- package/dist/apply-Bqoekfbe.mjs.map +1 -0
- package/dist/astro/index.d.mts +23 -9
- package/dist/astro/index.d.mts.map +1 -1
- package/dist/astro/index.mjs +90 -25
- package/dist/astro/index.mjs.map +1 -1
- package/dist/astro/middleware/auth.d.mts +3 -3
- package/dist/astro/middleware/auth.d.mts.map +1 -1
- package/dist/astro/middleware/auth.mjs +126 -55
- package/dist/astro/middleware/auth.mjs.map +1 -1
- package/dist/astro/middleware/redirect.mjs +2 -2
- package/dist/astro/middleware/request-context.mjs +1 -1
- package/dist/astro/middleware.d.mts.map +1 -1
- package/dist/astro/middleware.mjs +80 -41
- package/dist/astro/middleware.mjs.map +1 -1
- package/dist/astro/types.d.mts +27 -6
- package/dist/astro/types.d.mts.map +1 -1
- package/dist/{byline-CL847F26.mjs → byline-BGj9p9Ht.mjs} +53 -31
- package/dist/byline-BGj9p9Ht.mjs.map +1 -0
- package/dist/{bylines-C2a-2TGt.mjs → bylines-BihaoIDY.mjs} +12 -10
- package/dist/{bylines-C2a-2TGt.mjs.map → bylines-BihaoIDY.mjs.map} +1 -1
- package/dist/cli/index.mjs +17 -14
- package/dist/cli/index.mjs.map +1 -1
- package/dist/{config-CKE8p9xM.mjs → config-Cq8H0SfX.mjs} +2 -10
- package/dist/{config-CKE8p9xM.mjs.map → config-Cq8H0SfX.mjs.map} +1 -1
- package/dist/{content-D6C2WsZC.mjs → content-BsBoyj8G.mjs} +35 -5
- package/dist/content-BsBoyj8G.mjs.map +1 -0
- package/dist/db/index.mjs +2 -2
- package/dist/{default-Cyi4aAxu.mjs → default-WYlzADZL.mjs} +1 -1
- package/dist/{default-Cyi4aAxu.mjs.map → default-WYlzADZL.mjs.map} +1 -1
- package/dist/{dialect-helpers-B9uSp2GJ.mjs → dialect-helpers-DhTzaUxP.mjs} +4 -1
- package/dist/dialect-helpers-DhTzaUxP.mjs.map +1 -0
- package/dist/{error-Cxz0tQeO.mjs → error-DrxtnGPg.mjs} +1 -1
- package/dist/{error-Cxz0tQeO.mjs.map → error-DrxtnGPg.mjs.map} +1 -1
- package/dist/{index-CLBc4gw-.d.mts → index-Cff7AimE.d.mts} +77 -15
- package/dist/index-Cff7AimE.d.mts.map +1 -0
- package/dist/index.d.mts +6 -6
- package/dist/index.mjs +19 -19
- package/dist/{load-yOOlckBj.mjs → load-Veizk2cT.mjs} +1 -1
- package/dist/{load-yOOlckBj.mjs.map → load-Veizk2cT.mjs.map} +1 -1
- package/dist/{loader-fz8Q_3EO.mjs → loader-BmYdf3Dr.mjs} +4 -2
- package/dist/loader-BmYdf3Dr.mjs.map +1 -0
- package/dist/{manifest-schema-CL8DWO9b.mjs → manifest-schema-CuMio1A9.mjs} +1 -1
- package/dist/{manifest-schema-CL8DWO9b.mjs.map → manifest-schema-CuMio1A9.mjs.map} +1 -1
- package/dist/media/local-runtime.d.mts +4 -4
- package/dist/page/index.d.mts +10 -1
- package/dist/page/index.d.mts.map +1 -1
- package/dist/page/index.mjs +8 -4
- package/dist/page/index.mjs.map +1 -1
- package/dist/plugins/adapt-sandbox-entry.d.mts +3 -3
- package/dist/plugins/adapt-sandbox-entry.mjs +1 -1
- package/dist/{query-BVYN0PJ6.mjs → query-sesiOndV.mjs} +20 -8
- package/dist/{query-BVYN0PJ6.mjs.map → query-sesiOndV.mjs.map} +1 -1
- package/dist/{redirect-DIfIni3r.mjs → redirect-DUAk-Yl_.mjs} +9 -2
- package/dist/redirect-DUAk-Yl_.mjs.map +1 -0
- package/dist/{registry-BNYQKX_d.mjs → registry-DU18yVo0.mjs} +14 -4
- package/dist/registry-DU18yVo0.mjs.map +1 -0
- package/dist/{runner-BraqvGYk.mjs → runner-Biufrii2.mjs} +157 -132
- package/dist/runner-Biufrii2.mjs.map +1 -0
- package/dist/runner-EAtf0ZIe.d.mts.map +1 -1
- package/dist/runtime.d.mts +3 -3
- package/dist/runtime.mjs +2 -2
- package/dist/{search-C1gg67nN.mjs → search-BXB-jfu2.mjs} +241 -109
- package/dist/search-BXB-jfu2.mjs.map +1 -0
- package/dist/seed/index.d.mts +1 -1
- package/dist/seed/index.mjs +10 -10
- package/dist/seo/index.d.mts +1 -1
- package/dist/storage/local.d.mts +1 -1
- package/dist/storage/local.mjs +1 -1
- package/dist/storage/s3.d.mts +11 -3
- package/dist/storage/s3.d.mts.map +1 -1
- package/dist/storage/s3.mjs +76 -15
- package/dist/storage/s3.mjs.map +1 -1
- package/dist/{tokens-DpgrkrXK.mjs → tokens-DrB-W6Q-.mjs} +1 -1
- package/dist/{tokens-DpgrkrXK.mjs.map → tokens-DrB-W6Q-.mjs.map} +1 -1
- package/dist/{types-BRuPJGdV.d.mts → types-BbsYgi_R.d.mts} +3 -1
- package/dist/types-BbsYgi_R.d.mts.map +1 -0
- package/dist/{types-CUBbjgmP.mjs → types-Bec-r_3_.mjs} +1 -1
- package/dist/types-Bec-r_3_.mjs.map +1 -0
- package/dist/{types-DaNLHo_T.d.mts → types-C1-PVaS_.d.mts} +14 -6
- package/dist/types-C1-PVaS_.d.mts.map +1 -0
- package/dist/types-CMMN0pNg.mjs.map +1 -1
- package/dist/{types-BQo5JS0J.d.mts → types-CaKte3hR.d.mts} +78 -6
- package/dist/types-CaKte3hR.d.mts.map +1 -0
- package/dist/{types-CiA5Gac0.mjs → types-DuNbGKjF.mjs} +1 -1
- package/dist/{types-CiA5Gac0.mjs.map → types-DuNbGKjF.mjs.map} +1 -1
- package/dist/{validate-_rsF-Dx_.mjs → validate-CXnRKfJK.mjs} +2 -2
- package/dist/{validate-_rsF-Dx_.mjs.map → validate-CXnRKfJK.mjs.map} +1 -1
- package/dist/{validate-CqRJb_xU.mjs → validate-VPnKoIzW.mjs} +11 -11
- package/dist/{validate-CqRJb_xU.mjs.map → validate-VPnKoIzW.mjs.map} +1 -1
- package/dist/{validate-HtxZeaBi.d.mts → validate-bfg9OR6N.d.mts} +2 -2
- package/dist/{validate-HtxZeaBi.d.mts.map → validate-bfg9OR6N.d.mts.map} +1 -1
- package/dist/version-REAapfsU.mjs +7 -0
- package/dist/version-REAapfsU.mjs.map +1 -0
- package/package.json +6 -6
- package/src/api/csrf.ts +13 -2
- package/src/api/handlers/content.ts +7 -0
- package/src/api/handlers/dashboard.ts +4 -8
- package/src/api/handlers/device-flow.ts +55 -37
- package/src/api/handlers/index.ts +6 -1
- package/src/api/handlers/redirects.ts +95 -3
- package/src/api/handlers/seo.ts +48 -21
- package/src/api/public-url.ts +84 -0
- package/src/api/schemas/content.ts +2 -2
- package/src/api/schemas/menus.ts +12 -2
- package/src/api/schemas/redirects.ts +1 -0
- package/src/astro/integration/index.ts +30 -7
- package/src/astro/integration/routes.ts +13 -2
- package/src/astro/integration/runtime.ts +7 -5
- package/src/astro/integration/vite-config.ts +55 -9
- package/src/astro/middleware/auth.ts +60 -56
- package/src/astro/middleware/csp.ts +25 -0
- package/src/astro/middleware.ts +31 -3
- package/src/astro/routes/PluginRegistry.tsx +8 -2
- package/src/astro/routes/admin.astro +7 -2
- package/src/astro/routes/api/admin/users/[id]/disable.ts +18 -12
- package/src/astro/routes/api/admin/users/[id]/index.ts +26 -5
- package/src/astro/routes/api/auth/invite/complete.ts +3 -2
- package/src/astro/routes/api/auth/oauth/[provider]/callback.ts +2 -1
- package/src/astro/routes/api/auth/oauth/[provider].ts +2 -1
- package/src/astro/routes/api/auth/passkey/options.ts +3 -2
- package/src/astro/routes/api/auth/passkey/register/options.ts +3 -2
- package/src/astro/routes/api/auth/passkey/register/verify.ts +3 -2
- package/src/astro/routes/api/auth/passkey/verify.ts +3 -2
- package/src/astro/routes/api/auth/signup/complete.ts +3 -2
- package/src/astro/routes/api/comments/[collection]/[contentId]/index.ts +2 -0
- package/src/astro/routes/api/content/[collection]/index.ts +31 -3
- package/src/astro/routes/api/import/wordpress/execute.ts +9 -0
- package/src/astro/routes/api/import/wordpress/rewrite-urls.ts +2 -0
- package/src/astro/routes/api/import/wordpress-plugin/execute.ts +10 -0
- package/src/astro/routes/api/manifest.ts +4 -1
- package/src/astro/routes/api/media/providers/[providerId]/[itemId].ts +7 -2
- package/src/astro/routes/api/oauth/authorize.ts +12 -7
- package/src/astro/routes/api/oauth/device/code.ts +5 -1
- package/src/astro/routes/api/setup/admin-verify.ts +3 -2
- package/src/astro/routes/api/setup/admin.ts +3 -2
- package/src/astro/routes/api/setup/dev-bypass.ts +2 -1
- package/src/astro/routes/api/setup/index.ts +3 -2
- package/src/astro/routes/api/snapshot.ts +2 -1
- package/src/astro/routes/api/themes/preview.ts +2 -1
- package/src/astro/routes/api/well-known/auth.ts +1 -0
- package/src/astro/routes/api/well-known/oauth-authorization-server.ts +3 -2
- package/src/astro/routes/api/well-known/oauth-protected-resource.ts +3 -2
- package/src/astro/routes/robots.txt.ts +5 -1
- package/src/astro/routes/sitemap-[collection].xml.ts +104 -0
- package/src/astro/routes/sitemap.xml.ts +18 -23
- package/src/astro/storage/adapters.ts +19 -5
- package/src/astro/storage/types.ts +12 -4
- package/src/astro/types.ts +28 -1
- package/src/auth/passkey-config.ts +6 -10
- package/src/bylines/index.ts +13 -10
- package/src/cli/commands/login.ts +5 -2
- package/src/components/InlinePortableTextEditor.tsx +5 -3
- package/src/content/converters/portable-text-to-prosemirror.ts +50 -2
- package/src/database/dialect-helpers.ts +3 -0
- package/src/database/migrations/034_published_at_index.ts +29 -0
- package/src/database/migrations/runner.ts +2 -0
- package/src/database/repositories/byline.ts +48 -42
- package/src/database/repositories/content.ts +28 -1
- package/src/database/repositories/options.ts +9 -3
- package/src/database/repositories/redirect.ts +13 -0
- package/src/database/repositories/seo.ts +34 -17
- package/src/database/repositories/types.ts +2 -0
- package/src/database/validate.ts +10 -10
- package/src/emdash-runtime.ts +66 -19
- package/src/import/index.ts +1 -1
- package/src/import/sources/wxr.ts +45 -2
- package/src/index.ts +10 -1
- package/src/loader.ts +2 -0
- package/src/mcp/server.ts +85 -5
- package/src/menus/index.ts +6 -1
- package/src/page/context.ts +13 -1
- package/src/page/jsonld.ts +10 -6
- package/src/page/seo-contributions.ts +1 -1
- package/src/plugins/context.ts +145 -35
- package/src/plugins/manager.ts +12 -0
- package/src/plugins/types.ts +80 -4
- package/src/query.ts +18 -0
- package/src/redirects/loops.ts +318 -0
- package/src/schema/registry.ts +8 -0
- package/src/search/fts-manager.ts +4 -0
- package/src/settings/index.ts +64 -0
- package/src/storage/s3.ts +94 -25
- package/src/storage/types.ts +13 -5
- package/src/utils/chunks.ts +17 -0
- package/src/utils/slugify.ts +11 -0
- package/src/version.ts +12 -0
- package/dist/apply-kC39ev1Z.mjs.map +0 -1
- package/dist/byline-CL847F26.mjs.map +0 -1
- package/dist/content-D6C2WsZC.mjs.map +0 -1
- package/dist/dialect-helpers-B9uSp2GJ.mjs.map +0 -1
- package/dist/index-CLBc4gw-.d.mts.map +0 -1
- package/dist/loader-fz8Q_3EO.mjs.map +0 -1
- package/dist/redirect-DIfIni3r.mjs.map +0 -1
- package/dist/registry-BNYQKX_d.mjs.map +0 -1
- package/dist/runner-BraqvGYk.mjs.map +0 -1
- package/dist/search-C1gg67nN.mjs.map +0 -1
- package/dist/types-BQo5JS0J.d.mts.map +0 -1
- package/dist/types-BRuPJGdV.d.mts.map +0 -1
- package/dist/types-CUBbjgmP.mjs.map +0 -1
- package/dist/types-DaNLHo_T.d.mts.map +0 -1
- /package/src/astro/routes/api/media/file/{[key].ts → [...key].ts} +0 -0
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { n as validateJsonFieldName, r as validatePluginIdentifier, t as validateIdentifier } from "./validate-VPnKoIzW.mjs";
|
|
2
|
+
import { o as jsonExtractExpr } from "./dialect-helpers-DhTzaUxP.mjs";
|
|
3
|
+
import { a as slugify, r as RevisionRepository, t as ContentRepository } from "./content-BsBoyj8G.mjs";
|
|
4
4
|
import { r as encodeBase64, t as decodeBase64 } from "./base64-MBPo9ozB.mjs";
|
|
5
5
|
import { n as decodeCursor, r as encodeCursor, t as EmDashValidationError } from "./types-CMMN0pNg.mjs";
|
|
6
6
|
import { t as MediaRepository } from "./media-DqHVh136.mjs";
|
|
7
|
-
import { a as stripCredentialHeaders, i as ssrfSafeFetch, o as validateExternalUrl, r as SsrfError
|
|
8
|
-
import { a as withTransaction, i as FTSManager, n as SchemaRegistry } from "./registry-
|
|
9
|
-
import { t as RedirectRepository } from "./redirect-
|
|
10
|
-
import { t as BylineRepository } from "./byline-
|
|
11
|
-
import {
|
|
12
|
-
import { n as getDb } from "./loader-
|
|
13
|
-
import { i as pluginManifestSchema } from "./manifest-schema-
|
|
14
|
-
import { t as generatePreviewToken } from "./tokens-
|
|
7
|
+
import { a as stripCredentialHeaders, f as OptionsRepository, i as ssrfSafeFetch, o as validateExternalUrl, r as SsrfError } from "./apply-Bqoekfbe.mjs";
|
|
8
|
+
import { a as withTransaction, i as FTSManager, n as SchemaRegistry } from "./registry-DU18yVo0.mjs";
|
|
9
|
+
import { t as RedirectRepository } from "./redirect-DUAk-Yl_.mjs";
|
|
10
|
+
import { n as SQL_BATCH_SIZE, r as chunks, t as BylineRepository } from "./byline-BGj9p9Ht.mjs";
|
|
11
|
+
import { r as isI18nEnabled } from "./config-Cq8H0SfX.mjs";
|
|
12
|
+
import { n as getDb } from "./loader-BmYdf3Dr.mjs";
|
|
13
|
+
import { i as pluginManifestSchema } from "./manifest-schema-CuMio1A9.mjs";
|
|
14
|
+
import { t as generatePreviewToken } from "./tokens-DrB-W6Q-.mjs";
|
|
15
15
|
import { sql } from "kysely";
|
|
16
16
|
import { ulid } from "ulidx";
|
|
17
17
|
import { z } from "astro/zod";
|
|
@@ -827,6 +827,13 @@ var SeoRepository = class {
|
|
|
827
827
|
this.db = db;
|
|
828
828
|
}
|
|
829
829
|
/**
|
|
830
|
+
* Check whether a collection has SEO enabled (`has_seo = 1`).
|
|
831
|
+
* Returns `false` if the collection does not exist.
|
|
832
|
+
*/
|
|
833
|
+
async isEnabled(collection) {
|
|
834
|
+
return (await this.db.selectFrom("_emdash_collections").select("has_seo").where("slug", "=", collection).executeTakeFirst())?.has_seo === 1;
|
|
835
|
+
}
|
|
836
|
+
/**
|
|
830
837
|
* Get SEO data for a content item. Returns null defaults if no row exists.
|
|
831
838
|
*/
|
|
832
839
|
async get(collection, contentId) {
|
|
@@ -841,24 +848,27 @@ var SeoRepository = class {
|
|
|
841
848
|
};
|
|
842
849
|
}
|
|
843
850
|
/**
|
|
844
|
-
* Get SEO data for multiple content items
|
|
851
|
+
* Get SEO data for multiple content items.
|
|
845
852
|
* Returns a Map keyed by content_id. Items without SEO rows get defaults.
|
|
853
|
+
*
|
|
854
|
+
* Chunks the `content_id IN (…)` clause so the total bound-parameter count
|
|
855
|
+
* per statement (ids + the `collection = ?` filter) stays within Cloudflare
|
|
856
|
+
* D1's 100-variable limit regardless of how many content items are passed.
|
|
846
857
|
*/
|
|
847
858
|
async getMany(collection, contentIds) {
|
|
848
859
|
const result = /* @__PURE__ */ new Map();
|
|
849
860
|
if (contentIds.length === 0) return result;
|
|
850
|
-
const
|
|
851
|
-
const
|
|
852
|
-
for (const
|
|
853
|
-
const
|
|
854
|
-
|
|
861
|
+
for (const id of contentIds) result.set(id, { ...SEO_DEFAULTS$1 });
|
|
862
|
+
const uniqueContentIds = [...new Set(contentIds)];
|
|
863
|
+
for (const chunk of chunks(uniqueContentIds, SQL_BATCH_SIZE)) {
|
|
864
|
+
const rows = await this.db.selectFrom("_emdash_seo").selectAll().where("collection", "=", collection).where("content_id", "in", chunk).execute();
|
|
865
|
+
for (const row of rows) result.set(row.content_id, {
|
|
855
866
|
title: row.seo_title ?? null,
|
|
856
867
|
description: row.seo_description ?? null,
|
|
857
868
|
image: row.seo_image ?? null,
|
|
858
869
|
canonical: row.seo_canonical ?? null,
|
|
859
870
|
noIndex: row.seo_no_index === 1
|
|
860
871
|
});
|
|
861
|
-
else result.set(id, { ...SEO_DEFAULTS$1 });
|
|
862
872
|
}
|
|
863
873
|
return result;
|
|
864
874
|
}
|
|
@@ -1220,7 +1230,9 @@ async function handleContentCreate(db, collection, body) {
|
|
|
1220
1230
|
status: body.status || "draft",
|
|
1221
1231
|
authorId: body.authorId,
|
|
1222
1232
|
locale: body.locale,
|
|
1223
|
-
translationOf: body.translationOf
|
|
1233
|
+
translationOf: body.translationOf,
|
|
1234
|
+
createdAt: body.createdAt,
|
|
1235
|
+
publishedAt: body.publishedAt
|
|
1224
1236
|
});
|
|
1225
1237
|
if (body.bylines !== void 0) {
|
|
1226
1238
|
await bylineRepo.setContentBylines(collection, created.id, body.bylines);
|
|
@@ -1454,6 +1466,7 @@ async function handleContentPermanentDelete(db, collection, id) {
|
|
|
1454
1466
|
if (wasDeleted) {
|
|
1455
1467
|
await new SeoRepository(trx).delete(collection, resolvedId);
|
|
1456
1468
|
await new CommentRepository(trx).deleteByContent(collection, resolvedId);
|
|
1469
|
+
await new RevisionRepository(trx).deleteByEntry(collection, resolvedId);
|
|
1457
1470
|
}
|
|
1458
1471
|
return wasDeleted;
|
|
1459
1472
|
})) return {
|
|
@@ -2629,7 +2642,7 @@ const contentListQuery = cursorPaginationQuery.extend({
|
|
|
2629
2642
|
const contentCreateBody = z$1.object({
|
|
2630
2643
|
data: z$1.record(z$1.string(), z$1.unknown()),
|
|
2631
2644
|
slug: z$1.string().nullish(),
|
|
2632
|
-
status: z$1.
|
|
2645
|
+
status: z$1.enum(["draft"]).optional(),
|
|
2633
2646
|
bylines: z$1.array(contentBylineInputSchema).optional(),
|
|
2634
2647
|
locale: localeCode.optional(),
|
|
2635
2648
|
translationOf: z$1.string().optional(),
|
|
@@ -2638,7 +2651,7 @@ const contentCreateBody = z$1.object({
|
|
|
2638
2651
|
const contentUpdateBody = z$1.object({
|
|
2639
2652
|
data: z$1.record(z$1.string(), z$1.unknown()).optional(),
|
|
2640
2653
|
slug: z$1.string().nullish(),
|
|
2641
|
-
status: z$1.
|
|
2654
|
+
status: z$1.enum(["draft"]).optional(),
|
|
2642
2655
|
authorId: z$1.string().nullish(),
|
|
2643
2656
|
bylines: z$1.array(contentBylineInputSchema).optional(),
|
|
2644
2657
|
_rev: z$1.string().optional().meta({ description: "Opaque revision token for optimistic concurrency" }),
|
|
@@ -3111,9 +3124,58 @@ const passkeyRegisterVerifyBody = z$1.object({
|
|
|
3111
3124
|
const passkeyRenameBody = z$1.object({ name: z$1.string().min(1) }).meta({ id: "PasskeyRenameBody" });
|
|
3112
3125
|
const authMeActionBody = z$1.object({ action: z$1.string().min(1) }).meta({ id: "AuthMeActionBody" });
|
|
3113
3126
|
|
|
3127
|
+
//#endregion
|
|
3128
|
+
//#region src/utils/url.ts
|
|
3129
|
+
/**
|
|
3130
|
+
* URL scheme validation utilities
|
|
3131
|
+
*
|
|
3132
|
+
* Prevents XSS via dangerous URL schemes (javascript:, data:, vbscript:, etc.)
|
|
3133
|
+
* by allowlisting known-safe schemes before rendering into href attributes.
|
|
3134
|
+
*/
|
|
3135
|
+
/**
|
|
3136
|
+
* Matches URLs that are safe to render in href attributes.
|
|
3137
|
+
*
|
|
3138
|
+
* Allowed:
|
|
3139
|
+
* - http:// and https://
|
|
3140
|
+
* - mailto: and tel:
|
|
3141
|
+
* - Relative paths (starting with /)
|
|
3142
|
+
* - Fragment links (starting with #)
|
|
3143
|
+
* - Protocol-relative URLs are NOT allowed (starting with //) as they can
|
|
3144
|
+
* redirect to attacker-controlled hosts.
|
|
3145
|
+
*/
|
|
3146
|
+
const SAFE_URL_SCHEME_RE = /^(https?:|mailto:|tel:|\/(?!\/)|#)/i;
|
|
3147
|
+
/**
|
|
3148
|
+
* Returns the URL unchanged if it uses a safe scheme, otherwise returns "#".
|
|
3149
|
+
*
|
|
3150
|
+
* Use this at the render layer as the primary defense against XSS via
|
|
3151
|
+
* dangerous URL schemes like `javascript:`, `data:`, or `vbscript:`.
|
|
3152
|
+
*
|
|
3153
|
+
* @example
|
|
3154
|
+
* ```ts
|
|
3155
|
+
* sanitizeHref("https://example.com") // "https://example.com"
|
|
3156
|
+
* sanitizeHref("/about") // "/about"
|
|
3157
|
+
* sanitizeHref("#section") // "#section"
|
|
3158
|
+
* sanitizeHref("mailto:a@b.com") // "mailto:a@b.com"
|
|
3159
|
+
* sanitizeHref("javascript:alert(1)") // "#"
|
|
3160
|
+
* sanitizeHref("data:text/html,<script>") // "#"
|
|
3161
|
+
* sanitizeHref("") // "#"
|
|
3162
|
+
* ```
|
|
3163
|
+
*/
|
|
3164
|
+
function sanitizeHref(url) {
|
|
3165
|
+
if (!url) return "#";
|
|
3166
|
+
return SAFE_URL_SCHEME_RE.test(url) ? url : "#";
|
|
3167
|
+
}
|
|
3168
|
+
/**
|
|
3169
|
+
* Returns true if the URL uses a safe scheme for rendering in href attributes.
|
|
3170
|
+
*/
|
|
3171
|
+
function isSafeHref(url) {
|
|
3172
|
+
return SAFE_URL_SCHEME_RE.test(url);
|
|
3173
|
+
}
|
|
3174
|
+
|
|
3114
3175
|
//#endregion
|
|
3115
3176
|
//#region src/api/schemas/menus.ts
|
|
3116
3177
|
const menuItemType = z$1.string().min(1);
|
|
3178
|
+
const safeHref = z$1.string().trim().refine(isSafeHref, "URL must use http, https, mailto, tel, a relative path, or a fragment identifier");
|
|
3117
3179
|
const createMenuBody = z$1.object({
|
|
3118
3180
|
name: z$1.string().min(1),
|
|
3119
3181
|
label: z$1.string().min(1)
|
|
@@ -3124,7 +3186,7 @@ const createMenuItemBody = z$1.object({
|
|
|
3124
3186
|
label: z$1.string().min(1),
|
|
3125
3187
|
referenceCollection: z$1.string().optional(),
|
|
3126
3188
|
referenceId: z$1.string().optional(),
|
|
3127
|
-
customUrl:
|
|
3189
|
+
customUrl: safeHref.optional(),
|
|
3128
3190
|
target: z$1.string().optional(),
|
|
3129
3191
|
titleAttr: z$1.string().optional(),
|
|
3130
3192
|
cssClasses: z$1.string().optional(),
|
|
@@ -3133,7 +3195,7 @@ const createMenuItemBody = z$1.object({
|
|
|
3133
3195
|
}).meta({ id: "CreateMenuItemBody" });
|
|
3134
3196
|
const updateMenuItemBody = z$1.object({
|
|
3135
3197
|
label: z$1.string().min(1).optional(),
|
|
3136
|
-
customUrl:
|
|
3198
|
+
customUrl: safeHref.optional(),
|
|
3137
3199
|
target: z$1.string().optional(),
|
|
3138
3200
|
titleAttr: z$1.string().optional(),
|
|
3139
3201
|
cssClasses: z$1.string().optional(),
|
|
@@ -3600,7 +3662,8 @@ const redirectSchema = z$1.object({
|
|
|
3600
3662
|
}).meta({ id: "Redirect" });
|
|
3601
3663
|
const redirectListResponseSchema = z$1.object({
|
|
3602
3664
|
items: z$1.array(redirectSchema),
|
|
3603
|
-
nextCursor: z$1.string().optional()
|
|
3665
|
+
nextCursor: z$1.string().optional(),
|
|
3666
|
+
loopRedirectIds: z$1.array(z$1.string()).optional()
|
|
3604
3667
|
}).meta({ id: "RedirectListResponse" });
|
|
3605
3668
|
const notFoundEntrySchema = z$1.object({
|
|
3606
3669
|
id: z$1.string(),
|
|
@@ -3918,10 +3981,13 @@ function isTextBlock(block) {
|
|
|
3918
3981
|
return block._type === "block";
|
|
3919
3982
|
}
|
|
3920
3983
|
/**
|
|
3921
|
-
* Type guard for image blocks
|
|
3984
|
+
* Type guard for image blocks.
|
|
3985
|
+
* Checks both `_type` and that `asset` is a valid object — image blocks
|
|
3986
|
+
* without an `asset` wrapper (e.g. `{ _type: "image", url: "..." }`) are
|
|
3987
|
+
* malformed and should not be cast to `PortableTextImageBlock`.
|
|
3922
3988
|
*/
|
|
3923
3989
|
function isImageBlock(block) {
|
|
3924
|
-
return block._type === "image";
|
|
3990
|
+
return block._type === "image" && "asset" in block && typeof block.asset === "object" && block.asset !== null;
|
|
3925
3991
|
}
|
|
3926
3992
|
/**
|
|
3927
3993
|
* Type guard for code blocks
|
|
@@ -3935,6 +4001,7 @@ function isCodeBlock(block) {
|
|
|
3935
4001
|
function convertBlock(block) {
|
|
3936
4002
|
if (isTextBlock(block)) return convertTextBlock(block);
|
|
3937
4003
|
if (isImageBlock(block)) return convertImage(block);
|
|
4004
|
+
if (block._type === "image") return convertMalformedImage(block);
|
|
3938
4005
|
if (isCodeBlock(block)) return convertCodeBlock(block);
|
|
3939
4006
|
if (block._type === "break") return { type: "horizontalRule" };
|
|
3940
4007
|
return {
|
|
@@ -4119,6 +4186,27 @@ function convertImage(block) {
|
|
|
4119
4186
|
};
|
|
4120
4187
|
}
|
|
4121
4188
|
/**
|
|
4189
|
+
* Convert a malformed image block (missing `asset` wrapper) to ProseMirror.
|
|
4190
|
+
* Handles blocks like `{ _type: "image", url: "...", alt: "..." }` that may
|
|
4191
|
+
* originate from migrations or third-party imports.
|
|
4192
|
+
*/
|
|
4193
|
+
function convertMalformedImage(block) {
|
|
4194
|
+
return {
|
|
4195
|
+
type: "image",
|
|
4196
|
+
attrs: {
|
|
4197
|
+
src: "url" in block && typeof block.url === "string" ? block.url : "",
|
|
4198
|
+
alt: "alt" in block && typeof block.alt === "string" ? block.alt : "",
|
|
4199
|
+
title: "caption" in block && typeof block.caption === "string" ? block.caption : "",
|
|
4200
|
+
mediaId: void 0,
|
|
4201
|
+
provider: void 0,
|
|
4202
|
+
width: "width" in block && typeof block.width === "number" ? block.width : void 0,
|
|
4203
|
+
height: "height" in block && typeof block.height === "number" ? block.height : void 0,
|
|
4204
|
+
displayWidth: "displayWidth" in block && typeof block.displayWidth === "number" ? block.displayWidth : void 0,
|
|
4205
|
+
displayHeight: "displayHeight" in block && typeof block.displayHeight === "number" ? block.displayHeight : void 0
|
|
4206
|
+
}
|
|
4207
|
+
};
|
|
4208
|
+
}
|
|
4209
|
+
/**
|
|
4122
4210
|
* Convert code block to ProseMirror
|
|
4123
4211
|
*/
|
|
4124
4212
|
function convertCodeBlock(block) {
|
|
@@ -4132,54 +4220,6 @@ function convertCodeBlock(block) {
|
|
|
4132
4220
|
};
|
|
4133
4221
|
}
|
|
4134
4222
|
|
|
4135
|
-
//#endregion
|
|
4136
|
-
//#region src/utils/url.ts
|
|
4137
|
-
/**
|
|
4138
|
-
* URL scheme validation utilities
|
|
4139
|
-
*
|
|
4140
|
-
* Prevents XSS via dangerous URL schemes (javascript:, data:, vbscript:, etc.)
|
|
4141
|
-
* by allowlisting known-safe schemes before rendering into href attributes.
|
|
4142
|
-
*/
|
|
4143
|
-
/**
|
|
4144
|
-
* Matches URLs that are safe to render in href attributes.
|
|
4145
|
-
*
|
|
4146
|
-
* Allowed:
|
|
4147
|
-
* - http:// and https://
|
|
4148
|
-
* - mailto: and tel:
|
|
4149
|
-
* - Relative paths (starting with /)
|
|
4150
|
-
* - Fragment links (starting with #)
|
|
4151
|
-
* - Protocol-relative URLs are NOT allowed (starting with //) as they can
|
|
4152
|
-
* redirect to attacker-controlled hosts.
|
|
4153
|
-
*/
|
|
4154
|
-
const SAFE_URL_SCHEME_RE = /^(https?:|mailto:|tel:|\/(?!\/)|#)/i;
|
|
4155
|
-
/**
|
|
4156
|
-
* Returns the URL unchanged if it uses a safe scheme, otherwise returns "#".
|
|
4157
|
-
*
|
|
4158
|
-
* Use this at the render layer as the primary defense against XSS via
|
|
4159
|
-
* dangerous URL schemes like `javascript:`, `data:`, or `vbscript:`.
|
|
4160
|
-
*
|
|
4161
|
-
* @example
|
|
4162
|
-
* ```ts
|
|
4163
|
-
* sanitizeHref("https://example.com") // "https://example.com"
|
|
4164
|
-
* sanitizeHref("/about") // "/about"
|
|
4165
|
-
* sanitizeHref("#section") // "#section"
|
|
4166
|
-
* sanitizeHref("mailto:a@b.com") // "mailto:a@b.com"
|
|
4167
|
-
* sanitizeHref("javascript:alert(1)") // "#"
|
|
4168
|
-
* sanitizeHref("data:text/html,<script>") // "#"
|
|
4169
|
-
* sanitizeHref("") // "#"
|
|
4170
|
-
* ```
|
|
4171
|
-
*/
|
|
4172
|
-
function sanitizeHref(url) {
|
|
4173
|
-
if (!url) return "#";
|
|
4174
|
-
return SAFE_URL_SCHEME_RE.test(url) ? url : "#";
|
|
4175
|
-
}
|
|
4176
|
-
/**
|
|
4177
|
-
* Returns true if the URL uses a safe scheme for rendering in href attributes.
|
|
4178
|
-
*/
|
|
4179
|
-
function isSafeHref(url) {
|
|
4180
|
-
return SAFE_URL_SCHEME_RE.test(url);
|
|
4181
|
-
}
|
|
4182
|
-
|
|
4183
4223
|
//#endregion
|
|
4184
4224
|
//#region src/cli/wxr/parser.ts
|
|
4185
4225
|
const PHP_SERIALIZED_STRING_PATTERN = /s:\d+:"([^"]+)"/g;
|
|
@@ -5327,21 +5367,45 @@ function createStorageAccess(db, pluginId, storageConfig) {
|
|
|
5327
5367
|
return storage;
|
|
5328
5368
|
}
|
|
5329
5369
|
/**
|
|
5370
|
+
* Extract `seo` from a plugin-supplied content write input and return both
|
|
5371
|
+
* parts. Mutates nothing — returns a new field map without the `seo` key.
|
|
5372
|
+
*/
|
|
5373
|
+
function splitSeoFromInput(input) {
|
|
5374
|
+
const { seo, ...fields } = input;
|
|
5375
|
+
if (seo !== void 0 && (seo === null || typeof seo !== "object" || Array.isArray(seo))) throw new Error("content.seo must be an object");
|
|
5376
|
+
return {
|
|
5377
|
+
fields,
|
|
5378
|
+
seo
|
|
5379
|
+
};
|
|
5380
|
+
}
|
|
5381
|
+
/**
|
|
5382
|
+
* Reject writing SEO to a collection that does not have it enabled.
|
|
5383
|
+
* Matches the REST API behavior (VALIDATION_ERROR).
|
|
5384
|
+
*/
|
|
5385
|
+
async function assertSeoEnabled(seoRepo, collection, seo) {
|
|
5386
|
+
const hasSeo = await seoRepo.isEnabled(collection);
|
|
5387
|
+
if (seo !== void 0 && !hasSeo) throw new Error(`Collection "${collection}" does not have SEO enabled. Remove the seo field or enable SEO on this collection.`);
|
|
5388
|
+
return hasSeo;
|
|
5389
|
+
}
|
|
5390
|
+
/**
|
|
5330
5391
|
* Create read-only content access
|
|
5331
5392
|
*/
|
|
5332
5393
|
function createContentAccess(db) {
|
|
5333
5394
|
const contentRepo = new ContentRepository(db);
|
|
5395
|
+
const seoRepo = new SeoRepository(db);
|
|
5334
5396
|
return {
|
|
5335
5397
|
async get(collection, id) {
|
|
5336
5398
|
const item = await contentRepo.findById(collection, id);
|
|
5337
5399
|
if (!item) return null;
|
|
5338
|
-
|
|
5400
|
+
const result = {
|
|
5339
5401
|
id: item.id,
|
|
5340
5402
|
type: item.type,
|
|
5341
5403
|
data: item.data,
|
|
5342
5404
|
createdAt: item.createdAt,
|
|
5343
5405
|
updatedAt: item.updatedAt
|
|
5344
5406
|
};
|
|
5407
|
+
if (await seoRepo.isEnabled(collection)) result.seo = await seoRepo.get(collection, item.id);
|
|
5408
|
+
return result;
|
|
5345
5409
|
},
|
|
5346
5410
|
async list(collection, options) {
|
|
5347
5411
|
let orderBy;
|
|
@@ -5357,14 +5421,22 @@ function createContentAccess(db) {
|
|
|
5357
5421
|
cursor: options?.cursor,
|
|
5358
5422
|
orderBy
|
|
5359
5423
|
});
|
|
5424
|
+
const items = result.items.map((item) => ({
|
|
5425
|
+
id: item.id,
|
|
5426
|
+
type: item.type,
|
|
5427
|
+
data: item.data,
|
|
5428
|
+
createdAt: item.createdAt,
|
|
5429
|
+
updatedAt: item.updatedAt
|
|
5430
|
+
}));
|
|
5431
|
+
if (items.length > 0 && await seoRepo.isEnabled(collection)) {
|
|
5432
|
+
const seoMap = await seoRepo.getMany(collection, items.map((i) => i.id));
|
|
5433
|
+
for (const item of items) {
|
|
5434
|
+
const seo = seoMap.get(item.id);
|
|
5435
|
+
if (seo) item.seo = seo;
|
|
5436
|
+
}
|
|
5437
|
+
}
|
|
5360
5438
|
return {
|
|
5361
|
-
items
|
|
5362
|
-
id: item.id,
|
|
5363
|
-
type: item.type,
|
|
5364
|
-
data: item.data,
|
|
5365
|
-
createdAt: item.createdAt,
|
|
5366
|
-
updatedAt: item.updatedAt
|
|
5367
|
-
})),
|
|
5439
|
+
items,
|
|
5368
5440
|
cursor: result.nextCursor,
|
|
5369
5441
|
hasMore: !!result.nextCursor
|
|
5370
5442
|
};
|
|
@@ -5372,37 +5444,62 @@ function createContentAccess(db) {
|
|
|
5372
5444
|
};
|
|
5373
5445
|
}
|
|
5374
5446
|
/**
|
|
5375
|
-
* Create full content access with write operations
|
|
5447
|
+
* Create full content access with write operations.
|
|
5448
|
+
*
|
|
5449
|
+
* `create` and `update` accept a reserved `seo` key in their `data`
|
|
5450
|
+
* argument. When present, it is routed to the core SEO panel
|
|
5451
|
+
* (`_emdash_seo`) via `SeoRepository.upsert`, in the same transaction as
|
|
5452
|
+
* the content write. The returned `ContentItem.seo` reflects the resulting
|
|
5453
|
+
* SEO state for SEO-enabled collections.
|
|
5376
5454
|
*/
|
|
5377
5455
|
function createContentAccessWithWrite(db) {
|
|
5378
|
-
const contentRepo = new ContentRepository(db);
|
|
5379
5456
|
return {
|
|
5380
5457
|
...createContentAccess(db),
|
|
5381
5458
|
async create(collection, data) {
|
|
5382
|
-
const
|
|
5383
|
-
|
|
5384
|
-
|
|
5459
|
+
const { fields, seo } = splitSeoFromInput(data);
|
|
5460
|
+
return withTransaction(db, async (trx) => {
|
|
5461
|
+
const trxContentRepo = new ContentRepository(trx);
|
|
5462
|
+
const trxSeoRepo = new SeoRepository(trx);
|
|
5463
|
+
const hasSeo = await assertSeoEnabled(trxSeoRepo, collection, seo);
|
|
5464
|
+
const item = await trxContentRepo.create({
|
|
5465
|
+
type: collection,
|
|
5466
|
+
data: fields
|
|
5467
|
+
});
|
|
5468
|
+
const result = {
|
|
5469
|
+
id: item.id,
|
|
5470
|
+
type: item.type,
|
|
5471
|
+
data: item.data,
|
|
5472
|
+
createdAt: item.createdAt,
|
|
5473
|
+
updatedAt: item.updatedAt
|
|
5474
|
+
};
|
|
5475
|
+
if (hasSeo) result.seo = seo !== void 0 ? await trxSeoRepo.upsert(collection, item.id, seo) : await trxSeoRepo.get(collection, item.id);
|
|
5476
|
+
return result;
|
|
5385
5477
|
});
|
|
5386
|
-
return {
|
|
5387
|
-
id: item.id,
|
|
5388
|
-
type: item.type,
|
|
5389
|
-
data: item.data,
|
|
5390
|
-
createdAt: item.createdAt,
|
|
5391
|
-
updatedAt: item.updatedAt
|
|
5392
|
-
};
|
|
5393
5478
|
},
|
|
5394
5479
|
async update(collection, id, data) {
|
|
5395
|
-
const
|
|
5396
|
-
return {
|
|
5397
|
-
|
|
5398
|
-
|
|
5399
|
-
|
|
5400
|
-
|
|
5401
|
-
|
|
5402
|
-
|
|
5480
|
+
const { fields, seo } = splitSeoFromInput(data);
|
|
5481
|
+
return withTransaction(db, async (trx) => {
|
|
5482
|
+
const trxContentRepo = new ContentRepository(trx);
|
|
5483
|
+
const trxSeoRepo = new SeoRepository(trx);
|
|
5484
|
+
const hasSeo = await assertSeoEnabled(trxSeoRepo, collection, seo);
|
|
5485
|
+
const item = Object.keys(fields).length > 0 ? await trxContentRepo.update(collection, id, { data: fields }) : await (async () => {
|
|
5486
|
+
const existing = await trxContentRepo.findById(collection, id);
|
|
5487
|
+
if (!existing) throw new Error("Content not found");
|
|
5488
|
+
return existing;
|
|
5489
|
+
})();
|
|
5490
|
+
const result = {
|
|
5491
|
+
id: item.id,
|
|
5492
|
+
type: item.type,
|
|
5493
|
+
data: item.data,
|
|
5494
|
+
createdAt: item.createdAt,
|
|
5495
|
+
updatedAt: item.updatedAt
|
|
5496
|
+
};
|
|
5497
|
+
if (hasSeo) result.seo = seo !== void 0 ? await trxSeoRepo.upsert(collection, item.id, seo) : await trxSeoRepo.get(collection, item.id);
|
|
5498
|
+
return result;
|
|
5499
|
+
});
|
|
5403
5500
|
},
|
|
5404
5501
|
async delete(collection, id) {
|
|
5405
|
-
return
|
|
5502
|
+
return new ContentRepository(db).delete(collection, id);
|
|
5406
5503
|
}
|
|
5407
5504
|
};
|
|
5408
5505
|
}
|
|
@@ -5494,6 +5591,7 @@ function createMediaAccessWithWrite(db, getUploadUrlFn, storage) {
|
|
|
5494
5591
|
const MAX_PLUGIN_REDIRECTS = 5;
|
|
5495
5592
|
function isHostAllowed(host, allowedHosts) {
|
|
5496
5593
|
return allowedHosts.some((pattern) => {
|
|
5594
|
+
if (pattern === "*") return true;
|
|
5497
5595
|
if (pattern.startsWith("*.")) {
|
|
5498
5596
|
const suffix = pattern.slice(1);
|
|
5499
5597
|
return host.endsWith(suffix) || host === pattern.slice(2);
|
|
@@ -7035,6 +7133,14 @@ var PluginManager = class {
|
|
|
7035
7133
|
};
|
|
7036
7134
|
}
|
|
7037
7135
|
/**
|
|
7136
|
+
* Set the email pipeline used when creating plugin contexts.
|
|
7137
|
+
* Reinitializes routes/hooks if already initialized so ctx.email is available immediately.
|
|
7138
|
+
*/
|
|
7139
|
+
setEmailPipeline(pipeline) {
|
|
7140
|
+
this.factoryOptions.emailPipeline = pipeline;
|
|
7141
|
+
if (this.initialized) this.reinitialize();
|
|
7142
|
+
}
|
|
7143
|
+
/**
|
|
7038
7144
|
* Register a plugin definition
|
|
7039
7145
|
* This resolves the definition and adds it to the manager, but doesn't install it
|
|
7040
7146
|
*/
|
|
@@ -7955,8 +8061,8 @@ function wxrPostToNormalizedItem(post, attachmentMap) {
|
|
|
7955
8061
|
title: post.title || "Untitled",
|
|
7956
8062
|
content,
|
|
7957
8063
|
excerpt: post.excerpt,
|
|
7958
|
-
date: post.
|
|
7959
|
-
modified: post.
|
|
8064
|
+
date: parseWxrDate(post.postDateGmt, post.pubDate, post.postDate) ?? /* @__PURE__ */ new Date(),
|
|
8065
|
+
modified: parseWxrDate(post.postModifiedGmt, void 0, post.postModified),
|
|
7960
8066
|
author: post.creator,
|
|
7961
8067
|
categories: post.categories,
|
|
7962
8068
|
tags: post.tags,
|
|
@@ -7967,6 +8073,31 @@ function wxrPostToNormalizedItem(post, attachmentMap) {
|
|
|
7967
8073
|
customTaxonomies
|
|
7968
8074
|
};
|
|
7969
8075
|
}
|
|
8076
|
+
/**
|
|
8077
|
+
* WordPress uses "0000-00-00 00:00:00" as a sentinel for missing GMT dates
|
|
8078
|
+
* (e.g. unpublished drafts). This must be treated as absent.
|
|
8079
|
+
*/
|
|
8080
|
+
const WXR_ZERO_DATE = "0000-00-00 00:00:00";
|
|
8081
|
+
/**
|
|
8082
|
+
* Parse a WXR date with the correct fallback chain:
|
|
8083
|
+
* 1. GMT date (always UTC, most reliable)
|
|
8084
|
+
* 2. pubDate (RFC 2822, includes timezone offset)
|
|
8085
|
+
* 3. Site-local date (MySQL datetime without timezone, imprecise but best available)
|
|
8086
|
+
*
|
|
8087
|
+
* Returns undefined when none of the inputs yield a valid date.
|
|
8088
|
+
* Callers that need a guaranteed Date should use `?? new Date()`.
|
|
8089
|
+
*/
|
|
8090
|
+
function parseWxrDate(gmtDate, pubDate, localDate) {
|
|
8091
|
+
if (gmtDate && gmtDate !== WXR_ZERO_DATE) return /* @__PURE__ */ new Date(gmtDate.replace(" ", "T") + "Z");
|
|
8092
|
+
if (pubDate) {
|
|
8093
|
+
const d = new Date(pubDate);
|
|
8094
|
+
if (!isNaN(d.getTime())) return d;
|
|
8095
|
+
}
|
|
8096
|
+
if (localDate) {
|
|
8097
|
+
const d = new Date(localDate.replace(" ", "T"));
|
|
8098
|
+
if (!isNaN(d.getTime())) return d;
|
|
8099
|
+
}
|
|
8100
|
+
}
|
|
7970
8101
|
|
|
7971
8102
|
//#endregion
|
|
7972
8103
|
//#region src/import/sources/wordpress-rest.ts
|
|
@@ -8606,7 +8737,7 @@ async function resolveMenuItem(item, db, urlPatterns) {
|
|
|
8606
8737
|
return {
|
|
8607
8738
|
id: item.id,
|
|
8608
8739
|
label: item.label,
|
|
8609
|
-
url,
|
|
8740
|
+
url: sanitizeHref(url),
|
|
8610
8741
|
target: item.target || void 0,
|
|
8611
8742
|
titleAttr: item.title_attr || void 0,
|
|
8612
8743
|
cssClasses: item.css_classes || void 0,
|
|
@@ -8632,6 +8763,7 @@ function interpolateUrlPattern(pattern, slug, id) {
|
|
|
8632
8763
|
async function resolveContentUrl(collection, entryId, db, urlPatterns) {
|
|
8633
8764
|
if (!entryId) return null;
|
|
8634
8765
|
try {
|
|
8766
|
+
validateIdentifier(collection, "menu item collection");
|
|
8635
8767
|
const row = (await sql`
|
|
8636
8768
|
SELECT slug FROM ${sql.ref(`ec_${collection}`)} WHERE id = ${entryId} LIMIT 1
|
|
8637
8769
|
`.execute(db)).rows[0];
|
|
@@ -8806,7 +8938,7 @@ async function getTermsForEntries(collection, entryIds, taxonomyName) {
|
|
|
8806
8938
|
* Get entries by term (wraps getEmDashCollection)
|
|
8807
8939
|
*/
|
|
8808
8940
|
async function getEntriesByTerm(collection, taxonomyName, termSlug) {
|
|
8809
|
-
const { getEmDashCollection } = await import("./query-
|
|
8941
|
+
const { getEmDashCollection } = await import("./query-sesiOndV.mjs").then((n) => n.a);
|
|
8810
8942
|
const { entries } = await getEmDashCollection(collection, { where: { [taxonomyName]: termSlug } });
|
|
8811
8943
|
return entries;
|
|
8812
8944
|
}
|
|
@@ -9314,5 +9446,5 @@ function extractSearchableFields(entry, fields) {
|
|
|
9314
9446
|
}
|
|
9315
9447
|
|
|
9316
9448
|
//#endregion
|
|
9317
|
-
export {
|
|
9318
|
-
//# sourceMappingURL=search-
|
|
9449
|
+
export { sanitizeHeadersForSandbox as $, getAllSources as A, handleContentGet as At, createNoopSandboxRunner as B, handleContentUnschedule as Bt, isPreviewRequest as C, handleContentCompare as Ct, parseWxrDate as D, handleContentDelete as Dt, wordpressRestSource as E, handleContentCreate as Et, registerSource as F, handleContentPublish as Ft, DEV_CONSOLE_EMAIL_PLUGIN_ID as G, image as Gt, createPluginManager as H, validateRev as Ht, importReusableBlocksAsSections as I, handleContentRestore as It, HookPipeline as J, devConsoleEmailDeliver as K, isStandardPluginDefinition as L, handleContentSchedule as Lt, getSource as M, handleContentList as Mt, getUrlSources as N, handleContentListTrashed as Nt, wxrSource as O, handleContentDiscardDraft as Ot, probeUrl as P, handleContentPermanentDelete as Pt, extractRequestMeta as Q, NoopSandboxRunner as R, handleContentTranslations as Rt, getPreviewToken as S, hashString as St, getPreviewUrl as T, handleContentCountTrashed as Tt, PluginRouteError as U, portableText as Ut, PluginManager as V, handleContentUpdate as Vt, PluginRouteRegistry as W, reference as Wt, resolveExclusiveHooks as X, createHookPipeline as Y, CronExecutor as Z, getTermsForEntries as _, handleRevisionGet as _t, search as a, isSafeHref as at, getCommentCount as b, generateManifest as bt, getWidgetArea as c, getSection as ct, getEntriesByTerm as d, getCollectionInfo as dt, definePlugin as et, getEntryTerms as f, handleMediaCreate as ft, getTerm as g, handleMediaUpdate as gt, getTaxonomyTerms as h, handleMediaList as ht, getSuggestions as i, prosemirrorToPortableText as it, getFileSources as j, handleContentGetIncludingTrashed as jt, clearSources as k, handleContentDuplicate as kt, getWidgetAreas as l, getSections as lt, getTaxonomyDefs as m, handleMediaGet as mt, extractSearchableFields as n, parseWxrString as nt, searchCollection as o, sanitizeHref as ot, getTaxonomyDef as p, handleMediaDelete as pt, EmailPipeline as q, getSearchStats as r, portableTextToProsemirror as rt, searchWithDb as s, loadBundleFromR2 as st, extractPlainText as t, parseWxr as tt, getWidgetComponents as u, PluginStateRepository as ut, getMenu as v, handleRevisionList as vt, buildPreviewUrl as w, handleContentCountScheduled as wt, getComments as x, computeContentHash as xt, getMenus as y, handleRevisionRestore as yt, SandboxNotAvailableError as z, handleContentUnpublish as zt };
|
|
9450
|
+
//# sourceMappingURL=search-BXB-jfu2.mjs.map
|