emdash 0.1.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (202) hide show
  1. package/dist/{apply-kC39ev1Z.mjs → apply-Bqoekfbe.mjs} +57 -10
  2. package/dist/apply-Bqoekfbe.mjs.map +1 -0
  3. package/dist/astro/index.d.mts +23 -9
  4. package/dist/astro/index.d.mts.map +1 -1
  5. package/dist/astro/index.mjs +90 -25
  6. package/dist/astro/index.mjs.map +1 -1
  7. package/dist/astro/middleware/auth.d.mts +3 -3
  8. package/dist/astro/middleware/auth.d.mts.map +1 -1
  9. package/dist/astro/middleware/auth.mjs +126 -55
  10. package/dist/astro/middleware/auth.mjs.map +1 -1
  11. package/dist/astro/middleware/redirect.mjs +2 -2
  12. package/dist/astro/middleware/request-context.mjs +1 -1
  13. package/dist/astro/middleware.d.mts.map +1 -1
  14. package/dist/astro/middleware.mjs +80 -41
  15. package/dist/astro/middleware.mjs.map +1 -1
  16. package/dist/astro/types.d.mts +27 -6
  17. package/dist/astro/types.d.mts.map +1 -1
  18. package/dist/{byline-CL847F26.mjs → byline-BGj9p9Ht.mjs} +53 -31
  19. package/dist/byline-BGj9p9Ht.mjs.map +1 -0
  20. package/dist/{bylines-C2a-2TGt.mjs → bylines-BihaoIDY.mjs} +12 -10
  21. package/dist/{bylines-C2a-2TGt.mjs.map → bylines-BihaoIDY.mjs.map} +1 -1
  22. package/dist/cli/index.mjs +17 -14
  23. package/dist/cli/index.mjs.map +1 -1
  24. package/dist/{config-CKE8p9xM.mjs → config-Cq8H0SfX.mjs} +2 -10
  25. package/dist/{config-CKE8p9xM.mjs.map → config-Cq8H0SfX.mjs.map} +1 -1
  26. package/dist/{content-D6C2WsZC.mjs → content-BsBoyj8G.mjs} +35 -5
  27. package/dist/content-BsBoyj8G.mjs.map +1 -0
  28. package/dist/db/index.mjs +2 -2
  29. package/dist/{default-Cyi4aAxu.mjs → default-WYlzADZL.mjs} +1 -1
  30. package/dist/{default-Cyi4aAxu.mjs.map → default-WYlzADZL.mjs.map} +1 -1
  31. package/dist/{dialect-helpers-B9uSp2GJ.mjs → dialect-helpers-DhTzaUxP.mjs} +4 -1
  32. package/dist/dialect-helpers-DhTzaUxP.mjs.map +1 -0
  33. package/dist/{error-Cxz0tQeO.mjs → error-DrxtnGPg.mjs} +1 -1
  34. package/dist/{error-Cxz0tQeO.mjs.map → error-DrxtnGPg.mjs.map} +1 -1
  35. package/dist/{index-CLBc4gw-.d.mts → index-Cff7AimE.d.mts} +77 -15
  36. package/dist/index-Cff7AimE.d.mts.map +1 -0
  37. package/dist/index.d.mts +6 -6
  38. package/dist/index.mjs +19 -19
  39. package/dist/{load-yOOlckBj.mjs → load-Veizk2cT.mjs} +1 -1
  40. package/dist/{load-yOOlckBj.mjs.map → load-Veizk2cT.mjs.map} +1 -1
  41. package/dist/{loader-fz8Q_3EO.mjs → loader-BmYdf3Dr.mjs} +4 -2
  42. package/dist/loader-BmYdf3Dr.mjs.map +1 -0
  43. package/dist/{manifest-schema-CL8DWO9b.mjs → manifest-schema-CuMio1A9.mjs} +1 -1
  44. package/dist/{manifest-schema-CL8DWO9b.mjs.map → manifest-schema-CuMio1A9.mjs.map} +1 -1
  45. package/dist/media/local-runtime.d.mts +4 -4
  46. package/dist/page/index.d.mts +10 -1
  47. package/dist/page/index.d.mts.map +1 -1
  48. package/dist/page/index.mjs +8 -4
  49. package/dist/page/index.mjs.map +1 -1
  50. package/dist/plugins/adapt-sandbox-entry.d.mts +3 -3
  51. package/dist/plugins/adapt-sandbox-entry.mjs +1 -1
  52. package/dist/{query-BVYN0PJ6.mjs → query-sesiOndV.mjs} +20 -8
  53. package/dist/{query-BVYN0PJ6.mjs.map → query-sesiOndV.mjs.map} +1 -1
  54. package/dist/{redirect-DIfIni3r.mjs → redirect-DUAk-Yl_.mjs} +9 -2
  55. package/dist/redirect-DUAk-Yl_.mjs.map +1 -0
  56. package/dist/{registry-BNYQKX_d.mjs → registry-DU18yVo0.mjs} +14 -4
  57. package/dist/registry-DU18yVo0.mjs.map +1 -0
  58. package/dist/{runner-BraqvGYk.mjs → runner-Biufrii2.mjs} +157 -132
  59. package/dist/runner-Biufrii2.mjs.map +1 -0
  60. package/dist/runner-EAtf0ZIe.d.mts.map +1 -1
  61. package/dist/runtime.d.mts +3 -3
  62. package/dist/runtime.mjs +2 -2
  63. package/dist/{search-C1gg67nN.mjs → search-BXB-jfu2.mjs} +241 -109
  64. package/dist/search-BXB-jfu2.mjs.map +1 -0
  65. package/dist/seed/index.d.mts +1 -1
  66. package/dist/seed/index.mjs +10 -10
  67. package/dist/seo/index.d.mts +1 -1
  68. package/dist/storage/local.d.mts +1 -1
  69. package/dist/storage/local.mjs +1 -1
  70. package/dist/storage/s3.d.mts +11 -3
  71. package/dist/storage/s3.d.mts.map +1 -1
  72. package/dist/storage/s3.mjs +76 -15
  73. package/dist/storage/s3.mjs.map +1 -1
  74. package/dist/{tokens-DpgrkrXK.mjs → tokens-DrB-W6Q-.mjs} +1 -1
  75. package/dist/{tokens-DpgrkrXK.mjs.map → tokens-DrB-W6Q-.mjs.map} +1 -1
  76. package/dist/{types-BRuPJGdV.d.mts → types-BbsYgi_R.d.mts} +3 -1
  77. package/dist/types-BbsYgi_R.d.mts.map +1 -0
  78. package/dist/{types-CUBbjgmP.mjs → types-Bec-r_3_.mjs} +1 -1
  79. package/dist/types-Bec-r_3_.mjs.map +1 -0
  80. package/dist/{types-DaNLHo_T.d.mts → types-C1-PVaS_.d.mts} +14 -6
  81. package/dist/types-C1-PVaS_.d.mts.map +1 -0
  82. package/dist/types-CMMN0pNg.mjs.map +1 -1
  83. package/dist/{types-BQo5JS0J.d.mts → types-CaKte3hR.d.mts} +78 -6
  84. package/dist/types-CaKte3hR.d.mts.map +1 -0
  85. package/dist/{types-CiA5Gac0.mjs → types-DuNbGKjF.mjs} +1 -1
  86. package/dist/{types-CiA5Gac0.mjs.map → types-DuNbGKjF.mjs.map} +1 -1
  87. package/dist/{validate-_rsF-Dx_.mjs → validate-CXnRKfJK.mjs} +2 -2
  88. package/dist/{validate-_rsF-Dx_.mjs.map → validate-CXnRKfJK.mjs.map} +1 -1
  89. package/dist/{validate-CqRJb_xU.mjs → validate-VPnKoIzW.mjs} +11 -11
  90. package/dist/{validate-CqRJb_xU.mjs.map → validate-VPnKoIzW.mjs.map} +1 -1
  91. package/dist/{validate-HtxZeaBi.d.mts → validate-bfg9OR6N.d.mts} +2 -2
  92. package/dist/{validate-HtxZeaBi.d.mts.map → validate-bfg9OR6N.d.mts.map} +1 -1
  93. package/dist/version-REAapfsU.mjs +7 -0
  94. package/dist/version-REAapfsU.mjs.map +1 -0
  95. package/package.json +6 -6
  96. package/src/api/csrf.ts +13 -2
  97. package/src/api/handlers/content.ts +7 -0
  98. package/src/api/handlers/dashboard.ts +4 -8
  99. package/src/api/handlers/device-flow.ts +55 -37
  100. package/src/api/handlers/index.ts +6 -1
  101. package/src/api/handlers/redirects.ts +95 -3
  102. package/src/api/handlers/seo.ts +48 -21
  103. package/src/api/public-url.ts +84 -0
  104. package/src/api/schemas/content.ts +2 -2
  105. package/src/api/schemas/menus.ts +12 -2
  106. package/src/api/schemas/redirects.ts +1 -0
  107. package/src/astro/integration/index.ts +30 -7
  108. package/src/astro/integration/routes.ts +13 -2
  109. package/src/astro/integration/runtime.ts +7 -5
  110. package/src/astro/integration/vite-config.ts +55 -9
  111. package/src/astro/middleware/auth.ts +60 -56
  112. package/src/astro/middleware/csp.ts +25 -0
  113. package/src/astro/middleware.ts +31 -3
  114. package/src/astro/routes/PluginRegistry.tsx +8 -2
  115. package/src/astro/routes/admin.astro +7 -2
  116. package/src/astro/routes/api/admin/users/[id]/disable.ts +18 -12
  117. package/src/astro/routes/api/admin/users/[id]/index.ts +26 -5
  118. package/src/astro/routes/api/auth/invite/complete.ts +3 -2
  119. package/src/astro/routes/api/auth/oauth/[provider]/callback.ts +2 -1
  120. package/src/astro/routes/api/auth/oauth/[provider].ts +2 -1
  121. package/src/astro/routes/api/auth/passkey/options.ts +3 -2
  122. package/src/astro/routes/api/auth/passkey/register/options.ts +3 -2
  123. package/src/astro/routes/api/auth/passkey/register/verify.ts +3 -2
  124. package/src/astro/routes/api/auth/passkey/verify.ts +3 -2
  125. package/src/astro/routes/api/auth/signup/complete.ts +3 -2
  126. package/src/astro/routes/api/comments/[collection]/[contentId]/index.ts +2 -0
  127. package/src/astro/routes/api/content/[collection]/index.ts +31 -3
  128. package/src/astro/routes/api/import/wordpress/execute.ts +9 -0
  129. package/src/astro/routes/api/import/wordpress/rewrite-urls.ts +2 -0
  130. package/src/astro/routes/api/import/wordpress-plugin/execute.ts +10 -0
  131. package/src/astro/routes/api/manifest.ts +4 -1
  132. package/src/astro/routes/api/media/providers/[providerId]/[itemId].ts +7 -2
  133. package/src/astro/routes/api/oauth/authorize.ts +12 -7
  134. package/src/astro/routes/api/oauth/device/code.ts +5 -1
  135. package/src/astro/routes/api/setup/admin-verify.ts +3 -2
  136. package/src/astro/routes/api/setup/admin.ts +3 -2
  137. package/src/astro/routes/api/setup/dev-bypass.ts +2 -1
  138. package/src/astro/routes/api/setup/index.ts +3 -2
  139. package/src/astro/routes/api/snapshot.ts +2 -1
  140. package/src/astro/routes/api/themes/preview.ts +2 -1
  141. package/src/astro/routes/api/well-known/auth.ts +1 -0
  142. package/src/astro/routes/api/well-known/oauth-authorization-server.ts +3 -2
  143. package/src/astro/routes/api/well-known/oauth-protected-resource.ts +3 -2
  144. package/src/astro/routes/robots.txt.ts +5 -1
  145. package/src/astro/routes/sitemap-[collection].xml.ts +104 -0
  146. package/src/astro/routes/sitemap.xml.ts +18 -23
  147. package/src/astro/storage/adapters.ts +19 -5
  148. package/src/astro/storage/types.ts +12 -4
  149. package/src/astro/types.ts +28 -1
  150. package/src/auth/passkey-config.ts +6 -10
  151. package/src/bylines/index.ts +13 -10
  152. package/src/cli/commands/login.ts +5 -2
  153. package/src/components/InlinePortableTextEditor.tsx +5 -3
  154. package/src/content/converters/portable-text-to-prosemirror.ts +50 -2
  155. package/src/database/dialect-helpers.ts +3 -0
  156. package/src/database/migrations/034_published_at_index.ts +29 -0
  157. package/src/database/migrations/runner.ts +2 -0
  158. package/src/database/repositories/byline.ts +48 -42
  159. package/src/database/repositories/content.ts +28 -1
  160. package/src/database/repositories/options.ts +9 -3
  161. package/src/database/repositories/redirect.ts +13 -0
  162. package/src/database/repositories/seo.ts +34 -17
  163. package/src/database/repositories/types.ts +2 -0
  164. package/src/database/validate.ts +10 -10
  165. package/src/emdash-runtime.ts +66 -19
  166. package/src/import/index.ts +1 -1
  167. package/src/import/sources/wxr.ts +45 -2
  168. package/src/index.ts +10 -1
  169. package/src/loader.ts +2 -0
  170. package/src/mcp/server.ts +85 -5
  171. package/src/menus/index.ts +6 -1
  172. package/src/page/context.ts +13 -1
  173. package/src/page/jsonld.ts +10 -6
  174. package/src/page/seo-contributions.ts +1 -1
  175. package/src/plugins/context.ts +145 -35
  176. package/src/plugins/manager.ts +12 -0
  177. package/src/plugins/types.ts +80 -4
  178. package/src/query.ts +18 -0
  179. package/src/redirects/loops.ts +318 -0
  180. package/src/schema/registry.ts +8 -0
  181. package/src/search/fts-manager.ts +4 -0
  182. package/src/settings/index.ts +64 -0
  183. package/src/storage/s3.ts +94 -25
  184. package/src/storage/types.ts +13 -5
  185. package/src/utils/chunks.ts +17 -0
  186. package/src/utils/slugify.ts +11 -0
  187. package/src/version.ts +12 -0
  188. package/dist/apply-kC39ev1Z.mjs.map +0 -1
  189. package/dist/byline-CL847F26.mjs.map +0 -1
  190. package/dist/content-D6C2WsZC.mjs.map +0 -1
  191. package/dist/dialect-helpers-B9uSp2GJ.mjs.map +0 -1
  192. package/dist/index-CLBc4gw-.d.mts.map +0 -1
  193. package/dist/loader-fz8Q_3EO.mjs.map +0 -1
  194. package/dist/redirect-DIfIni3r.mjs.map +0 -1
  195. package/dist/registry-BNYQKX_d.mjs.map +0 -1
  196. package/dist/runner-BraqvGYk.mjs.map +0 -1
  197. package/dist/search-C1gg67nN.mjs.map +0 -1
  198. package/dist/types-BQo5JS0J.d.mts.map +0 -1
  199. package/dist/types-BRuPJGdV.d.mts.map +0 -1
  200. package/dist/types-CUBbjgmP.mjs.map +0 -1
  201. package/dist/types-DaNLHo_T.d.mts.map +0 -1
  202. /package/src/astro/routes/api/media/file/{[key].ts → [...key].ts} +0 -0
@@ -1,11 +1,11 @@
1
1
  import { f as MediaProvider, p as MediaProviderCapabilities } from "../placeholder-SvFCKbz_.mjs";
2
2
  import { t as Database } from "../types-DRjfYOEv.mjs";
3
- import { Ai as MediaItem, Cr as SandboxRunner, Lr as MediaListResponse, Rr as MediaResponse, _i as ContentResponse, cn as EmDashConfig, gi as ContentListResponse, nn as EmailPipeline, rn as HookPipeline } from "../index-CLBc4gw-.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-Cff7AimE.mjs";
4
4
  import "../runner-EAtf0ZIe.mjs";
5
- import { r as ContentItem } from "../types-BRuPJGdV.mjs";
6
- import { it as Element, q as ResolvedPlugin } from "../types-BQo5JS0J.mjs";
7
- import "../validate-HtxZeaBi.mjs";
8
- import { d as Storage } from "../types-DaNLHo_T.mjs";
5
+ import { r as ContentItem } from "../types-BbsYgi_R.mjs";
6
+ import { G as PublicPageContext, J as ResolvedPlugin, O as PageMetadataContribution, T as PageFragmentContribution, at as Element } from "../types-CaKte3hR.mjs";
7
+ import "../validate-bfg9OR6N.mjs";
8
+ import { d as Storage } from "../types-C1-PVaS_.mjs";
9
9
  import "../index.mjs";
10
10
  import { Kysely } from "kysely";
11
11
 
@@ -24,10 +24,16 @@ interface ManifestCollection {
24
24
  label?: string;
25
25
  required?: boolean;
26
26
  widget?: string;
27
+ /**
28
+ * Field options. Two shapes:
29
+ * - Legacy enum: `Array<{ value, label }>` for select / multiSelect widgets
30
+ * - Plugin widgets: `Record<string, unknown>` for arbitrary per-field config
31
+ * (e.g. a checkbox grid receiving its column definitions)
32
+ */
27
33
  options?: Array<{
28
34
  value: string;
29
35
  label: string;
30
- }>;
36
+ }> | Record<string, unknown>;
31
37
  }>;
32
38
  }
33
39
  /**
@@ -83,6 +89,7 @@ type ManifestAuthMode = string;
83
89
  */
84
90
  interface EmDashManifest {
85
91
  version: string;
92
+ commit?: string;
86
93
  hash: string;
87
94
  collections: Record<string, ManifestCollection>;
88
95
  plugins: Record<string, ManifestPlugin>;
@@ -107,6 +114,16 @@ interface EmDashManifest {
107
114
  locales: string[];
108
115
  prefixDefaultLocale?: boolean;
109
116
  };
117
+ /**
118
+ * Taxonomy definitions for the admin sidebar.
119
+ */
120
+ taxonomies: Array<{
121
+ name: string;
122
+ label: string;
123
+ labelSingular?: string;
124
+ hierarchical: boolean;
125
+ collections: string[];
126
+ }>;
110
127
  /**
111
128
  * Whether the plugin marketplace is configured.
112
129
  * When true, the admin UI can show marketplace browse/install features.
@@ -160,6 +177,8 @@ interface EmDashHandlers {
160
177
  authorId?: string;
161
178
  locale?: string;
162
179
  translationOf?: string;
180
+ createdAt?: string | null;
181
+ publishedAt?: string | null;
163
182
  }) => Promise<HandlerResponse>;
164
183
  handleContentUpdate: (collection: string, id: string, body: {
165
184
  data?: Record<string, unknown>;
@@ -245,6 +264,8 @@ interface EmDashHandlers {
245
264
  getSandboxRunner: () => SandboxRunner | null;
246
265
  syncMarketplacePlugins: () => Promise<void>;
247
266
  setPluginStatus: (pluginId: string, status: "active" | "inactive") => Promise<void>;
267
+ collectPageMetadata: (page: PublicPageContext) => Promise<PageMetadataContribution[]>;
268
+ collectPageFragments: (page: PublicPageContext) => Promise<PageFragmentContribution[]>;
248
269
  }
249
270
  //#endregion
250
271
  export { type ContentItem, type ContentListResponse, type ContentResponse, type Database, EmDashHandlers, EmDashManifest, HandlerResponse, ManifestAuthMode, ManifestCollection, ManifestPlugin, type MediaItem, type MediaListResponse, type MediaResponse, type Storage };
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.mts","names":[],"sources":["../../src/astro/types.ts"],"mappings":"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"}
1
+ {"version":3,"file":"types.d.mts","names":[],"sources":["../../src/astro/types.ts"],"mappings":"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"}
@@ -1,9 +1,26 @@
1
- import { s as listTablesLike } from "./dialect-helpers-B9uSp2GJ.mjs";
2
- import { t as validateIdentifier } from "./validate-CqRJb_xU.mjs";
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
4
  import { sql } from "kysely";
5
5
  import { ulid } from "ulidx";
6
6
 
7
+ //#region src/utils/chunks.ts
8
+ /**
9
+ * Split an array into chunks of at most `size` elements.
10
+ *
11
+ * Used to keep SQL `IN (?, ?, …)` clauses within Cloudflare D1's
12
+ * bound-parameter limit (~100 per statement).
13
+ */
14
+ function chunks(arr, size) {
15
+ if (arr.length === 0) return [];
16
+ const result = [];
17
+ for (let i = 0; i < arr.length; i += size) result.push(arr.slice(i, i + size));
18
+ return result;
19
+ }
20
+ /** Conservative default chunk size for SQL IN clauses (well within D1's limit). */
21
+ const SQL_BATCH_SIZE = 50;
22
+
23
+ //#endregion
7
24
  //#region src/database/repositories/byline.ts
8
25
  function rowToByline(row) {
9
26
  return {
@@ -133,31 +150,34 @@ var BylineRepository = class {
133
150
  async getContentBylinesMany(collectionSlug, contentIds) {
134
151
  const result = /* @__PURE__ */ new Map();
135
152
  if (contentIds.length === 0) return result;
136
- const rows = await this.db.selectFrom("_emdash_content_bylines as cb").innerJoin("_emdash_bylines as b", "b.id", "cb.byline_id").select([
137
- "cb.content_id as content_id",
138
- "cb.sort_order as sort_order",
139
- "cb.role_label as role_label",
140
- "b.id as id",
141
- "b.slug as slug",
142
- "b.display_name as display_name",
143
- "b.bio as bio",
144
- "b.avatar_media_id as avatar_media_id",
145
- "b.website_url as website_url",
146
- "b.user_id as user_id",
147
- "b.is_guest as is_guest",
148
- "b.created_at as created_at",
149
- "b.updated_at as updated_at"
150
- ]).where("cb.collection_slug", "=", collectionSlug).where("cb.content_id", "in", contentIds).orderBy("cb.sort_order", "asc").execute();
151
- for (const row of rows) {
152
- const contentId = row.content_id;
153
- const credit = {
154
- byline: rowToByline(row),
155
- sortOrder: row.sort_order,
156
- roleLabel: row.role_label
157
- };
158
- const existing = result.get(contentId);
159
- if (existing) existing.push(credit);
160
- else result.set(contentId, [credit]);
153
+ const uniqueContentIds = [...new Set(contentIds)];
154
+ for (const chunk of chunks(uniqueContentIds, SQL_BATCH_SIZE)) {
155
+ const rows = await this.db.selectFrom("_emdash_content_bylines as cb").innerJoin("_emdash_bylines as b", "b.id", "cb.byline_id").select([
156
+ "cb.content_id as content_id",
157
+ "cb.sort_order as sort_order",
158
+ "cb.role_label as role_label",
159
+ "b.id as id",
160
+ "b.slug as slug",
161
+ "b.display_name as display_name",
162
+ "b.bio as bio",
163
+ "b.avatar_media_id as avatar_media_id",
164
+ "b.website_url as website_url",
165
+ "b.user_id as user_id",
166
+ "b.is_guest as is_guest",
167
+ "b.created_at as created_at",
168
+ "b.updated_at as updated_at"
169
+ ]).where("cb.collection_slug", "=", collectionSlug).where("cb.content_id", "in", chunk).orderBy("cb.sort_order", "asc").execute();
170
+ for (const row of rows) {
171
+ const contentId = row.content_id;
172
+ const credit = {
173
+ byline: rowToByline(row),
174
+ sortOrder: row.sort_order,
175
+ roleLabel: row.role_label
176
+ };
177
+ const existing = result.get(contentId);
178
+ if (existing) existing.push(credit);
179
+ else result.set(contentId, [credit]);
180
+ }
161
181
  }
162
182
  return result;
163
183
  }
@@ -168,8 +188,10 @@ var BylineRepository = class {
168
188
  async findByUserIds(userIds) {
169
189
  const result = /* @__PURE__ */ new Map();
170
190
  if (userIds.length === 0) return result;
171
- const rows = await this.db.selectFrom("_emdash_bylines").selectAll().where("user_id", "in", userIds).execute();
172
- for (const row of rows) if (row.user_id) result.set(row.user_id, rowToByline(row));
191
+ for (const chunk of chunks(userIds, SQL_BATCH_SIZE)) {
192
+ const rows = await this.db.selectFrom("_emdash_bylines").selectAll().where("user_id", "in", chunk).execute();
193
+ for (const row of rows) if (row.user_id) result.set(row.user_id, rowToByline(row));
194
+ }
173
195
  return result;
174
196
  }
175
197
  async setContentBylines(collectionSlug, contentId, inputBylines) {
@@ -209,5 +231,5 @@ var BylineRepository = class {
209
231
  };
210
232
 
211
233
  //#endregion
212
- export { BylineRepository as t };
213
- //# sourceMappingURL=byline-CL847F26.mjs.map
234
+ export { SQL_BATCH_SIZE as n, chunks as r, BylineRepository as t };
235
+ //# sourceMappingURL=byline-BGj9p9Ht.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"byline-BGj9p9Ht.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 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 this.db.transaction().execute(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-CqRJb_xU.mjs";
3
- import { t as BylineRepository } from "./byline-CL847F26.mjs";
4
- import { n as getDb } from "./loader-fz8Q_3EO.mjs";
2
+ import { t as validateIdentifier } from "./validate-VPnKoIzW.mjs";
3
+ import { n as SQL_BATCH_SIZE, r as chunks, t as BylineRepository } from "./byline-BGj9p9Ht.mjs";
4
+ import { n as getDb } from "./loader-BmYdf3Dr.mjs";
5
5
  import { sql } from "kysely";
6
6
 
7
7
  //#region src/bylines/index.ts
@@ -120,17 +120,19 @@ async function getBylinesForEntries(collection, entryIds) {
120
120
  * Returns Map<entryId, authorId> (only entries with non-null author_id).
121
121
  */
122
122
  async function getAuthorIds(db, collection, entryIds) {
123
+ validateIdentifier(collection, "collection");
123
124
  const tableName = `ec_${collection}`;
124
- validateIdentifier(tableName, "content table");
125
- const result = await sql`
126
- SELECT id, author_id FROM ${sql.ref(tableName)}
127
- WHERE id IN (${sql.join(entryIds.map((id) => sql`${id}`))})
128
- `.execute(db);
129
125
  const map = /* @__PURE__ */ new Map();
130
- for (const row of result.rows) if (row.author_id) map.set(row.id, row.author_id);
126
+ for (const chunk of chunks(entryIds, SQL_BATCH_SIZE)) {
127
+ const result = await sql`
128
+ SELECT id, author_id FROM ${sql.ref(tableName)}
129
+ WHERE id IN (${sql.join(chunk.map((id) => sql`${id}`))})
130
+ `.execute(db);
131
+ for (const row of result.rows) if (row.author_id) map.set(row.id, row.author_id);
132
+ }
131
133
  return map;
132
134
  }
133
135
 
134
136
  //#endregion
135
137
  export { getByline as n, getBylineBySlug as r, bylines_exports as t };
136
- //# sourceMappingURL=bylines-C2a-2TGt.mjs.map
138
+ //# sourceMappingURL=bylines-BihaoIDY.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"bylines-C2a-2TGt.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\";\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\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\tconst tableName = `ec_${collection}`;\n\tvalidateIdentifier(tableName, \"content table\");\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\tconst tableName = `ec_${collection}`;\n\tvalidateIdentifier(tableName, \"content table\");\n\n\tconst result = await sql<{ id: string; author_id: string | null }>`\n\t\tSELECT id, author_id FROM ${sql.ref(tableName)}\n\t\tWHERE id IN (${sql.join(entryIds.map((id) => sql`${id}`))})\n\t`.execute(db);\n\n\tconst map = new Map<string, string>();\n\tfor (const row of result.rows) {\n\t\tif (row.author_id) {\n\t\t\tmap.set(row.id, row.author_id);\n\t\t}\n\t}\n\treturn map;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BA,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;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;CAC/B,MAAM,YAAY,MAAM;AACxB,oBAAmB,WAAW,gBAAgB;CAE9C,MAAM,SAAS,MAAM,GAA6C;8BACrC,IAAI,IAAI,UAAU,CAAC;iBAChC,IAAI,KAAK,SAAS,KAAK,OAAO,GAAG,GAAG,KAAK,CAAC,CAAC;GACzD,QAAQ,GAAG;CAEb,MAAM,sBAAM,IAAI,KAAqB;AACrC,MAAK,MAAM,OAAO,OAAO,KACxB,KAAI,IAAI,UACP,KAAI,IAAI,IAAI,IAAI,IAAI,UAAU;AAGhC,QAAO"}
1
+ {"version":3,"file":"bylines-BihaoIDY.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 * 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\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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BA,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;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"}
@@ -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-B9uSp2GJ.mjs";
5
- import { r as runMigrations, t as getMigrationStatus } from "../runner-BraqvGYk.mjs";
6
- import { t as ContentRepository } from "../content-D6C2WsZC.mjs";
4
+ import { s as listTablesLike } from "../dialect-helpers-DhTzaUxP.mjs";
5
+ import { r as runMigrations, t as getMigrationStatus } from "../runner-Biufrii2.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 { d as TaxonomyRepository, t as applySeed, u as OptionsRepository } from "../apply-kC39ev1Z.mjs";
11
- import { n as SchemaRegistry } from "../registry-BNYQKX_d.mjs";
12
- import "../redirect-DIfIni3r.mjs";
13
- import "../byline-CL847F26.mjs";
14
- import { i as isI18nEnabled } from "../config-CKE8p9xM.mjs";
15
- import "../loader-fz8Q_3EO.mjs";
16
- import { i as pluginManifestSchema } from "../manifest-schema-CL8DWO9b.mjs";
17
- import { t as validateSeed } from "../validate-_rsF-Dx_.mjs";
10
+ import { f as OptionsRepository, p as TaxonomyRepository, t as applySeed } from "../apply-Bqoekfbe.mjs";
11
+ import { n as SchemaRegistry } from "../registry-DU18yVo0.mjs";
12
+ import "../redirect-DUAk-Yl_.mjs";
13
+ import "../byline-BGj9p9Ht.mjs";
14
+ import { r as isI18nEnabled } from "../config-Cq8H0SfX.mjs";
15
+ import "../loader-BmYdf3Dr.mjs";
16
+ import { i as pluginManifestSchema } from "../manifest-schema-CuMio1A9.mjs";
17
+ import { t as validateSeed } from "../validate-CXnRKfJK.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";
@@ -1587,7 +1587,7 @@ async function pollForToken(tokenEndpoint, deviceCode, interval, expiresIn, fetc
1587
1587
  grant_type: "urn:ietf:params:oauth:grant-type:device_code"
1588
1588
  })
1589
1589
  });
1590
- if (res.ok) return await res.json();
1590
+ if (res.ok) return (await res.json()).data;
1591
1591
  const body = await res.json();
1592
1592
  if (body.error === "authorization_pending") continue;
1593
1593
  if (body.error === "slow_down") {
@@ -1699,13 +1699,16 @@ const loginCommand = defineCommand({
1699
1699
  "Content-Type": "application/json",
1700
1700
  "X-EmDash-Request": "1"
1701
1701
  },
1702
- body: JSON.stringify({ client_id: "emdash-cli" })
1702
+ body: JSON.stringify({
1703
+ client_id: "emdash-cli",
1704
+ scope: "admin"
1705
+ })
1703
1706
  });
1704
1707
  if (!codeRes.ok) {
1705
1708
  consola$1.error(`Failed to request device code: ${codeRes.status}`);
1706
1709
  process.exit(2);
1707
1710
  }
1708
- const deviceCode = await codeRes.json();
1711
+ const deviceCode = (await codeRes.json()).data;
1709
1712
  console.log();
1710
1713
  consola$1.info(`Open your browser to:`);
1711
1714
  console.log(` ${pc.cyan(pc.bold(deviceCode.verification_uri))}`);