emdash 0.8.0 → 0.10.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 (317) hide show
  1. package/dist/{adapters-BKSf3T9R.d.mts → adapters-BktHA7EO.d.mts} +1 -1
  2. package/dist/{adapters-BKSf3T9R.d.mts.map → adapters-BktHA7EO.d.mts.map} +1 -1
  3. package/dist/{apply-x0eMK1lX.mjs → apply-UsrFuO7l.mjs} +207 -355
  4. package/dist/apply-UsrFuO7l.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 +118 -4
  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 +14 -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 +15 -10
  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 +8 -5
  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 +70 -121
  22. package/dist/astro/middleware.mjs.map +1 -1
  23. package/dist/astro/types.d.mts +25 -10
  24. package/dist/astro/types.d.mts.map +1 -1
  25. package/dist/{byline-Chbr2GoP.mjs → byline-C3vnhIpU.mjs} +4 -4
  26. package/dist/{byline-Chbr2GoP.mjs.map → byline-C3vnhIpU.mjs.map} +1 -1
  27. package/dist/bylines-esI7ioa9.mjs +113 -0
  28. package/dist/bylines-esI7ioa9.mjs.map +1 -0
  29. package/dist/cache-fTzxgMFJ.mjs +65 -0
  30. package/dist/cache-fTzxgMFJ.mjs.map +1 -0
  31. package/dist/{chunks-HGz06Soa.mjs → chunks-Da2-b-oA.mjs} +8 -2
  32. package/dist/{chunks-HGz06Soa.mjs.map → chunks-Da2-b-oA.mjs.map} +1 -1
  33. package/dist/cli/index.mjs +456 -90
  34. package/dist/cli/index.mjs.map +1 -1
  35. package/dist/client/cf-access.d.mts +1 -1
  36. package/dist/client/index.d.mts +1 -1
  37. package/dist/client/index.mjs +3 -3
  38. package/dist/client/index.mjs.map +1 -1
  39. package/dist/{config-BXwuX8Bx.mjs → config-CVssduLe.mjs} +1 -1
  40. package/dist/{config-BXwuX8Bx.mjs.map → config-CVssduLe.mjs.map} +1 -1
  41. package/dist/{content-BcQPYxdV.mjs → content-C7G4QXkK.mjs} +42 -14
  42. package/dist/content-C7G4QXkK.mjs.map +1 -0
  43. package/dist/db/index.d.mts +3 -3
  44. package/dist/db/index.mjs +2 -2
  45. package/dist/db/libsql.d.mts +1 -1
  46. package/dist/db/libsql.d.mts.map +1 -1
  47. package/dist/db/libsql.mjs +7 -2
  48. package/dist/db/libsql.mjs.map +1 -1
  49. package/dist/db/postgres.d.mts +1 -1
  50. package/dist/db/sqlite.d.mts +1 -1
  51. package/dist/db/sqlite.d.mts.map +1 -1
  52. package/dist/db/sqlite.mjs +8 -3
  53. package/dist/db/sqlite.mjs.map +1 -1
  54. package/dist/{db-errors-l1Qh2RPR.mjs → db-errors-B7P2pSCn.mjs} +1 -1
  55. package/dist/{db-errors-l1Qh2RPR.mjs.map → db-errors-B7P2pSCn.mjs.map} +1 -1
  56. package/dist/{default-DCVqE5ib.mjs → default-pHuz9WF6.mjs} +1 -1
  57. package/dist/{default-DCVqE5ib.mjs.map → default-pHuz9WF6.mjs.map} +1 -1
  58. package/dist/{dialect-helpers-DhTzaUxP.mjs → dialect-helpers-BKCvISIQ.mjs} +19 -2
  59. package/dist/dialect-helpers-BKCvISIQ.mjs.map +1 -0
  60. package/dist/{error-zG5T1UGA.mjs → error-DqnRMM5z.mjs} +1 -1
  61. package/dist/{error-zG5T1UGA.mjs.map → error-DqnRMM5z.mjs.map} +1 -1
  62. package/dist/{index-DIb-CzNx.d.mts → index-DjPMOfO0.d.mts} +162 -87
  63. package/dist/index-DjPMOfO0.d.mts.map +1 -0
  64. package/dist/index.d.mts +11 -11
  65. package/dist/index.mjs +27 -24
  66. package/dist/{load-CyEoextb.mjs → load-sXRuM7Us.mjs} +2 -2
  67. package/dist/{load-CyEoextb.mjs.map → load-sXRuM7Us.mjs.map} +1 -1
  68. package/dist/{loader-CndGj8kM.mjs → loader-Bx2_9-5e.mjs} +53 -8
  69. package/dist/loader-Bx2_9-5e.mjs.map +1 -0
  70. package/dist/{manifest-schema-DH9xhc6t.mjs → manifest-schema-CXAbd1vH.mjs} +33 -3
  71. package/dist/manifest-schema-CXAbd1vH.mjs.map +1 -0
  72. package/dist/media/index.d.mts +1 -1
  73. package/dist/media/index.mjs +1 -1
  74. package/dist/media/local-runtime.d.mts +7 -7
  75. package/dist/{mode-BnAOqItE.mjs → mode-YhqNVef_.mjs} +1 -1
  76. package/dist/{mode-BnAOqItE.mjs.map → mode-YhqNVef_.mjs.map} +1 -1
  77. package/dist/options-nPxWnrya.mjs +117 -0
  78. package/dist/options-nPxWnrya.mjs.map +1 -0
  79. package/dist/page/index.d.mts +2 -2
  80. package/dist/{patterns-CrCYkMBb.mjs → patterns-DsUZ4uxI.mjs} +1 -1
  81. package/dist/{patterns-CrCYkMBb.mjs.map → patterns-DsUZ4uxI.mjs.map} +1 -1
  82. package/dist/{placeholder-D29tWZ7o.d.mts → placeholder-CDPtkelt.d.mts} +1 -1
  83. package/dist/{placeholder-D29tWZ7o.d.mts.map → placeholder-CDPtkelt.d.mts.map} +1 -1
  84. package/dist/{placeholder-C-fk5hYI.mjs → placeholder-Ci0RLeCk.mjs} +1 -1
  85. package/dist/{placeholder-C-fk5hYI.mjs.map → placeholder-Ci0RLeCk.mjs.map} +1 -1
  86. package/dist/plugins/adapt-sandbox-entry.d.mts +5 -5
  87. package/dist/plugins/adapt-sandbox-entry.d.mts.map +1 -1
  88. package/dist/plugins/adapt-sandbox-entry.mjs +6 -5
  89. package/dist/plugins/adapt-sandbox-entry.mjs.map +1 -1
  90. package/dist/public-url-B1AxbbbQ.mjs +51 -0
  91. package/dist/public-url-B1AxbbbQ.mjs.map +1 -0
  92. package/dist/{query-fqEdLFms.mjs → query-Bo-msrmu.mjs} +114 -16
  93. package/dist/query-Bo-msrmu.mjs.map +1 -0
  94. package/dist/{redirect-D_pshWdf.mjs → redirect-C5H7VGIX.mjs} +11 -6
  95. package/dist/redirect-C5H7VGIX.mjs.map +1 -0
  96. package/dist/{registry-C3Mr0ODu.mjs → registry-Beb7wxFc.mjs} +39 -5
  97. package/dist/registry-Beb7wxFc.mjs.map +1 -0
  98. package/dist/{request-cache-Ci7f5pBb.mjs → request-cache-C-tIpYIw.mjs} +1 -1
  99. package/dist/{request-cache-Ci7f5pBb.mjs.map → request-cache-C-tIpYIw.mjs.map} +1 -1
  100. package/dist/runner-Clwe4Mme.d.mts +44 -0
  101. package/dist/runner-Clwe4Mme.d.mts.map +1 -0
  102. package/dist/{runner-tQ7BJ4T7.mjs → runner-DMnlIkh4.mjs} +616 -191
  103. package/dist/runner-DMnlIkh4.mjs.map +1 -0
  104. package/dist/runtime.d.mts +6 -6
  105. package/dist/runtime.mjs +2 -2
  106. package/dist/{search-BoZYFuUk.mjs → search-DkN-BqsS.mjs} +270 -152
  107. package/dist/search-DkN-BqsS.mjs.map +1 -0
  108. package/dist/secrets-CZ8rxLX3.mjs +314 -0
  109. package/dist/secrets-CZ8rxLX3.mjs.map +1 -0
  110. package/dist/seed/index.d.mts +2 -2
  111. package/dist/seed/index.mjs +13 -11
  112. package/dist/seo/index.d.mts +1 -1
  113. package/dist/storage/local.d.mts +1 -1
  114. package/dist/storage/local.mjs +1 -1
  115. package/dist/storage/s3.d.mts +1 -1
  116. package/dist/storage/s3.mjs +1 -1
  117. package/dist/taxonomies-CTtewrSQ.mjs +407 -0
  118. package/dist/taxonomies-CTtewrSQ.mjs.map +1 -0
  119. package/dist/taxonomy-DSxx2K2L.mjs +218 -0
  120. package/dist/taxonomy-DSxx2K2L.mjs.map +1 -0
  121. package/dist/{tokens-D9vnZqYS.mjs → tokens-CyRDPVW2.mjs} +1 -1
  122. package/dist/{tokens-D9vnZqYS.mjs.map → tokens-CyRDPVW2.mjs.map} +1 -1
  123. package/dist/{transaction-Cn2rjY78.mjs → transaction-D44LBXvU.mjs} +1 -1
  124. package/dist/{transaction-Cn2rjY78.mjs.map → transaction-D44LBXvU.mjs.map} +1 -1
  125. package/dist/{transport-CUnEL3Vs.d.mts → transport-DX_5rpsq.d.mts} +1 -1
  126. package/dist/{transport-CUnEL3Vs.d.mts.map → transport-DX_5rpsq.d.mts.map} +1 -1
  127. package/dist/{transport-C9ugt2Nr.mjs → transport-xpzIjCIB.mjs} +6 -5
  128. package/dist/{transport-C9ugt2Nr.mjs.map → transport-xpzIjCIB.mjs.map} +1 -1
  129. package/dist/{types-BrA0xf5I.d.mts → types-B_CXXnzh.d.mts} +1 -1
  130. package/dist/{types-BrA0xf5I.d.mts.map → types-B_CXXnzh.d.mts.map} +1 -1
  131. package/dist/{types-DIMwPFub.d.mts → types-C-aFbqmA.d.mts} +1 -1
  132. package/dist/{types-DIMwPFub.d.mts.map → types-C-aFbqmA.d.mts.map} +1 -1
  133. package/dist/types-CoO6mpV3.mjs +68 -0
  134. package/dist/types-CoO6mpV3.mjs.map +1 -0
  135. package/dist/{types-i36XcA_X.d.mts → types-D19uBYWn.d.mts} +83 -7
  136. package/dist/types-D19uBYWn.d.mts.map +1 -0
  137. package/dist/{types-BmPPSUEx.d.mts → types-Dl1fgFjn.d.mts} +24 -2
  138. package/dist/{types-BmPPSUEx.d.mts.map → types-Dl1fgFjn.d.mts.map} +1 -1
  139. package/dist/{types-CS8FIX7L.d.mts → types-Dtx1mSMX.d.mts} +9 -1
  140. package/dist/types-Dtx1mSMX.d.mts.map +1 -0
  141. package/dist/{types-Bm1dn-q3.mjs → types-Eg829jj9.mjs} +1 -1
  142. package/dist/{types-Bm1dn-q3.mjs.map → types-Eg829jj9.mjs.map} +1 -1
  143. package/dist/{types-CgqmmMJB.mjs → types-K-EkEQCI.mjs} +1 -1
  144. package/dist/{types-CgqmmMJB.mjs.map → types-K-EkEQCI.mjs.map} +1 -1
  145. package/dist/{validate-CxVsLehf.mjs → validate-CBIbxM3L.mjs} +14 -10
  146. package/dist/validate-CBIbxM3L.mjs.map +1 -0
  147. package/dist/{validate-DHxmpFJt.d.mts → validate-DHGwADqO.d.mts} +18 -5
  148. package/dist/validate-DHGwADqO.d.mts.map +1 -0
  149. package/dist/{validation-C-ZpN2GI.mjs → validation-B1NYiEos.mjs} +6 -6
  150. package/dist/{validation-C-ZpN2GI.mjs.map → validation-B1NYiEos.mjs.map} +1 -1
  151. package/dist/version-CMD42IRC.mjs +7 -0
  152. package/dist/{version-Bbq8TCrz.mjs.map → version-CMD42IRC.mjs.map} +1 -1
  153. package/dist/{zod-generator-CpwccCIv.mjs → zod-generator-BNJDQBSZ.mjs} +11 -6
  154. package/dist/{zod-generator-CpwccCIv.mjs.map → zod-generator-BNJDQBSZ.mjs.map} +1 -1
  155. package/locals.d.ts +1 -6
  156. package/package.json +9 -8
  157. package/src/api/handlers/comments.ts +6 -4
  158. package/src/api/handlers/content.ts +40 -1
  159. package/src/api/handlers/dashboard.ts +29 -36
  160. package/src/api/handlers/device-flow.ts +5 -0
  161. package/src/api/handlers/marketplace.ts +11 -4
  162. package/src/api/handlers/menus.ts +256 -75
  163. package/src/api/handlers/oauth-authorization.ts +72 -33
  164. package/src/api/handlers/revision.ts +23 -14
  165. package/src/api/handlers/taxonomies.ts +273 -100
  166. package/src/api/public-url.ts +48 -2
  167. package/src/api/schemas/comments.ts +2 -2
  168. package/src/api/schemas/common.ts +7 -0
  169. package/src/api/schemas/content.ts +17 -0
  170. package/src/api/schemas/menus.ts +23 -0
  171. package/src/api/schemas/sections.ts +3 -3
  172. package/src/api/schemas/taxonomies.ts +39 -0
  173. package/src/api/schemas/users.ts +1 -1
  174. package/src/api/types.ts +5 -1
  175. package/src/astro/integration/index.ts +17 -0
  176. package/src/astro/integration/routes.ts +10 -0
  177. package/src/astro/integration/runtime.ts +30 -0
  178. package/src/astro/integration/virtual-modules.ts +32 -2
  179. package/src/astro/integration/vite-config.ts +6 -1
  180. package/src/astro/middleware/auth.ts +13 -6
  181. package/src/astro/middleware/redirect.ts +29 -16
  182. package/src/astro/middleware/request-context.ts +15 -5
  183. package/src/astro/middleware.ts +23 -9
  184. package/src/astro/routes/api/auth/invite/complete.ts +6 -1
  185. package/src/astro/routes/api/auth/passkey/register/verify.ts +6 -1
  186. package/src/astro/routes/api/auth/passkey/verify.ts +6 -1
  187. package/src/astro/routes/api/auth/signup/complete.ts +6 -1
  188. package/src/astro/routes/api/comments/[collection]/[contentId]/index.ts +2 -2
  189. package/src/astro/routes/api/content/[collection]/[id]/discard-draft.ts +4 -2
  190. package/src/astro/routes/api/content/[collection]/[id]/permanent.ts +1 -1
  191. package/src/astro/routes/api/content/[collection]/[id]/preview-url.ts +34 -12
  192. package/src/astro/routes/api/content/[collection]/[id]/publish.ts +32 -2
  193. package/src/astro/routes/api/content/[collection]/[id]/restore.ts +4 -2
  194. package/src/astro/routes/api/content/[collection]/[id]/revisions.ts +3 -2
  195. package/src/astro/routes/api/content/[collection]/[id]/terms/[taxonomy].ts +8 -4
  196. package/src/astro/routes/api/content/[collection]/[id].ts +12 -0
  197. package/src/astro/routes/api/import/wordpress/execute.ts +3 -1
  198. package/src/astro/routes/api/import/wordpress/prepare.ts +7 -8
  199. package/src/astro/routes/api/import/wordpress/rewrite-url-helpers.ts +196 -0
  200. package/src/astro/routes/api/import/wordpress/rewrite-urls.ts +9 -177
  201. package/src/astro/routes/api/import/wordpress-plugin/execute.ts +3 -1
  202. package/src/astro/routes/api/manifest.ts +62 -45
  203. package/src/astro/routes/api/media/[id]/confirm.ts +10 -1
  204. package/src/astro/routes/api/media/providers/[providerId]/index.ts +12 -3
  205. package/src/astro/routes/api/menus/[name]/items.ts +16 -6
  206. package/src/astro/routes/api/menus/[name]/reorder.ts +8 -3
  207. package/src/astro/routes/api/menus/[name]/translations.ts +82 -0
  208. package/src/astro/routes/api/menus/[name].ts +19 -10
  209. package/src/astro/routes/api/menus/index.ts +9 -6
  210. package/src/astro/routes/api/openapi.json.ts +27 -10
  211. package/src/astro/routes/api/redirects/404s/index.ts +10 -4
  212. package/src/astro/routes/api/redirects/404s/summary.ts +4 -2
  213. package/src/astro/routes/api/redirects/[id].ts +10 -4
  214. package/src/astro/routes/api/redirects/index.ts +7 -3
  215. package/src/astro/routes/api/revisions/[revisionId]/index.ts +1 -1
  216. package/src/astro/routes/api/schema/collections/[slug]/fields/[fieldSlug].ts +0 -2
  217. package/src/astro/routes/api/schema/collections/[slug]/fields/index.ts +0 -1
  218. package/src/astro/routes/api/schema/collections/[slug]/fields/reorder.ts +0 -1
  219. package/src/astro/routes/api/schema/collections/[slug]/index.ts +2 -2
  220. package/src/astro/routes/api/schema/collections/index.ts +1 -1
  221. package/src/astro/routes/api/search/index.ts +10 -2
  222. package/src/astro/routes/api/sections/[slug].ts +10 -4
  223. package/src/astro/routes/api/sections/index.ts +7 -3
  224. package/src/astro/routes/api/setup/admin-verify.ts +6 -1
  225. package/src/astro/routes/api/snapshot.ts +44 -18
  226. package/src/astro/routes/api/taxonomies/[name]/terms/[slug]/translations.ts +89 -0
  227. package/src/astro/routes/api/taxonomies/[name]/terms/[slug].ts +22 -22
  228. package/src/astro/routes/api/taxonomies/[name]/terms/index.ts +11 -14
  229. package/src/astro/routes/api/taxonomies/index.ts +9 -7
  230. package/src/astro/routes/api/themes/preview.ts +11 -5
  231. package/src/astro/types.ts +23 -3
  232. package/src/auth/allowed-origins.ts +168 -0
  233. package/src/auth/passkey-config.ts +35 -13
  234. package/src/bylines/index.ts +37 -88
  235. package/src/cli/commands/auth.ts +28 -6
  236. package/src/cli/commands/bundle-utils.ts +11 -2
  237. package/src/cli/commands/bundle.ts +28 -8
  238. package/src/cli/commands/content.ts +13 -0
  239. package/src/cli/commands/export-seed.ts +82 -21
  240. package/src/cli/commands/login.ts +8 -1
  241. package/src/cli/commands/plugin-init.ts +216 -90
  242. package/src/cli/commands/publish.ts +24 -0
  243. package/src/cli/commands/secrets.ts +183 -0
  244. package/src/cli/credentials.ts +1 -1
  245. package/src/cli/index.ts +5 -1
  246. package/src/client/index.ts +4 -4
  247. package/src/client/transport.ts +17 -7
  248. package/src/components/Break.astro +2 -2
  249. package/src/components/EmDashHead.astro +18 -13
  250. package/src/components/Embed.astro +1 -1
  251. package/src/components/Gallery.astro +1 -1
  252. package/src/components/Image.astro +1 -1
  253. package/src/components/InlinePortableTextEditor.tsx +104 -18
  254. package/src/config/secrets.ts +528 -0
  255. package/src/database/dialect-helpers.ts +50 -0
  256. package/src/database/migrations/034_published_at_index.ts +1 -1
  257. package/src/database/migrations/035_bounded_404_log.ts +56 -39
  258. package/src/database/migrations/036_i18n_menus_and_taxonomies.ts +477 -0
  259. package/src/database/migrations/runner.ts +158 -23
  260. package/src/database/repositories/content.ts +47 -12
  261. package/src/database/repositories/redirect.ts +14 -3
  262. package/src/database/repositories/taxonomy.ts +212 -82
  263. package/src/database/types.ts +10 -2
  264. package/src/db/libsql.ts +1 -3
  265. package/src/db/sqlite.ts +2 -5
  266. package/src/emdash-runtime.ts +84 -159
  267. package/src/i18n/resolve.ts +37 -0
  268. package/src/index.ts +9 -0
  269. package/src/loader.ts +73 -3
  270. package/src/mcp/server.ts +180 -54
  271. package/src/menus/index.ts +143 -124
  272. package/src/menus/types.ts +15 -1
  273. package/src/page/site-identity.ts +58 -0
  274. package/src/plugins/adapt-sandbox-entry.ts +22 -10
  275. package/src/plugins/context.ts +13 -10
  276. package/src/plugins/define-plugin.ts +40 -12
  277. package/src/plugins/hooks.ts +23 -19
  278. package/src/plugins/index.ts +9 -0
  279. package/src/plugins/manifest-schema.ts +37 -2
  280. package/src/plugins/types.ts +151 -11
  281. package/src/preview/urls.ts +23 -3
  282. package/src/query.ts +148 -5
  283. package/src/redirects/cache.ts +38 -18
  284. package/src/schema/registry.ts +56 -0
  285. package/src/schema/zod-generator.ts +39 -7
  286. package/src/seed/apply.ts +142 -54
  287. package/src/seed/types.ts +14 -1
  288. package/src/seed/validate.ts +27 -13
  289. package/src/settings/index.ts +80 -6
  290. package/src/settings/types.ts +23 -1
  291. package/src/taxonomies/index.ts +237 -210
  292. package/src/taxonomies/types.ts +10 -0
  293. package/dist/apply-x0eMK1lX.mjs.map +0 -1
  294. package/dist/bylines-CRNsVG88.mjs +0 -157
  295. package/dist/bylines-CRNsVG88.mjs.map +0 -1
  296. package/dist/cache-BkKBuIvS.mjs +0 -56
  297. package/dist/cache-BkKBuIvS.mjs.map +0 -1
  298. package/dist/chunk-ClPoSABd.mjs +0 -21
  299. package/dist/content-BcQPYxdV.mjs.map +0 -1
  300. package/dist/dialect-helpers-DhTzaUxP.mjs.map +0 -1
  301. package/dist/index-DIb-CzNx.d.mts.map +0 -1
  302. package/dist/loader-CndGj8kM.mjs.map +0 -1
  303. package/dist/manifest-schema-DH9xhc6t.mjs.map +0 -1
  304. package/dist/query-fqEdLFms.mjs.map +0 -1
  305. package/dist/redirect-D_pshWdf.mjs.map +0 -1
  306. package/dist/registry-C3Mr0ODu.mjs.map +0 -1
  307. package/dist/runner-OURCaApa.d.mts +0 -34
  308. package/dist/runner-OURCaApa.d.mts.map +0 -1
  309. package/dist/runner-tQ7BJ4T7.mjs.map +0 -1
  310. package/dist/search-BoZYFuUk.mjs.map +0 -1
  311. package/dist/taxonomies-B4IAshV8.mjs +0 -308
  312. package/dist/taxonomies-B4IAshV8.mjs.map +0 -1
  313. package/dist/types-CS8FIX7L.d.mts.map +0 -1
  314. package/dist/types-i36XcA_X.d.mts.map +0 -1
  315. package/dist/validate-CxVsLehf.mjs.map +0 -1
  316. package/dist/validate-DHxmpFJt.d.mts.map +0 -1
  317. package/dist/version-Bbq8TCrz.mjs +0 -7
package/src/cli/index.ts CHANGED
@@ -11,7 +11,8 @@
11
11
  * - dev: Run dev server with local D1
12
12
  * - seed: Apply a seed file to the database
13
13
  * - export-seed: Export database schema and content as a seed file
14
- * - auth: Authentication utilities (secret generation)
14
+ * - secrets: Generate and inspect EmDash secrets (encryption keys, etc.)
15
+ * - auth: [DEPRECATED] Generate auth secret (use `secrets` instead)
15
16
  * - login/logout/whoami: Session management
16
17
  * - content: Create, read, update, delete content
17
18
  * - schema: Manage collections and fields
@@ -36,6 +37,7 @@ import { menuCommand } from "./commands/menu.js";
36
37
  import { pluginCommand } from "./commands/plugin.js";
37
38
  import { schemaCommand } from "./commands/schema.js";
38
39
  import { searchCommand } from "./commands/search-cmd.js";
40
+ import { secretsCommand } from "./commands/secrets.js";
39
41
  import { seedCommand } from "./commands/seed.js";
40
42
  import { taxonomyCommand } from "./commands/taxonomy.js";
41
43
  import { typesCommand } from "./commands/types.js";
@@ -53,6 +55,8 @@ const main = defineCommand({
53
55
  doctor: doctorCommand,
54
56
  seed: seedCommand,
55
57
  "export-seed": exportSeedCommand,
58
+ secrets: secretsCommand,
59
+ // Deprecated alias kept for backwards compat; will be removed in a future minor.
56
60
  auth: authCommand,
57
61
  login: loginCommand,
58
62
  logout: logoutCommand,
@@ -723,8 +723,8 @@ export class EmDashClient {
723
723
 
724
724
  /** List taxonomies */
725
725
  async taxonomies(): Promise<Taxonomy[]> {
726
- const data = await this.request<{ items: Taxonomy[] }>("GET", "/taxonomies");
727
- return data.items;
726
+ const data = await this.request<{ taxonomies: Taxonomy[] }>("GET", "/taxonomies");
727
+ return data.taxonomies;
728
728
  }
729
729
 
730
730
  /** List terms in a taxonomy */
@@ -757,8 +757,8 @@ export class EmDashClient {
757
757
 
758
758
  /** List menus */
759
759
  async menus(): Promise<Menu[]> {
760
- const data = await this.request<{ items: Menu[] }>("GET", "/menus");
761
- return data.items;
760
+ // Handler returns a bare array, not { items: [...] }
761
+ return this.request<Menu[]>("GET", "/menus");
762
762
  }
763
763
 
764
764
  /** Get a menu with its items */
@@ -155,24 +155,34 @@ export function refreshInterceptor(options: {
155
155
 
156
156
  if (!res.ok) return null;
157
157
 
158
- const data = (await res.json()) as {
158
+ interface TokenFields {
159
159
  access_token: string;
160
160
  refresh_token?: string;
161
161
  expires_in?: number;
162
- };
163
- const expiresAt = data.expires_in
164
- ? new Date(Date.now() + data.expires_in * 1000).toISOString()
162
+ }
163
+
164
+ const json = (await res.json()) as Record<string, unknown>;
165
+
166
+ // The token endpoint wraps the response in { data: ... } via apiSuccess.
167
+ // Handle both wrapped and bare shapes for robustness.
168
+ const tokenData: TokenFields =
169
+ json.data && typeof json.data === "object" && "access_token" in json.data
170
+ ? (json.data as TokenFields)
171
+ : (json as unknown as TokenFields);
172
+
173
+ const expiresAt = tokenData.expires_in
174
+ ? new Date(Date.now() + tokenData.expires_in * 1000).toISOString()
165
175
  : new Date(Date.now() + 3600_000).toISOString();
166
176
 
167
177
  if (options.onTokenRefreshed) {
168
178
  options.onTokenRefreshed(
169
- data.access_token,
170
- data.refresh_token ?? options.refreshToken,
179
+ tokenData.access_token,
180
+ tokenData.refresh_token ?? options.refreshToken,
171
181
  expiresAt,
172
182
  );
173
183
  }
174
184
 
175
- return data.access_token;
185
+ return tokenData.access_token;
176
186
  }
177
187
 
178
188
  return async (request, next) => {
@@ -32,11 +32,11 @@ const style = node?.style || "line";
32
32
  }
33
33
  .emdash-break-line {
34
34
  border: none;
35
- border-top: 1px solid #e0e0e0;
35
+ border-top: 1px solid var(--emdash-break-color, var(--color-border, #e0e0e0));
36
36
  }
37
37
  .emdash-break-dots {
38
38
  text-align: center;
39
- color: #999;
39
+ color: var(--emdash-break-dots-color, var(--color-muted, #999));
40
40
  letter-spacing: 0.5em;
41
41
  }
42
42
  .emdash-break-space {
@@ -20,8 +20,9 @@ import {
20
20
  generateBaseSeoContributions,
21
21
  generateSiteSeoContributions,
22
22
  } from "../page/seo-contributions.js";
23
+ import { renderSiteIdentity } from "../page/site-identity.js";
23
24
  import { getPageRuntime } from "../page/index.js";
24
- import { getSiteSetting } from "../settings/index.js";
25
+ import { getSiteSettings } from "../settings/index.js";
25
26
 
26
27
  interface Props {
27
28
  page: PublicPageContext;
@@ -34,29 +35,32 @@ const runtime = getPageRuntime(Astro.locals as Record<string, unknown>);
34
35
  const baseContributions: PageMetadataContribution[] = generateBaseSeoContributions(page);
35
36
 
36
37
  let metadataHtml = "";
38
+ let siteIdentityHtml = "";
37
39
  let fragmentsHtml = "";
38
40
 
39
41
  if (runtime) {
40
- // Run independent async loads in parallel: site SEO settings (for
41
- // search engine verification meta tags) and plugin page-metadata
42
- // contributions. Plugin contributions come BEFORE site/base in the
43
- // array, so resolvePageMetadata's first-wins dedup lets plugins
44
- // override defaults.
42
+ // Run independent async loads in parallel: site settings (SEO meta
43
+ // tags + favicon) and plugin page-metadata contributions. Plugin
44
+ // contributions come BEFORE site/base in the contribution array,
45
+ // so resolvePageMetadata's first-wins dedup lets plugins override
46
+ // defaults.
45
47
  //
46
- // `getSiteSetting("seo")` is request-cached and crucially — reads
47
- // from `getSiteSettings()`'s cached batch when a parent template has
48
- // already called it. So this is either a single-key query or free,
49
- // not a second round-trip.
50
- const [seoSettings, pluginContributions, fragments] = await Promise.all([
51
- getSiteSetting("seo"),
48
+ // `getSiteSettings()` is request-cached and worker-cached, so when
49
+ // a parent template has already called it (the standard pattern in
50
+ // `Base.astro`), this is free. Otherwise it's a single batched
51
+ // query that supersedes any per-key fetch this component would
52
+ // otherwise have done.
53
+ const [siteSettings, pluginContributions, fragments] = await Promise.all([
54
+ getSiteSettings(),
52
55
  runtime.collectPageMetadata(page),
53
56
  runtime.collectPageFragments(page),
54
57
  ]);
55
58
 
56
- const siteContributions = generateSiteSeoContributions(seoSettings);
59
+ const siteContributions = generateSiteSeoContributions(siteSettings.seo);
57
60
  const allContributions = [...pluginContributions, ...siteContributions, ...baseContributions];
58
61
  const resolved = resolvePageMetadata(allContributions);
59
62
  metadataHtml = renderPageMetadata(resolved);
63
+ siteIdentityHtml = renderSiteIdentity({ favicon: siteSettings.favicon });
60
64
  fragmentsHtml = renderFragments(fragments, "head");
61
65
  } else {
62
66
  // No runtime (EmDash not initialized) — still render base SEO
@@ -66,4 +70,5 @@ if (runtime) {
66
70
  ---
67
71
 
68
72
  <Fragment set:html={metadataHtml} />
73
+ <Fragment set:html={siteIdentityHtml} />
69
74
  <Fragment set:html={fragmentsHtml} />
@@ -121,7 +121,7 @@ const isSelfHostedAudio = provider === "audio";
121
121
  }
122
122
  .emdash-embed figcaption {
123
123
  font-size: 0.875rem;
124
- color: #666;
124
+ color: var(--emdash-caption-color, var(--color-muted, #666));
125
125
  margin-top: 0.5rem;
126
126
  text-align: center;
127
127
  }
@@ -83,7 +83,7 @@ if (!images.length) {
83
83
  }
84
84
  .emdash-gallery-item figcaption {
85
85
  font-size: 0.75rem;
86
- color: #666;
86
+ color: var(--emdash-caption-color, var(--color-muted, #666));
87
87
  margin-top: 0.25rem;
88
88
  text-align: center;
89
89
  }
@@ -176,7 +176,7 @@ const imgStyle = placeholderStyle ? `${baseStyle} ${placeholderStyle}` : baseSty
176
176
  }
177
177
  .emdash-image figcaption {
178
178
  font-size: 0.875rem;
179
- color: #666;
179
+ color: var(--emdash-caption-color, var(--color-muted, #666));
180
180
  margin-top: 0.5rem;
181
181
  text-align: center;
182
182
  }
@@ -10,7 +10,7 @@
10
10
  */
11
11
 
12
12
  import { autoUpdate, flip, offset, shift, useFloating } from "@floating-ui/react";
13
- import { Extension, type JSONContent, type Range } from "@tiptap/core";
13
+ import { Extension, Node, mergeAttributes, type JSONContent, type Range } from "@tiptap/core";
14
14
  import Focus from "@tiptap/extension-focus";
15
15
  import Image from "@tiptap/extension-image";
16
16
  import Link from "@tiptap/extension-link";
@@ -202,12 +202,18 @@ function convertPMNode(node: PMNode): PTBlock | PTBlock[] | null {
202
202
  }
203
203
  case "horizontalRule":
204
204
  return { _type: "break", _key: k(), style: "lineBreak" };
205
- case "pluginBlock":
205
+ case "pluginBlock": {
206
+ // Spread the captured data back out so the block round-trips losslessly.
207
+ // `data` holds every field except _type / _key / id (which live on
208
+ // dedicated attrs).
209
+ const { blockType, id, data } = node.attrs ?? {};
206
210
  return {
207
- _type: attrStr(node.attrs, "blockType") || "embed",
211
+ ...(data && typeof data === "object" ? data : {}),
212
+ _type: typeof blockType === "string" ? blockType : "embed",
208
213
  _key: k(),
209
- id: attrStr(node.attrs, "id"),
214
+ id: typeof id === "string" ? id : "",
210
215
  };
216
+ }
211
217
  default:
212
218
  return null;
213
219
  }
@@ -412,21 +418,23 @@ function convertPTBlock(block: PTBlock): JSONContent | null {
412
418
  },
413
419
  };
414
420
  }
415
- // Unknown block types — treat as plugin blocks if they have an id
416
- const embedBlock = block as { _type: string; url?: string; id?: string };
417
- if (embedBlock.id || embedBlock.url) {
418
- return {
419
- type: "pluginBlock",
420
- attrs: {
421
- blockType: block._type,
422
- id: embedBlock.id || embedBlock.url || "",
423
- },
424
- };
425
- }
426
- // Truly unknown — render as code-marked text
421
+ // Unknown block types — treat as plugin blocks. Capture every field other
422
+ // than the well-known ones into `data` so the block round-trips losslessly,
423
+ // even if no plugin currently registers this type. Matches the admin
424
+ // editor's behaviour at PortableTextEditor.tsx:572-588.
425
+ const { _type, _key, id, url, ...rest } = block as { _type: string; _key: string } & Record<
426
+ string,
427
+ unknown
428
+ >;
429
+ // Filter out _-prefixed keys to prevent accumulation across edit cycles.
430
+ const data = Object.fromEntries(Object.entries(rest).filter(([key]) => !key.startsWith("_")));
427
431
  return {
428
- type: "paragraph",
429
- content: [{ type: "text", text: `[${block._type}]`, marks: [{ type: "code" }] }],
432
+ type: "pluginBlock",
433
+ attrs: {
434
+ blockType: typeof _type === "string" ? _type : "embed",
435
+ id: typeof id === "string" ? id : typeof url === "string" ? url : "",
436
+ data,
437
+ },
430
438
  };
431
439
  }
432
440
 
@@ -762,6 +770,61 @@ const initialSlashMenuState: SlashMenuState = {
762
770
  range: null,
763
771
  };
764
772
 
773
+ /**
774
+ * Minimal `pluginBlock` TipTap node for the inline (visual-editing) editor.
775
+ *
776
+ * Plugin-contributed Portable Text block types (e.g. `marketing.hero`) are
777
+ * editable in the admin via a Block Kit modal. The visual-editing surface
778
+ * deliberately does NOT offer that UX — it would need to fetch the manifest,
779
+ * mount the modal, and round-trip through plugin-block plumbing that lives in
780
+ * `@emdash-cms/admin`. Instead, the inline editor renders these blocks as a
781
+ * read-only placeholder so editors can see they exist and edit the surrounding
782
+ * content without losing the block's data.
783
+ *
784
+ * The full block payload is preserved on `data` and round-tripped losslessly
785
+ * through PT ↔ PM conversion (see convertPTBlock/convertPMNode). Without this
786
+ * extension, ProseMirror's schema would silently filter unknown nodes on load
787
+ * and the next save would persist the block's disappearance.
788
+ */
789
+ const PluginBlockNode = Node.create({
790
+ name: "pluginBlock",
791
+ group: "block",
792
+ atom: true,
793
+ selectable: true,
794
+ draggable: true,
795
+
796
+ addAttributes() {
797
+ // All three attributes are stored on the ProseMirror node but not
798
+ // rendered as DOM attributes — they're metadata for the round-trip,
799
+ // not styling or behaviour the placeholder DOM needs to expose.
800
+ const noDom = { rendered: false, parseHTML: () => null };
801
+ return {
802
+ blockType: { default: "", ...noDom },
803
+ id: { default: "", ...noDom },
804
+ data: { default: {}, ...noDom },
805
+ };
806
+ },
807
+
808
+ parseHTML() {
809
+ return [{ tag: 'div[data-emdash-plugin-block="true"]' }];
810
+ },
811
+
812
+ renderHTML({ HTMLAttributes, node }) {
813
+ const blockType = typeof node.attrs.blockType === "string" ? node.attrs.blockType : "";
814
+ const label = blockType || "Block";
815
+ return [
816
+ "div",
817
+ mergeAttributes(HTMLAttributes, {
818
+ "data-emdash-plugin-block": "true",
819
+ "data-block-type": blockType,
820
+ class: "emdash-plugin-block-placeholder",
821
+ contenteditable: "false",
822
+ }),
823
+ `Plugin block: ${label} (edit in admin)`,
824
+ ];
825
+ },
826
+ });
827
+
765
828
  function createSlashCommandsExtension(options: {
766
829
  filterCommands: (query: string) => SlashCommandItem[];
767
830
  onStateChange: React.Dispatch<React.SetStateAction<SlashMenuState>>;
@@ -1734,6 +1797,7 @@ export function InlinePortableTextEditor({
1734
1797
  mode: "all",
1735
1798
  }),
1736
1799
  Typography,
1800
+ PluginBlockNode,
1737
1801
  slashCommandsExtension,
1738
1802
  ],
1739
1803
  content: initialContent,
@@ -1932,7 +1996,29 @@ export function InlinePortableTextEditor({
1932
1996
  .emdash-inline-editor:focus {
1933
1997
  outline: none;
1934
1998
  }
1999
+ .emdash-plugin-block-placeholder {
2000
+ margin: 0.75rem 0;
2001
+ padding: 0.625rem 0.875rem;
2002
+ border: 1px dashed #d1d5db;
2003
+ border-radius: 0.5rem;
2004
+ background: #f9fafb;
2005
+ color: #4b5563;
2006
+ font-size: 0.875rem;
2007
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
2008
+ user-select: none;
2009
+ }
2010
+ @media (prefers-color-scheme: dark) {
2011
+ .emdash-plugin-block-placeholder {
2012
+ border-color: #374151;
2013
+ background: #111827;
2014
+ color: #9ca3af;
2015
+ }
2016
+ }
1935
2017
  `}</style>
1936
2018
  </div>
1937
2019
  );
1938
2020
  }
2021
+
2022
+ // Test-only exports for unit tests of the conversion functions.
2023
+ export { pmToPortableText as _pmToPortableText };
2024
+ export { portableTextToPM as _portableTextToPM };