emdash 0.7.0 → 0.9.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 (354) hide show
  1. package/dist/{adapters-Di31kZ28.d.mts → adapters-DoNJiveC.d.mts} +1 -1
  2. package/dist/{adapters-Di31kZ28.d.mts.map → adapters-DoNJiveC.d.mts.map} +1 -1
  3. package/dist/{apply-5uslYdUu.mjs → apply-BzltprvY.mjs} +90 -139
  4. package/dist/apply-BzltprvY.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 +194 -17
  8. package/dist/astro/index.mjs.map +1 -1
  9. package/dist/astro/middleware/auth.d.mts +6 -7
  10. package/dist/astro/middleware/auth.d.mts.map +1 -1
  11. package/dist/astro/middleware/auth.mjs +34 -57
  12. package/dist/astro/middleware/auth.mjs.map +1 -1
  13. package/dist/astro/middleware/redirect.d.mts.map +1 -1
  14. package/dist/astro/middleware/redirect.mjs +17 -12
  15. package/dist/astro/middleware/redirect.mjs.map +1 -1
  16. package/dist/astro/middleware/request-context.d.mts.map +1 -1
  17. package/dist/astro/middleware/request-context.mjs +9 -6
  18. package/dist/astro/middleware/request-context.mjs.map +1 -1
  19. package/dist/astro/middleware/setup.mjs +1 -1
  20. package/dist/astro/middleware.d.mts.map +1 -1
  21. package/dist/astro/middleware.mjs +301 -165
  22. package/dist/astro/middleware.mjs.map +1 -1
  23. package/dist/astro/types.d.mts +34 -10
  24. package/dist/astro/types.d.mts.map +1 -1
  25. package/dist/{base64-MBPo9ozB.mjs → base64-BRICGH2l.mjs} +1 -1
  26. package/dist/{base64-MBPo9ozB.mjs.map → base64-BRICGH2l.mjs.map} +1 -1
  27. package/dist/{byline-C4OVd8b3.mjs → byline-BSaNL1w7.mjs} +5 -5
  28. package/dist/byline-BSaNL1w7.mjs.map +1 -0
  29. package/dist/bylines-CvJ3PYz2.mjs +113 -0
  30. package/dist/bylines-CvJ3PYz2.mjs.map +1 -0
  31. package/dist/cache-C6N_hhN7.mjs +65 -0
  32. package/dist/cache-C6N_hhN7.mjs.map +1 -0
  33. package/dist/{chunks-HGz06Soa.mjs → chunks-NBQVDOci.mjs} +8 -2
  34. package/dist/{chunks-HGz06Soa.mjs.map → chunks-NBQVDOci.mjs.map} +1 -1
  35. package/dist/cli/index.mjs +229 -31
  36. package/dist/cli/index.mjs.map +1 -1
  37. package/dist/client/cf-access.d.mts +1 -1
  38. package/dist/client/index.d.mts +1 -1
  39. package/dist/client/index.mjs +3 -3
  40. package/dist/client/index.mjs.map +1 -1
  41. package/dist/{config-BXwuX8Bx.mjs → config-BI0V3ICQ.mjs} +1 -1
  42. package/dist/{config-BXwuX8Bx.mjs.map → config-BI0V3ICQ.mjs.map} +1 -1
  43. package/dist/{content-D7J5y73J.mjs → content-8lOYF0pr.mjs} +43 -28
  44. package/dist/content-8lOYF0pr.mjs.map +1 -0
  45. package/dist/db/index.d.mts +3 -3
  46. package/dist/db/index.mjs +2 -2
  47. package/dist/db/libsql.d.mts +1 -1
  48. package/dist/db/libsql.d.mts.map +1 -1
  49. package/dist/db/libsql.mjs +7 -2
  50. package/dist/db/libsql.mjs.map +1 -1
  51. package/dist/db/postgres.d.mts +1 -1
  52. package/dist/db/sqlite.d.mts +1 -1
  53. package/dist/db/sqlite.d.mts.map +1 -1
  54. package/dist/db/sqlite.mjs +8 -3
  55. package/dist/db/sqlite.mjs.map +1 -1
  56. package/dist/{db-errors-D0UT85nC.mjs → db-errors-WRezodiz.mjs} +1 -1
  57. package/dist/{db-errors-D0UT85nC.mjs.map → db-errors-WRezodiz.mjs.map} +1 -1
  58. package/dist/{default-CME5YdZ3.mjs → default-D8ksjWhO.mjs} +1 -1
  59. package/dist/{default-CME5YdZ3.mjs.map → default-D8ksjWhO.mjs.map} +1 -1
  60. package/dist/{dialect-helpers-DhTzaUxP.mjs → dialect-helpers-BKCvISIQ.mjs} +19 -2
  61. package/dist/dialect-helpers-BKCvISIQ.mjs.map +1 -0
  62. package/dist/{error-CiYn9yDu.mjs → error-D_-tqP-I.mjs} +1 -1
  63. package/dist/error-D_-tqP-I.mjs.map +1 -0
  64. package/dist/{index-De6_Xv3v.d.mts → index-BFRaVcD6.d.mts} +243 -40
  65. package/dist/index-BFRaVcD6.d.mts.map +1 -0
  66. package/dist/index.d.mts +11 -11
  67. package/dist/index.mjs +29 -25
  68. package/dist/{load-CBcmDIot.mjs → load-DDqMMvZL.mjs} +2 -2
  69. package/dist/{load-CBcmDIot.mjs.map → load-DDqMMvZL.mjs.map} +1 -1
  70. package/dist/{loader-DeiBJEMe.mjs → loader-CKLbBnhK.mjs} +32 -10
  71. package/dist/loader-CKLbBnhK.mjs.map +1 -0
  72. package/dist/{manifest-schema-V30qsMft.mjs → manifest-schema-DqWNC3lM.mjs} +45 -3
  73. package/dist/manifest-schema-DqWNC3lM.mjs.map +1 -0
  74. package/dist/media/index.d.mts +1 -1
  75. package/dist/media/index.mjs +1 -1
  76. package/dist/media/local-runtime.d.mts +7 -7
  77. package/dist/media/local-runtime.mjs +3 -3
  78. package/dist/{media-DqHVh136.mjs → media-BW32b4gi.mjs} +4 -7
  79. package/dist/media-BW32b4gi.mjs.map +1 -0
  80. package/dist/{mode-CpNnGkPz.mjs → mode-ier8jbBk.mjs} +1 -1
  81. package/dist/mode-ier8jbBk.mjs.map +1 -0
  82. package/dist/options-BVp3UsTS.mjs +117 -0
  83. package/dist/options-BVp3UsTS.mjs.map +1 -0
  84. package/dist/page/index.d.mts +2 -2
  85. package/dist/{placeholder-tzpqGWII.d.mts → placeholder-BE4o_2dc.d.mts} +1 -1
  86. package/dist/{placeholder-tzpqGWII.d.mts.map → placeholder-BE4o_2dc.d.mts.map} +1 -1
  87. package/dist/{placeholder-C-fk5hYI.mjs → placeholder-CIJejMlK.mjs} +1 -1
  88. package/dist/placeholder-CIJejMlK.mjs.map +1 -0
  89. package/dist/plugins/adapt-sandbox-entry.d.mts +5 -5
  90. package/dist/plugins/adapt-sandbox-entry.d.mts.map +1 -1
  91. package/dist/plugins/adapt-sandbox-entry.mjs +6 -5
  92. package/dist/plugins/adapt-sandbox-entry.mjs.map +1 -1
  93. package/dist/public-url-DByxYjUw.mjs +51 -0
  94. package/dist/public-url-DByxYjUw.mjs.map +1 -0
  95. package/dist/{query-g4Ug-9j9.mjs → query-Cg9ZKRQ0.mjs} +114 -16
  96. package/dist/query-Cg9ZKRQ0.mjs.map +1 -0
  97. package/dist/{redirect-CN0Rt9Ob.mjs → redirect-BhUBKRc1.mjs} +13 -8
  98. package/dist/redirect-BhUBKRc1.mjs.map +1 -0
  99. package/dist/{registry-Ci3WxVAr.mjs → registry-Dw70ChxB.mjs} +69 -11
  100. package/dist/registry-Dw70ChxB.mjs.map +1 -0
  101. package/dist/{request-cache-DiR961CV.mjs → request-cache-B-bmkipQ.mjs} +1 -1
  102. package/dist/request-cache-B-bmkipQ.mjs.map +1 -0
  103. package/dist/runner-Bnoj7vjK.d.mts +44 -0
  104. package/dist/runner-Bnoj7vjK.d.mts.map +1 -0
  105. package/dist/{runner-tQ7BJ4T7.mjs → runner-C7ADox5q.mjs} +185 -55
  106. package/dist/{runner-tQ7BJ4T7.mjs.map → runner-C7ADox5q.mjs.map} +1 -1
  107. package/dist/runtime.d.mts +6 -6
  108. package/dist/runtime.mjs +4 -4
  109. package/dist/{search-B0effn3j.mjs → search-dOGEccMa.mjs} +341 -152
  110. package/dist/search-dOGEccMa.mjs.map +1 -0
  111. package/dist/secrets-CW3reAnU.mjs +314 -0
  112. package/dist/secrets-CW3reAnU.mjs.map +1 -0
  113. package/dist/seed/index.d.mts +2 -2
  114. package/dist/seed/index.mjs +15 -14
  115. package/dist/seo/index.d.mts +1 -1
  116. package/dist/storage/local.d.mts +1 -1
  117. package/dist/storage/local.mjs +1 -1
  118. package/dist/storage/s3.d.mts +1 -1
  119. package/dist/storage/s3.d.mts.map +1 -1
  120. package/dist/storage/s3.mjs +4 -4
  121. package/dist/storage/s3.mjs.map +1 -1
  122. package/dist/{taxonomies-K2z0Uhnj.mjs → taxonomies-ZlRtD6AG.mjs} +14 -7
  123. package/dist/taxonomies-ZlRtD6AG.mjs.map +1 -0
  124. package/dist/{tokens-BFPFx3CA.mjs → tokens-D7zMmWi2.mjs} +2 -2
  125. package/dist/{tokens-BFPFx3CA.mjs.map → tokens-D7zMmWi2.mjs.map} +1 -1
  126. package/dist/{transport-BykRfpyy.mjs → transport-BeMCmin1.mjs} +6 -5
  127. package/dist/{transport-BykRfpyy.mjs.map → transport-BeMCmin1.mjs.map} +1 -1
  128. package/dist/{transport-H4Iwx7tC.d.mts → transport-DNEfeMaU.d.mts} +1 -1
  129. package/dist/{transport-H4Iwx7tC.d.mts.map → transport-DNEfeMaU.d.mts.map} +1 -1
  130. package/dist/types-4fVtCIm0.mjs +68 -0
  131. package/dist/types-4fVtCIm0.mjs.map +1 -0
  132. package/dist/{types-CnZYHyLW.d.mts → types-BSyXeCFW.d.mts} +24 -2
  133. package/dist/{types-CnZYHyLW.d.mts.map → types-BSyXeCFW.d.mts.map} +1 -1
  134. package/dist/{types-DgrIP0tF.d.mts → types-BuBIptGk.d.mts} +80 -106
  135. package/dist/types-BuBIptGk.d.mts.map +1 -0
  136. package/dist/{types-BH2L167P.mjs → types-CDbKp7ND.mjs} +1 -1
  137. package/dist/{types-BH2L167P.mjs.map → types-CDbKp7ND.mjs.map} +1 -1
  138. package/dist/{types-DDS4MxsT.mjs → types-CIOg5AR8.mjs} +1 -1
  139. package/dist/{types-DDS4MxsT.mjs.map → types-CIOg5AR8.mjs.map} +1 -1
  140. package/dist/{types-6CUZRrZP.d.mts → types-CJsYGpco.d.mts} +24 -2
  141. package/dist/{types-6CUZRrZP.d.mts.map → types-CJsYGpco.d.mts.map} +1 -1
  142. package/dist/types-CRxNbK-Z.mjs +68 -0
  143. package/dist/types-CRxNbK-Z.mjs.map +1 -0
  144. package/dist/{types-C2v0c34j.d.mts → types-CrtWgIvl.d.mts} +1 -1
  145. package/dist/{types-C2v0c34j.d.mts.map → types-CrtWgIvl.d.mts.map} +1 -1
  146. package/dist/{types-CFWjXmus.d.mts → types-M78DQ1lx.d.mts} +1 -1
  147. package/dist/{types-CFWjXmus.d.mts.map → types-M78DQ1lx.d.mts.map} +1 -1
  148. package/dist/{validate-CqsNItbt.mjs → validate-Baqf0slj.mjs} +3 -3
  149. package/dist/{validate-CqsNItbt.mjs.map → validate-Baqf0slj.mjs.map} +1 -1
  150. package/dist/{validate-kM8Pjuf7.d.mts → validate-BfQh_C_y.d.mts} +4 -4
  151. package/dist/{validate-kM8Pjuf7.d.mts.map → validate-BfQh_C_y.d.mts.map} +1 -1
  152. package/dist/validation-BfEI7tNe.mjs +144 -0
  153. package/dist/validation-BfEI7tNe.mjs.map +1 -0
  154. package/dist/version-DoxrVdYf.mjs +7 -0
  155. package/dist/{version-BnTKdfam.mjs.map → version-DoxrVdYf.mjs.map} +1 -1
  156. package/dist/zod-generator-CC0xNe_K.mjs +132 -0
  157. package/dist/zod-generator-CC0xNe_K.mjs.map +1 -0
  158. package/locals.d.ts +1 -6
  159. package/package.json +21 -7
  160. package/src/api/auth-storage.ts +37 -0
  161. package/src/api/error.ts +6 -0
  162. package/src/api/errors.ts +8 -0
  163. package/src/api/handlers/comments.ts +19 -4
  164. package/src/api/handlers/content.ts +151 -4
  165. package/src/api/handlers/device-flow.ts +5 -0
  166. package/src/api/handlers/index.ts +2 -0
  167. package/src/api/handlers/marketplace.ts +11 -4
  168. package/src/api/handlers/media.ts +8 -1
  169. package/src/api/handlers/menus.ts +160 -21
  170. package/src/api/handlers/oauth-authorization.ts +72 -33
  171. package/src/api/handlers/redirects.ts +16 -3
  172. package/src/api/handlers/revision.ts +23 -14
  173. package/src/api/handlers/sections.ts +8 -1
  174. package/src/api/handlers/taxonomies.ts +131 -22
  175. package/src/api/handlers/validation.ts +212 -0
  176. package/src/api/openapi/document.ts +4 -1
  177. package/src/api/public-url.ts +54 -5
  178. package/src/api/route-utils.ts +14 -0
  179. package/src/api/schemas/comments.ts +2 -2
  180. package/src/api/schemas/common.ts +1 -1
  181. package/src/api/schemas/content.ts +17 -0
  182. package/src/api/schemas/sections.ts +3 -3
  183. package/src/api/schemas/setup.ts +8 -0
  184. package/src/api/schemas/users.ts +1 -1
  185. package/src/api/schemas/widgets.ts +12 -10
  186. package/src/api/setup-complete.ts +40 -0
  187. package/src/api/types.ts +5 -1
  188. package/src/astro/integration/index.ts +30 -2
  189. package/src/astro/integration/routes.ts +28 -0
  190. package/src/astro/integration/runtime.ts +49 -1
  191. package/src/astro/integration/virtual-modules.ts +73 -2
  192. package/src/astro/integration/vite-config.ts +49 -13
  193. package/src/astro/middleware/auth.ts +34 -6
  194. package/src/astro/middleware/redirect.ts +29 -16
  195. package/src/astro/middleware/request-context.ts +15 -5
  196. package/src/astro/middleware.ts +41 -10
  197. package/src/astro/routes/PluginRegistry.tsx +10 -1
  198. package/src/astro/routes/api/auth/invite/complete.ts +6 -1
  199. package/src/astro/routes/api/auth/mode.ts +57 -0
  200. package/src/astro/routes/api/auth/oauth/[provider]/callback.ts +23 -3
  201. package/src/astro/routes/api/auth/oauth/[provider].ts +10 -4
  202. package/src/astro/routes/api/auth/passkey/register/verify.ts +6 -1
  203. package/src/astro/routes/api/auth/passkey/verify.ts +6 -1
  204. package/src/astro/routes/api/auth/signup/complete.ts +6 -1
  205. package/src/astro/routes/api/comments/[collection]/[contentId]/index.ts +2 -2
  206. package/src/astro/routes/api/content/[collection]/[id]/discard-draft.ts +4 -2
  207. package/src/astro/routes/api/content/[collection]/[id]/preview-url.ts +34 -12
  208. package/src/astro/routes/api/content/[collection]/[id]/publish.ts +32 -2
  209. package/src/astro/routes/api/content/[collection]/[id]/restore.ts +4 -2
  210. package/src/astro/routes/api/content/[collection]/[id]/revisions.ts +3 -2
  211. package/src/astro/routes/api/content/[collection]/[id]/terms/[taxonomy].ts +8 -4
  212. package/src/astro/routes/api/content/[collection]/[id]/translations.ts +1 -1
  213. package/src/astro/routes/api/content/[collection]/[id].ts +12 -0
  214. package/src/astro/routes/api/content/[collection]/index.ts +1 -9
  215. package/src/astro/routes/api/import/wordpress/execute.ts +3 -1
  216. package/src/astro/routes/api/import/wordpress/media.ts +2 -7
  217. package/src/astro/routes/api/import/wordpress/prepare.ts +9 -0
  218. package/src/astro/routes/api/import/wordpress-plugin/execute.ts +3 -1
  219. package/src/astro/routes/api/manifest.ts +62 -45
  220. package/src/astro/routes/api/media/[id]/confirm.ts +10 -1
  221. package/src/astro/routes/api/media/providers/[providerId]/index.ts +12 -3
  222. package/src/astro/routes/api/openapi.json.ts +27 -10
  223. package/src/astro/routes/api/redirects/404s/index.ts +10 -4
  224. package/src/astro/routes/api/redirects/404s/summary.ts +4 -2
  225. package/src/astro/routes/api/redirects/[id].ts +10 -4
  226. package/src/astro/routes/api/redirects/index.ts +7 -3
  227. package/src/astro/routes/api/revisions/[revisionId]/index.ts +1 -1
  228. package/src/astro/routes/api/schema/collections/[slug]/fields/[fieldSlug].ts +0 -2
  229. package/src/astro/routes/api/schema/collections/[slug]/fields/index.ts +0 -1
  230. package/src/astro/routes/api/schema/collections/[slug]/fields/reorder.ts +0 -1
  231. package/src/astro/routes/api/schema/collections/[slug]/index.ts +2 -2
  232. package/src/astro/routes/api/schema/collections/index.ts +1 -1
  233. package/src/astro/routes/api/search/index.ts +10 -2
  234. package/src/astro/routes/api/sections/[slug].ts +10 -4
  235. package/src/astro/routes/api/sections/index.ts +7 -3
  236. package/src/astro/routes/api/settings/email.ts +4 -9
  237. package/src/astro/routes/api/setup/admin-verify.ts +6 -1
  238. package/src/astro/routes/api/setup/admin.ts +8 -2
  239. package/src/astro/routes/api/setup/index.ts +2 -2
  240. package/src/astro/routes/api/setup/status.ts +3 -1
  241. package/src/astro/routes/api/snapshot.ts +44 -18
  242. package/src/astro/routes/api/taxonomies/index.ts +0 -1
  243. package/src/astro/routes/api/themes/preview.ts +11 -5
  244. package/src/astro/routes/api/widget-areas/[name]/widgets/[id].ts +4 -1
  245. package/src/astro/routes/api/widget-areas/[name]/widgets.ts +4 -1
  246. package/src/astro/routes/api/widget-areas/[name].ts +4 -1
  247. package/src/astro/routes/api/widget-areas/index.ts +4 -1
  248. package/src/astro/types.ts +32 -3
  249. package/src/auth/allowed-origins.ts +168 -0
  250. package/src/auth/mode.ts +15 -3
  251. package/src/auth/passkey-config.ts +35 -13
  252. package/src/auth/providers/github-admin.tsx +29 -0
  253. package/src/auth/providers/github.ts +31 -0
  254. package/src/auth/providers/google-admin.tsx +44 -0
  255. package/src/auth/providers/google.ts +31 -0
  256. package/src/auth/types.ts +114 -4
  257. package/src/bylines/index.ts +37 -88
  258. package/src/cli/commands/auth.ts +28 -6
  259. package/src/cli/commands/bundle-utils.ts +11 -2
  260. package/src/cli/commands/bundle.ts +31 -9
  261. package/src/cli/commands/content.ts +13 -0
  262. package/src/cli/commands/login.ts +8 -1
  263. package/src/cli/commands/publish.ts +24 -0
  264. package/src/cli/commands/secrets.ts +183 -0
  265. package/src/cli/credentials.ts +1 -1
  266. package/src/cli/index.ts +5 -1
  267. package/src/client/index.ts +4 -4
  268. package/src/client/transport.ts +17 -7
  269. package/src/components/Break.astro +2 -2
  270. package/src/components/EmDashHead.astro +18 -13
  271. package/src/components/EmDashImage.astro +7 -6
  272. package/src/components/Embed.astro +1 -1
  273. package/src/components/Gallery.astro +6 -4
  274. package/src/components/Image.astro +9 -4
  275. package/src/components/InlinePortableTextEditor.tsx +106 -19
  276. package/src/components/LiveSearch.astro +5 -14
  277. package/src/config/secrets.ts +528 -0
  278. package/src/database/dialect-helpers.ts +50 -0
  279. package/src/database/migrations/034_published_at_index.ts +1 -1
  280. package/src/database/migrations/035_bounded_404_log.ts +56 -39
  281. package/src/database/migrations/runner.ts +156 -23
  282. package/src/database/repositories/audit.ts +6 -8
  283. package/src/database/repositories/byline.ts +6 -8
  284. package/src/database/repositories/comment.ts +12 -16
  285. package/src/database/repositories/content.ts +76 -52
  286. package/src/database/repositories/index.ts +1 -1
  287. package/src/database/repositories/media.ts +10 -13
  288. package/src/database/repositories/plugin-storage.ts +4 -6
  289. package/src/database/repositories/redirect.ts +26 -19
  290. package/src/database/repositories/taxonomy.ts +40 -3
  291. package/src/database/repositories/types.ts +57 -8
  292. package/src/database/repositories/user.ts +6 -8
  293. package/src/db/libsql.ts +1 -3
  294. package/src/db/sqlite.ts +2 -5
  295. package/src/emdash-runtime.ts +388 -247
  296. package/src/index.ts +14 -1
  297. package/src/loader.ts +30 -6
  298. package/src/mcp/server.ts +781 -141
  299. package/src/media/normalize.ts +1 -1
  300. package/src/media/url.ts +78 -0
  301. package/src/page/site-identity.ts +58 -0
  302. package/src/plugins/adapt-sandbox-entry.ts +22 -10
  303. package/src/plugins/context.ts +13 -10
  304. package/src/plugins/define-plugin.ts +40 -12
  305. package/src/plugins/email-console.ts +10 -3
  306. package/src/plugins/hooks.ts +34 -19
  307. package/src/plugins/index.ts +9 -0
  308. package/src/plugins/manifest-schema.ts +49 -2
  309. package/src/plugins/types.ts +174 -13
  310. package/src/preview/urls.ts +23 -3
  311. package/src/query.ts +149 -6
  312. package/src/redirects/cache.ts +38 -18
  313. package/src/request-cache.ts +3 -0
  314. package/src/schema/registry.ts +97 -5
  315. package/src/schema/zod-generator.ts +27 -5
  316. package/src/search/fts-manager.ts +0 -2
  317. package/src/search/query.ts +111 -26
  318. package/src/search/types.ts +8 -1
  319. package/src/sections/index.ts +7 -9
  320. package/src/seed/apply.ts +2 -0
  321. package/src/settings/index.ts +80 -6
  322. package/src/settings/types.ts +23 -1
  323. package/src/storage/s3.ts +12 -6
  324. package/src/taxonomies/index.ts +11 -1
  325. package/src/virtual-modules.d.ts +21 -1
  326. package/src/widgets/index.ts +1 -1
  327. package/dist/apply-5uslYdUu.mjs.map +0 -1
  328. package/dist/byline-C4OVd8b3.mjs.map +0 -1
  329. package/dist/bylines-hPTW79hw.mjs +0 -157
  330. package/dist/bylines-hPTW79hw.mjs.map +0 -1
  331. package/dist/cache-BkKBuIvS.mjs +0 -56
  332. package/dist/cache-BkKBuIvS.mjs.map +0 -1
  333. package/dist/chunk-ClPoSABd.mjs +0 -21
  334. package/dist/content-D7J5y73J.mjs.map +0 -1
  335. package/dist/dialect-helpers-DhTzaUxP.mjs.map +0 -1
  336. package/dist/error-CiYn9yDu.mjs.map +0 -1
  337. package/dist/index-De6_Xv3v.d.mts.map +0 -1
  338. package/dist/loader-DeiBJEMe.mjs.map +0 -1
  339. package/dist/manifest-schema-V30qsMft.mjs.map +0 -1
  340. package/dist/media-DqHVh136.mjs.map +0 -1
  341. package/dist/mode-CpNnGkPz.mjs.map +0 -1
  342. package/dist/placeholder-C-fk5hYI.mjs.map +0 -1
  343. package/dist/query-g4Ug-9j9.mjs.map +0 -1
  344. package/dist/redirect-CN0Rt9Ob.mjs.map +0 -1
  345. package/dist/registry-Ci3WxVAr.mjs.map +0 -1
  346. package/dist/request-cache-DiR961CV.mjs.map +0 -1
  347. package/dist/runner-BR2xKwhn.d.mts +0 -34
  348. package/dist/runner-BR2xKwhn.d.mts.map +0 -1
  349. package/dist/search-B0effn3j.mjs.map +0 -1
  350. package/dist/taxonomies-K2z0Uhnj.mjs.map +0 -1
  351. package/dist/types-CMMN0pNg.mjs +0 -31
  352. package/dist/types-CMMN0pNg.mjs.map +0 -1
  353. package/dist/types-DgrIP0tF.d.mts.map +0 -1
  354. package/dist/version-BnTKdfam.mjs +0 -7
@@ -11,7 +11,7 @@
11
11
 
12
12
  import type { MediaProvider, MediaProviderItem, MediaValue } from "./types.js";
13
13
 
14
- const INTERNAL_MEDIA_PREFIX = "/_emdash/api/media/file/";
14
+ export const INTERNAL_MEDIA_PREFIX = "/_emdash/api/media/file/";
15
15
  const URL_PATTERN = /^https?:\/\//;
16
16
 
17
17
  /**
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Public media URL resolution.
3
+ *
4
+ * Used at render time by the Image components to decide whether a storage
5
+ * key should be served from the configured `publicUrl` (R2 custom domain,
6
+ * S3 CDN) or through the internal `/_emdash/api/media/file/{key}` route.
7
+ */
8
+ import type { Storage } from "../storage/types.js";
9
+ import { INTERNAL_MEDIA_PREFIX } from "./normalize.js";
10
+
11
+ // Keys accepted by the public-URL rewrite: the `{ulid}{ext}` shape produced by
12
+ // the upload pipeline, with letters, digits, dots, dashes, and underscores.
13
+ // Slashes, `?`, `#`, and `%` are rejected so attacker-controlled content in a
14
+ // portable-text `asset.url` cannot traverse or reroute on the CDN origin.
15
+ const SAFE_STORAGE_KEY = /^[A-Za-z0-9._-]+$/;
16
+
17
+ /**
18
+ * Resolve the public URL for a locally stored media key. Returns an empty
19
+ * string when no key is given. When a storage adapter is supplied, defers to
20
+ * `storage.getPublicUrl()`; otherwise returns the internal proxy route.
21
+ */
22
+ export function resolvePublicMediaUrl(
23
+ storage: Storage | null | undefined,
24
+ storageKey: string,
25
+ ): string {
26
+ if (!storageKey) return "";
27
+ if (storage) return storage.getPublicUrl(storageKey);
28
+ return `/_emdash/api/media/file/${storageKey}`;
29
+ }
30
+
31
+ /**
32
+ * Build the `getPublicMediaUrl` closure attached to `Astro.locals.emdash`.
33
+ * Shared by the anonymous fast path and the full-runtime path in middleware.
34
+ *
35
+ * @internal
36
+ */
37
+ export function createPublicMediaUrlResolver(
38
+ storage: Storage | null | undefined,
39
+ ): (key: string) => string {
40
+ return (key) => resolvePublicMediaUrl(storage, key);
41
+ }
42
+
43
+ /** Input shape for {@link buildRenderMediaUrl}. */
44
+ export interface RenderMediaRef {
45
+ /** Storage key with extension (the canonical shape from the upload pipeline). */
46
+ storageKey?: string;
47
+ /** Pre-baked URL (either an internal proxy URL or an external URL). */
48
+ url?: string;
49
+ /** Bare media id (ULID without extension); only the internal proxy can look this up. */
50
+ id?: string;
51
+ }
52
+
53
+ /**
54
+ * Build a render-time media URL. Prefers `storageKey`, then rewrites an
55
+ * internal `url` via `resolve`, then falls back to the internal proxy for a
56
+ * bare `id`. External URLs and non-matching internal-looking URLs pass
57
+ * through untouched. Returns `""` when nothing usable is present.
58
+ *
59
+ * @internal
60
+ */
61
+ export function buildRenderMediaUrl(
62
+ resolve: ((key: string) => string) | undefined,
63
+ ref: RenderMediaRef,
64
+ ): string {
65
+ const { storageKey, url, id } = ref;
66
+ if (storageKey) {
67
+ return resolve ? resolve(storageKey) : `${INTERNAL_MEDIA_PREFIX}${storageKey}`;
68
+ }
69
+ if (url) {
70
+ if (resolve && url.startsWith(INTERNAL_MEDIA_PREFIX)) {
71
+ const key = url.slice(INTERNAL_MEDIA_PREFIX.length);
72
+ if (SAFE_STORAGE_KEY.test(key)) return resolve(key);
73
+ }
74
+ return url;
75
+ }
76
+ if (id) return `${INTERNAL_MEDIA_PREFIX}${id}`;
77
+ return "";
78
+ }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Site identity head injection.
3
+ *
4
+ * Emits first-party `<head>` tags sourced from the user-configured Site
5
+ * Identity. These are rendered alongside, but separate from, the plugin
6
+ * contribution pipeline (`page/metadata.ts`) because:
7
+ *
8
+ * - Site identity is first-party, not plugin-supplied. The contribution
9
+ * pipeline's `isSafeHref` allowlist rejects same-origin paths like
10
+ * `/_emdash/api/media/file/...` (which is correct for sandboxed plugin
11
+ * contributions, but blocks our own favicon URLs).
12
+ * - The data shape is fixed and small. Routing it through a generic
13
+ * deduper buys nothing.
14
+ *
15
+ * Currently emits only `<link rel="icon">`. Other site-identity tags
16
+ * (`apple-touch-icon`, `theme-color`, `application-name`) need their own
17
+ * configurable fields in `SiteSettings` before they ship; emitting them
18
+ * automatically from the favicon would produce broken icons on iOS for
19
+ * SVG favicons or blurry home-screen icons when the favicon is a small
20
+ * PNG. Tracked separately.
21
+ *
22
+ * Templates that previously emitted their own `<link rel="icon">` are
23
+ * getting their lines dropped in the same change that introduced this
24
+ * helper.
25
+ */
26
+
27
+ import type { MediaReference } from "../settings/types.js";
28
+ import { escapeHtmlAttr } from "./metadata.js";
29
+
30
+ /**
31
+ * Subset of site settings consumed by `renderSiteIdentity`. Kept narrow
32
+ * so callers don't have to fetch fields they don't use.
33
+ */
34
+ export interface SiteIdentityInput {
35
+ favicon?: MediaReference;
36
+ }
37
+
38
+ /**
39
+ * Build the `<head>` HTML for site identity tags. Returns an empty string
40
+ * when no identity fields are configured.
41
+ */
42
+ export function renderSiteIdentity(input: SiteIdentityInput | undefined): string {
43
+ if (!input) return "";
44
+
45
+ const parts: string[] = [];
46
+
47
+ const favicon = input.favicon;
48
+ if (favicon?.url) {
49
+ let tag = `<link rel="icon" href="${escapeHtmlAttr(favicon.url)}"`;
50
+ if (favicon.contentType) {
51
+ tag += ` type="${escapeHtmlAttr(favicon.contentType)}"`;
52
+ }
53
+ tag += ">";
54
+ parts.push(tag);
55
+ }
56
+
57
+ return parts.join("\n");
58
+ }
@@ -12,6 +12,7 @@
12
12
 
13
13
  import type { PluginDescriptor } from "../astro/integration/runtime.js";
14
14
  import { PLUGIN_CAPABILITIES, HOOK_NAMES } from "./manifest-schema.js";
15
+ import { normalizeCapabilities } from "./types.js";
15
16
  import type {
16
17
  StandardPluginDefinition,
17
18
  StandardHookEntry,
@@ -147,7 +148,10 @@ export function adaptSandboxEntry(
147
148
  }
148
149
 
149
150
  // Build capabilities from descriptor.
150
- // Validate against the known set (same as defineNativePlugin).
151
+ // Validate against the known set (same as defineNativePlugin). Both
152
+ // current and deprecated names are accepted; deprecated names are
153
+ // silently normalized to current names below so the runtime only ever
154
+ // sees the canonical form.
151
155
  const rawCapabilities = descriptor.capabilities ?? [];
152
156
  for (const cap of rawCapabilities) {
153
157
  if (!VALID_CAPABILITIES_SET.has(cap)) {
@@ -157,20 +161,28 @@ export function adaptSandboxEntry(
157
161
  );
158
162
  }
159
163
  }
160
- // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- validated against VALID_CAPABILITIES_SET above; descriptor uses string[] for flexibility
161
- const capabilities = [...rawCapabilities] as PluginCapability[];
164
+
165
+ // Silent normalization: rewrite deprecated names to current names.
166
+ // Safe assertion — `normalizeCapabilities` only emits validated input
167
+ // plus current names from the rename map, all of which are in the union.
168
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- validated above; normalizeCapabilities only returns capabilities from the union
169
+ const capabilities = normalizeCapabilities(rawCapabilities) as PluginCapability[];
162
170
  const allowedHosts = descriptor.allowedHosts ?? [];
163
171
 
164
172
  // Capability implications: broader capabilities imply narrower ones
165
- // (mirrors the normalization in define-plugin.ts for native format)
166
- if (capabilities.includes("write:content") && !capabilities.includes("read:content")) {
167
- capabilities.push("read:content");
173
+ // (mirrors the normalization in define-plugin.ts for native format).
174
+ // Operates on canonical names only.
175
+ if (capabilities.includes("content:write") && !capabilities.includes("content:read")) {
176
+ capabilities.push("content:read");
168
177
  }
169
- if (capabilities.includes("write:media") && !capabilities.includes("read:media")) {
170
- capabilities.push("read:media");
178
+ if (capabilities.includes("media:write") && !capabilities.includes("media:read")) {
179
+ capabilities.push("media:read");
171
180
  }
172
- if (capabilities.includes("network:fetch:any") && !capabilities.includes("network:fetch")) {
173
- capabilities.push("network:fetch");
181
+ if (
182
+ capabilities.includes("network:request:unrestricted") &&
183
+ !capabilities.includes("network:request")
184
+ ) {
185
+ capabilities.push("network:request");
174
186
  }
175
187
 
176
188
  // Build storage config from descriptor.
@@ -647,14 +647,14 @@ export function createUnrestrictedHttpAccess(pluginId: string): HttpAccess {
647
647
  }
648
648
 
649
649
  /**
650
- * Create blocked HTTP access (for plugins without network:fetch capability)
650
+ * Create blocked HTTP access (for plugins without network:request capability)
651
651
  */
652
652
  export function createBlockedHttpAccess(pluginId: string): HttpAccess {
653
653
  return {
654
654
  async fetch(): Promise<never> {
655
655
  throw new Error(
656
- `Plugin "${pluginId}" does not have the "network:fetch" capability. ` +
657
- `Add "network:fetch" to the plugin's capabilities to enable HTTP requests.`,
656
+ `Plugin "${pluginId}" does not have the "network:request" capability. ` +
657
+ `Add "network:request" to the plugin's capabilities to enable HTTP requests.`,
658
658
  );
659
659
  },
660
660
  };
@@ -902,32 +902,35 @@ export class PluginContextFactory {
902
902
  const storage = createStorageAccess(this.db, plugin.id, plugin.storage);
903
903
 
904
904
  // Capability-gated: content
905
+ // Note: capabilities reach this point already normalized to the
906
+ // canonical names by definePlugin / adaptSandboxEntry. Deprecated
907
+ // names ("read:content", "write:content") never appear here.
905
908
  let content: ContentAccess | ContentAccessWithWrite | undefined;
906
- if (capabilities.has("write:content")) {
909
+ if (capabilities.has("content:write")) {
907
910
  content = createContentAccessWithWrite(this.db);
908
- } else if (capabilities.has("read:content")) {
911
+ } else if (capabilities.has("content:read")) {
909
912
  content = createContentAccess(this.db);
910
913
  }
911
914
 
912
915
  // Capability-gated: media
913
916
  let media: MediaAccess | MediaAccessWithWrite | undefined;
914
- if (capabilities.has("write:media") && this.getUploadUrl) {
917
+ if (capabilities.has("media:write") && this.getUploadUrl) {
915
918
  media = createMediaAccessWithWrite(this.db, this.getUploadUrl, this.storage);
916
- } else if (capabilities.has("read:media")) {
919
+ } else if (capabilities.has("media:read")) {
917
920
  media = createMediaAccess(this.db);
918
921
  }
919
922
 
920
923
  // Capability-gated: http
921
924
  let http: HttpAccess | undefined;
922
- if (capabilities.has("network:fetch:any")) {
925
+ if (capabilities.has("network:request:unrestricted")) {
923
926
  http = createUnrestrictedHttpAccess(plugin.id);
924
- } else if (capabilities.has("network:fetch")) {
927
+ } else if (capabilities.has("network:request")) {
925
928
  http = createHttpAccess(plugin.id, plugin.allowedHosts);
926
929
  }
927
930
 
928
931
  // Capability-gated: users
929
932
  let users: UserAccess | undefined;
930
- if (capabilities.has("read:users")) {
933
+ if (capabilities.has("users:read")) {
931
934
  users = createUserAccess(this.db);
932
935
  }
933
936
 
@@ -13,6 +13,7 @@
13
13
  *
14
14
  */
15
15
 
16
+ import { normalizeCapabilities } from "./types.js";
16
17
  import type {
17
18
  PluginDefinition,
18
19
  ResolvedPlugin,
@@ -20,6 +21,7 @@ import type {
20
21
  ResolvedPluginHooks,
21
22
  ResolvedHook,
22
23
  HookConfig,
24
+ PluginCapability,
23
25
  PluginStorageConfig,
24
26
  StandardPluginDefinition,
25
27
  } from "./types.js";
@@ -65,7 +67,7 @@ const SEMVER_PATTERN = /^\d+\.\d+\.\d+/;
65
67
  * export default definePlugin({
66
68
  * id: "my-plugin",
67
69
  * version: "1.0.0",
68
- * capabilities: ["read:content"],
70
+ * capabilities: ["content:read"],
69
71
  * hooks: {
70
72
  * "content:beforeSave": async (event, ctx) => {
71
73
  * ctx.log.info("Saving content", { collection: event.collection });
@@ -143,8 +145,24 @@ function defineNativePlugin<TStorage extends PluginStorageConfig>(
143
145
  throw new Error(`Invalid plugin version "${version}". Must be semver format (e.g., "1.0.0").`);
144
146
  }
145
147
 
146
- // Validate capabilities
147
- const validCapabilities = new Set([
148
+ // Validate capabilities. Both current names and deprecated aliases are
149
+ // accepted; aliases are silently rewritten to current names below so the
150
+ // runtime only ever sees the canonical form. Authors are warned at
151
+ // bundle/validate and hard-failed at publish.
152
+ const validCapabilities = new Set<string>([
153
+ // Current names
154
+ "network:request",
155
+ "network:request:unrestricted",
156
+ "content:read",
157
+ "content:write",
158
+ "media:read",
159
+ "media:write",
160
+ "users:read",
161
+ "email:send",
162
+ "hooks.email-transport:register",
163
+ "hooks.email-events:register",
164
+ "hooks.page-fragments:register",
165
+ // Deprecated aliases
148
166
  "network:fetch",
149
167
  "network:fetch:any",
150
168
  "read:content",
@@ -152,7 +170,6 @@ function defineNativePlugin<TStorage extends PluginStorageConfig>(
152
170
  "read:media",
153
171
  "write:media",
154
172
  "read:users",
155
- "email:send",
156
173
  "email:provide",
157
174
  "email:intercept",
158
175
  "page:inject",
@@ -163,16 +180,27 @@ function defineNativePlugin<TStorage extends PluginStorageConfig>(
163
180
  }
164
181
  }
165
182
 
166
- // Capability implications: broader capabilities imply narrower ones
167
- const normalizedCapabilities = [...capabilities];
168
- if (capabilities.includes("write:content") && !capabilities.includes("read:content")) {
169
- normalizedCapabilities.push("read:content");
183
+ // Silent normalization: rewrite deprecated names to current names. Done
184
+ // before the implication pass so implications work on canonical names.
185
+ // `as PluginCapability[]` is safe because `normalizeCapabilities` only
186
+ // returns strings from the validated input plus current names from the
187
+ // rename map, all of which are in the union.
188
+ const canonical = normalizeCapabilities(capabilities) as PluginCapability[];
189
+
190
+ // Capability implications: broader capabilities imply narrower ones.
191
+ // Operates on canonical names only.
192
+ const normalizedCapabilities: PluginCapability[] = [...canonical];
193
+ if (canonical.includes("content:write") && !canonical.includes("content:read")) {
194
+ normalizedCapabilities.push("content:read");
170
195
  }
171
- if (capabilities.includes("write:media") && !capabilities.includes("read:media")) {
172
- normalizedCapabilities.push("read:media");
196
+ if (canonical.includes("media:write") && !canonical.includes("media:read")) {
197
+ normalizedCapabilities.push("media:read");
173
198
  }
174
- if (capabilities.includes("network:fetch:any") && !capabilities.includes("network:fetch")) {
175
- normalizedCapabilities.push("network:fetch");
199
+ if (
200
+ canonical.includes("network:request:unrestricted") &&
201
+ !canonical.includes("network:request")
202
+ ) {
203
+ normalizedCapabilities.push("network:request");
176
204
  }
177
205
 
178
206
  // Normalize hooks
@@ -30,9 +30,16 @@ export interface StoredEmail {
30
30
  * instances (the runtime and the route handler may load separate copies
31
31
  * of this module, but globalThis is always the same object).
32
32
  */
33
- const GLOBAL_KEY = "__emdash_dev_emails__" as const;
34
- const storedEmails: StoredEmail[] = ((globalThis as Record<string, unknown>)[GLOBAL_KEY] ??=
35
- []) as StoredEmail[];
33
+ const GLOBAL_KEY = Symbol.for("emdash:dev-emails");
34
+ const g = globalThis as Record<symbol, unknown>;
35
+ const storedEmails: StoredEmail[] = (() => {
36
+ // eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- globalThis singleton pattern (see request-context.ts)
37
+ const existing = g[GLOBAL_KEY] as StoredEmail[] | undefined;
38
+ if (existing) return existing;
39
+ const fresh: StoredEmail[] = [];
40
+ g[GLOBAL_KEY] = fresh;
41
+ return fresh;
42
+ })();
36
43
 
37
44
  /**
38
45
  * Get all stored dev emails (most recent first).
@@ -248,28 +248,32 @@ export class HookPipeline {
248
248
  * capability will have that hook silently skipped at registration time.
249
249
  */
250
250
  private static readonly HOOK_REQUIRED_CAPABILITY: ReadonlyMap<string, string> = new Map([
251
- // Email
252
- ["email:beforeSend", "email:intercept"],
253
- ["email:afterSend", "email:intercept"],
254
- ["email:deliver", "email:provide"],
255
- // Content — beforeSave can mutate content, so requires write:content.
256
- // afterSave is read-only notification, so read:content suffices.
257
- ["content:beforeSave", "write:content"],
258
- ["content:afterSave", "read:content"],
259
- ["content:beforeDelete", "read:content"],
260
- ["content:afterDelete", "read:content"],
261
- ["content:afterPublish", "read:content"],
262
- ["content:afterUnpublish", "read:content"],
251
+ // Email — registering email:beforeSend/afterSend/deliver requires the
252
+ // matching `hooks.email-*:register` capability. These are distinct
253
+ // from `email:send` (which gates ctx.email) so that "this plugin
254
+ // reads/writes email events" is visible separately from "this
255
+ // plugin can send email".
256
+ ["email:beforeSend", "hooks.email-events:register"],
257
+ ["email:afterSend", "hooks.email-events:register"],
258
+ ["email:deliver", "hooks.email-transport:register"],
259
+ // Content — beforeSave can mutate content, so requires content:write.
260
+ // afterSave is read-only notification, so content:read suffices.
261
+ ["content:beforeSave", "content:write"],
262
+ ["content:afterSave", "content:read"],
263
+ ["content:beforeDelete", "content:read"],
264
+ ["content:afterDelete", "content:read"],
265
+ ["content:afterPublish", "content:read"],
266
+ ["content:afterUnpublish", "content:read"],
263
267
  // Media
264
- ["media:beforeUpload", "write:media"],
265
- ["media:afterUpload", "read:media"],
268
+ ["media:beforeUpload", "media:write"],
269
+ ["media:afterUpload", "media:read"],
266
270
  // Comments — hooks expose author email, IP hash, user agent
267
- ["comment:beforeCreate", "read:users"],
268
- ["comment:moderate", "read:users"],
269
- ["comment:afterCreate", "read:users"],
270
- ["comment:afterModerate", "read:users"],
271
+ ["comment:beforeCreate", "users:read"],
272
+ ["comment:moderate", "users:read"],
273
+ ["comment:afterCreate", "users:read"],
274
+ ["comment:afterModerate", "users:read"],
271
275
  // Page fragments — can inject arbitrary scripts into every public page
272
- ["page:fragments", "page:inject"],
276
+ ["page:fragments", "hooks.page-fragments:register"],
273
277
  ]);
274
278
 
275
279
  /**
@@ -1218,6 +1222,17 @@ export class HookPipeline {
1218
1222
  return hooks.filter((h) => h.exclusive).map((h) => ({ pluginId: h.pluginId }));
1219
1223
  }
1220
1224
 
1225
+ /**
1226
+ * Get all plugins that registered a non-exclusive handler for a given
1227
+ * hook (e.g. `email:beforeSend`, `email:afterSend`), preserving priority
1228
+ * order. Partitions with `getExclusiveHookProviders()`, which returns
1229
+ * plugins whose registration is marked `exclusive: true`.
1230
+ */
1231
+ getHookProviders(hookName: string): Array<{ pluginId: string }> {
1232
+ const hooks = this.hooks.get(hookName as HookNameV2) ?? [];
1233
+ return hooks.filter((h) => !h.exclusive).map((h) => ({ pluginId: h.pluginId }));
1234
+ }
1235
+
1221
1236
  /**
1222
1237
  * Invoke an exclusive hook — dispatch only to the selected provider.
1223
1238
  * Returns null if no provider is selected or if the selected hook
@@ -192,3 +192,12 @@ export type {
192
192
  StandardRouteEntry,
193
193
  } from "./types.js";
194
194
  export { isStandardPluginDefinition } from "./types.js";
195
+
196
+ // Capability normalization (legacy → canonical alias layer)
197
+ export {
198
+ CAPABILITY_RENAMES,
199
+ isDeprecatedCapability,
200
+ normalizeCapability,
201
+ normalizeCapabilities,
202
+ } from "./types.js";
203
+ export type { CurrentPluginCapability, DeprecatedPluginCapability } from "./types.js";
@@ -12,7 +12,31 @@ import { z } from "zod";
12
12
 
13
13
  // ── Enum values (must stay in sync with types.ts) ───────────────
14
14
 
15
- export const PLUGIN_CAPABILITIES = [
15
+ /**
16
+ * Current capability names — the ones authors should use going forward.
17
+ * See `PluginCapability` in `types.ts` for documentation of each.
18
+ */
19
+ export const CURRENT_PLUGIN_CAPABILITIES = [
20
+ "network:request",
21
+ "network:request:unrestricted",
22
+ "content:read",
23
+ "content:write",
24
+ "media:read",
25
+ "media:write",
26
+ "users:read",
27
+ "email:send",
28
+ "hooks.email-transport:register",
29
+ "hooks.email-events:register",
30
+ "hooks.page-fragments:register",
31
+ ] as const;
32
+
33
+ /**
34
+ * Legacy capability names accepted during the deprecation window.
35
+ * Normalized to current names via `normalizeCapability()` in types.ts
36
+ * before reaching the runtime. Plugin authors are warned at bundle/validate
37
+ * and hard-failed at publish.
38
+ */
39
+ export const DEPRECATED_PLUGIN_CAPABILITIES = [
16
40
  "network:fetch",
17
41
  "network:fetch:any",
18
42
  "read:content",
@@ -20,12 +44,23 @@ export const PLUGIN_CAPABILITIES = [
20
44
  "read:media",
21
45
  "write:media",
22
46
  "read:users",
23
- "email:send",
24
47
  "email:provide",
25
48
  "email:intercept",
26
49
  "page:inject",
27
50
  ] as const;
28
51
 
52
+ /**
53
+ * Full set of accepted capability strings — current + deprecated.
54
+ *
55
+ * The manifest schema accepts both during the transition. The runtime only
56
+ * ever sees current names because `normalizeCapability()` rewrites legacy
57
+ * names at every external boundary (definePlugin, adaptSandboxEntry).
58
+ */
59
+ export const PLUGIN_CAPABILITIES = [
60
+ ...CURRENT_PLUGIN_CAPABILITIES,
61
+ ...DEPRECATED_PLUGIN_CAPABILITIES,
62
+ ] as const;
63
+
29
64
  /** Must stay in sync with FieldType in schema/types.ts */
30
65
  const FIELD_TYPES = [
31
66
  "string",
@@ -131,6 +166,18 @@ const settingFieldSchema = z.discriminatedUnion("type", [
131
166
  default: z.string().optional(),
132
167
  }),
133
168
  z.object({ ...baseSettingFields, type: z.literal("secret") }),
169
+ z.object({
170
+ ...baseSettingFields,
171
+ type: z.literal("url"),
172
+ default: z.string().optional(),
173
+ placeholder: z.string().optional(),
174
+ }),
175
+ z.object({
176
+ ...baseSettingFields,
177
+ type: z.literal("email"),
178
+ default: z.string().optional(),
179
+ placeholder: z.string().optional(),
180
+ }),
134
181
  ]);
135
182
 
136
183
  const adminPageSchema = z.object({