emdash 0.2.0 → 0.4.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-N6BF7RCD.d.mts → adapters-C2BzVy0p.d.mts} +1 -1
- package/dist/{adapters-N6BF7RCD.d.mts.map → adapters-C2BzVy0p.d.mts.map} +1 -1
- package/dist/{apply-wmVEOSbR.mjs → apply-Cma_PiF6.mjs} +38 -23
- package/dist/apply-Cma_PiF6.mjs.map +1 -0
- package/dist/astro/index.d.mts +25 -11
- package/dist/astro/index.d.mts.map +1 -1
- package/dist/astro/index.mjs +38 -25
- package/dist/astro/index.mjs.map +1 -1
- package/dist/astro/middleware/auth.d.mts +5 -5
- package/dist/astro/middleware/auth.mjs +2 -2
- package/dist/astro/middleware/redirect.d.mts.map +1 -1
- package/dist/astro/middleware/redirect.mjs +20 -8
- package/dist/astro/middleware/redirect.mjs.map +1 -1
- package/dist/astro/middleware/request-context.mjs +12 -2
- 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 +52 -45
- package/dist/astro/middleware.mjs.map +1 -1
- package/dist/astro/types.d.mts +9 -9
- package/dist/astro/types.d.mts.map +1 -1
- package/dist/{byline-1WQPlISL.mjs → byline-WuOq9MFJ.mjs} +5 -4
- package/dist/byline-WuOq9MFJ.mjs.map +1 -0
- package/dist/{bylines-BYdTYmia.mjs → bylines-C_Wsnz4L.mjs} +38 -6
- package/dist/bylines-C_Wsnz4L.mjs.map +1 -0
- package/dist/cache-E3Dts-yT.mjs +56 -0
- package/dist/cache-E3Dts-yT.mjs.map +1 -0
- package/dist/cli/index.mjs +13 -13
- 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-Cq8H0SfX.mjs → config-DkxPrM9l.mjs} +1 -1
- package/dist/{config-Cq8H0SfX.mjs.map → config-DkxPrM9l.mjs.map} +1 -1
- package/dist/{content-BmXndhdi.mjs → content-BsBoyj8G.mjs} +20 -3
- package/dist/content-BsBoyj8G.mjs.map +1 -0
- package/dist/db/index.d.mts +3 -3
- package/dist/db/index.mjs +2 -2
- 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/{default-WYlzADZL.mjs → default-PUx9RK6u.mjs} +1 -1
- package/dist/{default-WYlzADZL.mjs.map → default-PUx9RK6u.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-DrxtnGPg.mjs → error-HBeQbVhV.mjs} +1 -1
- package/dist/{error-DrxtnGPg.mjs.map → error-HBeQbVhV.mjs.map} +1 -1
- package/dist/{index-UHEVQMus.d.mts → index-CRg3PWfZ.d.mts} +59 -33
- package/dist/index-CRg3PWfZ.d.mts.map +1 -0
- package/dist/index.d.mts +11 -11
- package/dist/index.mjs +20 -20
- package/dist/{load-Veizk2cT.mjs → load-BhSSm-TS.mjs} +1 -1
- package/dist/{load-Veizk2cT.mjs.map → load-BhSSm-TS.mjs.map} +1 -1
- package/dist/{loader-CHb2v0jm.mjs → loader-BYzwzORf.mjs} +4 -2
- package/dist/loader-BYzwzORf.mjs.map +1 -0
- package/dist/{manifest-schema-CuMio1A9.mjs → manifest-schema-BsXINkQD.mjs} +1 -1
- package/dist/{manifest-schema-CuMio1A9.mjs.map → manifest-schema-BsXINkQD.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-CYeM2rPt.mjs → mode-CyPLdO3C.mjs} +1 -1
- package/dist/{mode-CYeM2rPt.mjs.map → mode-CyPLdO3C.mjs.map} +1 -1
- package/dist/page/index.d.mts +1 -1
- package/dist/patterns-CrCYkMBb.mjs +93 -0
- package/dist/patterns-CrCYkMBb.mjs.map +1 -0
- package/dist/{placeholder-bOx1xCTY.d.mts → placeholder-BBCtpTES.d.mts} +1 -1
- package/dist/{placeholder-bOx1xCTY.d.mts.map → placeholder-BBCtpTES.d.mts.map} +1 -1
- package/dist/{placeholder-aiCD8aSZ.mjs → placeholder-DntBEQo7.mjs} +1 -1
- package/dist/{placeholder-aiCD8aSZ.mjs.map → placeholder-DntBEQo7.mjs.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-5Hcv_5ER.mjs → query-B6Vu0d2i.mjs} +35 -16
- package/dist/{query-5Hcv_5ER.mjs.map → query-B6Vu0d2i.mjs.map} +1 -1
- package/dist/{redirect-DIfIni3r.mjs → redirect-7lGhLBNZ.mjs} +10 -93
- package/dist/redirect-7lGhLBNZ.mjs.map +1 -0
- package/dist/{registry-1EvbAfsC.mjs → registry-BgnP3ysR.mjs} +27 -37
- package/dist/registry-BgnP3ysR.mjs.map +1 -0
- package/dist/{runner-BoN0-FPi.mjs → runner-Cd-_WyDo.mjs} +18 -6
- package/dist/runner-Cd-_WyDo.mjs.map +1 -0
- package/dist/{runner-DTqkzOzc.d.mts → runner-DYv3rX8P.d.mts} +10 -3
- package/dist/runner-DYv3rX8P.d.mts.map +1 -0
- package/dist/runtime.d.mts +6 -6
- package/dist/runtime.mjs +2 -2
- package/dist/{search-BsYMed12.mjs → search-B5p9D36n.mjs} +108 -57
- package/dist/search-B5p9D36n.mjs.map +1 -0
- package/dist/seed/index.d.mts +2 -2
- 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-DrB-W6Q-.mjs → tokens-DKHiCYCB.mjs} +1 -1
- package/dist/{tokens-DrB-W6Q-.mjs.map → tokens-DKHiCYCB.mjs.map} +1 -1
- package/dist/transaction-Cn2rjY78.mjs +28 -0
- package/dist/transaction-Cn2rjY78.mjs.map +1 -0
- package/dist/{transport-Bl8cTdYt.mjs → transport-BtcQ-Z7T.mjs} +1 -1
- package/dist/{transport-Bl8cTdYt.mjs.map → transport-BtcQ-Z7T.mjs.map} +1 -1
- package/dist/{transport-COOs9GSE.d.mts → transport-CKQA_G44.d.mts} +1 -1
- package/dist/{transport-COOs9GSE.d.mts.map → transport-CKQA_G44.d.mts.map} +1 -1
- package/dist/{types-7-UjSEyB.d.mts → types-B6BzlZxx.d.mts} +1 -1
- package/dist/{types-7-UjSEyB.d.mts.map → types-B6BzlZxx.d.mts.map} +1 -1
- package/dist/{types-6dqxBqsH.d.mts → types-BYWYxLcp.d.mts} +109 -5
- package/dist/types-BYWYxLcp.d.mts.map +1 -0
- package/dist/{types-CIsTnQvJ.d.mts → types-BmkQR1En.d.mts} +1 -1
- package/dist/{types-CIsTnQvJ.d.mts.map → types-BmkQR1En.d.mts.map} +1 -1
- package/dist/{types-BljtYPSd.d.mts → types-DNZpaCBk.d.mts} +14 -6
- package/dist/types-DNZpaCBk.d.mts.map +1 -0
- package/dist/{types-Bec-r_3_.mjs → types-Dz9_WMS6.mjs} +1 -1
- package/dist/types-Dz9_WMS6.mjs.map +1 -0
- package/dist/{types-CcreFIIH.d.mts → types-gLYVCXCQ.d.mts} +1 -1
- package/dist/{types-CcreFIIH.d.mts.map → types-gLYVCXCQ.d.mts.map} +1 -1
- package/dist/{types-DuNbGKjF.mjs → types-xxCWI3j0.mjs} +1 -1
- package/dist/{types-DuNbGKjF.mjs.map → types-xxCWI3j0.mjs.map} +1 -1
- package/dist/{validate-B7KP7VLM.d.mts → validate-CcNRWH6I.d.mts} +4 -4
- package/dist/{validate-B7KP7VLM.d.mts.map → validate-CcNRWH6I.d.mts.map} +1 -1
- package/dist/{validate-CXnRKfJK.mjs → validate-DuZDIxfy.mjs} +2 -2
- package/dist/{validate-CXnRKfJK.mjs.map → validate-DuZDIxfy.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/version-DlTDRdpv.mjs +7 -0
- package/dist/version-DlTDRdpv.mjs.map +1 -0
- package/package.json +7 -5
- package/src/api/handlers/content.ts +36 -25
- package/src/api/handlers/menus.ts +19 -16
- package/src/api/handlers/redirects.ts +95 -3
- package/src/api/schemas/redirects.ts +1 -0
- package/src/astro/integration/index.ts +2 -3
- package/src/astro/integration/runtime.ts +8 -14
- package/src/astro/integration/vite-config.ts +14 -4
- package/src/astro/middleware/redirect.ts +30 -15
- package/src/astro/middleware.ts +11 -19
- package/src/astro/routes/admin.astro +2 -2
- package/src/astro/routes/api/admin/bylines/[id]/index.ts +3 -0
- package/src/astro/routes/api/admin/bylines/index.ts +2 -0
- package/src/astro/routes/api/comments/[collection]/[contentId]/index.ts +2 -0
- package/src/astro/routes/api/import/wordpress/rewrite-urls.ts +2 -0
- package/src/astro/routes/api/manifest.ts +3 -1
- package/src/astro/routes/api/redirects/[id].ts +3 -0
- package/src/astro/routes/api/redirects/index.ts +2 -0
- package/src/astro/routes/api/schema/collections/[slug]/index.ts +2 -0
- package/src/astro/routes/api/schema/collections/index.ts +1 -0
- package/src/astro/storage/adapters.ts +19 -5
- package/src/astro/storage/types.ts +12 -4
- package/src/astro/types.ts +1 -0
- package/src/bylines/index.ts +50 -2
- package/src/cleanup.ts +3 -3
- package/src/cli/commands/bundle-utils.ts +5 -5
- package/src/database/dialect-helpers.ts +3 -0
- package/src/database/migrations/011_sections.ts +2 -2
- package/src/database/migrations/runner.ts +23 -2
- package/src/database/repositories/byline.ts +2 -1
- package/src/database/repositories/content.ts +5 -0
- package/src/database/repositories/redirect.ts +13 -0
- package/src/database/validate.ts +10 -10
- package/src/emdash-runtime.ts +23 -9
- package/src/index.ts +3 -0
- package/src/loader.ts +2 -0
- package/src/mcp/server.ts +40 -67
- package/src/menus/index.ts +4 -0
- package/src/plugins/context.ts +28 -4
- package/src/plugins/cron.ts +29 -4
- package/src/plugins/hooks.ts +22 -10
- package/src/plugins/index.ts +1 -0
- package/src/plugins/manager.ts +6 -2
- package/src/plugins/marketplace.ts +33 -3
- package/src/plugins/routes.ts +3 -3
- package/src/plugins/types.ts +7 -0
- package/src/query.ts +37 -14
- package/src/redirects/cache.ts +68 -0
- package/src/redirects/loops.ts +318 -0
- package/src/schema/registry.ts +3 -0
- package/src/search/fts-manager.ts +24 -11
- package/src/search/query.ts +8 -9
- package/src/seed/apply.ts +49 -28
- package/src/storage/s3.ts +94 -25
- package/src/storage/types.ts +13 -5
- package/src/utils/slugify.ts +11 -0
- package/src/version.ts +12 -0
- package/src/visual-editing/toolbar.ts +11 -1
- package/dist/apply-wmVEOSbR.mjs.map +0 -1
- package/dist/byline-1WQPlISL.mjs.map +0 -1
- package/dist/bylines-BYdTYmia.mjs.map +0 -1
- package/dist/content-BmXndhdi.mjs.map +0 -1
- package/dist/dialect-helpers-B9uSp2GJ.mjs.map +0 -1
- package/dist/index-UHEVQMus.d.mts.map +0 -1
- package/dist/loader-CHb2v0jm.mjs.map +0 -1
- package/dist/redirect-DIfIni3r.mjs.map +0 -1
- package/dist/registry-1EvbAfsC.mjs.map +0 -1
- package/dist/runner-BoN0-FPi.mjs.map +0 -1
- package/dist/runner-DTqkzOzc.d.mts.map +0 -1
- package/dist/search-BsYMed12.mjs.map +0 -1
- package/dist/types-6dqxBqsH.d.mts.map +0 -1
- package/dist/types-Bec-r_3_.mjs.map +0 -1
- package/dist/types-BljtYPSd.d.mts.map +0 -1
package/dist/astro/types.d.mts
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
import { f as MediaProvider, p as MediaProviderCapabilities } from "../placeholder-
|
|
2
|
-
import { t as Database } from "../types-
|
|
3
|
-
import {
|
|
4
|
-
import "../runner-
|
|
5
|
-
import { r as ContentItem } from "../types-
|
|
6
|
-
import {
|
|
7
|
-
import "../validate-
|
|
8
|
-
import { d as Storage } from "../types-
|
|
1
|
+
import { f as MediaProvider, p as MediaProviderCapabilities } from "../placeholder-BBCtpTES.mjs";
|
|
2
|
+
import { t as Database } from "../types-B6BzlZxx.mjs";
|
|
3
|
+
import { Dr as SandboxRunner, Hr as MediaResponse, Pi as MediaItem, Vr as MediaListResponse, an as EmailPipeline, bi as ContentListResponse, dn as EmDashConfig, on as HookPipeline, xi as ContentResponse } from "../index-CRg3PWfZ.mjs";
|
|
4
|
+
import "../runner-DYv3rX8P.mjs";
|
|
5
|
+
import { r as ContentItem } from "../types-BmkQR1En.mjs";
|
|
6
|
+
import { A as PageMetadataContribution, D as PageFragmentContribution, X as ResolvedPlugin, q as PublicPageContext, st as Element } from "../types-BYWYxLcp.mjs";
|
|
7
|
+
import "../validate-CcNRWH6I.mjs";
|
|
8
|
+
import { d as Storage } from "../types-DNZpaCBk.mjs";
|
|
9
9
|
import "../index.mjs";
|
|
10
10
|
import { Kysely } from "kysely";
|
|
11
|
-
import { Element } from "@emdash-cms/blocks";
|
|
12
11
|
|
|
13
12
|
//#region src/astro/types.d.ts
|
|
14
13
|
/**
|
|
@@ -90,6 +89,7 @@ type ManifestAuthMode = string;
|
|
|
90
89
|
*/
|
|
91
90
|
interface EmDashManifest {
|
|
92
91
|
version: string;
|
|
92
|
+
commit?: string;
|
|
93
93
|
hash: string;
|
|
94
94
|
collections: Record<string, ManifestCollection>;
|
|
95
95
|
plugins: Record<string, ManifestPlugin>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.mts","names":[],"sources":["../../src/astro/types.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.d.mts","names":[],"sources":["../../src/astro/types.ts"],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { t as validateIdentifier } from "./validate-VPnKoIzW.mjs";
|
|
2
|
+
import { s as listTablesLike } from "./dialect-helpers-DhTzaUxP.mjs";
|
|
3
3
|
import { n as decodeCursor, r as encodeCursor } from "./types-CMMN0pNg.mjs";
|
|
4
|
+
import { t as withTransaction } from "./transaction-Cn2rjY78.mjs";
|
|
4
5
|
import { sql } from "kysely";
|
|
5
6
|
import { ulid } from "ulidx";
|
|
6
7
|
|
|
@@ -108,7 +109,7 @@ var BylineRepository = class {
|
|
|
108
109
|
}
|
|
109
110
|
async delete(id) {
|
|
110
111
|
if (!await this.findById(id)) return false;
|
|
111
|
-
await this.db
|
|
112
|
+
await withTransaction(this.db, async (trx) => {
|
|
112
113
|
await trx.deleteFrom("_emdash_content_bylines").where("byline_id", "=", id).execute();
|
|
113
114
|
await trx.deleteFrom("_emdash_bylines").where("id", "=", id).execute();
|
|
114
115
|
const tableNames = await listTablesLike(trx, "ec_%");
|
|
@@ -232,4 +233,4 @@ var BylineRepository = class {
|
|
|
232
233
|
|
|
233
234
|
//#endregion
|
|
234
235
|
export { SQL_BATCH_SIZE as n, chunks as r, BylineRepository as t };
|
|
235
|
-
//# sourceMappingURL=byline-
|
|
236
|
+
//# sourceMappingURL=byline-WuOq9MFJ.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"byline-WuOq9MFJ.mjs","names":[],"sources":["../src/utils/chunks.ts","../src/database/repositories/byline.ts"],"sourcesContent":["/**\n * Split an array into chunks of at most `size` elements.\n *\n * Used to keep SQL `IN (?, ?, …)` clauses within Cloudflare D1's\n * bound-parameter limit (~100 per statement).\n */\nexport function chunks<T>(arr: T[], size: number): T[][] {\n\tif (arr.length === 0) return [];\n\tconst result: T[][] = [];\n\tfor (let i = 0; i < arr.length; i += size) {\n\t\tresult.push(arr.slice(i, i + size));\n\t}\n\treturn result;\n}\n\n/** Conservative default chunk size for SQL IN clauses (well within D1's limit). */\nexport const SQL_BATCH_SIZE = 50;\n","import { sql, type Kysely, type Selectable } from \"kysely\";\nimport { ulid } from \"ulidx\";\n\nimport { chunks, SQL_BATCH_SIZE } from \"../../utils/chunks.js\";\nimport { listTablesLike } from \"../dialect-helpers.js\";\nimport { withTransaction } from \"../transaction.js\";\nimport type { BylineTable, Database } from \"../types.js\";\nimport { validateIdentifier } from \"../validate.js\";\nimport {\n\tdecodeCursor,\n\tencodeCursor,\n\ttype BylineSummary,\n\ttype ContentBylineCredit,\n\ttype FindManyResult,\n} from \"./types.js\";\n\ntype BylineRow = Selectable<BylineTable>;\n\nexport interface CreateBylineInput {\n\tslug: string;\n\tdisplayName: string;\n\tbio?: string | null;\n\tavatarMediaId?: string | null;\n\twebsiteUrl?: string | null;\n\tuserId?: string | null;\n\tisGuest?: boolean;\n}\n\nexport interface UpdateBylineInput {\n\tslug?: string;\n\tdisplayName?: string;\n\tbio?: string | null;\n\tavatarMediaId?: string | null;\n\twebsiteUrl?: string | null;\n\tuserId?: string | null;\n\tisGuest?: boolean;\n}\n\nexport interface ContentBylineInput {\n\tbylineId: string;\n\troleLabel?: string | null;\n}\n\nfunction rowToByline(row: BylineRow): BylineSummary {\n\treturn {\n\t\tid: row.id,\n\t\tslug: row.slug,\n\t\tdisplayName: row.display_name,\n\t\tbio: row.bio,\n\t\tavatarMediaId: row.avatar_media_id,\n\t\twebsiteUrl: row.website_url,\n\t\tuserId: row.user_id,\n\t\tisGuest: row.is_guest === 1,\n\t\tcreatedAt: row.created_at,\n\t\tupdatedAt: row.updated_at,\n\t};\n}\n\nexport class BylineRepository {\n\tconstructor(private db: Kysely<Database>) {}\n\n\tasync findById(id: string): Promise<BylineSummary | null> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"_emdash_bylines\")\n\t\t\t.selectAll()\n\t\t\t.where(\"id\", \"=\", id)\n\t\t\t.executeTakeFirst();\n\t\treturn row ? rowToByline(row) : null;\n\t}\n\n\tasync findBySlug(slug: string): Promise<BylineSummary | null> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"_emdash_bylines\")\n\t\t\t.selectAll()\n\t\t\t.where(\"slug\", \"=\", slug)\n\t\t\t.executeTakeFirst();\n\t\treturn row ? rowToByline(row) : null;\n\t}\n\n\tasync findByUserId(userId: string): Promise<BylineSummary | null> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"_emdash_bylines\")\n\t\t\t.selectAll()\n\t\t\t.where(\"user_id\", \"=\", userId)\n\t\t\t.executeTakeFirst();\n\t\treturn row ? rowToByline(row) : null;\n\t}\n\n\tasync findMany(options?: {\n\t\tsearch?: string;\n\t\tisGuest?: boolean;\n\t\tuserId?: string;\n\t\tcursor?: string;\n\t\tlimit?: number;\n\t}): Promise<FindManyResult<BylineSummary>> {\n\t\tconst limit = Math.min(Math.max(options?.limit ?? 50, 1), 100);\n\n\t\tlet query = this.db\n\t\t\t.selectFrom(\"_emdash_bylines\")\n\t\t\t.selectAll()\n\t\t\t.orderBy(\"created_at\", \"desc\")\n\t\t\t.orderBy(\"id\", \"desc\")\n\t\t\t.limit(limit + 1);\n\n\t\tif (options?.search) {\n\t\t\tconst escaped = options.search\n\t\t\t\t.replaceAll(\"\\\\\", \"\\\\\\\\\")\n\t\t\t\t.replaceAll(\"%\", \"\\\\%\")\n\t\t\t\t.replaceAll(\"_\", \"\\\\_\");\n\t\t\tconst term = `%${escaped}%`;\n\t\t\tquery = query.where((eb) =>\n\t\t\t\teb.or([eb(\"display_name\", \"like\", term), eb(\"slug\", \"like\", term)]),\n\t\t\t);\n\t\t}\n\n\t\tif (options?.isGuest !== undefined) {\n\t\t\tquery = query.where(\"is_guest\", \"=\", options.isGuest ? 1 : 0);\n\t\t}\n\n\t\tif (options?.userId !== undefined) {\n\t\t\tquery = query.where(\"user_id\", \"=\", options.userId);\n\t\t}\n\n\t\tif (options?.cursor) {\n\t\t\tconst decoded = decodeCursor(options.cursor);\n\t\t\tif (decoded) {\n\t\t\t\tquery = query.where((eb) =>\n\t\t\t\t\teb.or([\n\t\t\t\t\t\teb(\"created_at\", \"<\", decoded.orderValue),\n\t\t\t\t\t\teb.and([eb(\"created_at\", \"=\", decoded.orderValue), eb(\"id\", \"<\", decoded.id)]),\n\t\t\t\t\t]),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tconst rows = await query.execute();\n\t\tconst items = rows.slice(0, limit).map(rowToByline);\n\t\tconst result: FindManyResult<BylineSummary> = { items };\n\n\t\tif (rows.length > limit) {\n\t\t\tconst last = items.at(-1);\n\t\t\tif (last) {\n\t\t\t\tresult.nextCursor = encodeCursor(last.createdAt, last.id);\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tasync create(input: CreateBylineInput): Promise<BylineSummary> {\n\t\tconst id = ulid();\n\t\tconst now = new Date().toISOString();\n\n\t\tawait this.db\n\t\t\t.insertInto(\"_emdash_bylines\")\n\t\t\t.values({\n\t\t\t\tid,\n\t\t\t\tslug: input.slug,\n\t\t\t\tdisplay_name: input.displayName,\n\t\t\t\tbio: input.bio ?? null,\n\t\t\t\tavatar_media_id: input.avatarMediaId ?? null,\n\t\t\t\twebsite_url: input.websiteUrl ?? null,\n\t\t\t\tuser_id: input.userId ?? null,\n\t\t\t\tis_guest: input.isGuest ? 1 : 0,\n\t\t\t\tcreated_at: now,\n\t\t\t\tupdated_at: now,\n\t\t\t})\n\t\t\t.execute();\n\n\t\tconst byline = await this.findById(id);\n\t\tif (!byline) {\n\t\t\tthrow new Error(\"Failed to create byline\");\n\t\t}\n\t\treturn byline;\n\t}\n\n\tasync update(id: string, input: UpdateBylineInput): Promise<BylineSummary | null> {\n\t\tconst existing = await this.findById(id);\n\t\tif (!existing) return null;\n\n\t\tconst updates: Record<string, unknown> = {\n\t\t\tupdated_at: new Date().toISOString(),\n\t\t};\n\n\t\tif (input.slug !== undefined) updates.slug = input.slug;\n\t\tif (input.displayName !== undefined) updates.display_name = input.displayName;\n\t\tif (input.bio !== undefined) updates.bio = input.bio;\n\t\tif (input.avatarMediaId !== undefined) updates.avatar_media_id = input.avatarMediaId;\n\t\tif (input.websiteUrl !== undefined) updates.website_url = input.websiteUrl;\n\t\tif (input.userId !== undefined) updates.user_id = input.userId;\n\t\tif (input.isGuest !== undefined) updates.is_guest = input.isGuest ? 1 : 0;\n\n\t\tawait this.db.updateTable(\"_emdash_bylines\").set(updates).where(\"id\", \"=\", id).execute();\n\t\treturn await this.findById(id);\n\t}\n\n\tasync delete(id: string): Promise<boolean> {\n\t\tconst existing = await this.findById(id);\n\t\tif (!existing) return false;\n\n\t\tawait withTransaction(this.db, async (trx) => {\n\t\t\tawait trx.deleteFrom(\"_emdash_content_bylines\").where(\"byline_id\", \"=\", id).execute();\n\n\t\t\tawait trx.deleteFrom(\"_emdash_bylines\").where(\"id\", \"=\", id).execute();\n\n\t\t\tconst tableNames = await listTablesLike(trx, \"ec_%\");\n\t\t\tfor (const tableName of tableNames) {\n\t\t\t\tvalidateIdentifier(tableName, \"content table\");\n\t\t\t\tawait sql`\n\t\t\t\t\tUPDATE ${sql.ref(tableName)}\n\t\t\t\t\tSET primary_byline_id = NULL\n\t\t\t\t\tWHERE primary_byline_id = ${id}\n\t\t\t\t`.execute(trx);\n\t\t\t}\n\t\t});\n\n\t\treturn true;\n\t}\n\n\tasync getContentBylines(\n\t\tcollectionSlug: string,\n\t\tcontentId: string,\n\t): Promise<ContentBylineCredit[]> {\n\t\tconst rows = await this.db\n\t\t\t.selectFrom(\"_emdash_content_bylines as cb\")\n\t\t\t.innerJoin(\"_emdash_bylines as b\", \"b.id\", \"cb.byline_id\")\n\t\t\t.select([\n\t\t\t\t\"cb.sort_order as sort_order\",\n\t\t\t\t\"cb.role_label as role_label\",\n\t\t\t\t\"b.id as id\",\n\t\t\t\t\"b.slug as slug\",\n\t\t\t\t\"b.display_name as display_name\",\n\t\t\t\t\"b.bio as bio\",\n\t\t\t\t\"b.avatar_media_id as avatar_media_id\",\n\t\t\t\t\"b.website_url as website_url\",\n\t\t\t\t\"b.user_id as user_id\",\n\t\t\t\t\"b.is_guest as is_guest\",\n\t\t\t\t\"b.created_at as created_at\",\n\t\t\t\t\"b.updated_at as updated_at\",\n\t\t\t])\n\t\t\t.where(\"cb.collection_slug\", \"=\", collectionSlug)\n\t\t\t.where(\"cb.content_id\", \"=\", contentId)\n\t\t\t.orderBy(\"cb.sort_order\", \"asc\")\n\t\t\t.execute();\n\n\t\treturn rows.map((row) => ({\n\t\t\tbyline: rowToByline(row),\n\t\t\tsortOrder: row.sort_order,\n\t\t\troleLabel: row.role_label,\n\t\t}));\n\t}\n\n\t/**\n\t * Batch-fetch byline credits for multiple content items in a single query.\n\t * Returns a Map keyed by contentId.\n\t */\n\tasync getContentBylinesMany(\n\t\tcollectionSlug: string,\n\t\tcontentIds: string[],\n\t): Promise<Map<string, ContentBylineCredit[]>> {\n\t\tconst result = new Map<string, ContentBylineCredit[]>();\n\t\tif (contentIds.length === 0) return result;\n\n\t\tconst uniqueContentIds = [...new Set(contentIds)];\n\t\tfor (const chunk of chunks(uniqueContentIds, SQL_BATCH_SIZE)) {\n\t\t\tconst rows = await this.db\n\t\t\t\t.selectFrom(\"_emdash_content_bylines as cb\")\n\t\t\t\t.innerJoin(\"_emdash_bylines as b\", \"b.id\", \"cb.byline_id\")\n\t\t\t\t.select([\n\t\t\t\t\t\"cb.content_id as content_id\",\n\t\t\t\t\t\"cb.sort_order as sort_order\",\n\t\t\t\t\t\"cb.role_label as role_label\",\n\t\t\t\t\t\"b.id as id\",\n\t\t\t\t\t\"b.slug as slug\",\n\t\t\t\t\t\"b.display_name as display_name\",\n\t\t\t\t\t\"b.bio as bio\",\n\t\t\t\t\t\"b.avatar_media_id as avatar_media_id\",\n\t\t\t\t\t\"b.website_url as website_url\",\n\t\t\t\t\t\"b.user_id as user_id\",\n\t\t\t\t\t\"b.is_guest as is_guest\",\n\t\t\t\t\t\"b.created_at as created_at\",\n\t\t\t\t\t\"b.updated_at as updated_at\",\n\t\t\t\t])\n\t\t\t\t.where(\"cb.collection_slug\", \"=\", collectionSlug)\n\t\t\t\t.where(\"cb.content_id\", \"in\", chunk)\n\t\t\t\t.orderBy(\"cb.sort_order\", \"asc\")\n\t\t\t\t.execute();\n\n\t\t\tfor (const row of rows) {\n\t\t\t\tconst contentId = row.content_id;\n\t\t\t\tconst credit: ContentBylineCredit = {\n\t\t\t\t\tbyline: rowToByline(row),\n\t\t\t\t\tsortOrder: row.sort_order,\n\t\t\t\t\troleLabel: row.role_label,\n\t\t\t\t};\n\t\t\t\tconst existing = result.get(contentId);\n\t\t\t\tif (existing) {\n\t\t\t\t\texisting.push(credit);\n\t\t\t\t} else {\n\t\t\t\t\tresult.set(contentId, [credit]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Batch-fetch byline profiles linked to user IDs in a single query.\n\t * Returns a Map keyed by userId.\n\t */\n\tasync findByUserIds(userIds: string[]): Promise<Map<string, BylineSummary>> {\n\t\tconst result = new Map<string, BylineSummary>();\n\t\tif (userIds.length === 0) return result;\n\n\t\tfor (const chunk of chunks(userIds, SQL_BATCH_SIZE)) {\n\t\t\tconst rows = await this.db\n\t\t\t\t.selectFrom(\"_emdash_bylines\")\n\t\t\t\t.selectAll()\n\t\t\t\t.where(\"user_id\", \"in\", chunk)\n\t\t\t\t.execute();\n\n\t\t\tfor (const row of rows) {\n\t\t\t\tif (row.user_id) {\n\t\t\t\t\tresult.set(row.user_id, rowToByline(row));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tasync setContentBylines(\n\t\tcollectionSlug: string,\n\t\tcontentId: string,\n\t\tinputBylines: ContentBylineInput[],\n\t): Promise<ContentBylineCredit[]> {\n\t\tvalidateIdentifier(collectionSlug, \"collection slug\");\n\t\tconst tableName = `ec_${collectionSlug}`;\n\t\tvalidateIdentifier(tableName, \"content table\");\n\n\t\tconst seen = new Set<string>();\n\t\tconst bylines = inputBylines.filter((item) => {\n\t\t\tif (seen.has(item.bylineId)) return false;\n\t\t\tseen.add(item.bylineId);\n\t\t\treturn true;\n\t\t});\n\n\t\t// This method is expected to be called within a transaction context\n\t\t// (content handlers wrap in withTransaction, seed applies sequentially).\n\t\t// All operations use this.db directly -- callers are responsible for\n\t\t// wrapping in a transaction when atomicity is required.\n\t\tif (bylines.length > 0) {\n\t\t\tconst ids = bylines.map((item) => item.bylineId);\n\t\t\tconst rows = await this.db\n\t\t\t\t.selectFrom(\"_emdash_bylines\")\n\t\t\t\t.select(\"id\")\n\t\t\t\t.where(\"id\", \"in\", ids)\n\t\t\t\t.execute();\n\t\t\tif (rows.length !== ids.length) {\n\t\t\t\tthrow new Error(\"One or more byline IDs do not exist\");\n\t\t\t}\n\t\t}\n\n\t\tawait this.db\n\t\t\t.deleteFrom(\"_emdash_content_bylines\")\n\t\t\t.where(\"collection_slug\", \"=\", collectionSlug)\n\t\t\t.where(\"content_id\", \"=\", contentId)\n\t\t\t.execute();\n\n\t\tfor (let i = 0; i < bylines.length; i++) {\n\t\t\tconst item = bylines[i];\n\t\t\tawait this.db\n\t\t\t\t.insertInto(\"_emdash_content_bylines\")\n\t\t\t\t.values({\n\t\t\t\t\tid: ulid(),\n\t\t\t\t\tcollection_slug: collectionSlug,\n\t\t\t\t\tcontent_id: contentId,\n\t\t\t\t\tbyline_id: item.bylineId,\n\t\t\t\t\tsort_order: i,\n\t\t\t\t\trole_label: item.roleLabel ?? null,\n\t\t\t\t\tcreated_at: new Date().toISOString(),\n\t\t\t\t})\n\t\t\t\t.execute();\n\t\t}\n\n\t\tawait sql`\n\t\t\tUPDATE ${sql.ref(tableName)}\n\t\t\tSET primary_byline_id = ${bylines[0]?.bylineId ?? null}\n\t\t\tWHERE id = ${contentId}\n\t\t`.execute(this.db);\n\n\t\treturn await this.getContentBylines(collectionSlug, contentId);\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as __exportAll } from "./chunk-ClPoSABd.mjs";
|
|
2
|
-
import { t as validateIdentifier } from "./validate-
|
|
3
|
-
import { n as SQL_BATCH_SIZE, r as chunks, t as BylineRepository } from "./byline-
|
|
4
|
-
import { n as getDb } from "./loader-
|
|
2
|
+
import { t as validateIdentifier } from "./validate-VPnKoIzW.mjs";
|
|
3
|
+
import { n as SQL_BATCH_SIZE, r as chunks, t as BylineRepository } from "./byline-WuOq9MFJ.mjs";
|
|
4
|
+
import { n as getDb } from "./loader-BYzwzORf.mjs";
|
|
5
5
|
import { sql } from "kysely";
|
|
6
6
|
|
|
7
7
|
//#region src/bylines/index.ts
|
|
@@ -15,9 +15,40 @@ import { sql } from "kysely";
|
|
|
15
15
|
var bylines_exports = /* @__PURE__ */ __exportAll({
|
|
16
16
|
getByline: () => getByline,
|
|
17
17
|
getBylineBySlug: () => getBylineBySlug,
|
|
18
|
-
getBylinesForEntries: () => getBylinesForEntries
|
|
18
|
+
getBylinesForEntries: () => getBylinesForEntries,
|
|
19
|
+
invalidateBylineCache: () => invalidateBylineCache
|
|
19
20
|
});
|
|
20
21
|
/**
|
|
22
|
+
* Cached result of "does any byline exist in the database?"
|
|
23
|
+
* null = not yet checked, true/false = cached result.
|
|
24
|
+
* Invalidated when bylines are created or deleted.
|
|
25
|
+
*/
|
|
26
|
+
let hasBylines = null;
|
|
27
|
+
/**
|
|
28
|
+
* Invalidate the cached "has any bylines" check.
|
|
29
|
+
* Call this when bylines are created, updated, or deleted.
|
|
30
|
+
*/
|
|
31
|
+
function invalidateBylineCache() {
|
|
32
|
+
hasBylines = null;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Check if any bylines exist in the database. Result is cached
|
|
36
|
+
* for the lifetime of the worker/process and invalidated on writes.
|
|
37
|
+
*/
|
|
38
|
+
async function hasAnyBylines() {
|
|
39
|
+
if (hasBylines !== null) return hasBylines;
|
|
40
|
+
try {
|
|
41
|
+
const db = await getDb();
|
|
42
|
+
hasBylines = (await sql`
|
|
43
|
+
SELECT id FROM _emdash_bylines LIMIT 1
|
|
44
|
+
`.execute(db)).rows.length > 0;
|
|
45
|
+
} catch (error) {
|
|
46
|
+
if ((error instanceof Error ? error.message : "").includes("no such table")) hasBylines = false;
|
|
47
|
+
else return false;
|
|
48
|
+
}
|
|
49
|
+
return hasBylines;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
21
52
|
* Get a byline by ID.
|
|
22
53
|
*
|
|
23
54
|
* @example
|
|
@@ -78,6 +109,7 @@ async function getBylinesForEntries(collection, entryIds) {
|
|
|
78
109
|
const result = /* @__PURE__ */ new Map();
|
|
79
110
|
for (const id of entryIds) result.set(id, []);
|
|
80
111
|
if (entryIds.length === 0) return result;
|
|
112
|
+
if (!await hasAnyBylines()) return result;
|
|
81
113
|
const db = await getDb();
|
|
82
114
|
const repo = new BylineRepository(db);
|
|
83
115
|
const bylinesMap = await repo.getContentBylinesMany(collection, entryIds);
|
|
@@ -120,8 +152,8 @@ async function getBylinesForEntries(collection, entryIds) {
|
|
|
120
152
|
* Returns Map<entryId, authorId> (only entries with non-null author_id).
|
|
121
153
|
*/
|
|
122
154
|
async function getAuthorIds(db, collection, entryIds) {
|
|
155
|
+
validateIdentifier(collection, "collection");
|
|
123
156
|
const tableName = `ec_${collection}`;
|
|
124
|
-
validateIdentifier(tableName, "content table");
|
|
125
157
|
const map = /* @__PURE__ */ new Map();
|
|
126
158
|
for (const chunk of chunks(entryIds, SQL_BATCH_SIZE)) {
|
|
127
159
|
const result = await sql`
|
|
@@ -135,4 +167,4 @@ async function getAuthorIds(db, collection, entryIds) {
|
|
|
135
167
|
|
|
136
168
|
//#endregion
|
|
137
169
|
export { getByline as n, getBylineBySlug as r, bylines_exports as t };
|
|
138
|
-
//# sourceMappingURL=bylines-
|
|
170
|
+
//# sourceMappingURL=bylines-C_Wsnz4L.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bylines-C_Wsnz4L.mjs","names":[],"sources":["../src/bylines/index.ts"],"sourcesContent":["/**\n * Runtime API for bylines\n *\n * Provides functions to query byline profiles and byline credits\n * associated with content entries. Follows the same pattern as\n * the taxonomies runtime API.\n */\n\nimport { sql } from \"kysely\";\n\nimport { BylineRepository } from \"../database/repositories/byline.js\";\nimport type { BylineSummary, ContentBylineCredit } from \"../database/repositories/types.js\";\nimport { validateIdentifier } from \"../database/validate.js\";\nimport { getDb } from \"../loader.js\";\nimport { chunks, SQL_BATCH_SIZE } from \"../utils/chunks.js\";\n\n/**\n * Cached result of \"does any byline exist in the database?\"\n * null = not yet checked, true/false = cached result.\n * Invalidated when bylines are created or deleted.\n */\nlet hasBylines: boolean | null = null;\n\n/**\n * Invalidate the cached \"has any bylines\" check.\n * Call this when bylines are created, updated, or deleted.\n */\nexport function invalidateBylineCache(): void {\n\thasBylines = null;\n}\n\n/**\n * Check if any bylines exist in the database. Result is cached\n * for the lifetime of the worker/process and invalidated on writes.\n */\nasync function hasAnyBylines(): Promise<boolean> {\n\tif (hasBylines !== null) return hasBylines;\n\n\ttry {\n\t\tconst db = await getDb();\n\t\tconst result = await sql<{ id: string }>`\n\t\t\tSELECT id FROM _emdash_bylines LIMIT 1\n\t\t`.execute(db);\n\t\thasBylines = result.rows.length > 0;\n\t} catch (error: unknown) {\n\t\t// Only treat \"no such table\" as a safe false -- anything else should\n\t\t// not be cached so the next request retries.\n\t\tconst message = error instanceof Error ? error.message : \"\";\n\t\tif (message.includes(\"no such table\")) {\n\t\t\thasBylines = false;\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\treturn hasBylines;\n}\n\n/**\n * Get a byline by ID.\n *\n * @example\n * ```ts\n * import { getByline } from \"emdash\";\n *\n * const byline = await getByline(\"01HXYZ...\");\n * if (byline) {\n * console.log(byline.displayName);\n * }\n * ```\n */\nexport async function getByline(id: string): Promise<BylineSummary | null> {\n\tconst db = await getDb();\n\tconst repo = new BylineRepository(db);\n\treturn repo.findById(id);\n}\n\n/**\n * Get a byline by slug.\n *\n * @example\n * ```ts\n * import { getBylineBySlug } from \"emdash\";\n *\n * const byline = await getBylineBySlug(\"jane-doe\");\n * if (byline) {\n * console.log(byline.displayName); // \"Jane Doe\"\n * }\n * ```\n */\nexport async function getBylineBySlug(slug: string): Promise<BylineSummary | null> {\n\tconst db = await getDb();\n\tconst repo = new BylineRepository(db);\n\treturn repo.findBySlug(slug);\n}\n\n/**\n * Get byline credits for a single content entry.\n *\n * Returns explicit byline credits from the junction table. If none exist\n * but the entry has an `authorId`, falls back to the user-linked byline\n * (marked as source: \"inferred\").\n *\n * @example\n * ```ts\n * import { getEntryBylines } from \"emdash\";\n *\n * const bylines = await getEntryBylines(\"posts\", post.data.id);\n * for (const credit of bylines) {\n * console.log(credit.byline.displayName, credit.roleLabel);\n * }\n * ```\n */\nexport async function getEntryBylines(\n\tcollection: string,\n\tentryId: string,\n): Promise<ContentBylineCredit[]> {\n\tvalidateIdentifier(collection, \"collection\");\n\tconst db = await getDb();\n\tconst repo = new BylineRepository(db);\n\n\tconst explicit = await repo.getContentBylines(collection, entryId);\n\tif (explicit.length > 0) {\n\t\treturn explicit.map((c) => ({ ...c, source: \"explicit\" as const }));\n\t}\n\n\t// Fallback: look up user-linked byline from author_id\n\tconst authorId = await getAuthorId(db, collection, entryId);\n\tif (authorId) {\n\t\tconst fallback = await repo.findByUserId(authorId);\n\t\tif (fallback) {\n\t\t\treturn [{ byline: fallback, sortOrder: 0, roleLabel: null, source: \"inferred\" }];\n\t\t}\n\t}\n\n\treturn [];\n}\n\n/**\n * Batch-fetch byline credits for multiple content entries in a single query.\n *\n * This is more efficient than calling getEntryBylines for each entry\n * when you need bylines for a list of entries (e.g., a blog index page).\n *\n * @param collection - The collection slug (e.g., \"posts\")\n * @param entryIds - Array of entry IDs\n * @returns Map from entry ID to array of byline credits\n *\n * @example\n * ```ts\n * import { getBylinesForEntries, getEmDashCollection } from \"emdash\";\n *\n * const { entries } = await getEmDashCollection(\"posts\");\n * const ids = entries.map(e => e.data.id);\n * const bylinesMap = await getBylinesForEntries(\"posts\", ids);\n *\n * for (const entry of entries) {\n * const bylines = bylinesMap.get(entry.data.id) ?? [];\n * // render bylines\n * }\n * ```\n */\nexport async function getBylinesForEntries(\n\tcollection: string,\n\tentryIds: string[],\n): Promise<Map<string, ContentBylineCredit[]>> {\n\tvalidateIdentifier(collection, \"collection\");\n\tconst result = new Map<string, ContentBylineCredit[]>();\n\n\t// Initialize all entry IDs with empty arrays\n\tfor (const id of entryIds) {\n\t\tresult.set(id, []);\n\t}\n\n\tif (entryIds.length === 0) {\n\t\treturn result;\n\t}\n\n\t// Skip DB queries entirely when no bylines have been created.\n\t// The cache is invalidated when bylines are created/deleted.\n\tif (!(await hasAnyBylines())) {\n\t\treturn result;\n\t}\n\n\tconst db = await getDb();\n\tconst repo = new BylineRepository(db);\n\n\t// 1. Batch fetch all explicit byline credits\n\tconst bylinesMap = await repo.getContentBylinesMany(collection, entryIds);\n\n\t// 2. Collect entry IDs that need fallback lookup\n\tconst fallbackEntryIds: string[] = [];\n\tconst needsFallback: Map<string, string> = new Map(); // entryId -> authorId\n\n\tfor (const id of entryIds) {\n\t\tif (!bylinesMap.has(id)) {\n\t\t\t// Need to check author_id for this entry — but we only have the IDs,\n\t\t\t// so batch-fetch them from the content table\n\t\t\tfallbackEntryIds.push(id);\n\t\t}\n\t}\n\n\t// Batch-fetch author_ids for entries that need fallback\n\tif (fallbackEntryIds.length > 0) {\n\t\tconst authorMap = await getAuthorIds(db, collection, fallbackEntryIds);\n\t\tfor (const [entryId, authorId] of authorMap) {\n\t\t\tneedsFallback.set(entryId, authorId);\n\t\t}\n\t}\n\n\t// 3. Batch fetch user-linked bylines for fallback\n\tconst uniqueAuthorIds = [...new Set(needsFallback.values())];\n\tconst authorBylineMap = await repo.findByUserIds(uniqueAuthorIds);\n\n\t// 4. Assign results\n\tfor (const id of entryIds) {\n\t\tconst explicit = bylinesMap.get(id);\n\t\tif (explicit && explicit.length > 0) {\n\t\t\tresult.set(\n\t\t\t\tid,\n\t\t\t\texplicit.map((c) => ({ ...c, source: \"explicit\" as const })),\n\t\t\t);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst authorId = needsFallback.get(id);\n\t\tif (authorId) {\n\t\t\tconst fallback = authorBylineMap.get(authorId);\n\t\t\tif (fallback) {\n\t\t\t\tresult.set(id, [{ byline: fallback, sortOrder: 0, roleLabel: null, source: \"inferred\" }]);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\t// Already initialized with empty array\n\t}\n\n\treturn result;\n}\n\n/**\n * Look up the author_id for a single content entry.\n * Uses raw SQL since we need dynamic table names.\n */\nasync function getAuthorId(\n\tdb: Awaited<ReturnType<typeof getDb>>,\n\tcollection: string,\n\tentryId: string,\n): Promise<string | null> {\n\tvalidateIdentifier(collection, \"collection\");\n\tconst tableName = `ec_${collection}`;\n\n\tconst result = await sql<{ author_id: string | null }>`\n\t\tSELECT author_id FROM ${sql.ref(tableName)}\n\t\tWHERE id = ${entryId}\n\t\tLIMIT 1\n\t`.execute(db);\n\n\treturn result.rows[0]?.author_id ?? null;\n}\n\n/**\n * Batch-fetch author_ids for multiple content entries.\n * Returns Map<entryId, authorId> (only entries with non-null author_id).\n */\nasync function getAuthorIds(\n\tdb: Awaited<ReturnType<typeof getDb>>,\n\tcollection: string,\n\tentryIds: string[],\n): Promise<Map<string, string>> {\n\tvalidateIdentifier(collection, \"collection\");\n\tconst tableName = `ec_${collection}`;\n\n\tconst map = new Map<string, string>();\n\tfor (const chunk of chunks(entryIds, SQL_BATCH_SIZE)) {\n\t\tconst result = await sql<{ id: string; author_id: string | null }>`\n\t\t\tSELECT id, author_id FROM ${sql.ref(tableName)}\n\t\t\tWHERE id IN (${sql.join(chunk.map((id) => sql`${id}`))})\n\t\t`.execute(db);\n\n\t\tfor (const row of result.rows) {\n\t\t\tif (row.author_id) {\n\t\t\t\tmap.set(row.id, row.author_id);\n\t\t\t}\n\t\t}\n\t}\n\treturn map;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAqBA,IAAI,aAA6B;;;;;AAMjC,SAAgB,wBAA8B;AAC7C,cAAa;;;;;;AAOd,eAAe,gBAAkC;AAChD,KAAI,eAAe,KAAM,QAAO;AAEhC,KAAI;EACH,MAAM,KAAK,MAAM,OAAO;AAIxB,gBAHe,MAAM,GAAmB;;IAEtC,QAAQ,GAAG,EACO,KAAK,SAAS;UAC1B,OAAgB;AAIxB,OADgB,iBAAiB,QAAQ,MAAM,UAAU,IAC7C,SAAS,gBAAgB,CACpC,cAAa;MAEb,QAAO;;AAIT,QAAO;;;;;;;;;;;;;;;AAgBR,eAAsB,UAAU,IAA2C;AAG1E,QADa,IAAI,iBADN,MAAM,OAAO,CACa,CACzB,SAAS,GAAG;;;;;;;;;;;;;;;AAgBzB,eAAsB,gBAAgB,MAA6C;AAGlF,QADa,IAAI,iBADN,MAAM,OAAO,CACa,CACzB,WAAW,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;AAqE7B,eAAsB,qBACrB,YACA,UAC8C;AAC9C,oBAAmB,YAAY,aAAa;CAC5C,MAAM,yBAAS,IAAI,KAAoC;AAGvD,MAAK,MAAM,MAAM,SAChB,QAAO,IAAI,IAAI,EAAE,CAAC;AAGnB,KAAI,SAAS,WAAW,EACvB,QAAO;AAKR,KAAI,CAAE,MAAM,eAAe,CAC1B,QAAO;CAGR,MAAM,KAAK,MAAM,OAAO;CACxB,MAAM,OAAO,IAAI,iBAAiB,GAAG;CAGrC,MAAM,aAAa,MAAM,KAAK,sBAAsB,YAAY,SAAS;CAGzE,MAAM,mBAA6B,EAAE;CACrC,MAAM,gCAAqC,IAAI,KAAK;AAEpD,MAAK,MAAM,MAAM,SAChB,KAAI,CAAC,WAAW,IAAI,GAAG,CAGtB,kBAAiB,KAAK,GAAG;AAK3B,KAAI,iBAAiB,SAAS,GAAG;EAChC,MAAM,YAAY,MAAM,aAAa,IAAI,YAAY,iBAAiB;AACtE,OAAK,MAAM,CAAC,SAAS,aAAa,UACjC,eAAc,IAAI,SAAS,SAAS;;CAKtC,MAAM,kBAAkB,CAAC,GAAG,IAAI,IAAI,cAAc,QAAQ,CAAC,CAAC;CAC5D,MAAM,kBAAkB,MAAM,KAAK,cAAc,gBAAgB;AAGjE,MAAK,MAAM,MAAM,UAAU;EAC1B,MAAM,WAAW,WAAW,IAAI,GAAG;AACnC,MAAI,YAAY,SAAS,SAAS,GAAG;AACpC,UAAO,IACN,IACA,SAAS,KAAK,OAAO;IAAE,GAAG;IAAG,QAAQ;IAAqB,EAAE,CAC5D;AACD;;EAGD,MAAM,WAAW,cAAc,IAAI,GAAG;AACtC,MAAI,UAAU;GACb,MAAM,WAAW,gBAAgB,IAAI,SAAS;AAC9C,OAAI,UAAU;AACb,WAAO,IAAI,IAAI,CAAC;KAAE,QAAQ;KAAU,WAAW;KAAG,WAAW;KAAM,QAAQ;KAAY,CAAC,CAAC;AACzF;;;;AAOH,QAAO;;;;;;AA4BR,eAAe,aACd,IACA,YACA,UAC+B;AAC/B,oBAAmB,YAAY,aAAa;CAC5C,MAAM,YAAY,MAAM;CAExB,MAAM,sBAAM,IAAI,KAAqB;AACrC,MAAK,MAAM,SAAS,OAAO,UAAU,eAAe,EAAE;EACrD,MAAM,SAAS,MAAM,GAA6C;+BACrC,IAAI,IAAI,UAAU,CAAC;kBAChC,IAAI,KAAK,MAAM,KAAK,OAAO,GAAG,GAAG,KAAK,CAAC,CAAC;IACtD,QAAQ,GAAG;AAEb,OAAK,MAAM,OAAO,OAAO,KACxB,KAAI,IAAI,UACP,KAAI,IAAI,IAAI,IAAI,IAAI,UAAU;;AAIjC,QAAO"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { t as __exportAll } from "./chunk-ClPoSABd.mjs";
|
|
2
|
+
import { i as matchPattern, n as interpolateDestination, t as compilePattern } from "./patterns-CrCYkMBb.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/redirects/cache.ts
|
|
5
|
+
var cache_exports = /* @__PURE__ */ __exportAll({
|
|
6
|
+
getCachedPatternRules: () => getCachedPatternRules,
|
|
7
|
+
invalidateRedirectCache: () => invalidateRedirectCache,
|
|
8
|
+
matchCachedPatterns: () => matchCachedPatterns,
|
|
9
|
+
setCachedPatternRules: () => setCachedPatternRules
|
|
10
|
+
});
|
|
11
|
+
/**
|
|
12
|
+
* Cached pattern rules with compiled regexes.
|
|
13
|
+
* null = not yet populated, array = cached.
|
|
14
|
+
*/
|
|
15
|
+
let cachedPatternRules = null;
|
|
16
|
+
/**
|
|
17
|
+
* Invalidate the cached redirect pattern rules.
|
|
18
|
+
* Call when redirects are created, updated, or deleted.
|
|
19
|
+
*/
|
|
20
|
+
function invalidateRedirectCache() {
|
|
21
|
+
cachedPatternRules = null;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Get the cached compiled pattern rules, or null if the cache is cold.
|
|
25
|
+
*/
|
|
26
|
+
function getCachedPatternRules() {
|
|
27
|
+
return cachedPatternRules;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Populate the pattern rules cache from a list of enabled pattern redirects.
|
|
31
|
+
*/
|
|
32
|
+
function setCachedPatternRules(redirects) {
|
|
33
|
+
cachedPatternRules = redirects.map((r) => ({
|
|
34
|
+
redirect: r,
|
|
35
|
+
compiled: compilePattern(r.source)
|
|
36
|
+
}));
|
|
37
|
+
return cachedPatternRules;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Match a path against the cached pattern rules.
|
|
41
|
+
* Returns the resolved destination and matching redirect, or null.
|
|
42
|
+
*/
|
|
43
|
+
function matchCachedPatterns(rules, pathname) {
|
|
44
|
+
for (const { redirect, compiled } of rules) {
|
|
45
|
+
const params = matchPattern(compiled, pathname);
|
|
46
|
+
if (params) return {
|
|
47
|
+
redirect,
|
|
48
|
+
destination: interpolateDestination(redirect.destination, params)
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
//#endregion
|
|
55
|
+
export { setCachedPatternRules as a, matchCachedPatterns as i, getCachedPatternRules as n, invalidateRedirectCache as r, cache_exports as t };
|
|
56
|
+
//# sourceMappingURL=cache-E3Dts-yT.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache-E3Dts-yT.mjs","names":[],"sources":["../src/redirects/cache.ts"],"sourcesContent":["/**\n * Redirect pattern cache.\n *\n * Module-level cache for compiled redirect pattern rules. The middleware\n * populates this on first request; route handlers invalidate it on writes.\n *\n * This module deliberately has NO Astro imports so it can be safely imported\n * from handlers, seed, CLI, and tests without dragging in `astro:middleware`.\n */\n\nimport type { Redirect } from \"../database/repositories/redirect.js\";\nimport type { CompiledPattern } from \"./patterns.js\";\nimport { compilePattern, interpolateDestination, matchPattern } from \"./patterns.js\";\n\nexport interface CachedRedirectRule {\n\tredirect: Redirect;\n\tcompiled: CompiledPattern;\n}\n\n/**\n * Cached pattern rules with compiled regexes.\n * null = not yet populated, array = cached.\n */\nlet cachedPatternRules: CachedRedirectRule[] | null = null;\n\n/**\n * Invalidate the cached redirect pattern rules.\n * Call when redirects are created, updated, or deleted.\n */\nexport function invalidateRedirectCache(): void {\n\tcachedPatternRules = null;\n}\n\n/**\n * Get the cached compiled pattern rules, or null if the cache is cold.\n */\nexport function getCachedPatternRules(): CachedRedirectRule[] | null {\n\treturn cachedPatternRules;\n}\n\n/**\n * Populate the pattern rules cache from a list of enabled pattern redirects.\n */\nexport function setCachedPatternRules(redirects: Redirect[]): CachedRedirectRule[] {\n\tcachedPatternRules = redirects.map((r) => ({\n\t\tredirect: r,\n\t\tcompiled: compilePattern(r.source),\n\t}));\n\treturn cachedPatternRules;\n}\n\n/**\n * Match a path against the cached pattern rules.\n * Returns the resolved destination and matching redirect, or null.\n */\nexport function matchCachedPatterns(\n\trules: CachedRedirectRule[],\n\tpathname: string,\n): { redirect: Redirect; destination: string } | null {\n\tfor (const { redirect, compiled } of rules) {\n\t\tconst params = matchPattern(compiled, pathname);\n\t\tif (params) {\n\t\t\tconst dest = interpolateDestination(redirect.destination, params);\n\t\t\treturn { redirect, destination: dest };\n\t\t}\n\t}\n\treturn null;\n}\n"],"mappings":";;;;;;;;;;;;;;AAuBA,IAAI,qBAAkD;;;;;AAMtD,SAAgB,0BAAgC;AAC/C,sBAAqB;;;;;AAMtB,SAAgB,wBAAqD;AACpE,QAAO;;;;;AAMR,SAAgB,sBAAsB,WAA6C;AAClF,sBAAqB,UAAU,KAAK,OAAO;EAC1C,UAAU;EACV,UAAU,eAAe,EAAE,OAAO;EAClC,EAAE;AACH,QAAO;;;;;;AAOR,SAAgB,oBACf,OACA,UACqD;AACrD,MAAK,MAAM,EAAE,UAAU,cAAc,OAAO;EAC3C,MAAM,SAAS,aAAa,UAAU,SAAS;AAC/C,MAAI,OAEH,QAAO;GAAE;GAAU,aADN,uBAAuB,SAAS,aAAa,OAAO;GAC3B;;AAGxC,QAAO"}
|
package/dist/cli/index.mjs
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { t as __exportAll } from "../chunk-ClPoSABd.mjs";
|
|
3
3
|
import { n as createDatabase } from "../connection-B4zVnQIa.mjs";
|
|
4
|
-
import { s as listTablesLike } from "../dialect-helpers-
|
|
5
|
-
import { r as runMigrations, t as getMigrationStatus } from "../runner-
|
|
6
|
-
import { t as ContentRepository } from "../content-
|
|
4
|
+
import { s as listTablesLike } from "../dialect-helpers-DhTzaUxP.mjs";
|
|
5
|
+
import { r as runMigrations, t as getMigrationStatus } from "../runner-Cd-_WyDo.mjs";
|
|
6
|
+
import { t as ContentRepository } from "../content-BsBoyj8G.mjs";
|
|
7
7
|
import { i as encodeBase64url } from "../base64-MBPo9ozB.mjs";
|
|
8
8
|
import "../types-CMMN0pNg.mjs";
|
|
9
9
|
import { t as MediaRepository } from "../media-DqHVh136.mjs";
|
|
10
|
-
import { f as OptionsRepository, p as TaxonomyRepository, t as applySeed } from "../apply-
|
|
11
|
-
import
|
|
12
|
-
import "../
|
|
13
|
-
import "../
|
|
14
|
-
import {
|
|
15
|
-
import "../loader-
|
|
16
|
-
import { i as pluginManifestSchema } from "../manifest-schema-
|
|
17
|
-
import { t as validateSeed } from "../validate-
|
|
10
|
+
import { f as OptionsRepository, p as TaxonomyRepository, t as applySeed } from "../apply-Cma_PiF6.mjs";
|
|
11
|
+
import "../redirect-7lGhLBNZ.mjs";
|
|
12
|
+
import "../byline-WuOq9MFJ.mjs";
|
|
13
|
+
import { r as isI18nEnabled } from "../config-DkxPrM9l.mjs";
|
|
14
|
+
import { n as SchemaRegistry } from "../registry-BgnP3ysR.mjs";
|
|
15
|
+
import "../loader-BYzwzORf.mjs";
|
|
16
|
+
import { i as pluginManifestSchema } from "../manifest-schema-BsXINkQD.mjs";
|
|
17
|
+
import { t as validateSeed } from "../validate-DuZDIxfy.mjs";
|
|
18
18
|
import { LocalStorage } from "../storage/local.mjs";
|
|
19
19
|
import { createHeaderAwareFetch, customHeadersInterceptor, getCachedAccessToken, isAccessRedirect, resolveCustomHeaders, runCloudflaredLogin } from "../client/cf-access.mjs";
|
|
20
20
|
import { EmDashClient } from "../client/index.mjs";
|
|
@@ -2259,13 +2259,13 @@ async function findBuildOutput(dir, baseName) {
|
|
|
2259
2259
|
*/
|
|
2260
2260
|
async function resolveSourceEntry(pluginDir, distPath) {
|
|
2261
2261
|
const cleaned = distPath.replace(LEADING_DOT_SLASH_RE, "");
|
|
2262
|
-
const direct = resolve(pluginDir, cleaned);
|
|
2263
|
-
if (await fileExists$1(direct)) return direct;
|
|
2264
2262
|
const srcPath = cleaned.replace(DIST_PREFIX_RE, "src/").replace(MJS_EXT_RE, ".ts");
|
|
2265
2263
|
const srcFull = resolve(pluginDir, srcPath);
|
|
2266
2264
|
if (await fileExists$1(srcFull)) return srcFull;
|
|
2267
2265
|
const tsxFull = resolve(pluginDir, srcPath.replace(TS_TO_TSX_RE, ".tsx"));
|
|
2268
2266
|
if (await fileExists$1(tsxFull)) return tsxFull;
|
|
2267
|
+
const direct = resolve(pluginDir, cleaned);
|
|
2268
|
+
if (await fileExists$1(direct)) return direct;
|
|
2269
2269
|
}
|
|
2270
2270
|
const TS_SOURCE_EXPORT_RE = /\.(?:ts|tsx|mts|cts|jsx)$/;
|
|
2271
2271
|
/**
|