emdash 0.4.0 → 0.6.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 (212) hide show
  1. package/dist/{adapters-C2BzVy0p.d.mts → adapters-Di31kZ28.d.mts} +16 -1
  2. package/dist/adapters-Di31kZ28.d.mts.map +1 -0
  3. package/dist/{apply-Cma_PiF6.mjs → apply-B4MsLM-w.mjs} +27 -12
  4. package/dist/apply-B4MsLM-w.mjs.map +1 -0
  5. package/dist/astro/index.d.mts +6 -6
  6. package/dist/astro/index.d.mts.map +1 -1
  7. package/dist/astro/index.mjs +208 -34
  8. package/dist/astro/index.mjs.map +1 -1
  9. package/dist/astro/middleware/auth.d.mts +5 -5
  10. package/dist/astro/middleware/auth.d.mts.map +1 -1
  11. package/dist/astro/middleware/auth.mjs +34 -9
  12. package/dist/astro/middleware/auth.mjs.map +1 -1
  13. package/dist/astro/middleware/redirect.mjs +1 -1
  14. package/dist/astro/middleware/request-context.d.mts.map +1 -1
  15. package/dist/astro/middleware/request-context.mjs +5 -3
  16. package/dist/astro/middleware/request-context.mjs.map +1 -1
  17. package/dist/astro/middleware/setup.mjs +1 -1
  18. package/dist/astro/middleware.d.mts.map +1 -1
  19. package/dist/astro/middleware.mjs +460 -180
  20. package/dist/astro/middleware.mjs.map +1 -1
  21. package/dist/astro/types.d.mts +8 -8
  22. package/dist/{byline-WuOq9MFJ.mjs → byline-C4OVd8b3.mjs} +3 -19
  23. package/dist/byline-C4OVd8b3.mjs.map +1 -0
  24. package/dist/{bylines-C_Wsnz4L.mjs → bylines-hPTW79hw.mjs} +20 -33
  25. package/dist/bylines-hPTW79hw.mjs.map +1 -0
  26. package/dist/{cache-E3Dts-yT.mjs → cache-BkKBuIvS.mjs} +1 -1
  27. package/dist/{cache-E3Dts-yT.mjs.map → cache-BkKBuIvS.mjs.map} +1 -1
  28. package/dist/chunks-HGz06Soa.mjs +19 -0
  29. package/dist/chunks-HGz06Soa.mjs.map +1 -0
  30. package/dist/cli/index.mjs +9 -8
  31. package/dist/cli/index.mjs.map +1 -1
  32. package/dist/client/cf-access.d.mts +1 -1
  33. package/dist/client/index.d.mts +1 -1
  34. package/dist/client/index.mjs +1 -1
  35. package/dist/{config-DkxPrM9l.mjs → config-BXwuX8Bx.mjs} +1 -1
  36. package/dist/{config-DkxPrM9l.mjs.map → config-BXwuX8Bx.mjs.map} +1 -1
  37. package/dist/{connection-B4zVnQIa.mjs → connection-2igzM-AT.mjs} +19 -2
  38. package/dist/connection-2igzM-AT.mjs.map +1 -0
  39. package/dist/database/instrumentation.d.mts +45 -0
  40. package/dist/database/instrumentation.d.mts.map +1 -0
  41. package/dist/database/instrumentation.mjs +61 -0
  42. package/dist/database/instrumentation.mjs.map +1 -0
  43. package/dist/db/index.d.mts +3 -3
  44. package/dist/db/index.mjs.map +1 -1
  45. package/dist/db/libsql.d.mts +1 -1
  46. package/dist/db/postgres.d.mts +1 -1
  47. package/dist/db/sqlite.d.mts +1 -1
  48. package/dist/db-errors-D0UT85nC.mjs +41 -0
  49. package/dist/db-errors-D0UT85nC.mjs.map +1 -0
  50. package/dist/{default-PUx9RK6u.mjs → default-CME5YdZ3.mjs} +1 -1
  51. package/dist/{default-PUx9RK6u.mjs.map → default-CME5YdZ3.mjs.map} +1 -1
  52. package/dist/{error-HBeQbVhV.mjs → error-CiYn9yDu.mjs} +1 -1
  53. package/dist/{error-HBeQbVhV.mjs.map → error-CiYn9yDu.mjs.map} +1 -1
  54. package/dist/{index-CRg3PWfZ.d.mts → index-BYv0mB9g.d.mts} +135 -19
  55. package/dist/index-BYv0mB9g.d.mts.map +1 -0
  56. package/dist/index.d.mts +11 -11
  57. package/dist/index.mjs +20 -18
  58. package/dist/{load-BhSSm-TS.mjs → load-CBcmDIot.mjs} +1 -1
  59. package/dist/{load-BhSSm-TS.mjs.map → load-CBcmDIot.mjs.map} +1 -1
  60. package/dist/{loader-BYzwzORf.mjs → loader-DeiBJEMe.mjs} +18 -12
  61. package/dist/loader-DeiBJEMe.mjs.map +1 -0
  62. package/dist/{manifest-schema-BsXINkQD.mjs → manifest-schema-V30qsMft.mjs} +1 -1
  63. package/dist/{manifest-schema-BsXINkQD.mjs.map → manifest-schema-V30qsMft.mjs.map} +1 -1
  64. package/dist/media/index.d.mts +1 -1
  65. package/dist/media/index.mjs +1 -1
  66. package/dist/media/local-runtime.d.mts +7 -7
  67. package/dist/{mode-CyPLdO3C.mjs → mode-CpNnGkPz.mjs} +1 -1
  68. package/dist/{mode-CyPLdO3C.mjs.map → mode-CpNnGkPz.mjs.map} +1 -1
  69. package/dist/page/index.d.mts +11 -2
  70. package/dist/page/index.d.mts.map +1 -1
  71. package/dist/page/index.mjs +23 -1
  72. package/dist/page/index.mjs.map +1 -1
  73. package/dist/{placeholder-DntBEQo7.mjs → placeholder-C-fk5hYI.mjs} +1 -1
  74. package/dist/{placeholder-DntBEQo7.mjs.map → placeholder-C-fk5hYI.mjs.map} +1 -1
  75. package/dist/{placeholder-BBCtpTES.d.mts → placeholder-tzpqGWII.d.mts} +1 -1
  76. package/dist/{placeholder-BBCtpTES.d.mts.map → placeholder-tzpqGWII.d.mts.map} +1 -1
  77. package/dist/plugins/adapt-sandbox-entry.d.mts +5 -5
  78. package/dist/plugins/adapt-sandbox-entry.mjs +1 -1
  79. package/dist/{query-B6Vu0d2i.mjs → query-Bk_3vKvU.mjs} +78 -11
  80. package/dist/query-Bk_3vKvU.mjs.map +1 -0
  81. package/dist/{registry-BgnP3ysR.mjs → registry-Ci3WxVAr.mjs} +133 -97
  82. package/dist/registry-Ci3WxVAr.mjs.map +1 -0
  83. package/dist/request-cache-DiR961CV.mjs +79 -0
  84. package/dist/request-cache-DiR961CV.mjs.map +1 -0
  85. package/dist/request-context.d.mts +19 -16
  86. package/dist/request-context.d.mts.map +1 -1
  87. package/dist/request-context.mjs.map +1 -1
  88. package/dist/{runner-DYv3rX8P.d.mts → runner-Fl2NcUUz.d.mts} +2 -2
  89. package/dist/{runner-DYv3rX8P.d.mts.map → runner-Fl2NcUUz.d.mts.map} +1 -1
  90. package/dist/runtime.d.mts +6 -6
  91. package/dist/runtime.mjs +1 -1
  92. package/dist/{search-B5p9D36n.mjs → search-DI4bM2w9.mjs} +110 -209
  93. package/dist/search-DI4bM2w9.mjs.map +1 -0
  94. package/dist/seed/index.d.mts +2 -2
  95. package/dist/seed/index.mjs +8 -7
  96. package/dist/seo/index.d.mts +1 -1
  97. package/dist/storage/local.d.mts +1 -1
  98. package/dist/storage/local.mjs +1 -1
  99. package/dist/storage/s3.d.mts +1 -1
  100. package/dist/storage/s3.mjs +1 -1
  101. package/dist/taxonomies-DbrKzDju.mjs +308 -0
  102. package/dist/taxonomies-DbrKzDju.mjs.map +1 -0
  103. package/dist/{tokens-DKHiCYCB.mjs → tokens-BFPFx3CA.mjs} +1 -1
  104. package/dist/{tokens-DKHiCYCB.mjs.map → tokens-BFPFx3CA.mjs.map} +1 -1
  105. package/dist/{transport-BtcQ-Z7T.mjs → transport-BykRfpyy.mjs} +1 -1
  106. package/dist/{transport-BtcQ-Z7T.mjs.map → transport-BykRfpyy.mjs.map} +1 -1
  107. package/dist/{transport-CKQA_G44.d.mts → transport-H4Iwx7tC.d.mts} +1 -1
  108. package/dist/{transport-CKQA_G44.d.mts.map → transport-H4Iwx7tC.d.mts.map} +1 -1
  109. package/dist/{types-BmkQR1En.d.mts → types-6CUZRrZP.d.mts} +1 -1
  110. package/dist/{types-BmkQR1En.d.mts.map → types-6CUZRrZP.d.mts.map} +1 -1
  111. package/dist/{types-B6BzlZxx.d.mts → types-8xrvl_68.d.mts} +1 -1
  112. package/dist/{types-B6BzlZxx.d.mts.map → types-8xrvl_68.d.mts.map} +1 -1
  113. package/dist/{types-Dz9_WMS6.mjs → types-BH2L167P.mjs} +1 -1
  114. package/dist/{types-Dz9_WMS6.mjs.map → types-BH2L167P.mjs.map} +1 -1
  115. package/dist/{types-DNZpaCBk.d.mts → types-CFWjXmus.d.mts} +1 -1
  116. package/dist/{types-DNZpaCBk.d.mts.map → types-CFWjXmus.d.mts.map} +1 -1
  117. package/dist/{types-gLYVCXCQ.d.mts → types-CnZYHyLW.d.mts} +55 -5
  118. package/dist/types-CnZYHyLW.d.mts.map +1 -0
  119. package/dist/{types-xxCWI3j0.mjs → types-DDS4MxsT.mjs} +11 -3
  120. package/dist/types-DDS4MxsT.mjs.map +1 -0
  121. package/dist/{types-BYWYxLcp.d.mts → types-DgrIP0tF.d.mts} +9 -2
  122. package/dist/types-DgrIP0tF.d.mts.map +1 -0
  123. package/dist/{validate-CcNRWH6I.d.mts → validate-CaLH1Ia2.d.mts} +5 -52
  124. package/dist/validate-CaLH1Ia2.d.mts.map +1 -0
  125. package/dist/{validate-DuZDIxfy.mjs → validate-CqsNItbt.mjs} +2 -2
  126. package/dist/{validate-DuZDIxfy.mjs.map → validate-CqsNItbt.mjs.map} +1 -1
  127. package/dist/version-Uaf2ynPX.mjs +7 -0
  128. package/dist/{version-DlTDRdpv.mjs.map → version-Uaf2ynPX.mjs.map} +1 -1
  129. package/package.json +10 -5
  130. package/src/after.ts +62 -0
  131. package/src/api/handlers/oauth-authorization.ts +2 -32
  132. package/src/api/handlers/oauth-clients.ts +40 -4
  133. package/src/api/handlers/taxonomies.ts +13 -0
  134. package/src/api/oauth/redirect-uri.ts +34 -0
  135. package/src/api/openapi/document.ts +126 -118
  136. package/src/api/schemas/auth.ts +7 -0
  137. package/src/api/schemas/media.ts +26 -15
  138. package/src/api/schemas/schema.ts +1 -0
  139. package/src/astro/integration/font-provider.ts +176 -0
  140. package/src/astro/integration/index.ts +42 -0
  141. package/src/astro/integration/routes.ts +17 -1
  142. package/src/astro/integration/runtime.ts +63 -0
  143. package/src/astro/integration/virtual-modules.ts +41 -39
  144. package/src/astro/integration/vite-config.ts +16 -5
  145. package/src/astro/middleware/auth.ts +39 -6
  146. package/src/astro/middleware/request-context.ts +15 -3
  147. package/src/astro/middleware.ts +340 -263
  148. package/src/astro/routes/admin.astro +10 -5
  149. package/src/astro/routes/api/auth/invite/register-options.ts +78 -0
  150. package/src/astro/routes/api/auth/passkey/verify.ts +5 -1
  151. package/src/astro/routes/api/content/[collection]/[id]/terms/[taxonomy].ts +5 -0
  152. package/src/astro/routes/api/import/wordpress/execute.ts +1 -1
  153. package/src/astro/routes/api/import/wordpress-plugin/execute.ts +1 -1
  154. package/src/astro/routes/api/media/upload-url.ts +10 -2
  155. package/src/astro/routes/api/media.ts +10 -7
  156. package/src/astro/routes/api/oauth/register.ts +178 -0
  157. package/src/astro/routes/api/oauth/token.ts +15 -0
  158. package/src/astro/routes/api/openapi.json.ts +15 -5
  159. package/src/astro/routes/api/schema/collections/[slug]/fields/[fieldSlug].ts +2 -0
  160. package/src/astro/routes/api/schema/collections/[slug]/fields/index.ts +1 -0
  161. package/src/astro/routes/api/schema/collections/[slug]/fields/reorder.ts +1 -0
  162. package/src/astro/routes/api/search/index.ts +5 -0
  163. package/src/astro/routes/api/search/suggest.ts +3 -0
  164. package/src/astro/routes/api/taxonomies/index.ts +1 -0
  165. package/src/astro/routes/api/well-known/oauth-authorization-server.ts +6 -4
  166. package/src/bylines/index.ts +22 -45
  167. package/src/components/EmDashHead.astro +23 -7
  168. package/src/components/Table.astro +73 -41
  169. package/src/components/index.ts +2 -12
  170. package/src/components/marks.ts +20 -0
  171. package/src/database/connection.ts +23 -1
  172. package/src/database/instrumentation.ts +98 -0
  173. package/src/db/adapters.ts +15 -0
  174. package/src/emdash-runtime.ts +309 -91
  175. package/src/index.ts +6 -0
  176. package/src/loader.ts +19 -24
  177. package/src/menus/index.ts +6 -3
  178. package/src/page/index.ts +1 -1
  179. package/src/page/seo-contributions.ts +36 -0
  180. package/src/plugins/context.ts +1 -0
  181. package/src/plugins/email-console.ts +9 -2
  182. package/src/plugins/types.ts +8 -0
  183. package/src/query.ts +104 -7
  184. package/src/request-cache.ts +106 -0
  185. package/src/request-context.ts +19 -0
  186. package/src/schema/query.ts +5 -2
  187. package/src/schema/registry.ts +243 -166
  188. package/src/schema/types.ts +13 -2
  189. package/src/schema/zod-generator.ts +4 -0
  190. package/src/search/fts-manager.ts +19 -5
  191. package/src/search/query.ts +4 -3
  192. package/src/seed/apply.ts +15 -1
  193. package/src/settings/index.ts +24 -5
  194. package/src/taxonomies/index.ts +324 -124
  195. package/src/utils/db-errors.ts +46 -0
  196. package/src/virtual-modules.d.ts +31 -10
  197. package/src/widgets/index.ts +54 -25
  198. package/dist/adapters-C2BzVy0p.d.mts.map +0 -1
  199. package/dist/apply-Cma_PiF6.mjs.map +0 -1
  200. package/dist/byline-WuOq9MFJ.mjs.map +0 -1
  201. package/dist/bylines-C_Wsnz4L.mjs.map +0 -1
  202. package/dist/connection-B4zVnQIa.mjs.map +0 -1
  203. package/dist/index-CRg3PWfZ.d.mts.map +0 -1
  204. package/dist/loader-BYzwzORf.mjs.map +0 -1
  205. package/dist/query-B6Vu0d2i.mjs.map +0 -1
  206. package/dist/registry-BgnP3ysR.mjs.map +0 -1
  207. package/dist/search-B5p9D36n.mjs.map +0 -1
  208. package/dist/types-BYWYxLcp.d.mts.map +0 -1
  209. package/dist/types-gLYVCXCQ.d.mts.map +0 -1
  210. package/dist/types-xxCWI3j0.mjs.map +0 -1
  211. package/dist/validate-CcNRWH6I.d.mts.map +0 -1
  212. package/dist/version-DlTDRdpv.mjs +0 -7
@@ -1,20 +1,6 @@
1
+ import { QueryRecorder } from "./database/instrumentation.mjs";
2
+
1
3
  //#region src/request-context.d.ts
2
- /**
3
- * EmDash Request Context
4
- *
5
- * Uses AsyncLocalStorage to provide request-scoped state to query functions
6
- * without requiring explicit parameter passing. The middleware wraps next()
7
- * in als.run(), making the context available to all code during rendering.
8
- *
9
- * For logged-out users with no CMS signals (no edit cookie, no preview param),
10
- * the middleware skips ALS entirely — zero overhead for normal traffic.
11
- *
12
- * The AsyncLocalStorage instance is stored on globalThis with a Symbol key
13
- * to guarantee a singleton even when bundlers duplicate this module across
14
- * code-split chunks. Without this, Rollup/Vite may inline the module into
15
- * multiple chunks (e.g. middleware and page components), each with its own
16
- * ALS instance — breaking request-scoped state propagation.
17
- */
18
4
  interface EmDashRequestContext {
19
5
  /** Whether the current request is in visual editing mode */
20
6
  editMode: boolean;
@@ -33,6 +19,23 @@ interface EmDashRequestContext {
33
19
  * the singleton instance. Also used by the DO preview pattern.
34
20
  */
35
21
  db?: unknown;
22
+ /**
23
+ * Indicates the per-request `db` points at an isolated database
24
+ * instance whose schema may diverge from the configured one
25
+ * (playground, DO preview sessions). When true, schema-derived caches
26
+ * (manifest, taxonomy defs, etc.) must not be reused across requests.
27
+ *
28
+ * Plain D1 Sessions API routing does NOT set this — sessions are just
29
+ * a routing hint over the same schema, so the module-scoped manifest
30
+ * cache remains valid.
31
+ */
32
+ dbIsIsolated?: boolean;
33
+ /**
34
+ * Query recorder attached by middleware when EMDASH_QUERY_LOG_FILE is set.
35
+ * The Kysely `log` hook appends an event per query; middleware flushes
36
+ * to NDJSON after the response.
37
+ */
38
+ queryRecorder?: QueryRecorder;
36
39
  }
37
40
  /**
38
41
  * Run a function within an EmDash request context.
@@ -1 +1 @@
1
- {"version":3,"file":"request-context.d.mts","names":[],"sources":["../src/request-context.ts"],"mappings":";;AAmBA;;;;;;;;;;;;AAqCA;;;UArCiB,oBAAA;EAqCsD;EAnCtE,QAAA;EAmC2E;EAjC3E,OAAA;IACC,UAAA;IACA,EAAA;EAAA;EA+BqE;EA5BtE,MAAA;EA4B0E;;;AAQ3E;;;;EA5BC,EAAA;AAAA;;;;;iBAoBe,cAAA,GAAA,CAAkB,GAAA,EAAK,oBAAA,EAAsB,EAAA,QAAU,CAAA,GAAI,CAAA;;;;;iBAQ3D,iBAAA,CAAA,GAAqB,oBAAA"}
1
+ {"version":3,"file":"request-context.d.mts","names":[],"sources":["../src/request-context.ts"],"mappings":";;;UAqBiB,oBAAA;EAsDD;EApDf,QAAA;EAoD6B;EAlD7B,OAAA;IACC,UAAA;IACA,EAAA;EAAA;EAgD0E;EA7C3E,MAAA;EA6CsC;;;;;;;EArCtC,EAAA;EA6CgC;;;;;;;;;;EAlChC,YAAA;;;;;;EAMA,aAAA,GAAgB,aAAA;AAAA;;;;;iBAoBD,cAAA,GAAA,CAAkB,GAAA,EAAK,oBAAA,EAAsB,EAAA,QAAU,CAAA,GAAI,CAAA;;;;;iBAQ3D,iBAAA,CAAA,GAAqB,oBAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"request-context.mjs","names":[],"sources":["../src/request-context.ts"],"sourcesContent":["/**\n * EmDash Request Context\n *\n * Uses AsyncLocalStorage to provide request-scoped state to query functions\n * without requiring explicit parameter passing. The middleware wraps next()\n * in als.run(), making the context available to all code during rendering.\n *\n * For logged-out users with no CMS signals (no edit cookie, no preview param),\n * the middleware skips ALS entirely — zero overhead for normal traffic.\n *\n * The AsyncLocalStorage instance is stored on globalThis with a Symbol key\n * to guarantee a singleton even when bundlers duplicate this module across\n * code-split chunks. Without this, Rollup/Vite may inline the module into\n * multiple chunks (e.g. middleware and page components), each with its own\n * ALS instance — breaking request-scoped state propagation.\n */\n\nimport { AsyncLocalStorage } from \"node:async_hooks\";\n\nexport interface EmDashRequestContext {\n\t/** Whether the current request is in visual editing mode */\n\teditMode: boolean;\n\t/** Preview token info, if this is a preview request */\n\tpreview?: {\n\t\tcollection: string;\n\t\tid: string;\n\t};\n\t/** Current locale from Astro's i18n routing (when configured) */\n\tlocale?: string;\n\t/**\n\t * Per-request database override.\n\t *\n\t * Set by middleware when D1 read replica sessions are enabled.\n\t * The runtime's `db` getter checks this first, falling back to\n\t * the singleton instance. Also used by the DO preview pattern.\n\t */\n\tdb?: unknown;\n}\n\nconst ALS_KEY = Symbol.for(\"emdash:request-context\");\n\nconst storage: AsyncLocalStorage<EmDashRequestContext> =\n\t// eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- globalThis singleton pattern\n\t((globalThis as Record<symbol, unknown>)[ALS_KEY] as\n\t\t| AsyncLocalStorage<EmDashRequestContext>\n\t\t| undefined) ??\n\t(() => {\n\t\tconst als = new AsyncLocalStorage<EmDashRequestContext>();\n\t\t(globalThis as Record<symbol, unknown>)[ALS_KEY] = als;\n\t\treturn als;\n\t})();\n\n/**\n * Run a function within an EmDash request context.\n * Called by middleware to wrap next().\n */\nexport function runWithContext<T>(ctx: EmDashRequestContext, fn: () => T): T {\n\treturn storage.run(ctx, fn);\n}\n\n/**\n * Get the current request context.\n * Returns undefined if no context is set (logged-out fast path).\n */\nexport function getRequestContext(): EmDashRequestContext | undefined {\n\treturn storage.getStore();\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAuCA,MAAM,UAAU,OAAO,IAAI,yBAAyB;AAEpD,MAAM,UAEH,WAAuC,mBAGlC;CACN,MAAM,MAAM,IAAI,mBAAyC;AACzD,CAAC,WAAuC,WAAW;AACnD,QAAO;IACJ;;;;;AAML,SAAgB,eAAkB,KAA2B,IAAgB;AAC5E,QAAO,QAAQ,IAAI,KAAK,GAAG;;;;;;AAO5B,SAAgB,oBAAsD;AACrE,QAAO,QAAQ,UAAU"}
1
+ {"version":3,"file":"request-context.mjs","names":[],"sources":["../src/request-context.ts"],"sourcesContent":["/**\n * EmDash Request Context\n *\n * Uses AsyncLocalStorage to provide request-scoped state to query functions\n * without requiring explicit parameter passing. The middleware wraps next()\n * in als.run(), making the context available to all code during rendering.\n *\n * For logged-out users with no CMS signals (no edit cookie, no preview param),\n * the middleware skips ALS entirely — zero overhead for normal traffic.\n *\n * The AsyncLocalStorage instance is stored on globalThis with a Symbol key\n * to guarantee a singleton even when bundlers duplicate this module across\n * code-split chunks. Without this, Rollup/Vite may inline the module into\n * multiple chunks (e.g. middleware and page components), each with its own\n * ALS instance — breaking request-scoped state propagation.\n */\n\nimport { AsyncLocalStorage } from \"node:async_hooks\";\n\nimport type { QueryRecorder } from \"./database/instrumentation.js\";\n\nexport interface EmDashRequestContext {\n\t/** Whether the current request is in visual editing mode */\n\teditMode: boolean;\n\t/** Preview token info, if this is a preview request */\n\tpreview?: {\n\t\tcollection: string;\n\t\tid: string;\n\t};\n\t/** Current locale from Astro's i18n routing (when configured) */\n\tlocale?: string;\n\t/**\n\t * Per-request database override.\n\t *\n\t * Set by middleware when D1 read replica sessions are enabled.\n\t * The runtime's `db` getter checks this first, falling back to\n\t * the singleton instance. Also used by the DO preview pattern.\n\t */\n\tdb?: unknown;\n\t/**\n\t * Indicates the per-request `db` points at an isolated database\n\t * instance whose schema may diverge from the configured one\n\t * (playground, DO preview sessions). When true, schema-derived caches\n\t * (manifest, taxonomy defs, etc.) must not be reused across requests.\n\t *\n\t * Plain D1 Sessions API routing does NOT set this — sessions are just\n\t * a routing hint over the same schema, so the module-scoped manifest\n\t * cache remains valid.\n\t */\n\tdbIsIsolated?: boolean;\n\t/**\n\t * Query recorder attached by middleware when EMDASH_QUERY_LOG_FILE is set.\n\t * The Kysely `log` hook appends an event per query; middleware flushes\n\t * to NDJSON after the response.\n\t */\n\tqueryRecorder?: QueryRecorder;\n}\n\nconst ALS_KEY = Symbol.for(\"emdash:request-context\");\n\nconst storage: AsyncLocalStorage<EmDashRequestContext> =\n\t// eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- globalThis singleton pattern\n\t((globalThis as Record<symbol, unknown>)[ALS_KEY] as\n\t\t| AsyncLocalStorage<EmDashRequestContext>\n\t\t| undefined) ??\n\t(() => {\n\t\tconst als = new AsyncLocalStorage<EmDashRequestContext>();\n\t\t(globalThis as Record<symbol, unknown>)[ALS_KEY] = als;\n\t\treturn als;\n\t})();\n\n/**\n * Run a function within an EmDash request context.\n * Called by middleware to wrap next().\n */\nexport function runWithContext<T>(ctx: EmDashRequestContext, fn: () => T): T {\n\treturn storage.run(ctx, fn);\n}\n\n/**\n * Get the current request context.\n * Returns undefined if no context is set (logged-out fast path).\n */\nexport function getRequestContext(): EmDashRequestContext | undefined {\n\treturn storage.getStore();\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AA0DA,MAAM,UAAU,OAAO,IAAI,yBAAyB;AAEpD,MAAM,UAEH,WAAuC,mBAGlC;CACN,MAAM,MAAM,IAAI,mBAAyC;AACzD,CAAC,WAAuC,WAAW;AACnD,QAAO;IACJ;;;;;AAML,SAAgB,eAAkB,KAA2B,IAAgB;AAC5E,QAAO,QAAQ,IAAI,KAAK,GAAG;;;;;;AAO5B,SAAgB,oBAAsD;AACrE,QAAO,QAAQ,UAAU"}
@@ -1,4 +1,4 @@
1
- import { t as Database } from "./types-B6BzlZxx.mjs";
1
+ import { t as Database } from "./types-8xrvl_68.mjs";
2
2
  import { Kysely } from "kysely";
3
3
 
4
4
  //#region src/database/migrations/runner.d.ts
@@ -31,4 +31,4 @@ declare function rollbackMigration(db: Kysely<Database>): Promise<{
31
31
  }>;
32
32
  //#endregion
33
33
  export { runMigrations as i, getMigrationStatus as n, rollbackMigration as r, MigrationStatus as t };
34
- //# sourceMappingURL=runner-DYv3rX8P.d.mts.map
34
+ //# sourceMappingURL=runner-Fl2NcUUz.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"runner-DYv3rX8P.d.mts","names":[],"sources":["../src/database/migrations/runner.ts"],"mappings":";;;;UAuFiB,eAAA;EAChB,OAAA;EACA,OAAA;AAAA;;AAUD;;iBAAsB,kBAAA,CAAmB,EAAA,EAAI,MAAA,CAAO,QAAA,IAAY,OAAA,CAAQ,eAAA;;;;;;;;;;;iBAkClD,aAAA,CAAc,EAAA,EAAI,MAAA,CAAO,QAAA,IAAY,OAAA;EAAU,OAAA;AAAA;AAArE;;;AAAA,iBA8CsB,iBAAA,CACrB,EAAA,EAAI,MAAA,CAAO,QAAA,IACT,OAAA;EAAU,UAAA;AAAA"}
1
+ {"version":3,"file":"runner-Fl2NcUUz.d.mts","names":[],"sources":["../src/database/migrations/runner.ts"],"mappings":";;;;UAuFiB,eAAA;EAChB,OAAA;EACA,OAAA;AAAA;;AAUD;;iBAAsB,kBAAA,CAAmB,EAAA,EAAI,MAAA,CAAO,QAAA,IAAY,OAAA,CAAQ,eAAA;;;;;;;;;;;iBAkClD,aAAA,CAAc,EAAA,EAAI,MAAA,CAAO,QAAA,IAAY,OAAA;EAAU,OAAA;AAAA;AAArE;;;AAAA,iBA8CsB,iBAAA,CACrB,EAAA,EAAI,MAAA,CAAO,QAAA,IACT,OAAA;EAAU,UAAA;AAAA"}
@@ -1,9 +1,9 @@
1
- import { f as MediaProvider } from "./placeholder-BBCtpTES.mjs";
2
- import "./types-B6BzlZxx.mjs";
3
- import { Fn as getDb, Mn as EntryData, Nn as EntryFilter, Pn as emdashLoader, jn as CollectionFilter } from "./index-CRg3PWfZ.mjs";
4
- import "./runner-DYv3rX8P.mjs";
5
- import "./types-BYWYxLcp.mjs";
6
- import "./validate-CcNRWH6I.mjs";
1
+ import { f as MediaProvider } from "./placeholder-tzpqGWII.mjs";
2
+ import "./types-8xrvl_68.mjs";
3
+ import { Fn as EntryFilter, In as emdashLoader, Ln as getDb, Nn as CollectionFilter, Pn as EntryData } from "./index-BYv0mB9g.mjs";
4
+ import "./runner-Fl2NcUUz.mjs";
5
+ import "./types-DgrIP0tF.mjs";
6
+ import "./validate-CaLH1Ia2.mjs";
7
7
 
8
8
  //#region src/media/provider-loader.d.ts
9
9
  /**
package/dist/runtime.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import "./dialect-helpers-DhTzaUxP.mjs";
2
2
  import "./base64-MBPo9ozB.mjs";
3
3
  import "./types-CMMN0pNg.mjs";
4
- import { n as getDb, t as emdashLoader } from "./loader-BYzwzORf.mjs";
4
+ import { n as getDb, t as emdashLoader } from "./loader-DeiBJEMe.mjs";
5
5
 
6
6
  //#region src/media/provider-loader.ts
7
7
  let virtualMediaProviders;
@@ -4,20 +4,22 @@ import { a as slugify, r as RevisionRepository, t as ContentRepository } from ".
4
4
  import { r as encodeBase64, t as decodeBase64 } from "./base64-MBPo9ozB.mjs";
5
5
  import { n as decodeCursor, r as encodeCursor, t as EmDashValidationError } from "./types-CMMN0pNg.mjs";
6
6
  import { t as MediaRepository } from "./media-DqHVh136.mjs";
7
- import { a as stripCredentialHeaders, f as OptionsRepository, i as ssrfSafeFetch, o as validateExternalUrl, r as SsrfError } from "./apply-Cma_PiF6.mjs";
7
+ import { a as stripCredentialHeaders, f as OptionsRepository, i as ssrfSafeFetch, o as validateExternalUrl, r as SsrfError } from "./apply-B4MsLM-w.mjs";
8
8
  import { t as withTransaction } from "./transaction-Cn2rjY78.mjs";
9
9
  import { t as RedirectRepository } from "./redirect-7lGhLBNZ.mjs";
10
- import { n as SQL_BATCH_SIZE, r as chunks, t as BylineRepository } from "./byline-WuOq9MFJ.mjs";
11
- import { r as isI18nEnabled } from "./config-DkxPrM9l.mjs";
12
- import { r as invalidateRedirectCache } from "./cache-E3Dts-yT.mjs";
13
- import { i as FTSManager, n as SchemaRegistry } from "./registry-BgnP3ysR.mjs";
14
- import { n as getDb } from "./loader-BYzwzORf.mjs";
15
- import { i as pluginManifestSchema } from "./manifest-schema-BsXINkQD.mjs";
16
- import { t as generatePreviewToken } from "./tokens-DKHiCYCB.mjs";
10
+ import { n as chunks, t as SQL_BATCH_SIZE } from "./chunks-HGz06Soa.mjs";
11
+ import { t as BylineRepository } from "./byline-C4OVd8b3.mjs";
12
+ import { r as isI18nEnabled } from "./config-BXwuX8Bx.mjs";
13
+ import { r as invalidateRedirectCache } from "./cache-BkKBuIvS.mjs";
14
+ import { i as FTSManager, n as SchemaRegistry } from "./registry-Ci3WxVAr.mjs";
15
+ import { n as getDb } from "./loader-DeiBJEMe.mjs";
16
+ import { n as requestCached } from "./request-cache-DiR961CV.mjs";
17
+ import { i as pluginManifestSchema } from "./manifest-schema-V30qsMft.mjs";
18
+ import { t as generatePreviewToken } from "./tokens-BFPFx3CA.mjs";
17
19
  import { sql } from "kysely";
20
+ import { AsyncLocalStorage } from "node:async_hooks";
18
21
  import { ulid } from "ulidx";
19
22
  import { z } from "astro/zod";
20
- import { AsyncLocalStorage } from "node:async_hooks";
21
23
  import { z as z$1 } from "zod";
22
24
  import { createGzipDecoder, unpackTar } from "modern-tar";
23
25
  import sax from "sax";
@@ -2229,7 +2231,9 @@ async function handleMediaDelete(db, id) {
2229
2231
  * ```
2230
2232
  */
2231
2233
  async function getCollectionInfo(slug) {
2232
- return getCollectionInfoWithDb(await getDb(), slug);
2234
+ return requestCached(`collection-info:${slug}`, async () => {
2235
+ return getCollectionInfoWithDb(await getDb(), slug);
2236
+ });
2233
2237
  }
2234
2238
  /**
2235
2239
  * Get collection metadata with an explicit db handle.
@@ -2751,14 +2755,8 @@ const mediaUpdateBody = z$1.object({
2751
2755
  width: z$1.number().int().positive().optional(),
2752
2756
  height: z$1.number().int().positive().optional()
2753
2757
  }).meta({ id: "MediaUpdateBody" });
2754
- /** Maximum allowed file upload size (50 MB). */
2755
- const MAX_UPLOAD_SIZE = 50 * 1024 * 1024;
2756
- const mediaUploadUrlBody = z$1.object({
2757
- filename: z$1.string().min(1, "filename is required"),
2758
- contentType: z$1.string().min(1, "contentType is required"),
2759
- size: z$1.number().int().positive().max(MAX_UPLOAD_SIZE, `File size must not exceed ${MAX_UPLOAD_SIZE / 1024 / 1024}MB`),
2760
- contentHash: z$1.string().optional()
2761
- }).meta({ id: "MediaUploadUrlBody" });
2758
+ /** Default maximum allowed file upload size (50 MB). */
2759
+ const DEFAULT_MAX_UPLOAD_SIZE = 50 * 1024 * 1024;
2762
2760
  const mediaConfirmBody = z$1.object({
2763
2761
  size: z$1.number().int().positive().optional(),
2764
2762
  width: z$1.number().int().positive().optional(),
@@ -2824,6 +2822,7 @@ const collectionSourcePattern = /^(template:.+|import:.+|manual|discovered|seed)
2824
2822
  const fieldTypeValues = z$1.enum([
2825
2823
  "string",
2826
2824
  "text",
2825
+ "url",
2827
2826
  "number",
2828
2827
  "integer",
2829
2828
  "boolean",
@@ -3105,6 +3104,10 @@ const inviteCreateBody = z$1.object({
3105
3104
  email: z$1.string().email(),
3106
3105
  role: roleLevel.optional()
3107
3106
  }).meta({ id: "InviteCreateBody" });
3107
+ const inviteRegisterOptionsBody = z$1.object({
3108
+ token: z$1.string().min(1),
3109
+ name: z$1.string().optional()
3110
+ }).meta({ id: "InviteRegisterOptionsBody" });
3108
3111
  const inviteCompleteBody = z$1.object({
3109
3112
  token: z$1.string().min(1),
3110
3113
  credential: registrationCredential$1,
@@ -4217,6 +4220,33 @@ function convertCodeBlock(block) {
4217
4220
  };
4218
4221
  }
4219
4222
 
4223
+ //#endregion
4224
+ //#region src/after.ts
4225
+ const waitUntilReady = (async () => {
4226
+ try {
4227
+ return (await import("virtual:emdash/wait-until")).waitUntil ?? null;
4228
+ } catch {
4229
+ return null;
4230
+ }
4231
+ })();
4232
+ waitUntilReady.catch(() => {});
4233
+ /**
4234
+ * Schedule `fn` to run without blocking the response.
4235
+ *
4236
+ * Errors are caught and logged — a deferred task should never surface
4237
+ * as an unhandled rejection because the response is long gone. Callers
4238
+ * that care about errors should handle them inside `fn`.
4239
+ */
4240
+ function after(fn) {
4241
+ const promise = Promise.resolve().then(fn).catch((error) => {
4242
+ console.error("[emdash] deferred task failed:", error);
4243
+ });
4244
+ waitUntilReady.then((waitUntil) => {
4245
+ if (waitUntil) waitUntil(promise);
4246
+ return null;
4247
+ });
4248
+ }
4249
+
4220
4250
  //#endregion
4221
4251
  //#region src/cli/wxr/parser.ts
4222
4252
  const PHP_SERIALIZED_STRING_PATTERN = /s:\d+:"([^"]+)"/g;
@@ -5439,7 +5469,8 @@ function createContentAccess(db) {
5439
5469
  const result = await contentRepo.findMany(collection, {
5440
5470
  limit: options?.limit ?? 50,
5441
5471
  cursor: options?.cursor,
5442
- orderBy
5472
+ orderBy,
5473
+ where: options?.where
5443
5474
  });
5444
5475
  const items = result.items.map((item) => ({
5445
5476
  id: item.id,
@@ -6930,8 +6961,14 @@ var EmailPipeline = class {
6930
6961
  const DEV_CONSOLE_EMAIL_PLUGIN_ID = "emdash-console-email";
6931
6962
  /** Maximum number of emails to keep in memory */
6932
6963
  const MAX_STORED_EMAILS = 100;
6933
- /** In-memory store for dev emails */
6934
- const storedEmails = [];
6964
+ /**
6965
+ * In-memory store for dev emails.
6966
+ * Uses globalThis so the same array is shared across Vite SSR module
6967
+ * instances (the runtime and the route handler may load separate copies
6968
+ * of this module, but globalThis is always the same object).
6969
+ */
6970
+ const GLOBAL_KEY = "__emdash_dev_emails__";
6971
+ const storedEmails = globalThis[GLOBAL_KEY] ??= [];
6935
6972
  /**
6936
6973
  * The email:deliver handler for the dev console provider.
6937
6974
  * Logs to console and stores in memory.
@@ -8671,8 +8708,10 @@ async function getCommentCountWithDb(db, collection, contentId) {
8671
8708
  * }
8672
8709
  * ```
8673
8710
  */
8674
- async function getMenu(name) {
8675
- return getMenuWithDb(name, await getDb());
8711
+ function getMenu(name) {
8712
+ return requestCached(`menu:${name}`, async () => {
8713
+ return getMenuWithDb(name, await getDb());
8714
+ });
8676
8715
  }
8677
8716
  /**
8678
8717
  * Get menu by name with resolved URLs (with explicit db)
@@ -8839,179 +8878,6 @@ async function resolveTaxonomyUrl(taxonomyId, db) {
8839
8878
  return `/${taxonomy.name}/${taxonomy.slug}`;
8840
8879
  }
8841
8880
 
8842
- //#endregion
8843
- //#region src/taxonomies/index.ts
8844
- /**
8845
- * Runtime API for taxonomies
8846
- *
8847
- * Provides functions to query taxonomy definitions and terms.
8848
- */
8849
- /**
8850
- * Get all taxonomy definitions
8851
- */
8852
- async function getTaxonomyDefs() {
8853
- return (await (await getDb()).selectFrom("_emdash_taxonomy_defs").selectAll().execute()).map((row) => ({
8854
- id: row.id,
8855
- name: row.name,
8856
- label: row.label,
8857
- labelSingular: row.label_singular ?? void 0,
8858
- hierarchical: row.hierarchical === 1,
8859
- collections: row.collections ? JSON.parse(row.collections) : []
8860
- }));
8861
- }
8862
- /**
8863
- * Get a single taxonomy definition by name
8864
- */
8865
- async function getTaxonomyDef(name) {
8866
- const row = await (await getDb()).selectFrom("_emdash_taxonomy_defs").selectAll().where("name", "=", name).executeTakeFirst();
8867
- if (!row) return null;
8868
- return {
8869
- id: row.id,
8870
- name: row.name,
8871
- label: row.label,
8872
- labelSingular: row.label_singular ?? void 0,
8873
- hierarchical: row.hierarchical === 1,
8874
- collections: row.collections ? JSON.parse(row.collections) : []
8875
- };
8876
- }
8877
- /**
8878
- * Get all terms for a taxonomy (as tree for hierarchical, flat for tags)
8879
- */
8880
- async function getTaxonomyTerms(taxonomyName) {
8881
- const db = await getDb();
8882
- const def = await getTaxonomyDef(taxonomyName);
8883
- if (!def) return [];
8884
- const rows = await db.selectFrom("taxonomies").selectAll().where("name", "=", taxonomyName).orderBy("label", "asc").execute();
8885
- const countsResult = await db.selectFrom("content_taxonomies").select(["taxonomy_id"]).select((eb) => eb.fn.count("entry_id").as("count")).groupBy("taxonomy_id").execute();
8886
- const counts = /* @__PURE__ */ new Map();
8887
- for (const row of countsResult) counts.set(row.taxonomy_id, row.count);
8888
- const flatTerms = rows.map((row) => ({
8889
- id: row.id,
8890
- name: row.name,
8891
- slug: row.slug,
8892
- label: row.label,
8893
- parent_id: row.parent_id,
8894
- data: row.data
8895
- }));
8896
- if (def.hierarchical) return buildTree(flatTerms, counts);
8897
- return flatTerms.map((term) => ({
8898
- id: term.id,
8899
- name: term.name,
8900
- slug: term.slug,
8901
- label: term.label,
8902
- children: [],
8903
- count: counts.get(term.id) ?? 0
8904
- }));
8905
- }
8906
- /**
8907
- * Get a single term by taxonomy and slug
8908
- */
8909
- async function getTerm(taxonomyName, slug) {
8910
- const db = await getDb();
8911
- const row = await db.selectFrom("taxonomies").selectAll().where("name", "=", taxonomyName).where("slug", "=", slug).executeTakeFirst();
8912
- if (!row) return null;
8913
- const count = (await db.selectFrom("content_taxonomies").select((eb) => eb.fn.count("entry_id").as("count")).where("taxonomy_id", "=", row.id).executeTakeFirst())?.count ?? 0;
8914
- const children = (await db.selectFrom("taxonomies").selectAll().where("parent_id", "=", row.id).orderBy("label", "asc").execute()).map((child) => ({
8915
- id: child.id,
8916
- name: child.name,
8917
- slug: child.slug,
8918
- label: child.label,
8919
- parentId: child.parent_id ?? void 0,
8920
- children: []
8921
- }));
8922
- return {
8923
- id: row.id,
8924
- name: row.name,
8925
- slug: row.slug,
8926
- label: row.label,
8927
- parentId: row.parent_id ?? void 0,
8928
- description: row.data ? JSON.parse(row.data).description : void 0,
8929
- children,
8930
- count
8931
- };
8932
- }
8933
- /**
8934
- * Get terms assigned to an entry
8935
- */
8936
- async function getEntryTerms(collection, entryId, taxonomyName) {
8937
- let query = (await getDb()).selectFrom("content_taxonomies").innerJoin("taxonomies", "taxonomies.id", "content_taxonomies.taxonomy_id").selectAll("taxonomies").where("content_taxonomies.collection", "=", collection).where("content_taxonomies.entry_id", "=", entryId);
8938
- if (taxonomyName) query = query.where("taxonomies.name", "=", taxonomyName);
8939
- return (await query.execute()).map((row) => ({
8940
- id: row.id,
8941
- name: row.name,
8942
- slug: row.slug,
8943
- label: row.label,
8944
- parentId: row.parent_id ?? void 0,
8945
- children: []
8946
- }));
8947
- }
8948
- /**
8949
- * Get terms for multiple entries in a single query (batched API)
8950
- *
8951
- * This is more efficient than calling getEntryTerms for each entry
8952
- * when you need terms for a list of entries.
8953
- *
8954
- * @param collection - The collection type (e.g., "posts")
8955
- * @param entryIds - Array of entry IDs
8956
- * @param taxonomyName - The taxonomy name (e.g., "categories")
8957
- * @returns Map from entry ID to array of terms
8958
- */
8959
- async function getTermsForEntries(collection, entryIds, taxonomyName) {
8960
- const result = /* @__PURE__ */ new Map();
8961
- for (const id of entryIds) result.set(id, []);
8962
- if (entryIds.length === 0) return result;
8963
- const rows = await (await getDb()).selectFrom("content_taxonomies").innerJoin("taxonomies", "taxonomies.id", "content_taxonomies.taxonomy_id").select([
8964
- "content_taxonomies.entry_id",
8965
- "taxonomies.id",
8966
- "taxonomies.name",
8967
- "taxonomies.slug",
8968
- "taxonomies.label",
8969
- "taxonomies.parent_id"
8970
- ]).where("content_taxonomies.collection", "=", collection).where("content_taxonomies.entry_id", "in", entryIds).where("taxonomies.name", "=", taxonomyName).execute();
8971
- for (const row of rows) {
8972
- const entryId = row.entry_id;
8973
- const term = {
8974
- id: row.id,
8975
- name: row.name,
8976
- slug: row.slug,
8977
- label: row.label,
8978
- parentId: row.parent_id ?? void 0,
8979
- children: []
8980
- };
8981
- const terms = result.get(entryId);
8982
- if (terms) terms.push(term);
8983
- }
8984
- return result;
8985
- }
8986
- /**
8987
- * Get entries by term (wraps getEmDashCollection)
8988
- */
8989
- async function getEntriesByTerm(collection, taxonomyName, termSlug) {
8990
- const { getEmDashCollection } = await import("./query-B6Vu0d2i.mjs").then((n) => n.o);
8991
- const { entries } = await getEmDashCollection(collection, { where: { [taxonomyName]: termSlug } });
8992
- return entries;
8993
- }
8994
- /**
8995
- * Build tree structure from flat terms
8996
- */
8997
- function buildTree(flatTerms, counts) {
8998
- const map = /* @__PURE__ */ new Map();
8999
- const roots = [];
9000
- for (const term of flatTerms) map.set(term.id, {
9001
- id: term.id,
9002
- name: term.name,
9003
- slug: term.slug,
9004
- label: term.label,
9005
- parentId: term.parent_id ?? void 0,
9006
- description: term.data ? JSON.parse(term.data).description : void 0,
9007
- children: [],
9008
- count: counts.get(term.id) ?? 0
9009
- });
9010
- for (const term of map.values()) if (term.parentId && map.has(term.parentId)) map.get(term.parentId).children.push(term);
9011
- else roots.push(term);
9012
- return roots;
9013
- }
9014
-
9015
8881
  //#endregion
9016
8882
  //#region src/widgets/components.ts
9017
8883
  /**
@@ -9121,18 +8987,53 @@ function getWidgetComponents$1() {
9121
8987
  //#endregion
9122
8988
  //#region src/widgets/index.ts
9123
8989
  /**
9124
- * Get a widget area by name, with all its widgets
8990
+ * Get a widget area by name, with all its widgets.
8991
+ *
8992
+ * Single query with a left join rather than area-then-widgets so the
8993
+ * common case costs one round-trip. An area with no widgets yields one
8994
+ * row with null widget columns, which we skip when mapping.
9125
8995
  */
9126
8996
  async function getWidgetArea(name) {
9127
- const db = await getDb();
9128
- const areaRow = await db.selectFrom("_emdash_widget_areas").selectAll().where("name", "=", name).executeTakeFirst();
9129
- if (!areaRow) return null;
9130
- const widgets = (await db.selectFrom("_emdash_widgets").selectAll().$castTo().where("area_id", "=", areaRow.id).orderBy("sort_order", "asc").execute()).map((row) => rowToWidget(row));
8997
+ const rows = await (await getDb()).selectFrom("_emdash_widget_areas as a").leftJoin("_emdash_widgets as w", "w.area_id", "a.id").select([
8998
+ "a.id as a_id",
8999
+ "a.name as a_name",
9000
+ "a.label as a_label",
9001
+ "a.description as a_description",
9002
+ "w.id as w_id",
9003
+ "w.type as w_type",
9004
+ "w.title as w_title",
9005
+ "w.content as w_content",
9006
+ "w.menu_name as w_menu_name",
9007
+ "w.component_id as w_component_id",
9008
+ "w.component_props as w_component_props",
9009
+ "w.area_id as w_area_id",
9010
+ "w.sort_order as w_sort_order",
9011
+ "w.created_at as w_created_at"
9012
+ ]).where("a.name", "=", name).orderBy("w.sort_order", "asc").execute();
9013
+ const first = rows[0];
9014
+ if (!first) return null;
9015
+ const widgets = [];
9016
+ for (const row of rows) {
9017
+ if (row.w_id === null) continue;
9018
+ const widgetRow = {
9019
+ id: row.w_id,
9020
+ type: row.w_type,
9021
+ title: row.w_title,
9022
+ content: row.w_content,
9023
+ menu_name: row.w_menu_name,
9024
+ component_id: row.w_component_id,
9025
+ component_props: row.w_component_props,
9026
+ area_id: row.w_area_id,
9027
+ sort_order: row.w_sort_order,
9028
+ created_at: row.w_created_at
9029
+ };
9030
+ widgets.push(rowToWidget(widgetRow));
9031
+ }
9131
9032
  return {
9132
- id: areaRow.id,
9133
- name: areaRow.name,
9134
- label: areaRow.label,
9135
- description: areaRow.description ?? void 0,
9033
+ id: first.a_id,
9034
+ name: first.a_name,
9035
+ label: first.a_label,
9036
+ description: first.a_description ?? void 0,
9136
9037
  widgets
9137
9038
  };
9138
9039
  }
@@ -9334,8 +9235,8 @@ async function getSuggestions(db, query, options = {}) {
9334
9235
  validateIdentifier(collection, "collection slug");
9335
9236
  const ftsTable = ftsManager.getFtsTableName(collection);
9336
9237
  const contentTable = ftsManager.getContentTableName(collection);
9337
- const prefixQuery = `${escapeQuery(query)}*`;
9338
- if (!prefixQuery || prefixQuery === "*") continue;
9238
+ const prefixQuery = escapeQuery(query);
9239
+ if (!prefixQuery) continue;
9339
9240
  const results = await sql`
9340
9241
  SELECT
9341
9242
  c.id,
@@ -9495,5 +9396,5 @@ function extractSearchableFields(entry, fields) {
9495
9396
  }
9496
9397
 
9497
9398
  //#endregion
9498
- export { sanitizeHeadersForSandbox as $, getAllSources as A, handleContentGet as At, createNoopSandboxRunner as B, handleContentUnschedule as Bt, isPreviewRequest as C, handleContentCompare as Ct, parseWxrDate as D, handleContentDelete as Dt, wordpressRestSource as E, handleContentCreate as Et, registerSource as F, handleContentPublish as Ft, DEV_CONSOLE_EMAIL_PLUGIN_ID as G, image as Gt, createPluginManager as H, validateRev as Ht, importReusableBlocksAsSections as I, handleContentRestore as It, HookPipeline as J, devConsoleEmailDeliver as K, isStandardPluginDefinition as L, handleContentSchedule as Lt, getSource as M, handleContentList as Mt, getUrlSources as N, handleContentListTrashed as Nt, wxrSource as O, handleContentDiscardDraft as Ot, probeUrl as P, handleContentPermanentDelete as Pt, extractRequestMeta as Q, NoopSandboxRunner as R, handleContentTranslations as Rt, getPreviewToken as S, hashString as St, getPreviewUrl as T, handleContentCountTrashed as Tt, PluginRouteError as U, portableText as Ut, PluginManager as V, handleContentUpdate as Vt, PluginRouteRegistry as W, reference as Wt, resolveExclusiveHooks as X, createHookPipeline as Y, CronExecutor as Z, getTermsForEntries as _, handleRevisionGet as _t, search as a, isSafeHref as at, getCommentCount as b, generateManifest as bt, getWidgetArea as c, getSection as ct, getEntriesByTerm as d, getCollectionInfo as dt, definePlugin as et, getEntryTerms as f, handleMediaCreate as ft, getTerm as g, handleMediaUpdate as gt, getTaxonomyTerms as h, handleMediaList as ht, getSuggestions as i, prosemirrorToPortableText as it, getFileSources as j, handleContentGetIncludingTrashed as jt, clearSources as k, handleContentDuplicate as kt, getWidgetAreas as l, getSections as lt, getTaxonomyDefs as m, handleMediaGet as mt, extractSearchableFields as n, parseWxrString as nt, searchCollection as o, sanitizeHref as ot, getTaxonomyDef as p, handleMediaDelete as pt, EmailPipeline as q, getSearchStats as r, portableTextToProsemirror as rt, searchWithDb as s, loadBundleFromR2 as st, extractPlainText as t, parseWxr as tt, getWidgetComponents as u, PluginStateRepository as ut, getMenu as v, handleRevisionList as vt, buildPreviewUrl as w, handleContentCountScheduled as wt, getComments as x, computeContentHash as xt, getMenus as y, handleRevisionRestore as yt, SandboxNotAvailableError as z, handleContentUnpublish as zt };
9499
- //# sourceMappingURL=search-B5p9D36n.mjs.map
9399
+ export { isSafeHref as $, isStandardPluginDefinition as A, handleContentRestore as At, EmailPipeline as B, getAllSources as C, handleContentDuplicate as Ct, probeUrl as D, handleContentListTrashed as Dt, getUrlSources as E, handleContentList as Et, createPluginManager as F, handleContentUpdate as Ft, extractRequestMeta as G, createHookPipeline as H, PluginRouteError as I, validateRev as It, parseWxr as J, sanitizeHeadersForSandbox as K, PluginRouteRegistry as L, portableText as Lt, SandboxNotAvailableError as M, handleContentTranslations as Mt, createNoopSandboxRunner as N, handleContentUnpublish as Nt, registerSource as O, handleContentPermanentDelete as Ot, PluginManager as P, handleContentUnschedule as Pt, prosemirrorToPortableText as Q, DEV_CONSOLE_EMAIL_PLUGIN_ID as R, reference as Rt, clearSources as S, handleContentDiscardDraft as St, getSource as T, handleContentGetIncludingTrashed as Tt, resolveExclusiveHooks as U, HookPipeline as V, CronExecutor as W, after as X, parseWxrString as Y, portableTextToProsemirror as Z, buildPreviewUrl as _, handleContentCompare as _t, search as a, getCollectionInfo as at, parseWxrDate as b, handleContentCreate as bt, getWidgetArea as c, handleMediaGet as ct, getMenu as d, handleRevisionGet as dt, sanitizeHref as et, getMenus as f, handleRevisionList as ft, isPreviewRequest as g, hashString as gt, getPreviewToken as h, computeContentHash as ht, getSuggestions as i, PluginStateRepository as it, NoopSandboxRunner as j, handleContentSchedule as jt, importReusableBlocksAsSections as k, handleContentPublish as kt, getWidgetAreas as l, handleMediaList as lt, getComments as m, generateManifest as mt, extractSearchableFields as n, getSection as nt, searchCollection as o, handleMediaCreate as ot, getCommentCount as p, handleRevisionRestore as pt, definePlugin as q, getSearchStats as r, getSections as rt, searchWithDb as s, handleMediaDelete as st, extractPlainText as t, loadBundleFromR2 as tt, getWidgetComponents as u, handleMediaUpdate as ut, getPreviewUrl as v, handleContentCountScheduled as vt, getFileSources as w, handleContentGet as wt, wxrSource as x, handleContentDelete as xt, wordpressRestSource as y, handleContentCountTrashed as yt, devConsoleEmailDeliver as z, image as zt };
9400
+ //# sourceMappingURL=search-DI4bM2w9.mjs.map