dineway 0.1.47 → 0.1.49

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 (293) hide show
  1. package/README.md +57 -54
  2. package/dist/{activity-events-CNk3clTT.mjs → activity-events-CwM7yxPW.mjs} +1 -1
  3. package/dist/{allowed-origins-QirBXiDj.mjs → allowed-origins-CyGnbgBd.mjs} +1 -1
  4. package/dist/api/route-utils.d.mts +8 -22
  5. package/dist/api/route-utils.mjs +10 -10
  6. package/dist/api/schemas/index.d.mts +2 -2
  7. package/dist/api/schemas/index.mjs +4 -4
  8. package/dist/{api-ePsOhL3q.mjs → api-BMIxRIEN.mjs} +65 -18
  9. package/dist/{apply-BpRBCqUt.mjs → apply-D_RlTYtC.mjs} +54 -48
  10. package/dist/astro/index.d.mts +8 -8
  11. package/dist/astro/index.mjs +67 -25
  12. package/dist/astro/middleware/auth.d.mts +7 -7
  13. package/dist/astro/middleware/auth.mjs +1 -1
  14. package/dist/astro/middleware/redirect.mjs +5 -5
  15. package/dist/astro/middleware/request-context.mjs +4 -4
  16. package/dist/astro/middleware/seed.d.mts +1 -1
  17. package/dist/astro/middleware/seed.mjs +2 -2
  18. package/dist/astro/middleware.d.mts +2 -1
  19. package/dist/astro/middleware.mjs +366 -147
  20. package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +3 -3
  21. package/dist/astro/routes/api/admin/allowed-domains/index.mjs +3 -3
  22. package/dist/astro/routes/api/admin/briefing.mjs +16 -16
  23. package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +2 -2
  24. package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +5 -5
  25. package/dist/astro/routes/api/admin/byline-fields/index.mjs +5 -5
  26. package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +5 -5
  27. package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +11 -11
  28. package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +11 -11
  29. package/dist/astro/routes/api/admin/bylines/index.mjs +11 -11
  30. package/dist/astro/routes/api/admin/comments/_id_/status.mjs +10 -10
  31. package/dist/astro/routes/api/admin/comments/_id_.mjs +4 -4
  32. package/dist/astro/routes/api/admin/comments/bulk.mjs +7 -7
  33. package/dist/astro/routes/api/admin/comments/counts.mjs +4 -4
  34. package/dist/astro/routes/api/admin/comments/index.mjs +7 -7
  35. package/dist/astro/routes/api/admin/context/_id_/history.mjs +23 -23
  36. package/dist/astro/routes/api/admin/context/_id_/index.mjs +23 -23
  37. package/dist/astro/routes/api/admin/context/_id_/review.mjs +26 -26
  38. package/dist/astro/routes/api/admin/context/_id_/supersede.mjs +26 -26
  39. package/dist/astro/routes/api/admin/context/diff.mjs +25 -25
  40. package/dist/astro/routes/api/admin/context/index.mjs +26 -26
  41. package/dist/astro/routes/api/admin/context/stale.mjs +25 -25
  42. package/dist/astro/routes/api/admin/hitl-requests/_id_/index.mjs +24 -24
  43. package/dist/astro/routes/api/admin/hitl-requests/_id_/resolve.mjs +26 -26
  44. package/dist/astro/routes/api/admin/hitl-requests/index.mjs +26 -26
  45. package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +23 -23
  46. package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +1 -1
  47. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +43 -43
  48. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +43 -43
  49. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +37 -37
  50. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +43 -43
  51. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +43 -43
  52. package/dist/astro/routes/api/admin/plugins/index.mjs +37 -37
  53. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +37 -37
  54. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +43 -43
  55. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +37 -37
  56. package/dist/astro/routes/api/admin/plugins/updates.mjs +37 -37
  57. package/dist/astro/routes/api/admin/review-requests/_id_/index.mjs +4 -4
  58. package/dist/astro/routes/api/admin/review-requests/_id_/resolve.mjs +25 -25
  59. package/dist/astro/routes/api/admin/review-requests/index.mjs +7 -7
  60. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +37 -37
  61. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +37 -37
  62. package/dist/astro/routes/api/admin/users/_id_/disable.mjs +1 -1
  63. package/dist/astro/routes/api/admin/users/_id_/index.mjs +4 -4
  64. package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +2 -2
  65. package/dist/astro/routes/api/admin/users/index.mjs +3 -3
  66. package/dist/astro/routes/api/auth/dev-bypass.mjs +1 -1
  67. package/dist/astro/routes/api/auth/invite/complete.mjs +6 -6
  68. package/dist/astro/routes/api/auth/invite/index.mjs +5 -5
  69. package/dist/astro/routes/api/auth/invite/register-options.mjs +5 -5
  70. package/dist/astro/routes/api/auth/magic-link/send.mjs +5 -5
  71. package/dist/astro/routes/api/auth/me.mjs +7 -7
  72. package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +1 -1
  73. package/dist/astro/routes/api/auth/oauth/_provider_.mjs +1 -1
  74. package/dist/astro/routes/api/auth/passkey/_id_.mjs +3 -3
  75. package/dist/astro/routes/api/auth/passkey/options.mjs +5 -5
  76. package/dist/astro/routes/api/auth/passkey/register/options.mjs +5 -5
  77. package/dist/astro/routes/api/auth/passkey/register/verify.mjs +6 -6
  78. package/dist/astro/routes/api/auth/passkey/verify.mjs +6 -6
  79. package/dist/astro/routes/api/auth/setup-token/index.mjs +4 -4
  80. package/dist/astro/routes/api/auth/signup/complete.mjs +6 -6
  81. package/dist/astro/routes/api/auth/signup/request.mjs +5 -5
  82. package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +11 -11
  83. package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +7 -6
  84. package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +4 -4
  85. package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +4 -4
  86. package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +8 -8
  87. package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +10 -9
  88. package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +4 -4
  89. package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +13 -11
  90. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +10 -10
  91. package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +7 -6
  92. package/dist/astro/routes/api/content/_collection_/_id_.mjs +10 -9
  93. package/dist/astro/routes/api/content/_collection_/authors.d.mts +7 -0
  94. package/dist/astro/routes/api/content/_collection_/authors.mjs +16 -0
  95. package/dist/astro/routes/api/content/_collection_/index.mjs +7 -7
  96. package/dist/astro/routes/api/content/_collection_/trash.mjs +3 -3
  97. package/dist/astro/routes/api/dashboard.mjs +7 -7
  98. package/dist/astro/routes/api/health.mjs +1 -1
  99. package/dist/astro/routes/api/import/probe.d.mts +2 -2
  100. package/dist/astro/routes/api/import/probe.mjs +6 -6
  101. package/dist/astro/routes/api/import/wordpress/analyze.mjs +3 -3
  102. package/dist/astro/routes/api/import/wordpress/execute.mjs +28 -28
  103. package/dist/astro/routes/api/import/wordpress/media.mjs +6 -6
  104. package/dist/astro/routes/api/import/wordpress/prepare.mjs +29 -29
  105. package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +27 -27
  106. package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +8 -8
  107. package/dist/astro/routes/api/import/wordpress-plugin/callback.mjs +1 -1
  108. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +29 -29
  109. package/dist/astro/routes/api/manifest.mjs +1 -1
  110. package/dist/astro/routes/api/mcp.mjs +49 -49
  111. package/dist/astro/routes/api/media/_id_/confirm.mjs +6 -6
  112. package/dist/astro/routes/api/media/_id_.mjs +3 -3
  113. package/dist/astro/routes/api/media/upload-url.mjs +8 -8
  114. package/dist/astro/routes/api/media.mjs +9 -9
  115. package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +26 -26
  116. package/dist/astro/routes/api/menus/_name_/items.mjs +26 -26
  117. package/dist/astro/routes/api/menus/_name_/reorder.mjs +26 -26
  118. package/dist/astro/routes/api/menus/_name_/translations.mjs +26 -26
  119. package/dist/astro/routes/api/menus/_name_.mjs +26 -26
  120. package/dist/astro/routes/api/menus/index.mjs +26 -26
  121. package/dist/astro/routes/api/oauth/authorize.mjs +2 -2
  122. package/dist/astro/routes/api/oauth/device/authorize.mjs +1 -1
  123. package/dist/astro/routes/api/oauth/device/code.mjs +2 -2
  124. package/dist/astro/routes/api/oauth/device/token.mjs +1 -1
  125. package/dist/astro/routes/api/oauth/token/refresh.mjs +1 -1
  126. package/dist/astro/routes/api/oauth/token/revoke.mjs +1 -1
  127. package/dist/astro/routes/api/oauth/token.mjs +2 -2
  128. package/dist/astro/routes/api/openapi.json.mjs +16 -2
  129. package/dist/astro/routes/api/redirects/404s/index.mjs +8 -8
  130. package/dist/astro/routes/api/redirects/404s/summary.mjs +8 -8
  131. package/dist/astro/routes/api/redirects/_id_.mjs +27 -27
  132. package/dist/astro/routes/api/redirects/index.mjs +27 -27
  133. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +38 -38
  134. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +38 -38
  135. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +38 -38
  136. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +38 -38
  137. package/dist/astro/routes/api/schema/collections/index.mjs +38 -38
  138. package/dist/astro/routes/api/schema/index.mjs +3 -3
  139. package/dist/astro/routes/api/schema/orphans/_slug_.mjs +37 -37
  140. package/dist/astro/routes/api/schema/orphans/index.mjs +37 -37
  141. package/dist/astro/routes/api/search/enable.mjs +8 -8
  142. package/dist/astro/routes/api/search/index.mjs +8 -8
  143. package/dist/astro/routes/api/search/rebuild.mjs +8 -8
  144. package/dist/astro/routes/api/search/stats.mjs +5 -5
  145. package/dist/astro/routes/api/search/suggest.mjs +8 -8
  146. package/dist/astro/routes/api/sections/_slug_.mjs +26 -26
  147. package/dist/astro/routes/api/sections/index.mjs +26 -26
  148. package/dist/astro/routes/api/settings/email.mjs +1 -1
  149. package/dist/astro/routes/api/settings.mjs +26 -26
  150. package/dist/astro/routes/api/setup/admin-verify.mjs +7 -7
  151. package/dist/astro/routes/api/setup/admin.mjs +5 -5
  152. package/dist/astro/routes/api/setup/dev-bypass.mjs +19 -19
  153. package/dist/astro/routes/api/setup/dev-reset.mjs +1 -1
  154. package/dist/astro/routes/api/setup/index.mjs +22 -22
  155. package/dist/astro/routes/api/setup/status.mjs +1 -1
  156. package/dist/astro/routes/api/snapshot.mjs +4 -4
  157. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +28 -28
  158. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +28 -28
  159. package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +28 -28
  160. package/dist/astro/routes/api/taxonomies/index.mjs +28 -28
  161. package/dist/astro/routes/api/themes/preview.mjs +4 -4
  162. package/dist/astro/routes/api/typegen.mjs +3 -3
  163. package/dist/astro/routes/api/well-known/auth.mjs +2 -2
  164. package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs +1 -1
  165. package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs +1 -1
  166. package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +25 -25
  167. package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +26 -26
  168. package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +26 -26
  169. package/dist/astro/routes/api/widget-areas/_name_.mjs +24 -24
  170. package/dist/astro/routes/api/widget-areas/index.mjs +26 -26
  171. package/dist/astro/routes/robots.txt.mjs +47 -24
  172. package/dist/astro/routes/sitemap-_collection_.xml.mjs +8 -8
  173. package/dist/astro/routes/sitemap.xml.mjs +8 -8
  174. package/dist/astro/session-driver.d.mts +1 -1
  175. package/dist/astro/session-driver.mjs +3 -3
  176. package/dist/astro/types.d.mts +15 -8
  177. package/dist/{audit-DuRbTm8L.mjs → audit-BeNsSyfU.mjs} +1 -1
  178. package/dist/{briefing-BFEWeJtR.mjs → briefing-CkTee1ex.mjs} +7 -7
  179. package/dist/{briefing-C4fJSVYW.mjs → briefing-DJX6irto.mjs} +1 -1
  180. package/dist/{byline-CXQcMsBu.mjs → byline-BVC1lV6G.mjs} +5 -5
  181. package/dist/{byline-fields-Dc7L6Yry.mjs → byline-fields-Cj39WhXC.mjs} +1 -1
  182. package/dist/{byline-fields-D7TJ_oHF.mjs → byline-fields-cNrLJVRs.mjs} +3 -3
  183. package/dist/{byline-fields-Cuo-JI3B.d.mts → byline-fields-uJlygdzM.d.mts} +34 -10
  184. package/dist/{byline-registry-CL8BxPPp.mjs → byline-registry-4v6tXMNX.mjs} +2 -2
  185. package/dist/{bylines-BgriNlW7.mjs → bylines-DwokOFj6.mjs} +38 -4
  186. package/dist/{bylines-D2vqm1aZ.mjs → bylines-LN9XISRo.mjs} +2 -2
  187. package/dist/{cache-GRK71jOU.mjs → cache-Bac05gBd.mjs} +2 -2
  188. package/dist/{chunks-DgEw12Bc.mjs → chunks-CuUt7K50.mjs} +1 -1
  189. package/dist/cli/index.mjs +709 -589
  190. package/dist/client/external-auth-headers.d.mts +1 -1
  191. package/dist/client/index.d.mts +1 -1
  192. package/dist/{comment-ogMaF1gk.mjs → comment-Beue8-15.mjs} +1 -1
  193. package/dist/{comments-CTSOKrZq.mjs → comments-DcjFIfqX.mjs} +1 -1
  194. package/dist/{content-BfyjOiMi.mjs → content-CBxYGWfL.mjs} +104 -41
  195. package/dist/{context-ZMHhwzkG.mjs → context-CQVNZaR8.mjs} +7 -7
  196. package/dist/{context-CdsYb1m8.mjs → context-Df1xVYyr.mjs} +2 -2
  197. package/dist/{context-route-helpers-YLWx2N1j.mjs → context-route-helpers-B9wj8Rmh.mjs} +1 -1
  198. package/dist/{dashboard-D0gWuzNp.mjs → dashboard-B7ZUNuyF.mjs} +4 -4
  199. package/dist/db/index.d.mts +2 -2
  200. package/dist/db/index.mjs +1 -1
  201. package/dist/{default-BHauvIdG.mjs → default-B6iaLvP7.mjs} +4 -2
  202. package/dist/{device-flow-B3_FEoMI.mjs → device-flow-BZVGftqi.mjs} +1 -1
  203. package/dist/{fts-manager-EHY2Kes9.mjs → fts-manager-B5l_qwrA.mjs} +1 -1
  204. package/dist/{hitl-requests-B1Zqgut6.mjs → hitl-requests-7NlzVeUA.mjs} +1 -1
  205. package/dist/{hitl-route-helpers-CjpWUMuw.mjs → hitl-route-helpers-k---_H3-.mjs} +2 -2
  206. package/dist/{import-CvHY6sf5.mjs → import-4YBXbDkI.mjs} +2 -2
  207. package/dist/{index-DJVaYiUV.d.mts → index-CZiWCQDp.d.mts} +1 -1
  208. package/dist/index.d.mts +10 -10
  209. package/dist/index.mjs +59 -59
  210. package/dist/{jsonld-AcPnCEGD.d.mts → jsonld-DZ67souc.d.mts} +1 -1
  211. package/dist/{load-BdbvtoDb.mjs → load-D9OiGr2m.mjs} +1 -1
  212. package/dist/{loader-Y0QvC_QO.mjs → loader--GOYux8M.mjs} +138 -36
  213. package/dist/media/index.mjs +2 -2
  214. package/dist/media/local-runtime.d.mts +7 -7
  215. package/dist/media/local-runtime.mjs +3 -3
  216. package/dist/{media-DhBwiCYR.mjs → media-CbKyYukG.mjs} +1 -1
  217. package/dist/{media-allowlist-BsXkT9RK.mjs → media-allowlist-BYxJIcTO.mjs} +1 -1
  218. package/dist/{menus-BzGQpw9d.mjs → menus-BZbXf-ej.mjs} +2 -2
  219. package/dist/{menus-fqqzXyHd.mjs → menus-C7F0sCrC.mjs} +13 -8
  220. package/dist/{normalize-O-hi3a27.mjs → normalize-ByemhhfW.mjs} +1 -1
  221. package/dist/{oauth-authorization-DsF81vki.mjs → oauth-authorization-DF-LCsIA.mjs} +1 -1
  222. package/dist/page/index.d.mts +2 -2
  223. package/dist/plugin-utils.d.mts +7 -7
  224. package/dist/plugins/adapt-sandbox-entry.d.mts +7 -7
  225. package/dist/{plugins-BQ5Joz6v.mjs → plugins-DzfqRREq.mjs} +195 -5
  226. package/dist/{preview-D5rvDhRt.mjs → preview-C-3YTX2U.mjs} +1 -1
  227. package/dist/public-url-B4xV4rGa.d.mts +19 -0
  228. package/dist/{public-url-DLUM5OOv.mjs → public-url-B_m9IwdV.mjs} +24 -18
  229. package/dist/{query-BJuUydtD.mjs → query-CZ3TH_Uu.mjs} +3 -3
  230. package/dist/{query-CSx0EdSW.mjs → query-Ds0EnMFX.mjs} +29 -18
  231. package/dist/{redirect-BqFMj67n.mjs → redirect-CEACczxo.mjs} +2 -2
  232. package/dist/{redirects-CJwHl_YG.mjs → redirects-DYj1yPxs.mjs} +4 -4
  233. package/dist/{redirects-q_cToaHv.mjs → redirects-ocRJmQHP.mjs} +23 -3
  234. package/dist/{registry-Cq3QRBW2.mjs → registry-D7HACema.mjs} +38 -6
  235. package/dist/{review-requests-tPw8_pAO.mjs → review-requests-BW2NxY-l.mjs} +1 -1
  236. package/dist/{review-requests-GYqjl2jO.mjs → review-requests-Qum4713s.mjs} +1 -1
  237. package/dist/{runner-Cnz4dl0f.d.mts → runner-09sTqtv0.d.mts} +1 -1
  238. package/dist/{runner-DTfG5v0G.mjs → runner-DzIpHGND.mjs} +328 -193
  239. package/dist/{runtime-Cd-kjPfN.d.mts → runtime-C4-2lSFg.d.mts} +261 -128
  240. package/dist/runtime.d.mts +8 -8
  241. package/dist/runtime.mjs +3 -3
  242. package/dist/schema-Bsi-VpYv.mjs +8 -0
  243. package/dist/{search-BAiFLz81.mjs → search-Gdrqj582.mjs} +3 -3
  244. package/dist/{secrets-CPoFLJjm.mjs → secrets-CeGpBFV2.mjs} +2 -2
  245. package/dist/{sections-DsuIrFDC.mjs → sections-BOjU13Y-.mjs} +2 -2
  246. package/dist/seed/index.d.mts +2 -2
  247. package/dist/seed/index.mjs +18 -18
  248. package/dist/seo/index.d.mts +1 -1
  249. package/dist/{seo-uMFBaR8G.mjs → seo-CLj8lS7Q.mjs} +1 -1
  250. package/dist/{service-CifrxCru.mjs → service-jGlhrICs.mjs} +1 -1
  251. package/dist/{settings-DNRQuX3d.mjs → settings-CUXOxzsT.mjs} +4 -4
  252. package/dist/{settings-BYGdocdj.mjs → settings-DlBsT2VS.mjs} +2 -2
  253. package/dist/{setup-complete-4EiBS1E5.mjs → setup-complete-BRrdPYjZ.mjs} +1 -1
  254. package/dist/{site-activity-6x1JccoR.mjs → site-activity-DONFrMBJ.mjs} +1 -1
  255. package/dist/{site-context-c1ZFa_OF.mjs → site-context-C8Az_P_I.mjs} +13 -13
  256. package/dist/{site-url-C-cu8Ff2.mjs → site-url-DIMD68go.mjs} +1 -1
  257. package/dist/{taxonomies-faQVeMgj.mjs → taxonomies-CZ-_DitR.mjs} +9 -7
  258. package/dist/{taxonomies-CQFmkP5u.mjs → taxonomies-D9Sw4wWM.mjs} +3 -3
  259. package/dist/{taxonomy-BnH-6VsX.mjs → taxonomy-B169Nm6B.mjs} +2 -2
  260. package/dist/{tokens-CjSgb0AC.mjs → tokens-SLmgowfd.mjs} +1 -1
  261. package/dist/{types-Ck7-WoUD.mjs → types-CSgR9nQB.mjs} +10 -3
  262. package/dist/{types-DYKtk8f1.d.mts → types-CuJOqHfM.d.mts} +128 -0
  263. package/dist/{types-DEAQG87T.d.mts → types-CwawBUTa.d.mts} +1 -1
  264. package/dist/{types-B7_vSiPD.d.mts → types-DRIKLmJI.d.mts} +14 -2
  265. package/dist/{types-UGmU5sWx.d.mts → types-DSPGWjxO.d.mts} +1 -1
  266. package/dist/ui/server-runtime.d.mts +58 -10
  267. package/dist/ui/server-runtime.mjs +98 -16
  268. package/dist/{user-CqZwN21P.mjs → user-DTLoZs16.mjs} +15 -1
  269. package/dist/{utils-wv-zvC-Y.mjs → utils-B8hBJ9Oz.mjs} +1 -1
  270. package/dist/{validate-CK4a1sIF.mjs → validate-DWmPO6oj.mjs} +5 -2
  271. package/dist/{validate-BJuG-ISL.d.mts → validate-DzjCdy6v.d.mts} +10 -2
  272. package/dist/version-C4gfn0PJ.mjs +6 -0
  273. package/dist/{widgets-CdDvF4fV.mjs → widgets-BpJ8EpPd.mjs} +1 -1
  274. package/dist/{wordpress-slugs-B6Gw9q3Q.mjs → wordpress-slugs-DHNR9LpG.mjs} +1 -1
  275. package/dist/{zod-generator-D1ROBNuC.mjs → zod-generator-K91-g665.mjs} +3 -2
  276. package/package.json +6 -5
  277. package/src/components/DinewayImage.astro +23 -5
  278. package/src/components/Image.astro +19 -3
  279. package/dist/schema-DmHMWnSA.mjs +0 -8
  280. package/dist/version-Cb1tZ6s_.mjs +0 -6
  281. /package/dist/{base64-C1Q9yr0B.mjs → base64-F8-DUraK.mjs} +0 -0
  282. /package/dist/{context-types-DQh_XKkn.mjs → context-types-r8oFvyOq.mjs} +0 -0
  283. /package/dist/{entity-aliases-uOrKvlPg.mjs → entity-aliases-4y93Yjuc.mjs} +0 -0
  284. /package/dist/{mime-8pAB8-77.mjs → mime-CbKsKDCB.mjs} +0 -0
  285. /package/dist/{options-BF11H_FD.mjs → options-LsPjZlqD.mjs} +0 -0
  286. /package/dist/{patterns-D9iDO3j8.mjs → patterns-DKAX6oqN.mjs} +0 -0
  287. /package/dist/{placeholder-BDo81Is5.mjs → placeholder-d54Qr_7n.mjs} +0 -0
  288. /package/dist/{provider-loader-B5PMjpN7.d.mts → provider-loader-9it4vd6L.d.mts} +0 -0
  289. /package/dist/{request-cache-w5cj5itT.mjs → request-cache-ho99schz.mjs} +0 -0
  290. /package/dist/{slugify-BzGxlOFx.mjs → slugify-BqebcqBg.mjs} +0 -0
  291. /package/dist/{transaction-D0FOsb3X.mjs → transaction-CFLhEOuH.mjs} +0 -0
  292. /package/dist/{transport-DidKKxvW.d.mts → transport-BnsNxh2l.d.mts} +0 -0
  293. /package/dist/{types-DbZhHtqS.mjs → types-CJ8DkL0q.mjs} +0 -0
@@ -1,35 +1,35 @@
1
1
  #!/usr/bin/env node
2
- import { a as __exportAll, i as runMigrations, n as getMigrationStatus, t as getMigrationFingerprint } from "../runner-DTfG5v0G.mjs";
2
+ import { a as __exportAll, i as runMigrations, n as getMigrationStatus, t as getMigrationFingerprint } from "../runner-DzIpHGND.mjs";
3
3
  import { t as createDatabase } from "../connection-CiJWiWya.mjs";
4
4
  import { t as validateIdentifier } from "../validate-VPnKoIzW.mjs";
5
5
  import { l as listTablesLike } from "../dialect-helpers-fk43GbDb.mjs";
6
- import { r as isI18nEnabled } from "../config-CVssduLe.mjs";
7
- import { n as slugify } from "../slugify-BzGxlOFx.mjs";
8
- import { t as ContentRepository } from "../content-BfyjOiMi.mjs";
9
- import { i as encodeBase64url } from "../base64-C1Q9yr0B.mjs";
10
- import "../types-Ck7-WoUD.mjs";
11
- import { t as MediaRepository } from "../media-DhBwiCYR.mjs";
12
- import { t as TaxonomyRepository } from "../taxonomy-BnH-6VsX.mjs";
13
- import { t as OptionsRepository } from "../options-BF11H_FD.mjs";
14
- import "../redirect-BqFMj67n.mjs";
15
- import "../request-cache-w5cj5itT.mjs";
16
- import "../byline-registry-CL8BxPPp.mjs";
17
- import { t as BylineRepository } from "../byline-CXQcMsBu.mjs";
18
- import "../fts-manager-EHY2Kes9.mjs";
19
- import { n as SchemaRegistry } from "../registry-Cq3QRBW2.mjs";
20
- import { a as isMissingTableError } from "../loader-Y0QvC_QO.mjs";
21
- import "../settings-DNRQuX3d.mjs";
22
- import { n as VERSION } from "../version-Cb1tZ6s_.mjs";
6
+ import { n as getI18nConfig, r as isI18nEnabled } from "../config-CVssduLe.mjs";
7
+ import { i as encodeBase64url } from "../base64-F8-DUraK.mjs";
8
+ import "../types-CSgR9nQB.mjs";
9
+ import { a as isMissingTableError } from "../loader--GOYux8M.mjs";
10
+ import { n as slugify } from "../slugify-BqebcqBg.mjs";
11
+ import { t as ContentRepository } from "../content-CBxYGWfL.mjs";
12
+ import { t as MediaRepository } from "../media-CbKyYukG.mjs";
13
+ import { t as TaxonomyRepository } from "../taxonomy-B169Nm6B.mjs";
14
+ import { t as OptionsRepository } from "../options-LsPjZlqD.mjs";
15
+ import "../redirect-CEACczxo.mjs";
16
+ import "../request-cache-ho99schz.mjs";
17
+ import "../byline-registry-4v6tXMNX.mjs";
18
+ import { t as BylineRepository } from "../byline-BVC1lV6G.mjs";
19
+ import "../fts-manager-B5l_qwrA.mjs";
20
+ import { n as SchemaRegistry } from "../registry-D7HACema.mjs";
21
+ import "../settings-CUXOxzsT.mjs";
22
+ import { n as VERSION } from "../version-C4gfn0PJ.mjs";
23
23
  import { i as pluginManifestSchema } from "../manifest-schema-qh2P7RDX.mjs";
24
24
  import "../ssrf-DiKqWd3N.mjs";
25
- import { t as validateSeed } from "../validate-CK4a1sIF.mjs";
26
- import { t as applySeed } from "../apply-BpRBCqUt.mjs";
27
- import { n as fingerprintKey, r as generateEncryptionKey, t as DinewaySecretsError } from "../secrets-CPoFLJjm.mjs";
25
+ import { t as validateSeed } from "../validate-DWmPO6oj.mjs";
26
+ import { t as applySeed } from "../apply-D_RlTYtC.mjs";
27
+ import { n as fingerprintKey, r as generateEncryptionKey, t as DinewaySecretsError } from "../secrets-CeGpBFV2.mjs";
28
28
  import { createHeaderAwareFetch, customHeadersInterceptor, isRedirectResponse, resolveCustomHeaders } from "../client/external-auth-headers.mjs";
29
29
  import { o as convertDataForRead } from "../transport-LSdZVXHF.mjs";
30
30
  import { DinewayClient } from "../client/index.mjs";
31
31
  import { LocalStorage } from "../storage/local.mjs";
32
- import { createHash } from "node:crypto";
32
+ import { createHash, randomUUID } from "node:crypto";
33
33
  import { sql } from "kysely";
34
34
  import { imageSize } from "image-size";
35
35
  import { createGzipDecoder, unpackTar } from "modern-tar";
@@ -37,15 +37,474 @@ import { createReadStream, createWriteStream, existsSync, mkdirSync, readFileSyn
37
37
  import { basename, dirname, extname, isAbsolute, join, relative, resolve } from "node:path";
38
38
  import { pathToFileURL } from "node:url";
39
39
  import { defineCommand, runCommand, runMain } from "citty";
40
+ import { createInterface } from "node:readline/promises";
40
41
  import consola, { consola as consola$1 } from "consola";
41
42
  import pc from "picocolors";
42
- import { homedir } from "node:os";
43
+ import { ForgewayClient } from "@forgeway/sdk";
43
44
  import { access, chmod, copyFile, mkdir, readFile, readdir, rm, stat, symlink, writeFile } from "node:fs/promises";
44
- import { createInterface } from "node:readline/promises";
45
+ import { homedir } from "node:os";
45
46
  import { spawn } from "node:child_process";
46
47
  import { pipeline } from "node:stream/promises";
47
48
  import { packTar } from "modern-tar/fs";
48
49
 
50
+ //#region src/cli/commands/deploy/utils/forgeway-secrets.ts
51
+ const DINEWAY_USER_CONFIG_DIR_NAME = "dineway";
52
+ const TRAILING_SLASH_PATTERN$3 = /\/$/;
53
+ function getDinewayUserConfigDir() {
54
+ return join(process.env.XDG_CONFIG_HOME || join(homedir(), ".config"), DINEWAY_USER_CONFIG_DIR_NAME);
55
+ }
56
+ function getForgewayAccountSecretPath() {
57
+ return join(getDinewayUserConfigDir(), "forgeway.json");
58
+ }
59
+ function normalizePlatformApiUrl$1(platformApiUrl) {
60
+ return platformApiUrl.replace(TRAILING_SLASH_PATTERN$3, "");
61
+ }
62
+ function normalizeEmail$2(email) {
63
+ return email.trim().toLowerCase();
64
+ }
65
+ function accountKey(platformApiUrl, email) {
66
+ return `${normalizePlatformApiUrl$1(platformApiUrl)}#${normalizeEmail$2(email)}`;
67
+ }
68
+ function normalizeLookup(lookup) {
69
+ if (typeof lookup === "string") return { cwd: lookup };
70
+ return lookup ?? {};
71
+ }
72
+ async function readAccountStore() {
73
+ try {
74
+ const raw = await readFile(getForgewayAccountSecretPath(), "utf-8");
75
+ return JSON.parse(raw);
76
+ } catch {
77
+ return { version: 1 };
78
+ }
79
+ }
80
+ async function writeAccountStore(store) {
81
+ await mkdir(getDinewayUserConfigDir(), {
82
+ recursive: true,
83
+ mode: 448
84
+ });
85
+ const file = getForgewayAccountSecretPath();
86
+ await writeFile(file, JSON.stringify({
87
+ ...store,
88
+ version: 1
89
+ }, null, " ") + "\n", {
90
+ encoding: "utf-8",
91
+ mode: 384
92
+ });
93
+ await chmod(file, 384);
94
+ }
95
+ function accountMatches(credentials, lookup) {
96
+ if (lookup.platformApiUrl && normalizePlatformApiUrl$1(credentials.platformApiUrl) !== normalizePlatformApiUrl$1(lookup.platformApiUrl)) return false;
97
+ if (lookup.email && normalizeEmail$2(credentials.user?.email ?? "") !== normalizeEmail$2(lookup.email)) return false;
98
+ return true;
99
+ }
100
+ async function readForgewayCredentials(lookup) {
101
+ const normalizedLookup = normalizeLookup(lookup);
102
+ const store = await readAccountStore();
103
+ const accounts = Object.values(store.accounts ?? {}).filter((credentials) => accountMatches(credentials, normalizedLookup));
104
+ if (normalizedLookup.platformApiUrl && normalizedLookup.email) return store.accounts?.[accountKey(normalizedLookup.platformApiUrl, normalizedLookup.email)] ?? null;
105
+ if (accounts.length === 1) return accounts[0] ?? null;
106
+ return null;
107
+ }
108
+ async function writeForgewayCredentials(credentials, lookup) {
109
+ const normalizedLookup = normalizeLookup(lookup);
110
+ const platformApiUrl = normalizePlatformApiUrl$1(normalizedLookup.platformApiUrl ?? credentials.platformApiUrl);
111
+ const email = normalizeEmail$2(normalizedLookup.email ?? credentials.user?.email ?? "");
112
+ if (!email) throw new Error("Forgeway credentials require a user email before they can be stored.");
113
+ const key = accountKey(platformApiUrl, email);
114
+ const store = await readAccountStore();
115
+ store.accounts = {
116
+ ...store.accounts,
117
+ [key]: {
118
+ ...credentials,
119
+ platformApiUrl
120
+ }
121
+ };
122
+ store.lastAccountKey = key;
123
+ await writeAccountStore(store);
124
+ }
125
+ async function listForgewayCredentials(platformApiUrl) {
126
+ const lookup = platformApiUrl ? { platformApiUrl } : {};
127
+ const store = await readAccountStore();
128
+ return Object.values(store.accounts ?? {}).filter((credentials) => accountMatches(credentials, lookup));
129
+ }
130
+
131
+ //#endregion
132
+ //#region src/cli/forgeway-account.ts
133
+ const TRAILING_SLASH_PATTERN$2 = /\/$/;
134
+ const SHADOW_EMAIL_PATTERN$2 = /^shadow_[a-f0-9]{16}@dineway\.ai$/i;
135
+ const DEFAULT_FORGEWAY_API_BASE_URL = "https://api.dineway.ai";
136
+ const DEFAULT_DINEWAY_WEB_URL = "https://dineway.ai";
137
+ function normalizeForgewayApiUrl(value) {
138
+ return (value || DEFAULT_FORGEWAY_API_BASE_URL).replace(TRAILING_SLASH_PATTERN$2, "");
139
+ }
140
+ function normalizeDinewayWebUrl(value) {
141
+ return (value || DEFAULT_DINEWAY_WEB_URL).replace(TRAILING_SLASH_PATTERN$2, "");
142
+ }
143
+ function normalizeForgewayEmail(value) {
144
+ return value?.trim().toLowerCase() ?? "";
145
+ }
146
+ function isShadowForgewayEmail(email) {
147
+ return Boolean(email && SHADOW_EMAIL_PATTERN$2.test(email));
148
+ }
149
+ function createForgewayAccountClient(platformApiUrl, accessToken) {
150
+ return new ForgewayClient({
151
+ baseUrl: normalizeForgewayApiUrl(platformApiUrl),
152
+ accessToken,
153
+ isServerMode: true,
154
+ auth: { detectOAuthCallback: false }
155
+ });
156
+ }
157
+ function normalizeForgewayUser$2(user) {
158
+ if (!user?.id || !user.email) throw new Error("Forgeway session response did not include a user email.");
159
+ return {
160
+ id: user.id,
161
+ name: user.profile?.name ?? user.name ?? user.email,
162
+ email: user.email,
163
+ avatarUrl: user.profile?.avatar_url ?? user.avatarUrl ?? user.avatar_url ?? null,
164
+ emailVerified: user.emailVerified ?? user.email_verified ?? false
165
+ };
166
+ }
167
+ function assertFormalForgewayUser(user) {
168
+ if (!user || user.emailVerified !== true || isShadowForgewayEmail(user.email)) throw new Error("Dineway account commands require a verified Forgeway account.");
169
+ return user;
170
+ }
171
+ async function readStoredForgewayAccount(lookup = {}) {
172
+ const platformApiUrl = normalizeForgewayApiUrl(lookup.platformApiUrl);
173
+ const email = normalizeForgewayEmail(lookup.email);
174
+ if (email) return readForgewayCredentials({
175
+ platformApiUrl,
176
+ email
177
+ });
178
+ const stored = await readForgewayCredentials({ platformApiUrl });
179
+ if (stored) return stored;
180
+ const accounts = (await listForgewayCredentials(platformApiUrl)).filter((credentials) => {
181
+ try {
182
+ assertFormalForgewayUser(credentials.user);
183
+ return true;
184
+ } catch {
185
+ return false;
186
+ }
187
+ });
188
+ return accounts.length === 1 ? accounts[0] ?? null : null;
189
+ }
190
+ async function refreshForgewayAccountCredentials(credentials) {
191
+ const user = assertFormalForgewayUser(credentials.user);
192
+ if (!credentials.refreshToken) throw new Error("Stored Forgeway account is missing a refresh token. Run `dineway account login`.");
193
+ const { data, error } = await createForgewayAccountClient(credentials.platformApiUrl).auth.refreshSession({ refreshToken: credentials.refreshToken });
194
+ if (error || !data?.accessToken) throw new Error(error?.message || "Failed to refresh Forgeway account. Run `dineway account login`.");
195
+ const refreshedUser = normalizeForgewayUser$2(data.user);
196
+ if (normalizeForgewayEmail(refreshedUser.email) !== normalizeForgewayEmail(user.email)) throw new Error("Forgeway refresh returned credentials for a different account.");
197
+ const updated = {
198
+ ...credentials,
199
+ platformApiUrl: normalizeForgewayApiUrl(credentials.platformApiUrl),
200
+ accessToken: data.accessToken,
201
+ refreshToken: data.refreshToken ?? credentials.refreshToken,
202
+ user: {
203
+ ...refreshedUser,
204
+ emailVerified: true
205
+ }
206
+ };
207
+ await writeForgewayCredentials(updated, {
208
+ platformApiUrl: updated.platformApiUrl,
209
+ email: updated.user?.email
210
+ });
211
+ return updated;
212
+ }
213
+ async function sendForgewayAccountLoginLink(input) {
214
+ const platformApiUrl = normalizeForgewayApiUrl(input.platformApiUrl);
215
+ const webUrl = normalizeDinewayWebUrl(input.webUrl);
216
+ const redirectTo = new URL("/cli-auth", webUrl).toString();
217
+ const { error } = await createForgewayAccountClient(platformApiUrl).auth.sendPasswordlessSignInEmail({
218
+ email: input.email,
219
+ redirectTo
220
+ });
221
+ if (error) throw new Error(error.message || "Failed to send Forgeway account sign-in link.");
222
+ }
223
+ async function completeForgewayAccountLogin(input) {
224
+ const platformApiUrl = normalizeForgewayApiUrl(input.platformApiUrl);
225
+ const { data, error } = await createForgewayAccountClient(platformApiUrl).auth.signInWithPasswordlessToken({ token: input.token });
226
+ if (error || !data?.accessToken || !data.refreshToken) throw new Error(error?.message || "Forgeway sign-in token is invalid or expired.");
227
+ const user = normalizeForgewayUser$2(data.user);
228
+ if (input.email && normalizeForgewayEmail(user.email) !== normalizeForgewayEmail(input.email)) throw new Error("Forgeway sign-in returned credentials for a different email.");
229
+ const credentials = {
230
+ platformApiUrl,
231
+ accessToken: data.accessToken,
232
+ refreshToken: data.refreshToken,
233
+ user: {
234
+ ...user,
235
+ emailVerified: true
236
+ }
237
+ };
238
+ await writeForgewayCredentials(credentials, {
239
+ platformApiUrl,
240
+ email: credentials.user?.email
241
+ });
242
+ return credentials;
243
+ }
244
+ async function getForgewayDinewayAccount(credentials) {
245
+ const refreshed = await refreshForgewayAccountCredentials(credentials);
246
+ const { data, error } = await createForgewayAccountClient(refreshed.platformApiUrl, refreshed.accessToken).dineway.getAccount();
247
+ if (error || !data) throw new Error(error?.message || "Failed to fetch Dineway account status from Forgeway.");
248
+ return {
249
+ credentials: refreshed,
250
+ account: data
251
+ };
252
+ }
253
+
254
+ //#endregion
255
+ //#region src/cli/output.ts
256
+ /**
257
+ * Redirect consola output to stderr so it doesn't pollute JSON on stdout.
258
+ *
259
+ * Call this early in any command that uses `output()` with `--json`.
260
+ * Safe to call multiple times — only applies the redirect once.
261
+ */
262
+ function configureOutputMode(args) {
263
+ if (args.json || !process.stdout.isTTY) {
264
+ consola$1.options.stdout = process.stderr;
265
+ consola$1.options.stderr = process.stderr;
266
+ }
267
+ }
268
+ /**
269
+ * Output data as JSON or pretty-printed.
270
+ *
271
+ * If stdout is not a TTY or --json is set, outputs JSON.
272
+ * Otherwise, outputs a formatted representation.
273
+ */
274
+ function output(data, args) {
275
+ if (args.json || !process.stdout.isTTY) process.stdout.write(JSON.stringify(data, null, 2) + "\n");
276
+ else prettyPrint(data);
277
+ }
278
+ function prettyPrint(data, indent = 0) {
279
+ if (data === null || data === void 0) {
280
+ consola$1.log("(empty)");
281
+ return;
282
+ }
283
+ if (Array.isArray(data)) {
284
+ if (data.length === 0) {
285
+ consola$1.log("(no items)");
286
+ return;
287
+ }
288
+ for (const item of data) {
289
+ prettyPrint(item, indent);
290
+ if (indent === 0) consola$1.log("---");
291
+ }
292
+ return;
293
+ }
294
+ if (typeof data === "object") {
295
+ const obj = Object(data);
296
+ if ("items" in obj && Array.isArray(obj.items)) {
297
+ prettyPrint(obj.items, indent);
298
+ if (typeof obj.nextCursor === "string") consola$1.log(`\nNext cursor: ${obj.nextCursor}`);
299
+ return;
300
+ }
301
+ const prefix = " ".repeat(indent);
302
+ for (const [key, value] of Object.entries(obj)) {
303
+ if (value === null || value === void 0) continue;
304
+ if (typeof value === "object" && !Array.isArray(value)) {
305
+ consola$1.log(`${prefix}${key}:`);
306
+ prettyPrint(value, indent + 1);
307
+ } else if (Array.isArray(value)) consola$1.log(`${prefix}${key}: [${value.length} items]`);
308
+ else {
309
+ const str = typeof value === "string" ? value : JSON.stringify(value);
310
+ const display = str.length > 80 ? str.slice(0, 77) + "..." : str;
311
+ consola$1.log(`${prefix}${key}: ${display}`);
312
+ }
313
+ }
314
+ return;
315
+ }
316
+ consola$1.log(typeof data === "string" ? data : JSON.stringify(data));
317
+ }
318
+
319
+ //#endregion
320
+ //#region src/cli/commands/account.ts
321
+ async function promptLine(question) {
322
+ const readline = createInterface({
323
+ input: process.stdin,
324
+ output: process.stdout
325
+ });
326
+ try {
327
+ return (await readline.question(question)).trim();
328
+ } finally {
329
+ readline.close();
330
+ }
331
+ }
332
+ function resolveApiUrl(args) {
333
+ return normalizeForgewayApiUrl(args["api-url"] ?? process.env.DINEWAY_API_BASE_URL ?? process.env.FORGEWAY_API_URL);
334
+ }
335
+ function outputAccountJson(value) {
336
+ console.log(JSON.stringify(value, null, " "));
337
+ }
338
+ const accountLoginCommand = defineCommand({
339
+ meta: {
340
+ name: "login",
341
+ description: "Log in to the Dineway Web / Forgeway account used for paid services"
342
+ },
343
+ args: {
344
+ email: {
345
+ type: "string",
346
+ alias: "e",
347
+ description: "Forgeway account email"
348
+ },
349
+ token: {
350
+ type: "string",
351
+ description: "Passwordless sign-in token from the Dineway CLI auth page"
352
+ },
353
+ "api-url": {
354
+ type: "string",
355
+ description: "Forgeway API URL",
356
+ default: DEFAULT_FORGEWAY_API_BASE_URL
357
+ },
358
+ "web-url": {
359
+ type: "string",
360
+ description: "Dineway Web URL used for the email link",
361
+ default: DEFAULT_DINEWAY_WEB_URL
362
+ },
363
+ "send-link": {
364
+ type: "boolean",
365
+ description: "Send the email link and exit without prompting for the token"
366
+ },
367
+ json: {
368
+ type: "boolean",
369
+ description: "Output as JSON"
370
+ }
371
+ },
372
+ async run({ args }) {
373
+ configureOutputMode(args);
374
+ const platformApiUrl = resolveApiUrl(args);
375
+ const webUrl = normalizeDinewayWebUrl(args["web-url"]);
376
+ const email = normalizeForgewayEmail(args.email) || normalizeForgewayEmail(await promptLine("Dineway account email: "));
377
+ if (!email) {
378
+ consola$1.error("Email is required.");
379
+ process.exit(2);
380
+ }
381
+ try {
382
+ const existing = await readStoredForgewayAccount({
383
+ platformApiUrl,
384
+ email
385
+ });
386
+ if (existing && !args.token && !args["send-link"]) {
387
+ const { account } = await getForgewayDinewayAccount(existing);
388
+ if (args.json) outputAccountJson({
389
+ loggedIn: true,
390
+ platformApiUrl,
391
+ account
392
+ });
393
+ else {
394
+ consola$1.success(`Already logged in as ${pc.bold(account.account.email ?? email)}`);
395
+ consola$1.info(`Plan: ${pc.cyan(account.plan.name)}`);
396
+ }
397
+ return;
398
+ }
399
+ if (!args.token) {
400
+ await sendForgewayAccountLoginLink({
401
+ email,
402
+ platformApiUrl,
403
+ webUrl
404
+ });
405
+ if (args.json) outputAccountJson({
406
+ sent: true,
407
+ email,
408
+ platformApiUrl,
409
+ cliAuthUrl: new URL("/cli-auth", webUrl).toString()
410
+ });
411
+ else {
412
+ consola$1.success(`Sent Dineway account sign-in link to ${pc.bold(email)}`);
413
+ consola$1.info("Open the email link, copy the CLI token, then paste it here.");
414
+ }
415
+ if (args["send-link"]) return;
416
+ }
417
+ const { account } = await getForgewayDinewayAccount(await completeForgewayAccountLogin({
418
+ token: typeof args.token === "string" && args.token.trim() ? args.token.trim() : await promptLine("CLI token: "),
419
+ platformApiUrl,
420
+ email
421
+ }));
422
+ if (args.json) outputAccountJson({
423
+ loggedIn: true,
424
+ platformApiUrl,
425
+ account
426
+ });
427
+ else {
428
+ consola$1.success(`Logged in as ${pc.bold(account.account.email ?? email)}`);
429
+ consola$1.info(`Plan: ${pc.cyan(account.plan.name)}`);
430
+ consola$1.info(`Credits: ${account.credits.availableCredits.toLocaleString()}`);
431
+ consola$1.info(`Hosted sites: ${account.sites.usedHostedSites.toLocaleString()} / ${account.sites.hostedSiteLimitLabel}`);
432
+ }
433
+ } catch (error) {
434
+ consola$1.error(error instanceof Error ? error.message : "Dineway account login failed");
435
+ process.exit(2);
436
+ }
437
+ }
438
+ });
439
+ const accountStatusCommand = defineCommand({
440
+ meta: {
441
+ name: "status",
442
+ description: "Show Dineway Web / Forgeway account plan, credits, and hosted site slots"
443
+ },
444
+ args: {
445
+ email: {
446
+ type: "string",
447
+ alias: "e",
448
+ description: "Forgeway account email"
449
+ },
450
+ "api-url": {
451
+ type: "string",
452
+ description: "Forgeway API URL",
453
+ default: DEFAULT_FORGEWAY_API_BASE_URL
454
+ },
455
+ json: {
456
+ type: "boolean",
457
+ description: "Output as JSON"
458
+ }
459
+ },
460
+ async run({ args }) {
461
+ configureOutputMode(args);
462
+ const platformApiUrl = resolveApiUrl(args);
463
+ try {
464
+ const credentials = await readStoredForgewayAccount({
465
+ platformApiUrl,
466
+ email: normalizeForgewayEmail(args.email)
467
+ });
468
+ if (!credentials) {
469
+ if (args.json) outputAccountJson({
470
+ loggedIn: false,
471
+ platformApiUrl
472
+ });
473
+ else consola$1.error("Not logged in. Run: dineway account login");
474
+ process.exit(2);
475
+ }
476
+ const { account } = await getForgewayDinewayAccount(credentials);
477
+ if (args.json) {
478
+ outputAccountJson({
479
+ loggedIn: true,
480
+ platformApiUrl,
481
+ account
482
+ });
483
+ return;
484
+ }
485
+ consola$1.info(`Email: ${pc.bold(account.account.email ?? credentials.user?.email ?? "unknown")}`);
486
+ consola$1.info(`Plan: ${pc.cyan(account.plan.name)}`);
487
+ consola$1.info(`Credits available: ${account.credits.availableCredits.toLocaleString()}`);
488
+ consola$1.info(`Hosted sites: ${account.sites.usedHostedSites.toLocaleString()} / ${account.sites.hostedSiteLimitLabel}`);
489
+ if (account.billing.subscription?.status) consola$1.info(`Billing: ${account.billing.subscription.status}`);
490
+ } catch (error) {
491
+ consola$1.error(error instanceof Error ? error.message : "Dineway account status failed");
492
+ process.exit(2);
493
+ }
494
+ }
495
+ });
496
+ const accountCommand = defineCommand({
497
+ meta: {
498
+ name: "account",
499
+ description: "Dineway Web account login, status, and billing helpers"
500
+ },
501
+ subCommands: {
502
+ login: accountLoginCommand,
503
+ status: accountStatusCommand
504
+ }
505
+ });
506
+
507
+ //#endregion
49
508
  //#region src/cli/credentials.ts
50
509
  /**
51
510
  * Credential storage for CLI auth tokens.
@@ -99,7 +558,7 @@ function findProjectRoot(from) {
99
558
  }
100
559
  return null;
101
560
  }
102
- function readStore$1() {
561
+ function readStore() {
103
562
  const path = getCredentialPath();
104
563
  try {
105
564
  if (existsSync(path)) {
@@ -109,7 +568,7 @@ function readStore$1() {
109
568
  } catch {}
110
569
  return {};
111
570
  }
112
- function writeStore$1(store) {
571
+ function writeStore(store) {
113
572
  mkdirSync(getConfigDir(), {
114
573
  recursive: true,
115
574
  mode: 448
@@ -124,7 +583,7 @@ function writeStore$1(store) {
124
583
  */
125
584
  function getCredentials(baseUrl) {
126
585
  const key = resolveCredentialKey(baseUrl);
127
- const cred = readStore$1()[key];
586
+ const cred = readStore()[key];
128
587
  if (!cred || !("accessToken" in cred)) return null;
129
588
  return cred;
130
589
  }
@@ -133,19 +592,19 @@ function getCredentials(baseUrl) {
133
592
  */
134
593
  function saveCredentials(baseUrl, cred) {
135
594
  const key = resolveCredentialKey(baseUrl);
136
- const store = readStore$1();
595
+ const store = readStore();
137
596
  store[key] = cred;
138
- writeStore$1(store);
597
+ writeStore(store);
139
598
  }
140
599
  /**
141
600
  * Remove credentials for a URL.
142
601
  */
143
602
  function removeCredentials(baseUrl) {
144
603
  const key = resolveCredentialKey(baseUrl);
145
- const store = readStore$1();
604
+ const store = readStore();
146
605
  if (key in store) {
147
606
  delete store[key];
148
- writeStore$1(store);
607
+ writeStore(store);
149
608
  return true;
150
609
  }
151
610
  return false;
@@ -162,7 +621,7 @@ function marketplaceKey(registryUrl) {
162
621
  */
163
622
  function getMarketplaceCredential(registryUrl) {
164
623
  const key = marketplaceKey(registryUrl);
165
- const cred = readStore$1()[key];
624
+ const cred = readStore()[key];
166
625
  if (!cred || !("token" in cred)) return null;
167
626
  if (new Date(cred.expiresAt) < /* @__PURE__ */ new Date()) return null;
168
627
  return cred;
@@ -172,19 +631,19 @@ function getMarketplaceCredential(registryUrl) {
172
631
  */
173
632
  function saveMarketplaceCredential(registryUrl, cred) {
174
633
  const key = marketplaceKey(registryUrl);
175
- const store = readStore$1();
634
+ const store = readStore();
176
635
  store[key] = cred;
177
- writeStore$1(store);
636
+ writeStore(store);
178
637
  }
179
638
  /**
180
639
  * Remove marketplace credential for a registry URL.
181
640
  */
182
641
  function removeMarketplaceCredential(registryUrl) {
183
642
  const key = marketplaceKey(registryUrl);
184
- const store = readStore$1();
643
+ const store = readStore();
185
644
  if (key in store) {
186
645
  delete store[key];
187
- writeStore$1(store);
646
+ writeStore(store);
188
647
  return true;
189
648
  }
190
649
  return false;
@@ -359,71 +818,6 @@ function createClientFromArgs(args) {
359
818
  });
360
819
  }
361
820
 
362
- //#endregion
363
- //#region src/cli/output.ts
364
- /**
365
- * Redirect consola output to stderr so it doesn't pollute JSON on stdout.
366
- *
367
- * Call this early in any command that uses `output()` with `--json`.
368
- * Safe to call multiple times — only applies the redirect once.
369
- */
370
- function configureOutputMode(args) {
371
- if (args.json || !process.stdout.isTTY) {
372
- consola$1.options.stdout = process.stderr;
373
- consola$1.options.stderr = process.stderr;
374
- }
375
- }
376
- /**
377
- * Output data as JSON or pretty-printed.
378
- *
379
- * If stdout is not a TTY or --json is set, outputs JSON.
380
- * Otherwise, outputs a formatted representation.
381
- */
382
- function output(data, args) {
383
- if (args.json || !process.stdout.isTTY) process.stdout.write(JSON.stringify(data, null, 2) + "\n");
384
- else prettyPrint(data);
385
- }
386
- function prettyPrint(data, indent = 0) {
387
- if (data === null || data === void 0) {
388
- consola$1.log("(empty)");
389
- return;
390
- }
391
- if (Array.isArray(data)) {
392
- if (data.length === 0) {
393
- consola$1.log("(no items)");
394
- return;
395
- }
396
- for (const item of data) {
397
- prettyPrint(item, indent);
398
- if (indent === 0) consola$1.log("---");
399
- }
400
- return;
401
- }
402
- if (typeof data === "object") {
403
- const obj = Object(data);
404
- if ("items" in obj && Array.isArray(obj.items)) {
405
- prettyPrint(obj.items, indent);
406
- if (typeof obj.nextCursor === "string") consola$1.log(`\nNext cursor: ${obj.nextCursor}`);
407
- return;
408
- }
409
- const prefix = " ".repeat(indent);
410
- for (const [key, value] of Object.entries(obj)) {
411
- if (value === null || value === void 0) continue;
412
- if (typeof value === "object" && !Array.isArray(value)) {
413
- consola$1.log(`${prefix}${key}:`);
414
- prettyPrint(value, indent + 1);
415
- } else if (Array.isArray(value)) consola$1.log(`${prefix}${key}: [${value.length} items]`);
416
- else {
417
- const str = typeof value === "string" ? value : JSON.stringify(value);
418
- const display = str.length > 80 ? str.slice(0, 77) + "..." : str;
419
- consola$1.log(`${prefix}${key}: ${display}`);
420
- }
421
- }
422
- return;
423
- }
424
- consola$1.log(typeof data === "string" ? data : JSON.stringify(data));
425
- }
426
-
427
821
  //#endregion
428
822
  //#region src/cli/commands/auth.ts
429
823
  /**
@@ -950,7 +1344,157 @@ const contentCommand = defineCommand({
950
1344
  restore: restoreCommand,
951
1345
  translations: translationsCommand
952
1346
  }
953
- });
1347
+ });
1348
+
1349
+ //#endregion
1350
+ //#region src/cli/paywall.ts
1351
+ const PAYWALL_MESSAGE_PATTERN = /\b(quota|credit|credits|upgrade|plan|billing|subscription|slot)\b/i;
1352
+ function isRecord$1(value) {
1353
+ return typeof value === "object" && value !== null;
1354
+ }
1355
+ function stringField(record, key) {
1356
+ const value = record[key];
1357
+ return typeof value === "string" && value.trim() ? value.trim() : void 0;
1358
+ }
1359
+ function getNestedError(value) {
1360
+ if (!isRecord$1(value)) return null;
1361
+ const nested = value.error;
1362
+ return isRecord$1(nested) ? nested : value;
1363
+ }
1364
+ function isHostedSitesResource(resource) {
1365
+ const normalized = resource.toLowerCase();
1366
+ return normalized === "deploy:forgeway" || normalized === "dineway.hosted_sites" || normalized.includes("hosted_site");
1367
+ }
1368
+ function isCreditResource(resource) {
1369
+ const normalized = resource.toLowerCase();
1370
+ return normalized.includes("credit") || normalized.includes("firecrawl") || normalized.includes("dataforseo") || normalized.startsWith("/api/");
1371
+ }
1372
+ function getCliPaywallRefreshStatus(paywall, account) {
1373
+ if (isHostedSitesResource(paywall.resource)) {
1374
+ const remainingHostedSites = account.sites?.remainingHostedSites;
1375
+ if (remainingHostedSites === null || (remainingHostedSites ?? 0) > 0) return {
1376
+ blocked: false,
1377
+ message: "Hosted capacity is now available. Re-run the blocked command."
1378
+ };
1379
+ return {
1380
+ blocked: true,
1381
+ message: "There is still no hosted capacity. Complete checkout in Dineway Web."
1382
+ };
1383
+ }
1384
+ if (isCreditResource(paywall.resource)) {
1385
+ if ((account.credits?.availableCredits ?? 0) > 0) return {
1386
+ blocked: false,
1387
+ message: "Provider credits are now available. Re-run the blocked command."
1388
+ };
1389
+ return {
1390
+ blocked: true,
1391
+ message: "There are still no provider credits. Complete checkout or top up credits in Dineway Web."
1392
+ };
1393
+ }
1394
+ return {
1395
+ blocked: false,
1396
+ message: "Account status refreshed. Re-run the blocked command when ready."
1397
+ };
1398
+ }
1399
+ function normalizeCliPaywallError(input) {
1400
+ const error = input.error;
1401
+ const status = error?.status ?? error?.statusCode;
1402
+ const message = error?.message ?? (input.error instanceof Error ? input.error.message : "");
1403
+ const body = error?.body;
1404
+ const candidate = getNestedError(body) ?? getNestedError(input.error) ?? {};
1405
+ if (stringField(candidate, "code") && stringField(candidate, "resource") && stringField(candidate, "reason") && typeof candidate.handoffRequired === "boolean") return {
1406
+ code: stringField(candidate, "code") ?? "PAYWALL_REQUIRED",
1407
+ resource: stringField(candidate, "resource") ?? input.resource,
1408
+ reason: stringField(candidate, "reason") ?? input.reason ?? message,
1409
+ requiredPlan: stringField(candidate, "requiredPlan"),
1410
+ pricingUrl: stringField(candidate, "pricingUrl") ?? new URL("/pricing", normalizeDinewayWebUrl(input.webUrl)).toString(),
1411
+ handoffRequired: candidate.handoffRequired === true
1412
+ };
1413
+ if ((status === 402 || status === 403 || status === 429) && PAYWALL_MESSAGE_PATTERN.test(message)) return {
1414
+ code: status === 429 ? "QUOTA_EXCEEDED" : "PAYWALL_REQUIRED",
1415
+ resource: input.resource,
1416
+ reason: input.reason ?? message,
1417
+ pricingUrl: new URL("/pricing", normalizeDinewayWebUrl(input.webUrl)).toString(),
1418
+ handoffRequired: true
1419
+ };
1420
+ return null;
1421
+ }
1422
+ async function promptEnter(message) {
1423
+ const readline = createInterface({
1424
+ input: process.stdin,
1425
+ output: process.stdout
1426
+ });
1427
+ try {
1428
+ await readline.question(message);
1429
+ } finally {
1430
+ readline.close();
1431
+ }
1432
+ }
1433
+ async function createHandoff(input) {
1434
+ const credentials = await readStoredForgewayAccount({ platformApiUrl: input.platformApiUrl });
1435
+ if (!credentials) return null;
1436
+ const { credentials: refreshed } = await getForgewayDinewayAccount(credentials);
1437
+ const response = await fetch(new URL("/api/dineway-web/handoffs", input.webUrl), {
1438
+ method: "POST",
1439
+ headers: {
1440
+ Authorization: `Bearer ${refreshed.accessToken}`,
1441
+ "Content-Type": "application/json",
1442
+ "X-Dineway-Request": "1"
1443
+ },
1444
+ body: JSON.stringify({
1445
+ target: "pricing",
1446
+ reason: input.paywall.reason,
1447
+ context: {
1448
+ resource: input.paywall.resource,
1449
+ code: input.paywall.code,
1450
+ requiredPlan: input.paywall.requiredPlan,
1451
+ ...input.context
1452
+ }
1453
+ })
1454
+ });
1455
+ const payload = await response.json().catch(() => null);
1456
+ if (!response.ok || !payload?.success || !payload.data?.url) return null;
1457
+ return payload.data.url;
1458
+ }
1459
+ async function handleCliPaywall(input) {
1460
+ const paywall = normalizeCliPaywallError(input);
1461
+ if (!paywall) return false;
1462
+ const platformApiUrl = normalizeForgewayApiUrl(input.platformApiUrl);
1463
+ const webUrl = normalizeDinewayWebUrl(input.webUrl ?? process.env.DINEWAY_WEB_URL);
1464
+ let url = paywall.pricingUrl;
1465
+ let handoffFailed = false;
1466
+ try {
1467
+ const handoffUrl = await createHandoff({
1468
+ paywall,
1469
+ platformApiUrl,
1470
+ webUrl,
1471
+ context: input.context
1472
+ });
1473
+ if (handoffUrl) url = handoffUrl;
1474
+ else handoffFailed = true;
1475
+ } catch {
1476
+ handoffFailed = true;
1477
+ }
1478
+ consola$1.error(paywall.reason);
1479
+ if (handoffFailed) consola$1.info(`Log in first: ${pc.cyan("dineway account login")}`);
1480
+ consola$1.info(`Continue in Dineway Web: ${pc.cyan(url)}`);
1481
+ if (!input.interactive) return true;
1482
+ await promptEnter("Press Enter to continue after upgrading, or Ctrl-C to cancel.");
1483
+ const credentials = await readStoredForgewayAccount({ platformApiUrl });
1484
+ if (!credentials) {
1485
+ consola$1.error("Still not logged in. Run: dineway account login");
1486
+ return true;
1487
+ }
1488
+ try {
1489
+ const { account } = await getForgewayDinewayAccount(credentials);
1490
+ const status = getCliPaywallRefreshStatus(paywall, account);
1491
+ if (status.blocked) consola$1.error(status.message);
1492
+ else consola$1.info(status.message);
1493
+ } catch {
1494
+ consola$1.error("Account is still blocked. Complete checkout or top up credits in Dineway Web.");
1495
+ }
1496
+ return true;
1497
+ }
954
1498
 
955
1499
  //#endregion
956
1500
  //#region src/cli/commands/deploy/utils/astro-adapter.ts
@@ -1637,136 +2181,6 @@ async function writeForgewayDeployMetadata(cwd, metadata) {
1637
2181
  });
1638
2182
  }
1639
2183
 
1640
- //#endregion
1641
- //#region src/cli/commands/deploy/utils/forgeway-secrets.ts
1642
- const DINEWAY_CONFIG_DIR_NAME = ".dineway";
1643
- const DINEWAY_USER_CONFIG_DIR_NAME = "dineway";
1644
- const TRAILING_SLASH_PATTERN$2 = /\/$/;
1645
- function getDinewayConfigDir(cwd = process.cwd()) {
1646
- return join(cwd, DINEWAY_CONFIG_DIR_NAME);
1647
- }
1648
- function getDinewayUserConfigDir() {
1649
- return join(process.env.XDG_CONFIG_HOME || join(homedir(), ".config"), DINEWAY_USER_CONFIG_DIR_NAME);
1650
- }
1651
- function getForgewaySecretPath(cwd = process.cwd()) {
1652
- return join(getDinewayConfigDir(cwd), "forgeway.json");
1653
- }
1654
- function getForgewayAccountSecretPath() {
1655
- return join(getDinewayUserConfigDir(), "forgeway.json");
1656
- }
1657
- function normalizePlatformApiUrl$1(platformApiUrl) {
1658
- return platformApiUrl.replace(TRAILING_SLASH_PATTERN$2, "");
1659
- }
1660
- function normalizeEmail$2(email) {
1661
- return email.trim().toLowerCase();
1662
- }
1663
- function accountKey(platformApiUrl, email) {
1664
- return `${normalizePlatformApiUrl$1(platformApiUrl)}#${normalizeEmail$2(email)}`;
1665
- }
1666
- function normalizeLookup(lookup) {
1667
- if (typeof lookup === "string") return { cwd: lookup };
1668
- return lookup ?? {};
1669
- }
1670
- async function readStore(cwd = process.cwd()) {
1671
- try {
1672
- const raw = await readFile(getForgewaySecretPath(cwd), "utf-8");
1673
- return JSON.parse(raw);
1674
- } catch {
1675
- return {};
1676
- }
1677
- }
1678
- async function writeStore(store, cwd = process.cwd()) {
1679
- await mkdir(getDinewayConfigDir(cwd), {
1680
- recursive: true,
1681
- mode: 448
1682
- });
1683
- const file = getForgewaySecretPath(cwd);
1684
- await writeFile(file, JSON.stringify(store, null, " ") + "\n", {
1685
- encoding: "utf-8",
1686
- mode: 384
1687
- });
1688
- await chmod(file, 384);
1689
- }
1690
- async function readAccountStore() {
1691
- try {
1692
- const raw = await readFile(getForgewayAccountSecretPath(), "utf-8");
1693
- return JSON.parse(raw);
1694
- } catch {
1695
- return { version: 1 };
1696
- }
1697
- }
1698
- async function writeAccountStore(store) {
1699
- await mkdir(getDinewayUserConfigDir(), {
1700
- recursive: true,
1701
- mode: 448
1702
- });
1703
- const file = getForgewayAccountSecretPath();
1704
- await writeFile(file, JSON.stringify({
1705
- ...store,
1706
- version: 1
1707
- }, null, " ") + "\n", {
1708
- encoding: "utf-8",
1709
- mode: 384
1710
- });
1711
- await chmod(file, 384);
1712
- }
1713
- function accountMatches(credentials, lookup) {
1714
- if (lookup.platformApiUrl && normalizePlatformApiUrl$1(credentials.platformApiUrl) !== normalizePlatformApiUrl$1(lookup.platformApiUrl)) return false;
1715
- if (lookup.email && normalizeEmail$2(credentials.user?.email ?? "") !== normalizeEmail$2(lookup.email)) return false;
1716
- return true;
1717
- }
1718
- async function readForgewayCredentials(lookup) {
1719
- const normalizedLookup = normalizeLookup(lookup);
1720
- const store = await readAccountStore();
1721
- const accounts = Object.values(store.accounts ?? {}).filter((credentials) => accountMatches(credentials, normalizedLookup));
1722
- if (normalizedLookup.platformApiUrl && normalizedLookup.email) return store.accounts?.[accountKey(normalizedLookup.platformApiUrl, normalizedLookup.email)] ?? null;
1723
- if (accounts.length === 1) return accounts[0] ?? null;
1724
- return null;
1725
- }
1726
- async function writeForgewayCredentials(credentials, lookup) {
1727
- const normalizedLookup = normalizeLookup(lookup);
1728
- const platformApiUrl = normalizePlatformApiUrl$1(normalizedLookup.platformApiUrl ?? credentials.platformApiUrl);
1729
- const email = normalizeEmail$2(normalizedLookup.email ?? credentials.user?.email ?? "");
1730
- if (!email) throw new Error("Forgeway credentials require a user email before they can be stored.");
1731
- const key = accountKey(platformApiUrl, email);
1732
- const store = await readAccountStore();
1733
- store.accounts = {
1734
- ...store.accounts,
1735
- [key]: {
1736
- ...credentials,
1737
- platformApiUrl
1738
- }
1739
- };
1740
- store.lastAccountKey = key;
1741
- await writeAccountStore(store);
1742
- }
1743
- async function listForgewayCredentials(platformApiUrl) {
1744
- const lookup = platformApiUrl ? { platformApiUrl } : {};
1745
- const store = await readAccountStore();
1746
- return Object.values(store.accounts ?? {}).filter((credentials) => accountMatches(credentials, lookup));
1747
- }
1748
- function shadowGrantKey(platformApiUrl, placeId) {
1749
- return `${platformApiUrl.replace(TRAILING_SLASH_PATTERN$2, "")}#${placeId ?? "__unbound__"}`;
1750
- }
1751
- async function readForgewayShadowGrant(platformApiUrl, placeId, cwd) {
1752
- const store = await readStore(cwd);
1753
- if (!store.shadowGrants) return null;
1754
- if (placeId) return store.shadowGrants[shadowGrantKey(platformApiUrl, placeId)] ?? null;
1755
- const lastKey = store.lastShadowGrantKey;
1756
- if (lastKey && store.shadowGrants[lastKey]?.platformApiUrl === platformApiUrl) return store.shadowGrants[lastKey];
1757
- return Object.values(store.shadowGrants).find((grant) => grant.platformApiUrl === platformApiUrl) ?? null;
1758
- }
1759
- async function writeForgewayShadowGrant(grant, cwd) {
1760
- const store = await readStore(cwd);
1761
- const key = shadowGrantKey(grant.platformApiUrl, grant.placeId);
1762
- store.shadowGrants = {
1763
- ...store.shadowGrants,
1764
- [key]: grant
1765
- };
1766
- store.lastShadowGrantKey = key;
1767
- await writeStore(store, cwd);
1768
- }
1769
-
1770
2184
  //#endregion
1771
2185
  //#region src/cli/commands/deploy/targets/forgeway.ts
1772
2186
  const DEFAULT_DINEWAY_API_BASE_URL$1 = "https://api.dineway.ai";
@@ -1790,7 +2204,6 @@ const DINEWAY_PACKAGE_NAME = "dineway";
1790
2204
  const SEMVER_VERSION_PATTERN = /^\d+\.\d+\.\d+(?:[-+].*)?$/;
1791
2205
  const LOCAL_PACKAGE_SPEC_PATTERN = /^(?:workspace|file|link|portal):/;
1792
2206
  const SHADOW_EMAIL_PATTERN$1 = /^shadow_[a-f0-9]{16}@dineway\.ai$/i;
1793
- const OTP_PATTERN = /^\d{6}$/;
1794
2207
  const FOOD_TYPES = new Set([
1795
2208
  "restaurant",
1796
2209
  "cafe",
@@ -1925,11 +2338,6 @@ async function parseErrorResponse(response) {
1925
2338
  function normalizeEmail$1(email) {
1926
2339
  return email.trim().toLowerCase();
1927
2340
  }
1928
- function normalizeOtp(otp) {
1929
- const value = otp.trim();
1930
- if (!OTP_PATTERN.test(value)) throw new Error("Forgeway email verification OTP must be a 6-digit numeric code.");
1931
- return value;
1932
- }
1933
2341
  function isShadowEmail$1(email) {
1934
2342
  return Boolean(email && SHADOW_EMAIL_PATTERN$1.test(email));
1935
2343
  }
@@ -1948,8 +2356,7 @@ async function refreshFormalAccessToken(context, deps) {
1948
2356
  platformApiUrl: context.platformApiUrl,
1949
2357
  accessToken: payload.accessToken,
1950
2358
  refreshToken: payload.refreshToken ?? context.refreshToken,
1951
- ...user ? { user } : {},
1952
- source: "shadow-email-upgrade"
2359
+ ...user ? { user } : {}
1953
2360
  };
1954
2361
  context.accessToken = updated.accessToken;
1955
2362
  context.refreshToken = updated.refreshToken;
@@ -1961,30 +2368,6 @@ async function refreshFormalAccessToken(context, deps) {
1961
2368
  });
1962
2369
  return payload.accessToken;
1963
2370
  }
1964
- async function refreshShadowAccessToken(context, deps) {
1965
- if (!context.refreshToken) throw new Error("Dineway shadow deploy grant is missing its refresh token.");
1966
- const response = await forgewayRequest(`${context.platformApiUrl}/api/auth/refresh?client_type=server`, {
1967
- method: "POST",
1968
- headers: { "Content-Type": "application/json" },
1969
- body: JSON.stringify({ refreshToken: context.refreshToken })
1970
- }, deps);
1971
- if (!response.ok) throw new Error("Failed to refresh Dineway shadow deploy grant. Run dineway deploy again.");
1972
- const payload = await response.json();
1973
- if (!payload.accessToken || !payload.refreshToken) throw new Error("Dineway shadow refresh response was missing tokens.");
1974
- context.accessToken = payload.accessToken;
1975
- context.refreshToken = payload.refreshToken;
1976
- await (deps.writeShadowGrant ?? writeForgewayShadowGrant)({
1977
- platformApiUrl: context.platformApiUrl,
1978
- placeId: context.placeId,
1979
- accessToken: payload.accessToken,
1980
- refreshToken: payload.refreshToken,
1981
- restaurantName: context.restaurantName,
1982
- city: context.city,
1983
- user: payload.user ? normalizeForgewayUser$1(payload.user) : void 0,
1984
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
1985
- }, context.projectDir);
1986
- return payload.accessToken;
1987
- }
1988
2371
  async function promptText(question, initialValue, deps) {
1989
2372
  if (deps.promptText) return await deps.promptText(question, initialValue);
1990
2373
  if (!process.stdin.isTTY) return "";
@@ -2027,14 +2410,14 @@ function isDinewayDependencySpecCompatible(dependencySpec, cliVersion) {
2027
2410
  if (LOCAL_PACKAGE_SPEC_PATTERN.test(spec)) return true;
2028
2411
  return spec.includes(cliVersion);
2029
2412
  }
2030
- async function assertProjectDinewayRuntimeCompatible(cwd, cliVersion = VERSION) {
2413
+ async function warnProjectDinewayRuntimeMismatch(cwd, cliVersion = VERSION) {
2031
2414
  if (!SEMVER_VERSION_PATTERN.test(cliVersion)) return;
2032
2415
  const pkg = await readProjectPackage(cwd);
2033
2416
  if (!pkg) return;
2034
2417
  const dependencySpec = getDependencySpec(pkg, DINEWAY_PACKAGE_NAME);
2035
2418
  if (!dependencySpec) return;
2036
2419
  if (isDinewayDependencySpecCompatible(dependencySpec, cliVersion)) return;
2037
- throw new Error(`Forgeway deploy requires the deployed Dineway runtime to match the deploy CLI because the CLI initializes the managed database before the site starts. The CLI is ${DINEWAY_PACKAGE_NAME}@${cliVersion}, but package.json declares ${DINEWAY_PACKAGE_NAME}: ${JSON.stringify(dependencySpec)}. Update package.json and reinstall with your package manager, for example: ${DINEWAY_PACKAGE_NAME}@^${cliVersion}. To deploy with the current manifest instead, run the matching CLI version.`);
2420
+ consola.warn(`Forgeway deploy finds that the package.json dineway runtime version does not match the deploy CLI. The CLI initializes the managed database before the site starts, so a mismatch can cause later migration or startup failures. The CLI is ${DINEWAY_PACKAGE_NAME}@${cliVersion}, but package.json declares ${DINEWAY_PACKAGE_NAME}: ${JSON.stringify(dependencySpec)}. If database migration fails, update package.json and reinstall with your package manager, for example: ${DINEWAY_PACKAGE_NAME}@^${cliVersion}. To keep deploying the current manifest, run the matching CLI version instead.`);
2038
2421
  }
2039
2422
  function explicitPublisherEmail(options) {
2040
2423
  return options.email ?? getEnv("DINEWAY_EMAIL") ?? getEnv("FORGEWAY_EMAIL");
@@ -2047,12 +2430,6 @@ function validatePublisherEmail(rawEmail) {
2047
2430
  if (!email || isShadowEmail$1(email)) throw new Error("Dineway account email must be a real owner email, not a shadow user email.");
2048
2431
  return email;
2049
2432
  }
2050
- async function resolveForgewayAccountEmail(options, saved, deps, preferredEmail) {
2051
- const suppliedEmail = options.email ?? getEnv("DINEWAY_EMAIL") ?? getEnv("FORGEWAY_EMAIL");
2052
- const savedEmail = savedPublisherEmail(saved);
2053
- if ((options.sendOtp || options.otp) && !suppliedEmail && !preferredEmail && !savedEmail) throw new Error("Forgeway OTP deploy requires --email or DINEWAY_EMAIL.");
2054
- return validatePublisherEmail(suppliedEmail ?? preferredEmail ?? savedEmail ?? await promptRequired("Dineway account email: ", void 0, deps, "Dineway account email is required. Pass --email or set DINEWAY_EMAIL."));
2055
- }
2056
2433
  function isStoredFormalCredentialForEmail(stored, email) {
2057
2434
  if (!stored?.accessToken || !stored.user) return false;
2058
2435
  if (email && normalizeEmail$1(stored.user.email) !== email) return false;
@@ -2065,95 +2442,6 @@ function assertVerifiedFormalAccountUser(user, expectedEmail) {
2065
2442
  if (expectedEmail && normalizeEmail$1(user.email) !== normalizeEmail$1(expectedEmail)) throw new Error("Forgeway refresh returned credentials for a different email.");
2066
2443
  return user;
2067
2444
  }
2068
- async function shadowUpgradeFetch(context, path, deps, options) {
2069
- const request = async (accessToken) => await forgewayRequest(`${context.platformApiUrl}${path}`, {
2070
- ...options,
2071
- headers: {
2072
- "Content-Type": "application/json",
2073
- Authorization: `Bearer ${accessToken}`,
2074
- ...options.headers
2075
- }
2076
- }, deps);
2077
- if (!context.accessToken) throw new Error("Dineway shadow deploy grant is missing its access token.");
2078
- let response = await request(context.accessToken);
2079
- if (response.status === 401) response = await request(await refreshShadowAccessToken(context, deps));
2080
- if (!response.ok) throw new ForgewayApiError(await parseErrorResponse(response), response.status);
2081
- return await response.json();
2082
- }
2083
- async function startShadowEmailUpgrade(context, email, deps) {
2084
- const payload = await shadowUpgradeFetch(context, "/api/auth/users/shadow/upgrade/email/start", deps, {
2085
- method: "POST",
2086
- body: JSON.stringify({ email })
2087
- });
2088
- if (payload.email && normalizeEmail$1(payload.email) !== email) throw new Error("Forgeway email verification response returned a different email.");
2089
- return payload;
2090
- }
2091
- async function verifyShadowEmailUpgrade(context, email, otp, deps) {
2092
- const payload = await shadowUpgradeFetch(context, "/api/auth/users/shadow/upgrade/email/verify", deps, {
2093
- method: "POST",
2094
- body: JSON.stringify({
2095
- email,
2096
- otp
2097
- })
2098
- });
2099
- if (!payload.accessToken || !payload.refreshToken || !payload.user) throw new Error("Forgeway email upgrade response was missing credentials.");
2100
- const user = normalizeForgewayUser$1(payload.user);
2101
- if (normalizeEmail$1(user.email) !== email) throw new Error("Forgeway email upgrade returned credentials for a different email.");
2102
- if (user.emailVerified !== true || isShadowEmail$1(user.email)) throw new Error("Forgeway email upgrade did not return a verified formal account.");
2103
- return {
2104
- platformApiUrl: context.platformApiUrl,
2105
- accessToken: payload.accessToken,
2106
- refreshToken: payload.refreshToken,
2107
- user,
2108
- source: "shadow-email-upgrade"
2109
- };
2110
- }
2111
- async function resolveFormalAccountCredentials(context, email, options, deps) {
2112
- const stored = await (deps.readCredentials ?? readForgewayCredentials)({
2113
- cwd: context.projectDir,
2114
- platformApiUrl: context.platformApiUrl,
2115
- email
2116
- });
2117
- if (!options.sendOtp && !options.otp && isStoredFormalCredentialForEmail(stored, email)) return {
2118
- status: "verified",
2119
- credentials: {
2120
- ...stored,
2121
- platformApiUrl: context.platformApiUrl
2122
- }
2123
- };
2124
- if (options.sendOtp) {
2125
- const response = await startShadowEmailUpgrade(context, email, deps);
2126
- return {
2127
- status: "otp-sent",
2128
- email: response.email ? normalizeEmail$1(response.email) : email,
2129
- expiresAt: response.expiresAt
2130
- };
2131
- }
2132
- if (options.otp) {
2133
- const credentials = await verifyShadowEmailUpgrade(context, email, normalizeOtp(options.otp), deps);
2134
- await (deps.writeCredentials ?? writeForgewayCredentials)(credentials, {
2135
- cwd: context.projectDir,
2136
- platformApiUrl: context.platformApiUrl,
2137
- email
2138
- });
2139
- return {
2140
- status: "verified",
2141
- credentials
2142
- };
2143
- }
2144
- await startShadowEmailUpgrade(context, email, deps);
2145
- consola.info(`Sent Forgeway email verification code to ${email}`);
2146
- const credentials = await verifyShadowEmailUpgrade(context, email, await promptRequired("Email verification code: ", void 0, deps, "Email verification code is required."), deps);
2147
- await (deps.writeCredentials ?? writeForgewayCredentials)(credentials, {
2148
- cwd: context.projectDir,
2149
- platformApiUrl: context.platformApiUrl,
2150
- email
2151
- });
2152
- return {
2153
- status: "verified",
2154
- credentials
2155
- };
2156
- }
2157
2445
  async function readCachedPublisherCredentials(cwd, platformApiUrl, email, deps) {
2158
2446
  const credentials = await (deps.readCredentials ?? readForgewayCredentials)({
2159
2447
  cwd,
@@ -2218,7 +2506,6 @@ async function resolveFormalProjectContext(cwd, options, deps) {
2218
2506
  const context = {
2219
2507
  projectDir: cwd,
2220
2508
  platformApiUrl,
2221
- authKind: "formal-account",
2222
2509
  accessToken: account.credentials.accessToken,
2223
2510
  refreshToken: account.credentials.refreshToken,
2224
2511
  user,
@@ -2232,7 +2519,7 @@ async function resolveFormalProjectContext(cwd, options, deps) {
2232
2519
  city: options.city
2233
2520
  };
2234
2521
  if (!context.placeId) {
2235
- const resolvedRestaurant = await resolveShadowRestaurantInfo(options, deps);
2522
+ const resolvedRestaurant = await resolveRequiredRestaurantInfo(options, deps);
2236
2523
  restaurant = resolvedRestaurant;
2237
2524
  context.placeId = await resolvePlaceIdWithFormalSearch({
2238
2525
  context,
@@ -2248,100 +2535,11 @@ async function resolveFormalProjectContext(cwd, options, deps) {
2248
2535
  restaurant
2249
2536
  };
2250
2537
  }
2251
- async function resolveShadowProjectContext(cwd, options, deps, preferredEmail) {
2252
- const saved = await readSavedForgewayMetadata(cwd);
2253
- const platformApiUrl = resolvePlatformApiUrl(saved.platformApiUrl);
2254
- const savedPlaceId = options.placeId ?? getEnv("DINEWAY_PLACE_ID") ?? (typeof saved.placeId === "string" ? saved.placeId : void 0);
2255
- let grant = await (deps.readShadowGrant ?? readForgewayShadowGrant)(platformApiUrl, savedPlaceId, cwd);
2256
- let restaurant;
2257
- if (!grant) {
2258
- const shadowRestaurant = await resolveShadowRestaurantInfo(options, deps);
2259
- restaurant = shadowRestaurant;
2260
- if (options.dryRun) throw new Error("Forgeway deploy needs a Dineway shadow deploy grant. Run without --dry-run to create it.");
2261
- grant = await createShadowGrant({
2262
- platformApiUrl,
2263
- placeId: savedPlaceId,
2264
- restaurantName: shadowRestaurant.name,
2265
- city: shadowRestaurant.city,
2266
- cwd,
2267
- deps
2268
- });
2269
- } else restaurant = {
2270
- name: options.restaurantName ?? grant.restaurantName,
2271
- city: options.city ?? grant.city
2272
- };
2273
- if (!grant.placeId) {
2274
- const shadowRestaurant = restaurant?.name && restaurant.city ? {
2275
- name: restaurant.name,
2276
- city: restaurant.city
2277
- } : await resolveShadowRestaurantInfo(options, deps);
2278
- restaurant = shadowRestaurant;
2279
- grant = savedPlaceId ? await bindShadowGrantPlace({
2280
- platformApiUrl,
2281
- grant,
2282
- placeId: savedPlaceId,
2283
- restaurant: shadowRestaurant,
2284
- cwd,
2285
- deps
2286
- }) : await resolvePlaceIdWithShadowSearch({
2287
- platformApiUrl,
2288
- grant,
2289
- restaurant: shadowRestaurant,
2290
- cwd,
2291
- deps
2292
- });
2293
- }
2294
- if (!grant.placeId) throw new Error("Could not resolve a Dineway place id for Forgeway deploy.");
2295
- const shadowContext = {
2296
- projectDir: cwd,
2297
- platformApiUrl,
2298
- authKind: "shadow-grant",
2299
- accessToken: grant.accessToken,
2300
- refreshToken: grant.refreshToken,
2301
- user: grant.user,
2302
- ossHost: platformApiUrl,
2303
- placeId: grant.placeId,
2304
- restaurantName: restaurant.name,
2305
- city: restaurant.city
2306
- };
2307
- const credentialsResult = await resolveFormalAccountCredentials(shadowContext, await resolveForgewayAccountEmail(options, saved, deps, preferredEmail), options, deps);
2308
- if (credentialsResult.status === "otp-sent") return credentialsResult;
2309
- const { credentials } = credentialsResult;
2310
- return {
2311
- status: "ready",
2312
- context: {
2313
- ...shadowContext,
2314
- authKind: "formal-account",
2315
- accessToken: credentials.accessToken,
2316
- refreshToken: credentials.refreshToken,
2317
- user: credentials.user,
2318
- ossHost: platformApiUrl
2319
- },
2320
- restaurant
2321
- };
2322
- }
2323
2538
  async function resolveProjectContext(cwd, options, deps) {
2324
- let preferredEmail;
2325
- if (!options.sendOtp && !options.otp) {
2326
- const formal = await resolveFormalProjectContext(cwd, options, deps);
2327
- if (formal.status !== "missing") return formal;
2328
- preferredEmail = formal.email;
2329
- }
2330
- return await resolveShadowProjectContext(cwd, options, deps, preferredEmail);
2331
- }
2332
- async function createShadowUser(platformApiUrl, placeId, deps) {
2333
- const response = await forgewayRequest(`${platformApiUrl}/api/auth/users/shadow`, {
2334
- method: "POST",
2335
- headers: { "Content-Type": "application/json" },
2336
- body: JSON.stringify({
2337
- ...placeId ? { placeId } : {},
2338
- language: "en"
2339
- })
2340
- }, deps);
2341
- if (!response.ok) throw new Error(await parseErrorResponse(response));
2342
- const payload = await response.json();
2343
- if (!payload.accessToken || !payload.refreshToken) throw new Error("Dineway shadow user response was missing tokens.");
2344
- return payload;
2539
+ const formal = await resolveFormalProjectContext(cwd, options, deps);
2540
+ if (formal.status !== "missing") return formal;
2541
+ if (formal.email) throw new Error(`No verified Dineway account credentials were found for ${formal.email}. Run: dineway account login --email ${formal.email}`);
2542
+ throw new Error("No verified Dineway account credentials were found. Run: dineway account login");
2345
2543
  }
2346
2544
  function isRecord(value) {
2347
2545
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -2522,80 +2720,6 @@ function extractPlaceCandidates(payload) {
2522
2720
  if (!Array.isArray(places)) throw new Error("Dineway place search response did not include places/results.");
2523
2721
  return places.filter(isRecord);
2524
2722
  }
2525
- function shadowContextFromGrant(cwd, platformApiUrl, grant, restaurant) {
2526
- return {
2527
- projectDir: cwd,
2528
- platformApiUrl,
2529
- authKind: "shadow-grant",
2530
- accessToken: grant.accessToken,
2531
- refreshToken: grant.refreshToken,
2532
- user: grant.user,
2533
- ossHost: platformApiUrl,
2534
- placeId: grant.placeId,
2535
- restaurantName: restaurant?.name ?? grant.restaurantName,
2536
- city: restaurant?.city ?? grant.city
2537
- };
2538
- }
2539
- function grantFromShadowContext(context, grant, overrides = {}) {
2540
- return {
2541
- ...grant,
2542
- platformApiUrl: context.platformApiUrl,
2543
- accessToken: context.accessToken ?? grant.accessToken,
2544
- refreshToken: context.refreshToken ?? grant.refreshToken,
2545
- placeId: context.placeId ?? grant.placeId,
2546
- restaurantName: context.restaurantName ?? grant.restaurantName,
2547
- city: context.city ?? grant.city,
2548
- user: context.user ?? grant.user,
2549
- updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
2550
- ...overrides
2551
- };
2552
- }
2553
- async function searchPlacesWithShadowGrant(options) {
2554
- const context = shadowContextFromGrant(options.cwd, options.platformApiUrl, options.grant, options.restaurant);
2555
- const payload = await shadowUpgradeFetch(context, "/api/places/search", options.deps, {
2556
- method: "POST",
2557
- body: JSON.stringify({ textQuery: `${options.restaurant.name} in ${options.restaurant.city}` })
2558
- });
2559
- return {
2560
- grant: grantFromShadowContext(context, options.grant),
2561
- candidates: extractPlaceCandidates(payload)
2562
- };
2563
- }
2564
- async function bindShadowGrantPlace(options) {
2565
- const context = shadowContextFromGrant(options.cwd, options.platformApiUrl, options.grant, options.restaurant);
2566
- const payload = await shadowUpgradeFetch(context, "/api/auth/users/shadow/place", options.deps, {
2567
- method: "POST",
2568
- body: JSON.stringify({
2569
- placeId: options.placeId,
2570
- language: "en"
2571
- })
2572
- });
2573
- const grant = grantFromShadowContext(context, options.grant, {
2574
- placeId: options.placeId,
2575
- accessToken: payload.accessToken ?? context.accessToken ?? options.grant.accessToken,
2576
- refreshToken: payload.refreshToken ?? context.refreshToken ?? options.grant.refreshToken,
2577
- restaurantName: options.restaurant.name,
2578
- city: options.restaurant.city,
2579
- user: payload.user ? normalizeForgewayUser$1(payload.user) : context.user ?? options.grant.user
2580
- });
2581
- await (options.deps.writeShadowGrant ?? writeForgewayShadowGrant)(grant, options.cwd);
2582
- return grant;
2583
- }
2584
- async function resolvePlaceIdWithShadowSearch(options) {
2585
- const { grant, candidates } = await searchPlacesWithShadowGrant(options);
2586
- if (candidates.length === 0) throw new Error(`Dineway place search returned no candidates for "${options.restaurant.name} in ${options.restaurant.city}".`);
2587
- const selected = selectPlaceCandidate(candidates, {
2588
- name: options.restaurant.name,
2589
- city: options.restaurant.city
2590
- });
2591
- const finalPlaceId = selected ? candidatePlaceId(selected.candidate) : "";
2592
- if (!PLACE_ID_PATTERN.test(finalPlaceId)) throw new Error("Could not resolve a valid Dineway place id for Forgeway deploy.");
2593
- return await bindShadowGrantPlace({
2594
- ...options,
2595
- grant,
2596
- placeId: finalPlaceId
2597
- });
2598
- }
2599
2723
  async function resolvePlaceIdWithFormalSearch(options) {
2600
2724
  const candidates = extractPlaceCandidates(await ossFetch(options.context, "/api/places/search", options.deps, {
2601
2725
  method: "POST",
@@ -2610,22 +2734,6 @@ async function resolvePlaceIdWithFormalSearch(options) {
2610
2734
  if (!PLACE_ID_PATTERN.test(finalPlaceId)) throw new Error("Could not resolve a valid Dineway place id for Forgeway deploy.");
2611
2735
  return finalPlaceId;
2612
2736
  }
2613
- async function createShadowGrant(options) {
2614
- if (options.placeId && !PLACE_ID_PATTERN.test(options.placeId)) throw new Error("Could not resolve a valid Dineway place id for Forgeway deploy.");
2615
- const auth = await createShadowUser(options.platformApiUrl, options.placeId, options.deps);
2616
- const grant = {
2617
- platformApiUrl: options.platformApiUrl,
2618
- ...options.placeId ? { placeId: options.placeId } : {},
2619
- accessToken: auth.accessToken,
2620
- refreshToken: auth.refreshToken,
2621
- restaurantName: options.restaurantName,
2622
- city: options.city,
2623
- user: auth.user ? normalizeForgewayUser$1(auth.user) : void 0,
2624
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
2625
- };
2626
- await (options.deps.writeShadowGrant ?? writeForgewayShadowGrant)(grant, options.cwd);
2627
- return grant;
2628
- }
2629
2737
  async function ossFetch(context, path, deps, options = {}) {
2630
2738
  const request = async (token) => await forgewayRequest(`${context.ossHost.replace(TRAILING_SLASH_PATTERN$1, "")}${path}`, {
2631
2739
  ...options,
@@ -2638,7 +2746,7 @@ async function ossFetch(context, path, deps, options = {}) {
2638
2746
  const token = context.accessToken;
2639
2747
  if (!token) throw new Error("Forgeway deploy context is missing an authorization token.");
2640
2748
  let response = await request(token);
2641
- if (response.status === 401) response = await request(context.authKind === "formal-account" ? await refreshFormalAccessToken(context, deps) : await refreshShadowAccessToken(context, deps));
2749
+ if (response.status === 401) response = await request(await refreshFormalAccessToken(context, deps));
2642
2750
  if (!response.ok) throw new ForgewayApiError(await parseErrorResponse(response), response.status);
2643
2751
  return await response.json();
2644
2752
  }
@@ -2689,7 +2797,7 @@ async function resolveRestaurantInfo(options, seedPath, deps, requireForSlug, us
2689
2797
  city
2690
2798
  };
2691
2799
  }
2692
- async function resolveShadowRestaurantInfo(options, deps) {
2800
+ async function resolveRequiredRestaurantInfo(options, deps) {
2693
2801
  return {
2694
2802
  name: options.restaurantName ?? await promptRequired("Restaurant name: ", void 0, deps, "Restaurant name is required. Pass --restaurant-name."),
2695
2803
  city: options.city ?? await promptRequired("City: ", void 0, deps, "City is required. Pass --city.")
@@ -2821,6 +2929,7 @@ async function runDinewayInitialization(options) {
2821
2929
  seedResult = await applySeed(db, seed, {
2822
2930
  includeContent: true,
2823
2931
  onConflict: "skip",
2932
+ repairSchema: true,
2824
2933
  storage: new LocalStorage({
2825
2934
  directory: uploadsDir,
2826
2935
  baseUrl: "/_dineway/api/media/file"
@@ -3093,27 +3202,16 @@ function formatDinewayAdminBootstrapMessage(bootstrap) {
3093
3202
  "CLI example: npx dineway whoami"
3094
3203
  ].join("\n");
3095
3204
  }
3096
- function formatForgewayOtpSentMessage(email, expiresAt) {
3097
- const lines = [
3098
- `Sent Forgeway email verification code to ${email}.`,
3099
- "Run the Forgeway deploy command again with the same restaurant/site options and --otp <code>.",
3100
- `Example: npx dineway deploy forgeway --email ${email} --otp 123456`
3101
- ];
3102
- if (expiresAt) lines.splice(1, 0, `Code expires at ${expiresAt}.`);
3103
- return lines.join("\n");
3104
- }
3105
3205
  async function deployForgeway(cwd, options, deps = {}) {
3106
3206
  if (options.dryRun) return { message: "[dry-run] Would resolve Forgeway project, create/reuse site, bind database, initialize Dineway, upload files, and start deployment." };
3107
3207
  const sourceDir = resolve(cwd);
3108
3208
  if (!(await stat(sourceDir).catch(() => null))?.isDirectory()) throw new Error(`"${sourceDir}" is not a valid directory.`);
3109
3209
  if (EXCLUDE_PATTERNS.includes(basename(sourceDir))) throw new Error(`"${basename(sourceDir)}" is an excluded directory and cannot be deployed.`);
3110
3210
  const database = parseDatabaseMode(options.database);
3111
- if (database !== "none") await assertProjectDinewayRuntimeCompatible(cwd, deps.dinewayVersion ?? VERSION);
3211
+ if (database !== "none") await warnProjectDinewayRuntimeMismatch(cwd, deps.dinewayVersion ?? VERSION);
3112
3212
  await ensureProjectGitignoreDinewayLocalState(cwd);
3113
3213
  const verbose = isVerboseDeploy(options);
3114
- const project = await resolveProjectContext(cwd, options, deps);
3115
- if (project.status === "otp-sent") return { message: formatForgewayOtpSentMessage(project.email, project.expiresAt) };
3116
- const { context, restaurant } = project;
3214
+ const { context, restaurant } = await resolveProjectContext(cwd, options, deps);
3117
3215
  const seedPath = options.skipSeed ? null : await resolveSeedPath$1(cwd, options.seed);
3118
3216
  if (options.skipSeed) consola.info("Skipping seed initialization by request");
3119
3217
  await ensureRestaurantClaim(context, restaurant, deps);
@@ -3173,7 +3271,6 @@ const forgewayTarget = {
3173
3271
  remoteBuild: true,
3174
3272
  supportLevel: "stable",
3175
3273
  async generateConfig(cwd, options) {
3176
- if (options.sendOtp) return [];
3177
3274
  return await configureAstroDeployAdapter(cwd, "vercel", options.dryRun);
3178
3275
  },
3179
3276
  async deploy(cwd, options) {
@@ -3705,16 +3802,6 @@ const deployCommand = defineCommand({
3705
3802
  description: "Dineway account email for deploy authorization",
3706
3803
  required: false
3707
3804
  },
3708
- "send-otp": {
3709
- type: "boolean",
3710
- description: "Send a Forgeway email verification code and exit without prompting or deploying",
3711
- default: false
3712
- },
3713
- otp: {
3714
- type: "string",
3715
- description: "Forgeway email verification code for non-interactive deploy authorization",
3716
- required: false
3717
- },
3718
3805
  "restaurant-name": {
3719
3806
  type: "string",
3720
3807
  description: "Restaurant name for first Forgeway site creation",
@@ -3762,8 +3849,6 @@ const deployCommand = defineCommand({
3762
3849
  site: args.site,
3763
3850
  placeId: args["place-id"],
3764
3851
  email: args.email,
3765
- sendOtp: args["send-otp"],
3766
- otp: args.otp,
3767
3852
  restaurantName: args["restaurant-name"],
3768
3853
  city: args.city,
3769
3854
  database: args.database,
@@ -3772,8 +3857,6 @@ const deployCommand = defineCommand({
3772
3857
  forceDbInit: args["force-db-init"],
3773
3858
  verbose: args.verbose
3774
3859
  };
3775
- if ((options.sendOtp || options.otp) && target.name !== "forgeway") throw new Error("--send-otp and --otp are only supported for Forgeway deploys.");
3776
- if (options.sendOtp && options.otp) throw new Error("Use either --send-otp or --otp, not both.");
3777
3860
  consola.start(`Preparing ${target.label} deploy`);
3778
3861
  await ensureTargetCli(target, cwd, {
3779
3862
  yes: options.yes,
@@ -3807,7 +3890,21 @@ const deployCommand = defineCommand({
3807
3890
  consola.info("[dry-run] Would ensure Dineway local state entries in .gitignore");
3808
3891
  consola.info(`[dry-run] Would save .dineway/deploy.json target=${target.name}`);
3809
3892
  }
3810
- const result = await target.deploy(cwd, options);
3893
+ const result = await target.deploy(cwd, options).catch(async (error) => {
3894
+ if (await handleCliPaywall({
3895
+ error,
3896
+ resource: `deploy:${target.name}`,
3897
+ platformApiUrl: process.env.DINEWAY_FORGEWAY_API_URL,
3898
+ webUrl: process.env.DINEWAY_WEB_URL,
3899
+ interactive: process.stdin.isTTY && !options.yes,
3900
+ context: {
3901
+ target: target.name,
3902
+ site: options.site,
3903
+ placeId: options.placeId
3904
+ }
3905
+ })) process.exit(2);
3906
+ throw error;
3907
+ });
3811
3908
  if (result.url) consola.success(result.url);
3812
3909
  consola.success(result.message);
3813
3910
  }
@@ -4209,7 +4306,8 @@ async function exportSeed(db, withContent) {
4209
4306
  };
4210
4307
  seed.settings = await exportSettings(db);
4211
4308
  seed.collections = await exportCollections(db);
4212
- const i18nEnabled = await detectI18nEnabled(db, seed.collections);
4309
+ const { i18nEnabled, defaultLocale } = await detectLocaleInfo(db, seed.collections);
4310
+ if (defaultLocale) seed.defaultLocale = defaultLocale;
4213
4311
  seed.taxonomies = await exportTaxonomies(db, i18nEnabled);
4214
4312
  seed.menus = await exportMenus(db, i18nEnabled);
4215
4313
  seed.widgetAreas = await exportWidgetAreas(db);
@@ -4251,34 +4349,43 @@ async function exportBylines(db) {
4251
4349
  };
4252
4350
  }
4253
4351
  /**
4254
- * Determine whether export should preserve locale-suffixed seed ids.
4352
+ * Determine locale-awareness and the data's default locale for the export.
4255
4353
  *
4256
4354
  * Runtime i18n config is initialized by middleware, but `dineway export-seed`
4257
4355
  * runs in a CLI process. When the runtime flag is unset, derive multi-locale
4258
4356
  * status from stored rows instead: a project is multi-locale when any
4259
4357
  * i18n-aware table contains more than one distinct locale.
4358
+ *
4359
+ * `defaultLocale` self-describes single-locale data so a non-`en` project
4360
+ * survives an export-seed -> seed round-trip outside the Astro runtime.
4260
4361
  */
4261
- async function detectI18nEnabled(db, collections) {
4262
- if (isI18nEnabled()) return true;
4362
+ async function detectLocaleInfo(db, collections) {
4363
+ const config = getI18nConfig();
4364
+ if (isI18nEnabled() && config) return {
4365
+ i18nEnabled: true,
4366
+ defaultLocale: config.defaultLocale
4367
+ };
4263
4368
  const locales = /* @__PURE__ */ new Set();
4264
4369
  const collectDistinctLocales = async (tableRef) => {
4265
4370
  const result = await sql`
4266
4371
  SELECT DISTINCT locale FROM ${tableRef}
4267
4372
  `.execute(db);
4268
4373
  for (const row of result.rows) if (row.locale) locales.add(row.locale);
4269
- return locales.size > 1;
4270
4374
  };
4271
- if (await collectDistinctLocales(sql.ref("_dineway_taxonomy_defs"))) return true;
4272
- if (await collectDistinctLocales(sql.ref("_dineway_menus"))) return true;
4375
+ await collectDistinctLocales(sql.ref("_dineway_taxonomy_defs"));
4376
+ await collectDistinctLocales(sql.ref("_dineway_menus"));
4273
4377
  for (const collection of collections) {
4274
4378
  validateIdentifier(collection.slug, "collection slug");
4275
4379
  try {
4276
- if (await collectDistinctLocales(sql.ref(`ec_${collection.slug}`))) return true;
4380
+ await collectDistinctLocales(sql.ref(`ec_${collection.slug}`));
4277
4381
  } catch (error) {
4278
4382
  if (!isMissingTableError(error)) throw error;
4279
4383
  }
4280
4384
  }
4281
- return false;
4385
+ return {
4386
+ i18nEnabled: locales.size > 1,
4387
+ defaultLocale: locales.size === 1 ? [...locales][0] : void 0
4388
+ };
4282
4389
  }
4283
4390
  /**
4284
4391
  * Export site settings
@@ -7293,13 +7400,15 @@ var ForgewaySeoGatewayClient = class {
7293
7400
  }
7294
7401
  async request(path, body, init) {
7295
7402
  const credentials = await this.refreshAccessToken(await this.loadCredentials());
7403
+ const method = init?.method ?? "POST";
7296
7404
  const response = await this.fetchImpl(`${credentials.platformApiUrl}${path}`, {
7297
- method: init?.method ?? "POST",
7405
+ method,
7298
7406
  headers: {
7299
7407
  Authorization: `Bearer ${credentials.accessToken}`,
7300
- "Content-Type": "application/json"
7408
+ "Content-Type": "application/json",
7409
+ "Idempotency-Key": init?.idempotencyKey ?? randomUUID()
7301
7410
  },
7302
- body: init?.method === "GET" ? void 0 : JSON.stringify(body ?? {})
7411
+ body: method === "GET" ? void 0 : JSON.stringify(body ?? {})
7303
7412
  });
7304
7413
  const payload = await parseJsonResponse(response);
7305
7414
  if (!response.ok) throw new ForgewaySeoApiError(errorMessage(payload, `Forgeway SEO request failed with status ${response.status}.`), response.status, payload);
@@ -7364,6 +7473,11 @@ async function runSeoRequest(args, path, body) {
7364
7473
  try {
7365
7474
  output(await new ForgewaySeoGatewayClient().request(path, body), args);
7366
7475
  } catch (error) {
7476
+ if (await handleCliPaywall({
7477
+ error,
7478
+ resource: path,
7479
+ context: { providerPath: path }
7480
+ })) process.exit(2);
7367
7481
  consola$1.error(error instanceof Error ? error.message : "Unknown error");
7368
7482
  process.exit(1);
7369
7483
  }
@@ -7506,6 +7620,11 @@ const firecrawlCommand = defineCommand({
7506
7620
  try {
7507
7621
  output(await new ForgewaySeoGatewayClient().request(`/api/firecrawl/crawl/${encodeURIComponent(crawlId)}`, void 0, { method: "GET" }), args);
7508
7622
  } catch (error) {
7623
+ if (await handleCliPaywall({
7624
+ error,
7625
+ resource: `/api/firecrawl/crawl/${crawlId}`,
7626
+ context: { providerPath: `/api/firecrawl/crawl/${crawlId}` }
7627
+ })) process.exit(2);
7509
7628
  consola$1.error(error instanceof Error ? error.message : "Unknown error");
7510
7629
  process.exit(1);
7511
7630
  }
@@ -7961,6 +8080,7 @@ runMain(defineCommand({
7961
8080
  },
7962
8081
  subCommands: {
7963
8082
  init: initCommand,
8083
+ account: accountCommand,
7964
8084
  types: typesCommand,
7965
8085
  dev: devCommand,
7966
8086
  deploy: deployCommand,