emdash 0.5.0 → 0.7.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/{adapters-C2BzVy0p.d.mts → adapters-Di31kZ28.d.mts} +16 -1
- package/dist/adapters-Di31kZ28.d.mts.map +1 -0
- package/dist/{apply-Cma_PiF6.mjs → apply-5uslYdUu.mjs} +197 -25
- package/dist/apply-5uslYdUu.mjs.map +1 -0
- package/dist/astro/index.d.mts +6 -6
- package/dist/astro/index.d.mts.map +1 -1
- package/dist/astro/index.mjs +203 -33
- package/dist/astro/index.mjs.map +1 -1
- package/dist/astro/middleware/auth.d.mts +5 -5
- package/dist/astro/middleware/auth.d.mts.map +1 -1
- package/dist/astro/middleware/auth.mjs +30 -4
- package/dist/astro/middleware/auth.mjs.map +1 -1
- package/dist/astro/middleware/redirect.mjs +2 -2
- package/dist/astro/middleware/request-context.d.mts.map +1 -1
- package/dist/astro/middleware/request-context.mjs +11 -4
- package/dist/astro/middleware/request-context.mjs.map +1 -1
- package/dist/astro/middleware/setup.mjs +1 -1
- package/dist/astro/middleware.d.mts.map +1 -1
- package/dist/astro/middleware.mjs +467 -186
- package/dist/astro/middleware.mjs.map +1 -1
- package/dist/astro/types.d.mts +17 -9
- package/dist/astro/types.d.mts.map +1 -1
- package/dist/{byline-WuOq9MFJ.mjs → byline-C4OVd8b3.mjs} +3 -19
- package/dist/byline-C4OVd8b3.mjs.map +1 -0
- package/dist/{bylines-C_Wsnz4L.mjs → bylines-hPTW79hw.mjs} +20 -33
- package/dist/bylines-hPTW79hw.mjs.map +1 -0
- package/dist/{cache-E3Dts-yT.mjs → cache-BkKBuIvS.mjs} +1 -1
- package/dist/{cache-E3Dts-yT.mjs.map → cache-BkKBuIvS.mjs.map} +1 -1
- package/dist/chunks-HGz06Soa.mjs +19 -0
- package/dist/chunks-HGz06Soa.mjs.map +1 -0
- package/dist/cli/index.mjs +12 -11
- package/dist/cli/index.mjs.map +1 -1
- package/dist/client/cf-access.d.mts +1 -1
- package/dist/client/index.d.mts +1 -1
- package/dist/client/index.mjs +1 -1
- package/dist/{config-DkxPrM9l.mjs → config-BXwuX8Bx.mjs} +1 -1
- package/dist/{config-DkxPrM9l.mjs.map → config-BXwuX8Bx.mjs.map} +1 -1
- package/dist/{connection-B4zVnQIa.mjs → connection-2igzM-AT.mjs} +19 -2
- package/dist/connection-2igzM-AT.mjs.map +1 -0
- package/dist/{content-BsBoyj8G.mjs → content-D7J5y73J.mjs} +27 -1
- package/dist/{content-BsBoyj8G.mjs.map → content-D7J5y73J.mjs.map} +1 -1
- package/dist/database/instrumentation.d.mts +45 -0
- package/dist/database/instrumentation.d.mts.map +1 -0
- package/dist/database/instrumentation.mjs +61 -0
- package/dist/database/instrumentation.mjs.map +1 -0
- package/dist/db/index.d.mts +3 -3
- package/dist/db/index.mjs +1 -1
- package/dist/db/index.mjs.map +1 -1
- package/dist/db/libsql.d.mts +1 -1
- package/dist/db/postgres.d.mts +1 -1
- package/dist/db/sqlite.d.mts +1 -1
- package/dist/db-errors-D0UT85nC.mjs +41 -0
- package/dist/db-errors-D0UT85nC.mjs.map +1 -0
- package/dist/{default-PUx9RK6u.mjs → default-CME5YdZ3.mjs} +1 -1
- package/dist/{default-PUx9RK6u.mjs.map → default-CME5YdZ3.mjs.map} +1 -1
- package/dist/{error-HBeQbVhV.mjs → error-CiYn9yDu.mjs} +1 -1
- package/dist/{error-HBeQbVhV.mjs.map → error-CiYn9yDu.mjs.map} +1 -1
- package/dist/{index-CCWzlriB.d.mts → index-De6_Xv3v.d.mts} +209 -19
- package/dist/index-De6_Xv3v.d.mts.map +1 -0
- package/dist/index.d.mts +11 -11
- package/dist/index.mjs +23 -21
- package/dist/{load-BhSSm-TS.mjs → load-CBcmDIot.mjs} +1 -1
- package/dist/{load-BhSSm-TS.mjs.map → load-CBcmDIot.mjs.map} +1 -1
- package/dist/{loader-BYzwzORf.mjs → loader-DeiBJEMe.mjs} +18 -12
- package/dist/loader-DeiBJEMe.mjs.map +1 -0
- package/dist/{manifest-schema-BsXINkQD.mjs → manifest-schema-V30qsMft.mjs} +1 -1
- package/dist/{manifest-schema-BsXINkQD.mjs.map → manifest-schema-V30qsMft.mjs.map} +1 -1
- package/dist/media/index.d.mts +1 -1
- package/dist/media/index.mjs +1 -1
- package/dist/media/local-runtime.d.mts +7 -7
- package/dist/{mode-CyPLdO3C.mjs → mode-CpNnGkPz.mjs} +1 -1
- package/dist/{mode-CyPLdO3C.mjs.map → mode-CpNnGkPz.mjs.map} +1 -1
- package/dist/page/index.d.mts +11 -2
- package/dist/page/index.d.mts.map +1 -1
- package/dist/page/index.mjs +23 -1
- package/dist/page/index.mjs.map +1 -1
- package/dist/{placeholder-DntBEQo7.mjs → placeholder-C-fk5hYI.mjs} +1 -1
- package/dist/{placeholder-DntBEQo7.mjs.map → placeholder-C-fk5hYI.mjs.map} +1 -1
- package/dist/{placeholder-BBCtpTES.d.mts → placeholder-tzpqGWII.d.mts} +1 -1
- package/dist/{placeholder-BBCtpTES.d.mts.map → placeholder-tzpqGWII.d.mts.map} +1 -1
- package/dist/plugins/adapt-sandbox-entry.d.mts +5 -5
- package/dist/plugins/adapt-sandbox-entry.mjs +1 -1
- package/dist/{query-B6Vu0d2i.mjs → query-g4Ug-9j9.mjs} +79 -12
- package/dist/query-g4Ug-9j9.mjs.map +1 -0
- package/dist/{redirect-7lGhLBNZ.mjs → redirect-CN0Rt9Ob.mjs} +66 -10
- package/dist/redirect-CN0Rt9Ob.mjs.map +1 -0
- package/dist/{registry-BgnP3ysR.mjs → registry-Ci3WxVAr.mjs} +133 -97
- package/dist/registry-Ci3WxVAr.mjs.map +1 -0
- package/dist/request-cache-DiR961CV.mjs +79 -0
- package/dist/request-cache-DiR961CV.mjs.map +1 -0
- package/dist/request-context.d.mts +19 -16
- package/dist/request-context.d.mts.map +1 -1
- package/dist/request-context.mjs.map +1 -1
- package/dist/{runner-DYv3rX8P.d.mts → runner-BR2xKwhn.d.mts} +2 -2
- package/dist/{runner-DYv3rX8P.d.mts.map → runner-BR2xKwhn.d.mts.map} +1 -1
- package/dist/{runner-Cd-_WyDo.mjs → runner-tQ7BJ4T7.mjs} +211 -134
- package/dist/runner-tQ7BJ4T7.mjs.map +1 -0
- package/dist/runtime.d.mts +6 -6
- package/dist/runtime.mjs +1 -1
- package/dist/{search-Cn1SYvYF.mjs → search-B0effn3j.mjs} +210 -226
- package/dist/search-B0effn3j.mjs.map +1 -0
- package/dist/seed/index.d.mts +2 -2
- package/dist/seed/index.mjs +10 -9
- 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 +1 -1
- package/dist/storage/s3.mjs +1 -1
- package/dist/taxonomies-K2z0Uhnj.mjs +308 -0
- package/dist/taxonomies-K2z0Uhnj.mjs.map +1 -0
- package/dist/{tokens-DKHiCYCB.mjs → tokens-BFPFx3CA.mjs} +1 -1
- package/dist/{tokens-DKHiCYCB.mjs.map → tokens-BFPFx3CA.mjs.map} +1 -1
- package/dist/{transport-BtcQ-Z7T.mjs → transport-BykRfpyy.mjs} +1 -1
- package/dist/{transport-BtcQ-Z7T.mjs.map → transport-BykRfpyy.mjs.map} +1 -1
- package/dist/{transport-CKQA_G44.d.mts → transport-H4Iwx7tC.d.mts} +1 -1
- package/dist/{transport-CKQA_G44.d.mts.map → transport-H4Iwx7tC.d.mts.map} +1 -1
- package/dist/{types-BmkQR1En.d.mts → types-6CUZRrZP.d.mts} +1 -1
- package/dist/{types-BmkQR1En.d.mts.map → types-6CUZRrZP.d.mts.map} +1 -1
- package/dist/{types-Dz9_WMS6.mjs → types-BH2L167P.mjs} +1 -1
- package/dist/{types-Dz9_WMS6.mjs.map → types-BH2L167P.mjs.map} +1 -1
- package/dist/{types-B6BzlZxx.d.mts → types-C2v0c34j.d.mts} +10 -1
- package/dist/{types-B6BzlZxx.d.mts.map → types-C2v0c34j.d.mts.map} +1 -1
- package/dist/{types-DNZpaCBk.d.mts → types-CFWjXmus.d.mts} +1 -1
- package/dist/{types-DNZpaCBk.d.mts.map → types-CFWjXmus.d.mts.map} +1 -1
- package/dist/{types-DeG21anB.d.mts → types-CnZYHyLW.d.mts} +55 -5
- package/dist/types-CnZYHyLW.d.mts.map +1 -0
- package/dist/{types-xxCWI3j0.mjs → types-DDS4MxsT.mjs} +11 -3
- package/dist/types-DDS4MxsT.mjs.map +1 -0
- package/dist/{types-C3ronwXb.d.mts → types-DgrIP0tF.d.mts} +102 -4
- package/dist/types-DgrIP0tF.d.mts.map +1 -0
- package/dist/{validate-DuZDIxfy.mjs → validate-CqsNItbt.mjs} +2 -2
- package/dist/{validate-DuZDIxfy.mjs.map → validate-CqsNItbt.mjs.map} +1 -1
- package/dist/{validate-Db1yNL3i.d.mts → validate-kM8Pjuf7.d.mts} +5 -52
- package/dist/validate-kM8Pjuf7.d.mts.map +1 -0
- package/dist/version-BnTKdfam.mjs +7 -0
- package/dist/{version-CMMjTuqu.mjs.map → version-BnTKdfam.mjs.map} +1 -1
- package/package.json +10 -5
- package/src/after.ts +62 -0
- package/src/api/handlers/content.ts +2 -0
- package/src/api/handlers/oauth-authorization.ts +2 -32
- package/src/api/handlers/oauth-clients.ts +40 -4
- package/src/api/handlers/taxonomies.ts +13 -0
- package/src/api/oauth/redirect-uri.ts +34 -0
- package/src/api/openapi/document.ts +126 -118
- package/src/api/schemas/content.ts +8 -0
- package/src/api/schemas/media.ts +26 -15
- package/src/api/schemas/schema.ts +1 -0
- package/src/astro/integration/font-provider.ts +178 -0
- package/src/astro/integration/index.ts +44 -0
- package/src/astro/integration/routes.ts +6 -0
- package/src/astro/integration/runtime.ts +117 -0
- package/src/astro/integration/virtual-modules.ts +41 -39
- package/src/astro/integration/vite-config.ts +16 -5
- package/src/astro/middleware/auth.ts +33 -1
- package/src/astro/middleware/request-context.ts +15 -3
- package/src/astro/middleware.ts +340 -263
- package/src/astro/routes/admin.astro +21 -10
- package/src/astro/routes/api/auth/magic-link/send.ts +2 -1
- package/src/astro/routes/api/auth/passkey/options.ts +2 -1
- package/src/astro/routes/api/auth/passkey/verify.ts +5 -1
- package/src/astro/routes/api/auth/signup/request.ts +26 -8
- package/src/astro/routes/api/comments/[collection]/[contentId]/index.ts +10 -6
- package/src/astro/routes/api/content/[collection]/[id]/compare.ts +1 -1
- package/src/astro/routes/api/content/[collection]/[id]/preview-url.ts +1 -1
- package/src/astro/routes/api/content/[collection]/[id]/revisions.ts +1 -1
- package/src/astro/routes/api/content/[collection]/[id]/terms/[taxonomy].ts +5 -0
- package/src/astro/routes/api/content/[collection]/[id]/translations.ts +26 -0
- package/src/astro/routes/api/content/[collection]/[id].ts +30 -2
- package/src/astro/routes/api/content/[collection]/index.ts +19 -1
- package/src/astro/routes/api/content/[collection]/trash.ts +1 -1
- package/src/astro/routes/api/import/wordpress/execute.ts +1 -1
- package/src/astro/routes/api/import/wordpress-plugin/analyze.ts +4 -3
- package/src/astro/routes/api/import/wordpress-plugin/execute.ts +5 -4
- package/src/astro/routes/api/manifest.ts +7 -0
- package/src/astro/routes/api/media/upload-url.ts +10 -2
- package/src/astro/routes/api/media.ts +10 -7
- package/src/astro/routes/api/oauth/device/code.ts +2 -1
- package/src/astro/routes/api/oauth/device/token.ts +2 -1
- package/src/astro/routes/api/oauth/register.ts +178 -0
- package/src/astro/routes/api/oauth/token.ts +15 -0
- package/src/astro/routes/api/openapi.json.ts +15 -5
- package/src/astro/routes/api/schema/collections/[slug]/fields/[fieldSlug].ts +2 -0
- package/src/astro/routes/api/schema/collections/[slug]/fields/index.ts +1 -0
- package/src/astro/routes/api/schema/collections/[slug]/fields/reorder.ts +1 -0
- package/src/astro/routes/api/search/index.ts +5 -0
- package/src/astro/routes/api/search/suggest.ts +3 -0
- package/src/astro/routes/api/setup/admin-verify.ts +30 -5
- package/src/astro/routes/api/setup/admin.ts +32 -8
- package/src/astro/routes/api/setup/index.ts +5 -2
- package/src/astro/routes/api/taxonomies/index.ts +1 -0
- package/src/astro/routes/api/well-known/oauth-authorization-server.ts +1 -1
- package/src/astro/types.ts +9 -0
- package/src/auth/rate-limit.ts +50 -22
- package/src/auth/setup-nonce.ts +22 -0
- package/src/auth/trusted-proxy.ts +92 -0
- package/src/bylines/index.ts +22 -45
- package/src/components/EmDashHead.astro +23 -7
- package/src/database/connection.ts +23 -1
- package/src/database/instrumentation.ts +98 -0
- package/src/database/migrations/035_bounded_404_log.ts +112 -0
- package/src/database/migrations/runner.ts +2 -0
- package/src/database/repositories/content.ts +39 -0
- package/src/database/repositories/options.ts +25 -0
- package/src/database/repositories/redirect.ts +111 -8
- package/src/database/types.ts +9 -0
- package/src/db/adapters.ts +15 -0
- package/src/emdash-runtime.ts +312 -92
- package/src/import/registry.ts +4 -3
- package/src/import/ssrf.ts +253 -12
- package/src/index.ts +6 -0
- package/src/loader.ts +19 -24
- package/src/mcp/server.ts +76 -3
- package/src/menus/index.ts +6 -3
- package/src/page/index.ts +1 -1
- package/src/page/seo-contributions.ts +36 -0
- package/src/plugins/context.ts +15 -3
- package/src/plugins/manager.ts +6 -0
- package/src/plugins/request-meta.ts +66 -15
- package/src/plugins/routes.ts +3 -1
- package/src/query.ts +104 -7
- package/src/request-cache.ts +106 -0
- package/src/request-context.ts +19 -0
- package/src/schema/query.ts +5 -2
- package/src/schema/registry.ts +243 -166
- package/src/schema/types.ts +13 -2
- package/src/schema/zod-generator.ts +4 -0
- package/src/search/fts-manager.ts +19 -5
- package/src/search/query.ts +4 -3
- package/src/seed/apply.ts +41 -1
- package/src/settings/index.ts +24 -5
- package/src/taxonomies/index.ts +324 -124
- package/src/utils/db-errors.ts +46 -0
- package/src/virtual-modules.d.ts +31 -10
- package/src/visual-editing/toolbar.ts +6 -1
- package/src/widgets/index.ts +54 -25
- package/dist/adapters-C2BzVy0p.d.mts.map +0 -1
- package/dist/apply-Cma_PiF6.mjs.map +0 -1
- package/dist/byline-WuOq9MFJ.mjs.map +0 -1
- package/dist/bylines-C_Wsnz4L.mjs.map +0 -1
- package/dist/connection-B4zVnQIa.mjs.map +0 -1
- package/dist/index-CCWzlriB.d.mts.map +0 -1
- package/dist/loader-BYzwzORf.mjs.map +0 -1
- package/dist/query-B6Vu0d2i.mjs.map +0 -1
- package/dist/redirect-7lGhLBNZ.mjs.map +0 -1
- package/dist/registry-BgnP3ysR.mjs.map +0 -1
- package/dist/runner-Cd-_WyDo.mjs.map +0 -1
- package/dist/search-Cn1SYvYF.mjs.map +0 -1
- package/dist/types-C3ronwXb.d.mts.map +0 -1
- package/dist/types-DeG21anB.d.mts.map +0 -1
- package/dist/types-xxCWI3j0.mjs.map +0 -1
- package/dist/validate-Db1yNL3i.d.mts.map +0 -1
- package/dist/version-CMMjTuqu.mjs +0 -7
|
@@ -1,23 +1,25 @@
|
|
|
1
1
|
import { n as validateJsonFieldName, r as validatePluginIdentifier, t as validateIdentifier } from "./validate-VPnKoIzW.mjs";
|
|
2
2
|
import { o as jsonExtractExpr } from "./dialect-helpers-DhTzaUxP.mjs";
|
|
3
|
-
import { a as slugify, r as RevisionRepository, t as ContentRepository } from "./content-
|
|
3
|
+
import { a as slugify, r as RevisionRepository, t as ContentRepository } from "./content-D7J5y73J.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
|
|
7
|
+
import { a as ssrfSafeFetch, i as resolveAndValidateExternalUrl, o as stripCredentialHeaders, p as OptionsRepository, r as SsrfError, s as validateExternalUrl } from "./apply-5uslYdUu.mjs";
|
|
8
8
|
import { t as withTransaction } from "./transaction-Cn2rjY78.mjs";
|
|
9
|
-
import { t as RedirectRepository } from "./redirect-
|
|
10
|
-
import { n as
|
|
11
|
-
import {
|
|
12
|
-
import { r as
|
|
13
|
-
import {
|
|
14
|
-
import { n as
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
9
|
+
import { t as RedirectRepository } from "./redirect-CN0Rt9Ob.mjs";
|
|
10
|
+
import { n as chunks, t as SQL_BATCH_SIZE } from "./chunks-HGz06Soa.mjs";
|
|
11
|
+
import { t as BylineRepository } from "./byline-C4OVd8b3.mjs";
|
|
12
|
+
import { r as isI18nEnabled } from "./config-BXwuX8Bx.mjs";
|
|
13
|
+
import { r as invalidateRedirectCache } from "./cache-BkKBuIvS.mjs";
|
|
14
|
+
import { i as FTSManager, n as SchemaRegistry } from "./registry-Ci3WxVAr.mjs";
|
|
15
|
+
import { n as getDb } from "./loader-DeiBJEMe.mjs";
|
|
16
|
+
import { n as requestCached } from "./request-cache-DiR961CV.mjs";
|
|
17
|
+
import { i as pluginManifestSchema } from "./manifest-schema-V30qsMft.mjs";
|
|
18
|
+
import { t as generatePreviewToken } from "./tokens-BFPFx3CA.mjs";
|
|
17
19
|
import { sql } from "kysely";
|
|
20
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
18
21
|
import { ulid } from "ulidx";
|
|
19
22
|
import { z } from "astro/zod";
|
|
20
|
-
import { AsyncLocalStorage } from "node:async_hooks";
|
|
21
23
|
import { z as z$1 } from "zod";
|
|
22
24
|
import { createGzipDecoder, unpackTar } from "modern-tar";
|
|
23
25
|
import sax from "sax";
|
|
@@ -1296,7 +1298,8 @@ async function handleContentUpdate(db, collection, id, body) {
|
|
|
1296
1298
|
data: body.data,
|
|
1297
1299
|
slug: body.slug,
|
|
1298
1300
|
status: body.status,
|
|
1299
|
-
authorId: body.authorId
|
|
1301
|
+
authorId: body.authorId,
|
|
1302
|
+
publishedAt: body.publishedAt
|
|
1300
1303
|
});
|
|
1301
1304
|
if (body.bylines !== void 0) {
|
|
1302
1305
|
await bylineRepo.setContentBylines(collection, resolvedId, body.bylines);
|
|
@@ -2229,7 +2232,9 @@ async function handleMediaDelete(db, id) {
|
|
|
2229
2232
|
* ```
|
|
2230
2233
|
*/
|
|
2231
2234
|
async function getCollectionInfo(slug) {
|
|
2232
|
-
return
|
|
2235
|
+
return requestCached(`collection-info:${slug}`, async () => {
|
|
2236
|
+
return getCollectionInfoWithDb(await getDb(), slug);
|
|
2237
|
+
});
|
|
2233
2238
|
}
|
|
2234
2239
|
/**
|
|
2235
2240
|
* Get collection metadata with an explicit db handle.
|
|
@@ -2636,6 +2641,11 @@ const contentListQuery = cursorPaginationQuery.extend({
|
|
|
2636
2641
|
order: z$1.enum(["asc", "desc"]).optional(),
|
|
2637
2642
|
locale: localeCode.optional()
|
|
2638
2643
|
}).meta({ id: "ContentListQuery" });
|
|
2644
|
+
/** ISO 8601 datetime for `publishedAt` / `createdAt`. Routes gate writes behind `content:publish_any`. */
|
|
2645
|
+
const contentDateOverride = z$1.iso.datetime({
|
|
2646
|
+
offset: true,
|
|
2647
|
+
message: "must be an ISO 8601 datetime"
|
|
2648
|
+
}).nullish();
|
|
2639
2649
|
const contentCreateBody = z$1.object({
|
|
2640
2650
|
data: z$1.record(z$1.string(), z$1.unknown()),
|
|
2641
2651
|
slug: z$1.string().nullish(),
|
|
@@ -2643,7 +2653,9 @@ const contentCreateBody = z$1.object({
|
|
|
2643
2653
|
bylines: z$1.array(contentBylineInputSchema).optional(),
|
|
2644
2654
|
locale: localeCode.optional(),
|
|
2645
2655
|
translationOf: z$1.string().optional(),
|
|
2646
|
-
seo: contentSeoInput.optional()
|
|
2656
|
+
seo: contentSeoInput.optional(),
|
|
2657
|
+
publishedAt: contentDateOverride,
|
|
2658
|
+
createdAt: contentDateOverride
|
|
2647
2659
|
}).meta({ id: "ContentCreateBody" });
|
|
2648
2660
|
const contentUpdateBody = z$1.object({
|
|
2649
2661
|
data: z$1.record(z$1.string(), z$1.unknown()).optional(),
|
|
@@ -2653,7 +2665,8 @@ const contentUpdateBody = z$1.object({
|
|
|
2653
2665
|
bylines: z$1.array(contentBylineInputSchema).optional(),
|
|
2654
2666
|
_rev: z$1.string().optional().meta({ description: "Opaque revision token for optimistic concurrency" }),
|
|
2655
2667
|
skipRevision: z$1.boolean().optional(),
|
|
2656
|
-
seo: contentSeoInput.optional()
|
|
2668
|
+
seo: contentSeoInput.optional(),
|
|
2669
|
+
publishedAt: contentDateOverride
|
|
2657
2670
|
}).meta({ id: "ContentUpdateBody" });
|
|
2658
2671
|
const contentScheduleBody = z$1.object({ scheduledAt: z$1.string().min(1, "scheduledAt is required").meta({
|
|
2659
2672
|
description: "ISO 8601 datetime for scheduled publishing",
|
|
@@ -2751,14 +2764,8 @@ const mediaUpdateBody = z$1.object({
|
|
|
2751
2764
|
width: z$1.number().int().positive().optional(),
|
|
2752
2765
|
height: z$1.number().int().positive().optional()
|
|
2753
2766
|
}).meta({ id: "MediaUpdateBody" });
|
|
2754
|
-
/**
|
|
2755
|
-
const
|
|
2756
|
-
const mediaUploadUrlBody = z$1.object({
|
|
2757
|
-
filename: z$1.string().min(1, "filename is required"),
|
|
2758
|
-
contentType: z$1.string().min(1, "contentType is required"),
|
|
2759
|
-
size: z$1.number().int().positive().max(MAX_UPLOAD_SIZE, `File size must not exceed ${MAX_UPLOAD_SIZE / 1024 / 1024}MB`),
|
|
2760
|
-
contentHash: z$1.string().optional()
|
|
2761
|
-
}).meta({ id: "MediaUploadUrlBody" });
|
|
2767
|
+
/** Default maximum allowed file upload size (50 MB). */
|
|
2768
|
+
const DEFAULT_MAX_UPLOAD_SIZE = 50 * 1024 * 1024;
|
|
2762
2769
|
const mediaConfirmBody = z$1.object({
|
|
2763
2770
|
size: z$1.number().int().positive().optional(),
|
|
2764
2771
|
width: z$1.number().int().positive().optional(),
|
|
@@ -2824,6 +2831,7 @@ const collectionSourcePattern = /^(template:.+|import:.+|manual|discovered|seed)
|
|
|
2824
2831
|
const fieldTypeValues = z$1.enum([
|
|
2825
2832
|
"string",
|
|
2826
2833
|
"text",
|
|
2834
|
+
"url",
|
|
2827
2835
|
"number",
|
|
2828
2836
|
"integer",
|
|
2829
2837
|
"boolean",
|
|
@@ -4221,6 +4229,33 @@ function convertCodeBlock(block) {
|
|
|
4221
4229
|
};
|
|
4222
4230
|
}
|
|
4223
4231
|
|
|
4232
|
+
//#endregion
|
|
4233
|
+
//#region src/after.ts
|
|
4234
|
+
const waitUntilReady = (async () => {
|
|
4235
|
+
try {
|
|
4236
|
+
return (await import("virtual:emdash/wait-until")).waitUntil ?? null;
|
|
4237
|
+
} catch {
|
|
4238
|
+
return null;
|
|
4239
|
+
}
|
|
4240
|
+
})();
|
|
4241
|
+
waitUntilReady.catch(() => {});
|
|
4242
|
+
/**
|
|
4243
|
+
* Schedule `fn` to run without blocking the response.
|
|
4244
|
+
*
|
|
4245
|
+
* Errors are caught and logged — a deferred task should never surface
|
|
4246
|
+
* as an unhandled rejection because the response is long gone. Callers
|
|
4247
|
+
* that care about errors should handle them inside `fn`.
|
|
4248
|
+
*/
|
|
4249
|
+
function after(fn) {
|
|
4250
|
+
const promise = Promise.resolve().then(fn).catch((error) => {
|
|
4251
|
+
console.error("[emdash] deferred task failed:", error);
|
|
4252
|
+
});
|
|
4253
|
+
waitUntilReady.then((waitUntil) => {
|
|
4254
|
+
if (waitUntil) waitUntil(promise);
|
|
4255
|
+
return null;
|
|
4256
|
+
});
|
|
4257
|
+
}
|
|
4258
|
+
|
|
4224
4259
|
//#endregion
|
|
4225
4260
|
//#region src/cli/wxr/parser.ts
|
|
4226
4261
|
const PHP_SERIALIZED_STRING_PATTERN = /s:\d+:"([^"]+)"/g;
|
|
@@ -4957,6 +4992,55 @@ function resolveHook(hook, pluginId) {
|
|
|
4957
4992
|
};
|
|
4958
4993
|
}
|
|
4959
4994
|
|
|
4995
|
+
//#endregion
|
|
4996
|
+
//#region src/auth/trusted-proxy.ts
|
|
4997
|
+
/**
|
|
4998
|
+
* RFC 7230 token — valid characters for an HTTP header name. Invalid names
|
|
4999
|
+
* passed to `Headers.get()` throw a TypeError at runtime, which would
|
|
5000
|
+
* otherwise surface as a 500 from every auth route.
|
|
5001
|
+
*/
|
|
5002
|
+
const HEADER_NAME_PATTERN = /^[!#$%&'*+\-.^_`|~0-9a-z]+$/;
|
|
5003
|
+
/**
|
|
5004
|
+
* Normalise a list of header names the way both the config path and any
|
|
5005
|
+
* caller passing a pre-resolved list should do: trim, lowercase, drop
|
|
5006
|
+
* empty, drop anything that isn't a valid RFC 7230 token. Invalid names
|
|
5007
|
+
* would crash `Headers.get()` at runtime.
|
|
5008
|
+
*/
|
|
5009
|
+
function normalizeTrustedHeaders(names) {
|
|
5010
|
+
return names.map((h) => h.trim().toLowerCase()).filter((h) => h.length > 0 && HEADER_NAME_PATTERN.test(h));
|
|
5011
|
+
}
|
|
5012
|
+
function isValidHeaderName(name) {
|
|
5013
|
+
return HEADER_NAME_PATTERN.test(name);
|
|
5014
|
+
}
|
|
5015
|
+
/** Cache for the env-derived value. `null` means "not yet parsed". */
|
|
5016
|
+
let _envCache = null;
|
|
5017
|
+
function getEnvTrustedHeaders() {
|
|
5018
|
+
if (_envCache !== null) return _envCache;
|
|
5019
|
+
let raw;
|
|
5020
|
+
try {
|
|
5021
|
+
const importMetaEnv = import.meta.env;
|
|
5022
|
+
raw = (typeof process !== "undefined" ? process.env?.EMDASH_TRUSTED_PROXY_HEADERS : void 0) || importMetaEnv?.EMDASH_TRUSTED_PROXY_HEADERS;
|
|
5023
|
+
} catch {
|
|
5024
|
+
raw = void 0;
|
|
5025
|
+
}
|
|
5026
|
+
if (!raw) {
|
|
5027
|
+
_envCache = [];
|
|
5028
|
+
return _envCache;
|
|
5029
|
+
}
|
|
5030
|
+
_envCache = raw.split(",").map((s) => s.trim().toLowerCase()).filter((s) => s.length > 0 && isValidHeaderName(s));
|
|
5031
|
+
return _envCache;
|
|
5032
|
+
}
|
|
5033
|
+
/**
|
|
5034
|
+
* Return the lowercased list of headers to trust for client-IP resolution.
|
|
5035
|
+
*
|
|
5036
|
+
* When `config?.trustedProxyHeaders` is explicitly set (even to `[]`), it
|
|
5037
|
+
* wins. Otherwise fall through to the env var, then to `[]`.
|
|
5038
|
+
*/
|
|
5039
|
+
function getTrustedProxyHeaders(config) {
|
|
5040
|
+
if (config && config.trustedProxyHeaders !== void 0) return config.trustedProxyHeaders.map((h) => h.trim().toLowerCase()).filter((h) => h.length > 0 && isValidHeaderName(h));
|
|
5041
|
+
return getEnvTrustedHeaders();
|
|
5042
|
+
}
|
|
5043
|
+
|
|
4960
5044
|
//#endregion
|
|
4961
5045
|
//#region src/plugins/request-meta.ts
|
|
4962
5046
|
/**
|
|
@@ -4978,6 +5062,20 @@ function parseFirstForwardedIp(header) {
|
|
|
4978
5062
|
return IP_PATTERN.test(trimmed) ? trimmed : null;
|
|
4979
5063
|
}
|
|
4980
5064
|
/**
|
|
5065
|
+
* Read an IP from an operator-declared trusted header. XFF-style headers
|
|
5066
|
+
* (any name ending in `forwarded-for`) are parsed as comma-separated lists
|
|
5067
|
+
* and the first entry is used; everything else is treated as a single
|
|
5068
|
+
* trimmed value.
|
|
5069
|
+
*/
|
|
5070
|
+
function readIpFromHeader(headers, name) {
|
|
5071
|
+
const value = headers.get(name);
|
|
5072
|
+
if (!value) return null;
|
|
5073
|
+
if (name.endsWith("forwarded-for")) return parseFirstForwardedIp(value);
|
|
5074
|
+
const trimmed = value.trim();
|
|
5075
|
+
if (!trimmed) return null;
|
|
5076
|
+
return IP_PATTERN.test(trimmed) ? trimmed : null;
|
|
5077
|
+
}
|
|
5078
|
+
/**
|
|
4981
5079
|
* Get the Cloudflare `cf` object from the request, if present.
|
|
4982
5080
|
* Returns undefined when not running on Cloudflare Workers.
|
|
4983
5081
|
*/
|
|
@@ -5004,24 +5102,39 @@ function extractGeo(cf) {
|
|
|
5004
5102
|
* Extract normalized request metadata from a Request object.
|
|
5005
5103
|
*
|
|
5006
5104
|
* IP resolution order:
|
|
5007
|
-
* 1. `CF-Connecting-IP`
|
|
5008
|
-
*
|
|
5009
|
-
*
|
|
5010
|
-
*
|
|
5011
|
-
*
|
|
5012
|
-
* 3. `
|
|
5013
|
-
|
|
5014
|
-
|
|
5105
|
+
* 1. `CF-Connecting-IP` — trusted only when a `cf` object is present on the
|
|
5106
|
+
* request. CF edge overwrites any client-supplied value, so this is the
|
|
5107
|
+
* cryptographically trustworthy path on Workers. Operator-declared
|
|
5108
|
+
* trusted headers cannot override it.
|
|
5109
|
+
* 2. `X-Forwarded-For` first entry — trusted only with a `cf` object.
|
|
5110
|
+
* 3. Operator-declared trusted proxy headers (from `config.trustedProxyHeaders`
|
|
5111
|
+
* or the `EMDASH_TRUSTED_PROXY_HEADERS` env var), tried in order. Used as
|
|
5112
|
+
* the primary source off-CF and as a fill-in on CF.
|
|
5113
|
+
* 4. `null`
|
|
5114
|
+
*
|
|
5115
|
+
* The second argument accepts either the EmDash config or a pre-resolved
|
|
5116
|
+
* list of trusted headers, so callers that already have the list don't have
|
|
5117
|
+
* to round-trip through the config every request.
|
|
5118
|
+
*/
|
|
5119
|
+
function extractRequestMeta(request, configOrTrustedHeaders) {
|
|
5015
5120
|
const headers = request.headers;
|
|
5016
5121
|
const cf = getCfObject(request);
|
|
5122
|
+
const trusted = resolveTrustedHeaders(configOrTrustedHeaders);
|
|
5017
5123
|
let ip = null;
|
|
5018
5124
|
if (cf) {
|
|
5019
5125
|
const cfIp = headers.get("cf-connecting-ip")?.trim();
|
|
5020
5126
|
if (cfIp && IP_PATTERN.test(cfIp)) ip = cfIp;
|
|
5127
|
+
if (!ip) {
|
|
5128
|
+
const xff = headers.get("x-forwarded-for");
|
|
5129
|
+
ip = xff ? parseFirstForwardedIp(xff) : null;
|
|
5130
|
+
}
|
|
5021
5131
|
}
|
|
5022
|
-
if (!ip
|
|
5023
|
-
const
|
|
5024
|
-
|
|
5132
|
+
if (!ip) for (const name of trusted) {
|
|
5133
|
+
const value = readIpFromHeader(headers, name);
|
|
5134
|
+
if (value) {
|
|
5135
|
+
ip = value;
|
|
5136
|
+
break;
|
|
5137
|
+
}
|
|
5025
5138
|
}
|
|
5026
5139
|
const userAgent = headers.get("user-agent")?.trim() || null;
|
|
5027
5140
|
const referer = headers.get("referer")?.trim() || null;
|
|
@@ -5033,6 +5146,10 @@ function extractRequestMeta(request) {
|
|
|
5033
5146
|
geo
|
|
5034
5147
|
};
|
|
5035
5148
|
}
|
|
5149
|
+
function resolveTrustedHeaders(value) {
|
|
5150
|
+
if (Array.isArray(value)) return normalizeTrustedHeaders(value);
|
|
5151
|
+
return getTrustedProxyHeaders(value);
|
|
5152
|
+
}
|
|
5036
5153
|
/**
|
|
5037
5154
|
* Headers that must never cross the RPC boundary to sandboxed plugins.
|
|
5038
5155
|
* Session tokens, auth credentials, and infrastructure headers are stripped
|
|
@@ -5681,7 +5798,7 @@ function createUnrestrictedHttpAccess(pluginId) {
|
|
|
5681
5798
|
let currentInit = init;
|
|
5682
5799
|
for (let i = 0; i <= MAX_PLUGIN_REDIRECTS; i++) {
|
|
5683
5800
|
try {
|
|
5684
|
-
|
|
5801
|
+
await resolveAndValidateExternalUrl(currentUrl);
|
|
5685
5802
|
} catch (e) {
|
|
5686
5803
|
const msg = e instanceof SsrfError ? e.message : "SSRF validation failed";
|
|
5687
5804
|
throw new Error(`Plugin "${pluginId}": blocked fetch to "${new URL(currentUrl).hostname}": ${msg}`, { cause: e });
|
|
@@ -6975,9 +7092,11 @@ async function devConsoleEmailDeliver(event, _ctx) {
|
|
|
6975
7092
|
var PluginRouteHandler = class {
|
|
6976
7093
|
contextFactory;
|
|
6977
7094
|
plugin;
|
|
7095
|
+
trustedProxyHeaders;
|
|
6978
7096
|
constructor(plugin, factoryOptions) {
|
|
6979
7097
|
this.plugin = plugin;
|
|
6980
7098
|
this.contextFactory = new PluginContextFactory(factoryOptions);
|
|
7099
|
+
this.trustedProxyHeaders = factoryOptions.trustedProxyHeaders ?? [];
|
|
6981
7100
|
}
|
|
6982
7101
|
/**
|
|
6983
7102
|
* Invoke a route by name
|
|
@@ -7010,7 +7129,7 @@ var PluginRouteHandler = class {
|
|
|
7010
7129
|
...this.contextFactory.createContext(this.plugin),
|
|
7011
7130
|
input: validatedInput,
|
|
7012
7131
|
request: options.request,
|
|
7013
|
-
requestMeta: extractRequestMeta(options.request)
|
|
7132
|
+
requestMeta: extractRequestMeta(options.request, this.trustedProxyHeaders)
|
|
7014
7133
|
};
|
|
7015
7134
|
try {
|
|
7016
7135
|
return {
|
|
@@ -7189,7 +7308,8 @@ var PluginManager = class {
|
|
|
7189
7308
|
this.factoryOptions = {
|
|
7190
7309
|
db: options.db,
|
|
7191
7310
|
storage: options.storage,
|
|
7192
|
-
getUploadUrl: options.getUploadUrl
|
|
7311
|
+
getUploadUrl: options.getUploadUrl,
|
|
7312
|
+
trustedProxyHeaders: options.trustedProxyHeaders
|
|
7193
7313
|
};
|
|
7194
7314
|
}
|
|
7195
7315
|
/**
|
|
@@ -7686,7 +7806,7 @@ async function probeUrl(url) {
|
|
|
7686
7806
|
let normalizedUrl = url.trim();
|
|
7687
7807
|
if (!normalizedUrl.startsWith("http")) normalizedUrl = `https://${normalizedUrl}`;
|
|
7688
7808
|
normalizedUrl = normalizedUrl.replace(TRAILING_SLASHES_PATTERN, "");
|
|
7689
|
-
|
|
7809
|
+
await resolveAndValidateExternalUrl(normalizedUrl);
|
|
7690
7810
|
const results = [];
|
|
7691
7811
|
const probePromises = getUrlSources().map(async (source) => {
|
|
7692
7812
|
try {
|
|
@@ -8682,8 +8802,10 @@ async function getCommentCountWithDb(db, collection, contentId) {
|
|
|
8682
8802
|
* }
|
|
8683
8803
|
* ```
|
|
8684
8804
|
*/
|
|
8685
|
-
|
|
8686
|
-
return
|
|
8805
|
+
function getMenu(name) {
|
|
8806
|
+
return requestCached(`menu:${name}`, async () => {
|
|
8807
|
+
return getMenuWithDb(name, await getDb());
|
|
8808
|
+
});
|
|
8687
8809
|
}
|
|
8688
8810
|
/**
|
|
8689
8811
|
* Get menu by name with resolved URLs (with explicit db)
|
|
@@ -8850,179 +8972,6 @@ async function resolveTaxonomyUrl(taxonomyId, db) {
|
|
|
8850
8972
|
return `/${taxonomy.name}/${taxonomy.slug}`;
|
|
8851
8973
|
}
|
|
8852
8974
|
|
|
8853
|
-
//#endregion
|
|
8854
|
-
//#region src/taxonomies/index.ts
|
|
8855
|
-
/**
|
|
8856
|
-
* Runtime API for taxonomies
|
|
8857
|
-
*
|
|
8858
|
-
* Provides functions to query taxonomy definitions and terms.
|
|
8859
|
-
*/
|
|
8860
|
-
/**
|
|
8861
|
-
* Get all taxonomy definitions
|
|
8862
|
-
*/
|
|
8863
|
-
async function getTaxonomyDefs() {
|
|
8864
|
-
return (await (await getDb()).selectFrom("_emdash_taxonomy_defs").selectAll().execute()).map((row) => ({
|
|
8865
|
-
id: row.id,
|
|
8866
|
-
name: row.name,
|
|
8867
|
-
label: row.label,
|
|
8868
|
-
labelSingular: row.label_singular ?? void 0,
|
|
8869
|
-
hierarchical: row.hierarchical === 1,
|
|
8870
|
-
collections: row.collections ? JSON.parse(row.collections) : []
|
|
8871
|
-
}));
|
|
8872
|
-
}
|
|
8873
|
-
/**
|
|
8874
|
-
* Get a single taxonomy definition by name
|
|
8875
|
-
*/
|
|
8876
|
-
async function getTaxonomyDef(name) {
|
|
8877
|
-
const row = await (await getDb()).selectFrom("_emdash_taxonomy_defs").selectAll().where("name", "=", name).executeTakeFirst();
|
|
8878
|
-
if (!row) return null;
|
|
8879
|
-
return {
|
|
8880
|
-
id: row.id,
|
|
8881
|
-
name: row.name,
|
|
8882
|
-
label: row.label,
|
|
8883
|
-
labelSingular: row.label_singular ?? void 0,
|
|
8884
|
-
hierarchical: row.hierarchical === 1,
|
|
8885
|
-
collections: row.collections ? JSON.parse(row.collections) : []
|
|
8886
|
-
};
|
|
8887
|
-
}
|
|
8888
|
-
/**
|
|
8889
|
-
* Get all terms for a taxonomy (as tree for hierarchical, flat for tags)
|
|
8890
|
-
*/
|
|
8891
|
-
async function getTaxonomyTerms(taxonomyName) {
|
|
8892
|
-
const db = await getDb();
|
|
8893
|
-
const def = await getTaxonomyDef(taxonomyName);
|
|
8894
|
-
if (!def) return [];
|
|
8895
|
-
const rows = await db.selectFrom("taxonomies").selectAll().where("name", "=", taxonomyName).orderBy("label", "asc").execute();
|
|
8896
|
-
const countsResult = await db.selectFrom("content_taxonomies").select(["taxonomy_id"]).select((eb) => eb.fn.count("entry_id").as("count")).groupBy("taxonomy_id").execute();
|
|
8897
|
-
const counts = /* @__PURE__ */ new Map();
|
|
8898
|
-
for (const row of countsResult) counts.set(row.taxonomy_id, row.count);
|
|
8899
|
-
const flatTerms = rows.map((row) => ({
|
|
8900
|
-
id: row.id,
|
|
8901
|
-
name: row.name,
|
|
8902
|
-
slug: row.slug,
|
|
8903
|
-
label: row.label,
|
|
8904
|
-
parent_id: row.parent_id,
|
|
8905
|
-
data: row.data
|
|
8906
|
-
}));
|
|
8907
|
-
if (def.hierarchical) return buildTree(flatTerms, counts);
|
|
8908
|
-
return flatTerms.map((term) => ({
|
|
8909
|
-
id: term.id,
|
|
8910
|
-
name: term.name,
|
|
8911
|
-
slug: term.slug,
|
|
8912
|
-
label: term.label,
|
|
8913
|
-
children: [],
|
|
8914
|
-
count: counts.get(term.id) ?? 0
|
|
8915
|
-
}));
|
|
8916
|
-
}
|
|
8917
|
-
/**
|
|
8918
|
-
* Get a single term by taxonomy and slug
|
|
8919
|
-
*/
|
|
8920
|
-
async function getTerm(taxonomyName, slug) {
|
|
8921
|
-
const db = await getDb();
|
|
8922
|
-
const row = await db.selectFrom("taxonomies").selectAll().where("name", "=", taxonomyName).where("slug", "=", slug).executeTakeFirst();
|
|
8923
|
-
if (!row) return null;
|
|
8924
|
-
const count = (await db.selectFrom("content_taxonomies").select((eb) => eb.fn.count("entry_id").as("count")).where("taxonomy_id", "=", row.id).executeTakeFirst())?.count ?? 0;
|
|
8925
|
-
const children = (await db.selectFrom("taxonomies").selectAll().where("parent_id", "=", row.id).orderBy("label", "asc").execute()).map((child) => ({
|
|
8926
|
-
id: child.id,
|
|
8927
|
-
name: child.name,
|
|
8928
|
-
slug: child.slug,
|
|
8929
|
-
label: child.label,
|
|
8930
|
-
parentId: child.parent_id ?? void 0,
|
|
8931
|
-
children: []
|
|
8932
|
-
}));
|
|
8933
|
-
return {
|
|
8934
|
-
id: row.id,
|
|
8935
|
-
name: row.name,
|
|
8936
|
-
slug: row.slug,
|
|
8937
|
-
label: row.label,
|
|
8938
|
-
parentId: row.parent_id ?? void 0,
|
|
8939
|
-
description: row.data ? JSON.parse(row.data).description : void 0,
|
|
8940
|
-
children,
|
|
8941
|
-
count
|
|
8942
|
-
};
|
|
8943
|
-
}
|
|
8944
|
-
/**
|
|
8945
|
-
* Get terms assigned to an entry
|
|
8946
|
-
*/
|
|
8947
|
-
async function getEntryTerms(collection, entryId, taxonomyName) {
|
|
8948
|
-
let query = (await getDb()).selectFrom("content_taxonomies").innerJoin("taxonomies", "taxonomies.id", "content_taxonomies.taxonomy_id").selectAll("taxonomies").where("content_taxonomies.collection", "=", collection).where("content_taxonomies.entry_id", "=", entryId);
|
|
8949
|
-
if (taxonomyName) query = query.where("taxonomies.name", "=", taxonomyName);
|
|
8950
|
-
return (await query.execute()).map((row) => ({
|
|
8951
|
-
id: row.id,
|
|
8952
|
-
name: row.name,
|
|
8953
|
-
slug: row.slug,
|
|
8954
|
-
label: row.label,
|
|
8955
|
-
parentId: row.parent_id ?? void 0,
|
|
8956
|
-
children: []
|
|
8957
|
-
}));
|
|
8958
|
-
}
|
|
8959
|
-
/**
|
|
8960
|
-
* Get terms for multiple entries in a single query (batched API)
|
|
8961
|
-
*
|
|
8962
|
-
* This is more efficient than calling getEntryTerms for each entry
|
|
8963
|
-
* when you need terms for a list of entries.
|
|
8964
|
-
*
|
|
8965
|
-
* @param collection - The collection type (e.g., "posts")
|
|
8966
|
-
* @param entryIds - Array of entry IDs
|
|
8967
|
-
* @param taxonomyName - The taxonomy name (e.g., "categories")
|
|
8968
|
-
* @returns Map from entry ID to array of terms
|
|
8969
|
-
*/
|
|
8970
|
-
async function getTermsForEntries(collection, entryIds, taxonomyName) {
|
|
8971
|
-
const result = /* @__PURE__ */ new Map();
|
|
8972
|
-
for (const id of entryIds) result.set(id, []);
|
|
8973
|
-
if (entryIds.length === 0) return result;
|
|
8974
|
-
const rows = await (await getDb()).selectFrom("content_taxonomies").innerJoin("taxonomies", "taxonomies.id", "content_taxonomies.taxonomy_id").select([
|
|
8975
|
-
"content_taxonomies.entry_id",
|
|
8976
|
-
"taxonomies.id",
|
|
8977
|
-
"taxonomies.name",
|
|
8978
|
-
"taxonomies.slug",
|
|
8979
|
-
"taxonomies.label",
|
|
8980
|
-
"taxonomies.parent_id"
|
|
8981
|
-
]).where("content_taxonomies.collection", "=", collection).where("content_taxonomies.entry_id", "in", entryIds).where("taxonomies.name", "=", taxonomyName).execute();
|
|
8982
|
-
for (const row of rows) {
|
|
8983
|
-
const entryId = row.entry_id;
|
|
8984
|
-
const term = {
|
|
8985
|
-
id: row.id,
|
|
8986
|
-
name: row.name,
|
|
8987
|
-
slug: row.slug,
|
|
8988
|
-
label: row.label,
|
|
8989
|
-
parentId: row.parent_id ?? void 0,
|
|
8990
|
-
children: []
|
|
8991
|
-
};
|
|
8992
|
-
const terms = result.get(entryId);
|
|
8993
|
-
if (terms) terms.push(term);
|
|
8994
|
-
}
|
|
8995
|
-
return result;
|
|
8996
|
-
}
|
|
8997
|
-
/**
|
|
8998
|
-
* Get entries by term (wraps getEmDashCollection)
|
|
8999
|
-
*/
|
|
9000
|
-
async function getEntriesByTerm(collection, taxonomyName, termSlug) {
|
|
9001
|
-
const { getEmDashCollection } = await import("./query-B6Vu0d2i.mjs").then((n) => n.o);
|
|
9002
|
-
const { entries } = await getEmDashCollection(collection, { where: { [taxonomyName]: termSlug } });
|
|
9003
|
-
return entries;
|
|
9004
|
-
}
|
|
9005
|
-
/**
|
|
9006
|
-
* Build tree structure from flat terms
|
|
9007
|
-
*/
|
|
9008
|
-
function buildTree(flatTerms, counts) {
|
|
9009
|
-
const map = /* @__PURE__ */ new Map();
|
|
9010
|
-
const roots = [];
|
|
9011
|
-
for (const term of flatTerms) map.set(term.id, {
|
|
9012
|
-
id: term.id,
|
|
9013
|
-
name: term.name,
|
|
9014
|
-
slug: term.slug,
|
|
9015
|
-
label: term.label,
|
|
9016
|
-
parentId: term.parent_id ?? void 0,
|
|
9017
|
-
description: term.data ? JSON.parse(term.data).description : void 0,
|
|
9018
|
-
children: [],
|
|
9019
|
-
count: counts.get(term.id) ?? 0
|
|
9020
|
-
});
|
|
9021
|
-
for (const term of map.values()) if (term.parentId && map.has(term.parentId)) map.get(term.parentId).children.push(term);
|
|
9022
|
-
else roots.push(term);
|
|
9023
|
-
return roots;
|
|
9024
|
-
}
|
|
9025
|
-
|
|
9026
8975
|
//#endregion
|
|
9027
8976
|
//#region src/widgets/components.ts
|
|
9028
8977
|
/**
|
|
@@ -9132,18 +9081,53 @@ function getWidgetComponents$1() {
|
|
|
9132
9081
|
//#endregion
|
|
9133
9082
|
//#region src/widgets/index.ts
|
|
9134
9083
|
/**
|
|
9135
|
-
* Get a widget area by name, with all its widgets
|
|
9084
|
+
* Get a widget area by name, with all its widgets.
|
|
9085
|
+
*
|
|
9086
|
+
* Single query with a left join rather than area-then-widgets so the
|
|
9087
|
+
* common case costs one round-trip. An area with no widgets yields one
|
|
9088
|
+
* row with null widget columns, which we skip when mapping.
|
|
9136
9089
|
*/
|
|
9137
9090
|
async function getWidgetArea(name) {
|
|
9138
|
-
const
|
|
9139
|
-
|
|
9140
|
-
|
|
9141
|
-
|
|
9091
|
+
const rows = await (await getDb()).selectFrom("_emdash_widget_areas as a").leftJoin("_emdash_widgets as w", "w.area_id", "a.id").select([
|
|
9092
|
+
"a.id as a_id",
|
|
9093
|
+
"a.name as a_name",
|
|
9094
|
+
"a.label as a_label",
|
|
9095
|
+
"a.description as a_description",
|
|
9096
|
+
"w.id as w_id",
|
|
9097
|
+
"w.type as w_type",
|
|
9098
|
+
"w.title as w_title",
|
|
9099
|
+
"w.content as w_content",
|
|
9100
|
+
"w.menu_name as w_menu_name",
|
|
9101
|
+
"w.component_id as w_component_id",
|
|
9102
|
+
"w.component_props as w_component_props",
|
|
9103
|
+
"w.area_id as w_area_id",
|
|
9104
|
+
"w.sort_order as w_sort_order",
|
|
9105
|
+
"w.created_at as w_created_at"
|
|
9106
|
+
]).where("a.name", "=", name).orderBy("w.sort_order", "asc").execute();
|
|
9107
|
+
const first = rows[0];
|
|
9108
|
+
if (!first) return null;
|
|
9109
|
+
const widgets = [];
|
|
9110
|
+
for (const row of rows) {
|
|
9111
|
+
if (row.w_id === null) continue;
|
|
9112
|
+
const widgetRow = {
|
|
9113
|
+
id: row.w_id,
|
|
9114
|
+
type: row.w_type,
|
|
9115
|
+
title: row.w_title,
|
|
9116
|
+
content: row.w_content,
|
|
9117
|
+
menu_name: row.w_menu_name,
|
|
9118
|
+
component_id: row.w_component_id,
|
|
9119
|
+
component_props: row.w_component_props,
|
|
9120
|
+
area_id: row.w_area_id,
|
|
9121
|
+
sort_order: row.w_sort_order,
|
|
9122
|
+
created_at: row.w_created_at
|
|
9123
|
+
};
|
|
9124
|
+
widgets.push(rowToWidget(widgetRow));
|
|
9125
|
+
}
|
|
9142
9126
|
return {
|
|
9143
|
-
id:
|
|
9144
|
-
name:
|
|
9145
|
-
label:
|
|
9146
|
-
description:
|
|
9127
|
+
id: first.a_id,
|
|
9128
|
+
name: first.a_name,
|
|
9129
|
+
label: first.a_label,
|
|
9130
|
+
description: first.a_description ?? void 0,
|
|
9147
9131
|
widgets
|
|
9148
9132
|
};
|
|
9149
9133
|
}
|
|
@@ -9345,8 +9329,8 @@ async function getSuggestions(db, query, options = {}) {
|
|
|
9345
9329
|
validateIdentifier(collection, "collection slug");
|
|
9346
9330
|
const ftsTable = ftsManager.getFtsTableName(collection);
|
|
9347
9331
|
const contentTable = ftsManager.getContentTableName(collection);
|
|
9348
|
-
const prefixQuery =
|
|
9349
|
-
if (!prefixQuery
|
|
9332
|
+
const prefixQuery = escapeQuery(query);
|
|
9333
|
+
if (!prefixQuery) continue;
|
|
9350
9334
|
const results = await sql`
|
|
9351
9335
|
SELECT
|
|
9352
9336
|
c.id,
|
|
@@ -9506,5 +9490,5 @@ function extractSearchableFields(entry, fields) {
|
|
|
9506
9490
|
}
|
|
9507
9491
|
|
|
9508
9492
|
//#endregion
|
|
9509
|
-
export {
|
|
9510
|
-
//# sourceMappingURL=search-
|
|
9493
|
+
export { prosemirrorToPortableText as $, isStandardPluginDefinition as A, handleContentPublish as At, EmailPipeline as B, image as Bt, getAllSources as C, handleContentDiscardDraft as Ct, probeUrl as D, handleContentList as Dt, getUrlSources as E, handleContentGetIncludingTrashed as Et, createPluginManager as F, handleContentUnschedule as Ft, extractRequestMeta as G, createHookPipeline as H, PluginRouteError as I, handleContentUpdate as It, definePlugin as J, sanitizeHeadersForSandbox as K, PluginRouteRegistry as L, validateRev as Lt, SandboxNotAvailableError as M, handleContentSchedule as Mt, createNoopSandboxRunner as N, handleContentTranslations as Nt, registerSource as O, handleContentListTrashed as Ot, PluginManager as P, handleContentUnpublish as Pt, portableTextToProsemirror as Q, DEV_CONSOLE_EMAIL_PLUGIN_ID as R, portableText as Rt, clearSources as S, handleContentDelete as St, getSource as T, handleContentGet as Tt, resolveExclusiveHooks as U, HookPipeline as V, CronExecutor as W, parseWxrString as X, parseWxr as Y, after as Z, buildPreviewUrl as _, hashString as _t, search as a, PluginStateRepository as at, parseWxrDate as b, handleContentCountTrashed as bt, getWidgetArea as c, handleMediaDelete as ct, getMenu as d, handleMediaUpdate as dt, isSafeHref as et, getMenus as f, handleRevisionGet as ft, isPreviewRequest as g, computeContentHash as gt, getPreviewToken as h, generateManifest as ht, getSuggestions as i, getSections as it, NoopSandboxRunner as j, handleContentRestore as jt, importReusableBlocksAsSections as k, handleContentPermanentDelete as kt, getWidgetAreas as l, handleMediaGet as lt, getComments as m, handleRevisionRestore as mt, extractSearchableFields as n, loadBundleFromR2 as nt, searchCollection as o, getCollectionInfo as ot, getCommentCount as p, handleRevisionList as pt, getTrustedProxyHeaders as q, getSearchStats as r, getSection as rt, searchWithDb as s, handleMediaCreate as st, extractPlainText as t, sanitizeHref as tt, getWidgetComponents as u, handleMediaList as ut, getPreviewUrl as v, handleContentCompare as vt, getFileSources as w, handleContentDuplicate as wt, wxrSource as x, handleContentCreate as xt, wordpressRestSource as y, handleContentCountScheduled as yt, devConsoleEmailDeliver as z, reference as zt };
|
|
9494
|
+
//# sourceMappingURL=search-B0effn3j.mjs.map
|