dineway 0.1.48 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (420) hide show
  1. package/dist/{activity-events-C9u37D5z.mjs → activity-events-y6eT8UW6.mjs} +6 -38
  2. package/dist/actor-CrObAPV0.mjs +37 -0
  3. package/dist/after-BfniwgIf.mjs +9 -0
  4. package/dist/{allowed-origins-DhipQNLb.mjs → allowed-origins-_oeyP6x-.mjs} +1 -1
  5. package/dist/api/route-utils.d.mts +10 -10
  6. package/dist/api/route-utils.mjs +17 -14
  7. package/dist/api/schemas/index.d.mts +2 -2
  8. package/dist/api/schemas/index.mjs +5 -4
  9. package/dist/{api-Eiy8_zVZ.mjs → api-ByrU2q-Z.mjs} +61 -37
  10. package/dist/{api-tokens-DtvdtIkm.mjs → api-tokens-CjVMQT-X.mjs} +6 -2
  11. package/dist/{apply-CX3no7XE.mjs → apply-bZswmZPm.mjs} +117 -77
  12. package/dist/astro/image-endpoint.d.mts +7 -0
  13. package/dist/astro/image-endpoint.mjs +54 -0
  14. package/dist/astro/index.d.mts +35 -11
  15. package/dist/astro/index.mjs +157 -23
  16. package/dist/astro/integration/shims/use-sync-external-store-with-selector.js +71 -0
  17. package/dist/astro/integration/shims/use-sync-external-store.js +1 -0
  18. package/dist/astro/middleware/auth.d.mts +10 -10
  19. package/dist/astro/middleware/auth.mjs +42 -24
  20. package/dist/astro/middleware/redirect.mjs +14 -5
  21. package/dist/astro/middleware/request-context.mjs +9 -6
  22. package/dist/astro/middleware/seed.d.mts +1 -1
  23. package/dist/astro/middleware/seed.mjs +2 -2
  24. package/dist/astro/middleware/setup.mjs +1 -1
  25. package/dist/astro/middleware.mjs +334 -193
  26. package/dist/astro/routes/admin.astro +6 -1
  27. package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +7 -6
  28. package/dist/astro/routes/api/admin/allowed-domains/index.mjs +7 -6
  29. package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +4 -4
  30. package/dist/astro/routes/api/admin/api-tokens/index.mjs +6 -6
  31. package/dist/astro/routes/api/admin/briefing.mjs +22 -18
  32. package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +4 -4
  33. package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +9 -8
  34. package/dist/astro/routes/api/admin/byline-fields/index.mjs +9 -8
  35. package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +9 -8
  36. package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +18 -15
  37. package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +18 -15
  38. package/dist/astro/routes/api/admin/bylines/index.mjs +18 -15
  39. package/dist/astro/routes/api/admin/comments/_id_/status.mjs +15 -13
  40. package/dist/astro/routes/api/admin/comments/_id_.mjs +7 -6
  41. package/dist/astro/routes/api/admin/comments/bulk.mjs +12 -10
  42. package/dist/astro/routes/api/admin/comments/counts.mjs +7 -6
  43. package/dist/astro/routes/api/admin/comments/index.mjs +12 -10
  44. package/dist/astro/routes/api/admin/context/_id_/history.mjs +27 -25
  45. package/dist/astro/routes/api/admin/context/_id_/index.mjs +27 -25
  46. package/dist/astro/routes/api/admin/context/_id_/review.mjs +32 -29
  47. package/dist/astro/routes/api/admin/context/_id_/supersede.mjs +32 -29
  48. package/dist/astro/routes/api/admin/context/diff.mjs +31 -28
  49. package/dist/astro/routes/api/admin/context/index.mjs +32 -29
  50. package/dist/astro/routes/api/admin/context/stale.mjs +31 -28
  51. package/dist/astro/routes/api/admin/hitl-requests/_id_/index.mjs +27 -25
  52. package/dist/astro/routes/api/admin/hitl-requests/_id_/resolve.mjs +31 -28
  53. package/dist/astro/routes/api/admin/hitl-requests/index.mjs +31 -28
  54. package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +28 -26
  55. package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +3 -3
  56. package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +6 -6
  57. package/dist/astro/routes/api/admin/oauth-clients/index.mjs +6 -6
  58. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +56 -52
  59. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +56 -52
  60. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +48 -44
  61. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +54 -50
  62. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +53 -49
  63. package/dist/astro/routes/api/admin/plugins/index.mjs +48 -44
  64. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +2 -2
  65. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +47 -43
  66. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +53 -49
  67. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +47 -43
  68. package/dist/astro/routes/api/admin/plugins/updates.mjs +47 -43
  69. package/dist/astro/routes/api/admin/review-requests/_id_/index.mjs +6 -6
  70. package/dist/astro/routes/api/admin/review-requests/_id_/resolve.mjs +32 -28
  71. package/dist/astro/routes/api/admin/review-requests/index.mjs +11 -10
  72. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +47 -43
  73. package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +2 -2
  74. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +47 -43
  75. package/dist/astro/routes/api/admin/users/_id_/disable.mjs +3 -3
  76. package/dist/astro/routes/api/admin/users/_id_/enable.mjs +2 -2
  77. package/dist/astro/routes/api/admin/users/_id_/index.mjs +8 -7
  78. package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +4 -4
  79. package/dist/astro/routes/api/admin/users/index.mjs +7 -6
  80. package/dist/astro/routes/api/auth/dev-bypass.mjs +4 -4
  81. package/dist/astro/routes/api/auth/invite/accept.mjs +2 -2
  82. package/dist/astro/routes/api/auth/invite/complete.mjs +12 -11
  83. package/dist/astro/routes/api/auth/invite/index.mjs +9 -8
  84. package/dist/astro/routes/api/auth/invite/register-options.mjs +11 -10
  85. package/dist/astro/routes/api/auth/logout.mjs +2 -2
  86. package/dist/astro/routes/api/auth/magic-link/send.mjs +11 -10
  87. package/dist/astro/routes/api/auth/magic-link/verify.mjs +3 -3
  88. package/dist/astro/routes/api/auth/me.mjs +10 -9
  89. package/dist/astro/routes/api/auth/mode.mjs +1 -1
  90. package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +3 -3
  91. package/dist/astro/routes/api/auth/oauth/_provider_.mjs +2 -2
  92. package/dist/astro/routes/api/auth/passkey/_id_.mjs +6 -5
  93. package/dist/astro/routes/api/auth/passkey/index.mjs +1 -1
  94. package/dist/astro/routes/api/auth/passkey/options.mjs +12 -11
  95. package/dist/astro/routes/api/auth/passkey/register/options.mjs +10 -9
  96. package/dist/astro/routes/api/auth/passkey/register/verify.mjs +11 -10
  97. package/dist/astro/routes/api/auth/passkey/verify.mjs +11 -10
  98. package/dist/astro/routes/api/auth/setup-token/index.mjs +6 -6
  99. package/dist/astro/routes/api/auth/setup-token/verify.mjs +2 -2
  100. package/dist/astro/routes/api/auth/signup/complete.mjs +12 -11
  101. package/dist/astro/routes/api/auth/signup/request.mjs +11 -10
  102. package/dist/astro/routes/api/auth/signup/verify.mjs +2 -2
  103. package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +16 -14
  104. package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.d.mts +8 -0
  105. package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +160 -0
  106. package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +2 -2
  107. package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +6 -6
  108. package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +6 -6
  109. package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +6 -6
  110. package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +12 -11
  111. package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +11 -10
  112. package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +6 -6
  113. package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +2 -2
  114. package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +11 -10
  115. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +17 -15
  116. package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +2 -2
  117. package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +6 -6
  118. package/dist/astro/routes/api/content/_collection_/_id_.mjs +11 -10
  119. package/dist/astro/routes/api/content/_collection_/authors.mjs +2 -2
  120. package/dist/astro/routes/api/content/_collection_/index.mjs +11 -10
  121. package/dist/astro/routes/api/content/_collection_/trash.mjs +7 -6
  122. package/dist/astro/routes/api/dashboard.mjs +10 -9
  123. package/dist/astro/routes/api/dev/emails.mjs +2 -2
  124. package/dist/astro/routes/api/health.mjs +1 -1
  125. package/dist/astro/routes/api/import/probe.d.mts +3 -3
  126. package/dist/astro/routes/api/import/probe.mjs +23 -11
  127. package/dist/astro/routes/api/import/wordpress/analyze.mjs +9 -6
  128. package/dist/astro/routes/api/import/wordpress/execute.d.mts +19 -1
  129. package/dist/astro/routes/api/import/wordpress/execute.mjs +85 -38
  130. package/dist/astro/routes/api/import/wordpress/media.d.mts +13 -1
  131. package/dist/astro/routes/api/import/wordpress/media.mjs +20 -14
  132. package/dist/astro/routes/api/import/wordpress/prepare.mjs +36 -33
  133. package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts +18 -1
  134. package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +121 -101
  135. package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
  136. package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +25 -13
  137. package/dist/astro/routes/api/import/wordpress-plugin/callback.mjs +1 -1
  138. package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +56 -2
  139. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +284 -56
  140. package/dist/astro/routes/api/manifest.mjs +14 -5
  141. package/dist/astro/routes/api/mcp.mjs +266 -70
  142. package/dist/astro/routes/api/media/_id_/confirm.mjs +39 -11
  143. package/dist/astro/routes/api/media/_id_.mjs +11 -7
  144. package/dist/astro/routes/api/media/file/_...key_.mjs +1 -1
  145. package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +2 -2
  146. package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +2 -2
  147. package/dist/astro/routes/api/media/providers/index.mjs +2 -2
  148. package/dist/astro/routes/api/media/upload-url.mjs +12 -11
  149. package/dist/astro/routes/api/media.mjs +28 -35
  150. package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +32 -29
  151. package/dist/astro/routes/api/menus/_name_/items.mjs +32 -29
  152. package/dist/astro/routes/api/menus/_name_/reorder.mjs +32 -29
  153. package/dist/astro/routes/api/menus/_name_/translations.mjs +32 -29
  154. package/dist/astro/routes/api/menus/_name_.mjs +32 -29
  155. package/dist/astro/routes/api/menus/index.mjs +32 -29
  156. package/dist/astro/routes/api/oauth/authorize.mjs +7 -7
  157. package/dist/astro/routes/api/oauth/device/authorize.mjs +6 -6
  158. package/dist/astro/routes/api/oauth/device/code.mjs +9 -9
  159. package/dist/astro/routes/api/oauth/device/token.mjs +8 -8
  160. package/dist/astro/routes/api/oauth/register.mjs +4 -4
  161. package/dist/astro/routes/api/oauth/token/refresh.mjs +6 -6
  162. package/dist/astro/routes/api/oauth/token/revoke.mjs +6 -6
  163. package/dist/astro/routes/api/oauth/token.mjs +6 -6
  164. package/dist/astro/routes/api/openapi.json.mjs +4 -3
  165. package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +30 -30
  166. package/dist/astro/routes/api/redirects/404s/index.mjs +12 -11
  167. package/dist/astro/routes/api/redirects/404s/summary.mjs +12 -11
  168. package/dist/astro/routes/api/redirects/_id_.mjs +33 -30
  169. package/dist/astro/routes/api/redirects/index.mjs +33 -30
  170. package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +2 -2
  171. package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +2 -2
  172. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +48 -44
  173. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +48 -44
  174. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +48 -44
  175. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +48 -44
  176. package/dist/astro/routes/api/schema/collections/index.mjs +48 -44
  177. package/dist/astro/routes/api/schema/index.mjs +13 -14
  178. package/dist/astro/routes/api/schema/orphans/_slug_.mjs +47 -43
  179. package/dist/astro/routes/api/schema/orphans/index.mjs +47 -43
  180. package/dist/astro/routes/api/search/enable.mjs +12 -11
  181. package/dist/astro/routes/api/search/index.mjs +11 -10
  182. package/dist/astro/routes/api/search/rebuild.mjs +12 -11
  183. package/dist/astro/routes/api/search/stats.mjs +7 -7
  184. package/dist/astro/routes/api/search/suggest.mjs +11 -10
  185. package/dist/astro/routes/api/sections/_slug_.mjs +32 -29
  186. package/dist/astro/routes/api/sections/index.mjs +32 -29
  187. package/dist/astro/routes/api/settings/email.mjs +4 -4
  188. package/dist/astro/routes/api/settings.mjs +32 -29
  189. package/dist/astro/routes/api/setup/admin-verify.mjs +14 -13
  190. package/dist/astro/routes/api/setup/admin.mjs +12 -11
  191. package/dist/astro/routes/api/setup/dev-bypass.mjs +32 -26
  192. package/dist/astro/routes/api/setup/dev-reset.mjs +2 -2
  193. package/dist/astro/routes/api/setup/index.mjs +30 -26
  194. package/dist/astro/routes/api/setup/status.mjs +3 -3
  195. package/dist/astro/routes/api/snapshot.mjs +9 -8
  196. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +35 -32
  197. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +35 -32
  198. package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +35 -32
  199. package/dist/astro/routes/api/taxonomies/index.mjs +35 -32
  200. package/dist/astro/routes/api/themes/preview.mjs +6 -6
  201. package/dist/astro/routes/api/typegen.mjs +4 -4
  202. package/dist/astro/routes/api/well-known/auth.mjs +3 -3
  203. package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs +3 -3
  204. package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs +3 -3
  205. package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +31 -28
  206. package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +32 -29
  207. package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +32 -29
  208. package/dist/astro/routes/api/widget-areas/_name_.mjs +29 -27
  209. package/dist/astro/routes/api/widget-areas/index.mjs +32 -29
  210. package/dist/astro/routes/api/widget-components.mjs +2 -2
  211. package/dist/astro/routes/robots.txt.mjs +9 -8
  212. package/dist/astro/routes/sitemap-_collection_.xml.mjs +24 -15
  213. package/dist/astro/routes/sitemap.xml.mjs +10 -9
  214. package/dist/astro/session-driver.d.mts +1 -1
  215. package/dist/astro/session-driver.mjs +3 -3
  216. package/dist/astro/types.d.mts +21 -13
  217. package/dist/{audit-D1cbG7xH.mjs → audit-ByVKIwWF.mjs} +1 -1
  218. package/dist/auth/providers/github.d.mts +1 -1
  219. package/dist/auth/providers/google.d.mts +1 -1
  220. package/dist/{auth-control-guard-Dr14I98m.mjs → auth-control-guard-CqeUmQsv.mjs} +1 -1
  221. package/dist/{authorize-BLO0m7fW.mjs → authorize-CcBxcHtz.mjs} +1 -1
  222. package/dist/{briefing-CObXGOGz.mjs → briefing-BJaJI8dm.mjs} +2 -1
  223. package/dist/{briefing-gKWiGLt1.mjs → briefing-CawZ59CY.mjs} +90 -28
  224. package/dist/bundle-7C_DpkEq.mjs +602 -0
  225. package/dist/{byline-1ntDwv8c.mjs → byline-e51-fWRs.mjs} +30 -62
  226. package/dist/{byline-fields-BX7rWKNU.d.mts → byline-fields-CUvbslGc.d.mts} +49 -6
  227. package/dist/{byline-fields-C9_iaPaM.mjs → byline-fields-D-N5qVIG.mjs} +1 -1
  228. package/dist/{byline-fields-B-ZkoVft.mjs → byline-fields-DOJO16Gm.mjs} +3 -3
  229. package/dist/{byline-registry-CUSvkasJ.mjs → byline-registry-87nNnYl4.mjs} +2 -2
  230. package/dist/{bylines-bC15ZqAv.mjs → bylines-CMQNCNFh.mjs} +9 -3
  231. package/dist/{bylines-DtxChhN_.mjs → bylines-y4LO-dTj.mjs} +5 -5
  232. package/dist/{cache-DbKyr60Q.mjs → cache-C-FNTFYK.mjs} +2 -2
  233. package/dist/{chunks-C5zp2xir.mjs → chunks-CxBt-GxR.mjs} +1 -1
  234. package/dist/cli/index.mjs +820 -1276
  235. package/dist/client/external-auth-headers.d.mts +1 -1
  236. package/dist/client/index.d.mts +1 -1
  237. package/dist/client/index.mjs +2 -1
  238. package/dist/{comment-CXDOQ93N.mjs → comment-DlA4iChg.mjs} +13 -3
  239. package/dist/comment-reaction-DfFao1ST.mjs +58 -0
  240. package/dist/{comments-hK-rdzJ9.mjs → comments-DApFGMsP.mjs} +1 -1
  241. package/dist/{content-QaryevFO.mjs → content-Bh4BDjv8.mjs} +51 -34
  242. package/dist/content-refresh-CgutSUfO.mjs +1576 -0
  243. package/dist/{context-CoYb_fvK.mjs → context-C5W3G18y.mjs} +111 -50
  244. package/dist/{context-DBL1ib4v.mjs → context-CK4ym2Sf.mjs} +2 -2
  245. package/dist/{context-route-helpers-CYQVmbIm.mjs → context-route-helpers-MASyGgWf.mjs} +2 -1
  246. package/dist/{cron-DxCAU_Sn.mjs → cron-cKcNTix_.mjs} +7 -3
  247. package/dist/{dashboard-DNlqsknJ.mjs → dashboard-DQkVT7Ei.mjs} +4 -4
  248. package/dist/db/index.d.mts +3 -3
  249. package/dist/db/index.mjs +1 -1
  250. package/dist/db/libsql.d.mts +1 -1
  251. package/dist/db/postgres.d.mts +1 -1
  252. package/dist/db/sqlite.d.mts +1 -1
  253. package/dist/{device-flow-DygsFPGL.mjs → device-flow-BnqRH-T9.mjs} +5 -5
  254. package/dist/{placeholder-BDo81Is5.mjs → enrich-DIFIFA8O.mjs} +36 -9
  255. package/dist/{error-DCSuUAZW.mjs → error-CytFlgcd.mjs} +5 -0
  256. package/dist/field-defs-cache-DRNdhBJv.mjs +49 -0
  257. package/dist/{fts-manager-CIZlScg5.mjs → fts-manager-Crzypjqu.mjs} +1 -1
  258. package/dist/hitl-Hw1RmWOq.mjs +677 -0
  259. package/dist/{hitl-requests-CGQwOEiq.mjs → hitl-requests-B4Vbcmaq.mjs} +2 -2
  260. package/dist/{hitl-route-helpers-GSDLNPpN.mjs → hitl-route-helpers-hEVzvP8l.mjs} +5 -4
  261. package/dist/import-Bh9biJfx.mjs +1354 -0
  262. package/dist/{index-CwRuZ-u8.d.mts → index-D4y6NGiy.d.mts} +75 -3
  263. package/dist/index.d.mts +17 -16
  264. package/dist/index.mjs +81 -69
  265. package/dist/{jsonld-DZ67souc.d.mts → jsonld-Dq0gsnOH.d.mts} +8 -4
  266. package/dist/{load-xE01Jm0V.mjs → load-DmYeniXl.mjs} +1 -1
  267. package/dist/{loader-tg63WSY2.mjs → loader-CjWqjweO.mjs} +117 -31
  268. package/dist/{manifest-schema-qh2P7RDX.mjs → manifest-schema-BxVPYMJR.mjs} +34 -1
  269. package/dist/mcp-reviewed-executor-TwVbMzG6.mjs +555 -0
  270. package/dist/media/image-endpoint.d.mts +32 -0
  271. package/dist/media/image-endpoint.mjs +111 -0
  272. package/dist/media/index.d.mts +27 -2
  273. package/dist/media/index.mjs +5 -3
  274. package/dist/media/local-runtime.d.mts +16 -11
  275. package/dist/media/local-runtime.mjs +10 -8
  276. package/dist/{media-DUAjMfvR.mjs → media-DMj0grzC.mjs} +3 -1
  277. package/dist/{media-allowlist-BsXkT9RK.mjs → media-allowlist-BlVCSzHx.mjs} +1 -1
  278. package/dist/media-url-lEKSrpr9.mjs +20 -0
  279. package/dist/{menus-WpFRMXjz.mjs → menus-TaW1gKnk.mjs} +19 -5
  280. package/dist/{menus-DU1eZqw_.mjs → menus-xvsnVZXw.mjs} +80 -15
  281. package/dist/{normalize-DUnoXAa9.mjs → normalize-5ek_z7de.mjs} +8 -1
  282. package/dist/{oauth-authorization-D-1p52Je.mjs → oauth-authorization-DiaGvRVz.mjs} +5 -5
  283. package/dist/{oauth-clients-CzeMGyUU.mjs → oauth-clients-Dl9E8dEM.mjs} +2 -2
  284. package/dist/object-cache/memory.d.mts +14 -0
  285. package/dist/object-cache/memory.mjs +55 -0
  286. package/dist/object-cache-D51qOseS.mjs +419 -0
  287. package/dist/page/index.d.mts +4 -3
  288. package/dist/page/index.mjs +2 -2
  289. package/dist/{parse-CneSgl7-.mjs → parse-CbymENaR.mjs} +1 -1
  290. package/dist/{parser-DxfsARXL.mjs → parser-C1nYd-81.mjs} +151 -9
  291. package/dist/{placeholder-CXfoCtCd.d.mts → placeholder-uvNRZBX9.d.mts} +12 -4
  292. package/dist/plugin-utils.d.mts +9 -9
  293. package/dist/plugins/adapt-sandbox-entry.d.mts +9 -9
  294. package/dist/plugins/adapt-sandbox-entry.mjs +11 -2
  295. package/dist/{plugins-C57YQi4l.mjs → plugins-BolVa-tl.mjs} +832 -64
  296. package/dist/{transport-LSdZVXHF.mjs → portable-text-dA_UlJwW.mjs} +1 -134
  297. package/dist/{preview-D5rvDhRt.mjs → preview-vSVg6fwG.mjs} +4 -3
  298. package/dist/process-cache-7xgAO9JY.mjs +106 -0
  299. package/dist/{provider-loader-9it4vd6L.d.mts → provider-loader-MD8zAbnH.d.mts} +1 -1
  300. package/dist/{public-url-DLUM5OOv.mjs → public-url-BEz_sM9n.mjs} +24 -18
  301. package/dist/{public-url-B5HaoGzj.d.mts → public-url-gsp3oUbu.d.mts} +5 -4
  302. package/dist/{query-BYc3oruA.mjs → query-CfRCdaL3.mjs} +281 -76
  303. package/dist/{query-DKEwzobh.mjs → query-jaAmw8E1.mjs} +11 -6
  304. package/dist/{rate-limit-i0G3IAOX.mjs → rate-limit-ZLdyWoZF.mjs} +2 -2
  305. package/dist/{redirect-C2zXRj3c.mjs → redirect-BAjt4Z6b.mjs} +2 -2
  306. package/dist/{redirects-YZo_znWG.mjs → redirects-BTdwpQtE.mjs} +47 -24
  307. package/dist/{redirects-ocRJmQHP.mjs → redirects-CA-xylPG.mjs} +19 -11
  308. package/dist/{registry-CTkbIDB9.mjs → registry-CtyVedcN.mjs} +130 -77
  309. package/dist/request-context.d.mts +2 -0
  310. package/dist/{request-meta-DAb6xaP9.mjs → request-meta-CUypToDJ.mjs} +1 -1
  311. package/dist/{review-requests-C0un5kdV.mjs → review-requests-C9Ff11Vq.mjs} +1 -1
  312. package/dist/{review-requests-gGMyYYhy.mjs → review-requests-DUyEmtmG.mjs} +1 -1
  313. package/dist/{runner-D4FL9usy.d.mts → runner-1tC2tIRV.d.mts} +1 -1
  314. package/dist/runner-DB7CRfOF.mjs +6740 -0
  315. package/dist/{runtime-DEWQpZ-4.d.mts → runtime-BOeiQsCv.d.mts} +2028 -1564
  316. package/dist/runtime.d.mts +10 -10
  317. package/dist/runtime.mjs +4 -4
  318. package/dist/schema-DXdYj4R3.mjs +8 -0
  319. package/dist/{search-axGQ1KY3.mjs → search-DSaLgEFI.mjs} +5 -3
  320. package/dist/{secrets-062Izo8i.mjs → secrets-CDZo2k8L.mjs} +15 -12
  321. package/dist/{sections-OLKgXL10.mjs → sections-PVVXHGfp.mjs} +2 -2
  322. package/dist/seed/index.d.mts +2 -2
  323. package/dist/seed/index.mjs +22 -19
  324. package/dist/seo/index.d.mts +1 -1
  325. package/dist/seo/index.mjs +3 -12
  326. package/dist/{seo-Cd45Po8L.mjs → seo-CQG3GCHQ.mjs} +5 -2
  327. package/dist/{seo-contributions-CqVvReEj.mjs → seo-contributions-C1EnikHB.mjs} +11 -3
  328. package/dist/{seo-5lJOtB5J.mjs → seo-qa7Dn0jK.mjs} +22 -4
  329. package/dist/{service-Bwad8s5h.mjs → service-DiN4ZuPp.mjs} +2 -2
  330. package/dist/session-user-CAKImna3.mjs +22 -0
  331. package/dist/{settings-yLjz_I4T.mjs → settings-BbqgHWpU.mjs} +28 -55
  332. package/dist/{settings-lAHjaUit.mjs → settings-i4VPP8bT.mjs} +2 -2
  333. package/dist/{setup-complete--PradA4R.mjs → setup-complete-B8fl-mjV.mjs} +1 -1
  334. package/dist/{site-activity-D7Xyropw.mjs → site-activity-Dy3FROs0.mjs} +1 -1
  335. package/dist/{site-context-DaN9Z91j.mjs → site-context-DQiL8Fl5.mjs} +23 -652
  336. package/dist/{site-url-DpGZo9Z6.mjs → site-url-BML3GQYm.mjs} +1 -1
  337. package/dist/status-DANd8ERo.mjs +21 -0
  338. package/dist/storage/local.d.mts +1 -1
  339. package/dist/storage/local.mjs +1 -1
  340. package/dist/storage/s3.d.mts +1 -1
  341. package/dist/storage/s3.mjs +1 -1
  342. package/dist/{taxonomies-uXVEoQso.mjs → taxonomies-9s-v03H-.mjs} +36 -29
  343. package/dist/taxonomies-DRiixp_E.mjs +443 -0
  344. package/dist/{taxonomy-CBmkmMuU.mjs → taxonomy-Dvsw6BOs.mjs} +44 -9
  345. package/dist/{tokens-CjSgb0AC.mjs → tokens-1RK1n6ED.mjs} +1 -1
  346. package/dist/transport-BNmCqLu7.mjs +134 -0
  347. package/dist/types-4garmdWa.mjs +66 -0
  348. package/dist/{types-DSPGWjxO.d.mts → types-C8XW6L19.d.mts} +225 -4
  349. package/dist/{types-GaCtZ1k9.d.mts → types-CDpH6MA4.d.mts} +18 -0
  350. package/dist/{types-DRIKLmJI.d.mts → types-C_ly5eTp.d.mts} +17 -2
  351. package/dist/types-DF7ZuGGk.d.mts +118 -0
  352. package/dist/types-DU0bU2Wu.d.mts +2392 -0
  353. package/dist/{types-CwawBUTa.d.mts → types-DW_-sFyz.d.mts} +2 -1
  354. package/dist/{types-DfuD0Afl.mjs → types-Dq1qT19x.mjs} +2 -2
  355. package/dist/ui/server-runtime.d.mts +15 -15
  356. package/dist/ui/server-runtime.mjs +25 -21
  357. package/dist/url-Cac7a9QZ.mjs +33 -0
  358. package/dist/{user-DtNmjNYt.mjs → user-BIZPzCb9.mjs} +2 -2
  359. package/dist/{utils-wv-zvC-Y.mjs → utils-CMDhr5Xd.mjs} +129 -7
  360. package/dist/{validate-BMs11tan.d.mts → validate-CZvb-BKB.d.mts} +10 -7
  361. package/dist/{validate-7SYRbz2f.mjs → validate-DNs0pTSc.mjs} +11 -6
  362. package/dist/version-BTvfRGc6.mjs +6 -0
  363. package/dist/{widgets-DR8EHuRO.mjs → widgets-f0ibZUIq.mjs} +46 -43
  364. package/dist/{wordpress-slugs-Dvhxh4cl.mjs → wordpress-slugs-BhHJX8XE.mjs} +1 -1
  365. package/dist/{zod-generator-BS9-umbk.mjs → zod-generator-B7TMjyFJ.mjs} +41 -13
  366. package/package.json +31 -8
  367. package/src/components/Block.astro +50 -0
  368. package/src/components/Comments.astro +143 -1
  369. package/src/components/DinewayHead.astro +19 -2
  370. package/src/components/DinewayImage.astro +66 -33
  371. package/src/components/DinewayMedia.astro +1 -2
  372. package/src/components/Image.astro +85 -40
  373. package/src/components/InlinePortableTextEditor.tsx +12 -2
  374. package/src/components/JsonLdScript.astro +9 -0
  375. package/src/components/LiveSearch.astro +40 -4
  376. package/src/components/index.ts +4 -0
  377. package/src/components/live-search-routing.ts +30 -0
  378. package/src/components/portable-text-text-align.ts +15 -0
  379. package/src/ui.ts +2 -0
  380. package/dist/entity-aliases-Egjmqc7I.mjs +0 -51
  381. package/dist/import-CvHY6sf5.mjs +0 -684
  382. package/dist/runner-B-tbV751.mjs +0 -2741
  383. package/dist/schema-B6zyB-Xn.mjs +0 -8
  384. package/dist/taxonomies-CNOGeC-3.mjs +0 -327
  385. package/dist/types-eu5UDgHN.d.mts +0 -652
  386. package/dist/version-xlzMSXF2.mjs +0 -6
  387. /package/dist/{adapters-OQCImOL7.d.mts → adapters-NVSs4UH7.d.mts} +0 -0
  388. /package/dist/{api-tokens-CYUoFGo7.mjs → api-tokens-2r7OWi_I.mjs} +0 -0
  389. /package/dist/{base64-C1Q9yr0B.mjs → base64-F8-DUraK.mjs} +0 -0
  390. /package/dist/{challenge-store-CRSz-Xim.mjs → challenge-store-Bjlepa2E.mjs} +0 -0
  391. /package/dist/{components--pg6zBvu.mjs → components-Bclf98Be.mjs} +0 -0
  392. /package/dist/{context-types-DQh_XKkn.mjs → context-types-DqTo6C79.mjs} +0 -0
  393. /package/dist/{default-B6iaLvP7.mjs → default--K40jqm0.mjs} +0 -0
  394. /package/dist/{email-console-BOVqIYpB.mjs → email-console-ChgKFO8-.mjs} +0 -0
  395. /package/dist/{escape-BDgouFFY.mjs → escape-Bd4P_xKg.mjs} +0 -0
  396. /package/dist/{experimental-workflows-Dh4DUoD_.mjs → experimental-workflows-BMsUnIAw.mjs} +0 -0
  397. /package/dist/{mime-8pAB8-77.mjs → mime-CA7Lgovc.mjs} +0 -0
  398. /package/dist/{mode-CpyEz8pe.mjs → mode-C4CIyjtR.mjs} +0 -0
  399. /package/dist/{oauth-state-store-qncPB_IU.mjs → oauth-state-store-CNoXafF7.mjs} +0 -0
  400. /package/dist/{oauth-user-lookup-BFjWF8wK.mjs → oauth-user-lookup-Ygw4bNyt.mjs} +0 -0
  401. /package/dist/{options-BvJoSSJR.mjs → options-DQPTH5n0.mjs} +0 -0
  402. /package/dist/{passkey-config-DzHQK90v.mjs → passkey-config-BUwu8BA3.mjs} +0 -0
  403. /package/dist/{patterns-r-0n824Y.mjs → patterns-BhAvqO0S.mjs} +0 -0
  404. /package/dist/{provider-loader-DzUxejk7.mjs → provider-loader-D0w9dqjm.mjs} +0 -0
  405. /package/dist/{redirect-BjIBtDWY.mjs → redirect-wphRBv4y.mjs} +0 -0
  406. /package/dist/{request-cache-CYMbwZc6.mjs → request-cache-D9GQBxMP.mjs} +0 -0
  407. /package/dist/{resolve-DTuDyYKs.mjs → resolve-Cb6Dbz-C.mjs} +0 -0
  408. /package/dist/{setup-nonce-pyGfc9hV.mjs → setup-nonce-CoyjILvW.mjs} +0 -0
  409. /package/dist/{sidecar-client-mJxwayYN.mjs → sidecar-client-C3mqXg4C.mjs} +0 -0
  410. /package/dist/{slugify-BzGxlOFx.mjs → slugify-KSsVD_D3.mjs} +0 -0
  411. /package/dist/{ssrf-DiKqWd3N.mjs → ssrf-DWe8jwAp.mjs} +0 -0
  412. /package/dist/{transaction-CShMWIej.mjs → transaction-C2EOMTJA.mjs} +0 -0
  413. /package/dist/{transport-BnsNxh2l.d.mts → transport-CcJu3Co8.d.mts} +0 -0
  414. /package/dist/{trusted-proxy-BgIIcbsN.mjs → trusted-proxy-DTXQ2IMv.mjs} +0 -0
  415. /package/dist/{types-BO8TGjS8.mjs → types-B3t5cxhU.mjs} +0 -0
  416. /package/dist/{types-nP9vGUFq.d.mts → types-C46EvNdc.d.mts} +0 -0
  417. /package/dist/{types-Cg276-3z.mjs → types-C5CVgwsV.mjs} +0 -0
  418. /package/dist/{types-DZpT-PnG.d.mts → types-POH8PQZh.d.mts} +0 -0
  419. /package/dist/{types-Dryvv7LH.d.mts → types-Rc3gQqqw.d.mts} +0 -0
  420. /package/dist/{url-w7Mp5qAD.mjs → url-CpyFDFpO.mjs} +0 -0
@@ -1,51 +1,510 @@
1
1
  #!/usr/bin/env node
2
- import { a as __exportAll, i as runMigrations, n as getMigrationStatus, t as getMigrationFingerprint } from "../runner-B-tbV751.mjs";
2
+ import { a as __exportAll, i as runMigrations, n as getMigrationStatus, t as getMigrationFingerprint } from "../runner-DB7CRfOF.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
6
  import { n as getI18nConfig, r as isI18nEnabled } from "../config-CVssduLe.mjs";
7
- import { n as slugify } from "../slugify-BzGxlOFx.mjs";
8
- import { t as ContentRepository } from "../content-QaryevFO.mjs";
9
- import { i as encodeBase64url } from "../base64-C1Q9yr0B.mjs";
10
- import "../types-DfuD0Afl.mjs";
11
- import { t as MediaRepository } from "../media-DUAjMfvR.mjs";
12
- import { t as TaxonomyRepository } from "../taxonomy-CBmkmMuU.mjs";
13
- import { t as OptionsRepository } from "../options-BvJoSSJR.mjs";
14
- import "../redirect-C2zXRj3c.mjs";
15
- import "../request-cache-CYMbwZc6.mjs";
16
- import "../byline-registry-CUSvkasJ.mjs";
17
- import { t as BylineRepository } from "../byline-1ntDwv8c.mjs";
18
- import "../fts-manager-CIZlScg5.mjs";
19
- import { n as SchemaRegistry } from "../registry-CTkbIDB9.mjs";
20
- import { a as isMissingTableError } from "../loader-tg63WSY2.mjs";
21
- import "../settings-yLjz_I4T.mjs";
22
- import { n as VERSION } from "../version-xlzMSXF2.mjs";
23
- import { i as pluginManifestSchema } from "../manifest-schema-qh2P7RDX.mjs";
24
- import "../ssrf-DiKqWd3N.mjs";
25
- import { t as validateSeed } from "../validate-7SYRbz2f.mjs";
26
- import { t as applySeed } from "../apply-CX3no7XE.mjs";
27
- import { n as fingerprintKey, r as generateEncryptionKey, t as DinewaySecretsError } from "../secrets-062Izo8i.mjs";
7
+ import { i as encodeBase64url } from "../base64-F8-DUraK.mjs";
8
+ import "../types-Dq1qT19x.mjs";
9
+ import { o as isMissingTableError } from "../loader-CjWqjweO.mjs";
10
+ import "../object-cache-D51qOseS.mjs";
11
+ import { n as slugify } from "../slugify-KSsVD_D3.mjs";
12
+ import { t as ContentRepository } from "../content-Bh4BDjv8.mjs";
13
+ import { t as MediaRepository } from "../media-DMj0grzC.mjs";
14
+ import { t as TaxonomyRepository } from "../taxonomy-Dvsw6BOs.mjs";
15
+ import { t as OptionsRepository } from "../options-DQPTH5n0.mjs";
16
+ import "../redirect-BAjt4Z6b.mjs";
17
+ import "../request-cache-D9GQBxMP.mjs";
18
+ import "../byline-registry-87nNnYl4.mjs";
19
+ import "../field-defs-cache-DRNdhBJv.mjs";
20
+ import { t as BylineRepository } from "../byline-e51-fWRs.mjs";
21
+ import "../content-refresh-CgutSUfO.mjs";
22
+ import "../fts-manager-Crzypjqu.mjs";
23
+ import { n as SchemaRegistry } from "../registry-CtyVedcN.mjs";
24
+ import "../settings-BbqgHWpU.mjs";
25
+ import { n as VERSION } from "../version-BTvfRGc6.mjs";
26
+ import { a as reconcileManifestAccess, i as pluginManifestSchema } from "../manifest-schema-BxVPYMJR.mjs";
27
+ import "../ssrf-DWe8jwAp.mjs";
28
+ import { n as fingerprintKey, r as generateEncryptionKey, t as DinewaySecretsError } from "../secrets-CDZo2k8L.mjs";
29
+ import { t as validateSeed } from "../validate-DNs0pTSc.mjs";
30
+ import { t as applySeed } from "../apply-bZswmZPm.mjs";
28
31
  import { createHeaderAwareFetch, customHeadersInterceptor, isRedirectResponse, resolveCustomHeaders } from "../client/external-auth-headers.mjs";
29
- import { o as convertDataForRead } from "../transport-LSdZVXHF.mjs";
32
+ import { t as convertDataForRead } from "../portable-text-dA_UlJwW.mjs";
30
33
  import { DinewayClient } from "../client/index.mjs";
31
34
  import { LocalStorage } from "../storage/local.mjs";
32
- import { createHash } from "node:crypto";
35
+ import { r as fileExists$11, t as bundleCommand } from "../bundle-7C_DpkEq.mjs";
36
+ import { createHash, randomUUID } from "node:crypto";
33
37
  import { sql } from "kysely";
34
- import { imageSize } from "image-size";
35
38
  import { createGzipDecoder, unpackTar } from "modern-tar";
36
- import { createReadStream, createWriteStream, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
37
- import { basename, dirname, extname, isAbsolute, join, relative, resolve } from "node:path";
38
- import { pathToFileURL } from "node:url";
39
+ import { createReadStream, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
40
+ import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
39
41
  import { defineCommand, runCommand, runMain } from "citty";
42
+ import { createInterface } from "node:readline/promises";
40
43
  import consola, { consola as consola$1 } from "consola";
41
44
  import pc from "picocolors";
45
+ import { ForgewayClient } from "@forgeway/sdk";
46
+ import { access, chmod, mkdir, readFile, readdir, stat, writeFile } from "node:fs/promises";
42
47
  import { homedir } from "node:os";
43
- import { access, chmod, copyFile, mkdir, readFile, readdir, rm, stat, symlink, writeFile } from "node:fs/promises";
44
- import { createInterface } from "node:readline/promises";
45
48
  import { spawn } from "node:child_process";
46
- import { pipeline } from "node:stream/promises";
47
- 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;
@@ -303,125 +762,60 @@ const connectionArgs = {
303
762
  description: "Auth token"
304
763
  },
305
764
  header: {
306
- type: "string",
307
- alias: "H",
308
- description: "Custom header \"Name: Value\" (repeatable, or use DINEWAY_HEADERS env)"
309
- },
310
- json: {
311
- type: "boolean",
312
- description: "Output as JSON"
313
- }
314
- };
315
- /**
316
- * Create a DinewayClient from CLI args, env vars, and stored credentials.
317
- *
318
- * Auth resolution order:
319
- * 1. --token flag
320
- * 2. DINEWAY_TOKEN env var
321
- * 3. Stored credentials (~/.config/dineway/auth.json)
322
- * 4. Dev bypass (if URL is localhost)
323
- *
324
- * Custom headers are merged from (in priority order):
325
- * 1. Stored credentials (persisted during `dineway login --header`)
326
- * 2. DINEWAY_HEADERS env var
327
- * 3. --header CLI flags
328
- */
329
- function createClientFromArgs(args) {
330
- const baseUrl = resolveDinewayBaseUrl(args.url);
331
- let token = resolveDinewayToken(args.token);
332
- const isLocal = baseUrl.includes("localhost") || baseUrl.includes("127.0.0.1");
333
- const cred = !token ? getCredentials(baseUrl) : null;
334
- const customHeaders = {
335
- ...cred?.customHeaders,
336
- ...resolveCustomHeaders()
337
- };
338
- const extraInterceptors = [];
339
- if (Object.keys(customHeaders).length > 0) extraInterceptors.push(customHeadersInterceptor(customHeaders));
340
- if (!token && cred) if (new Date(cred.expiresAt) > /* @__PURE__ */ new Date()) token = cred.accessToken;
341
- else return new DinewayClient({
342
- baseUrl,
343
- token: cred.accessToken,
344
- refreshToken: cred.refreshToken,
345
- onTokenRefresh: (newAccessToken, expiresIn) => {
346
- saveCredentials(baseUrl, {
347
- ...cred,
348
- accessToken: newAccessToken,
349
- expiresAt: new Date(Date.now() + expiresIn * 1e3).toISOString()
350
- });
351
- },
352
- interceptors: extraInterceptors
353
- });
354
- return new DinewayClient({
355
- baseUrl,
356
- token,
357
- devBypass: !token && isLocal,
358
- interceptors: extraInterceptors
359
- });
360
- }
361
-
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;
765
+ type: "string",
766
+ alias: "H",
767
+ description: "Custom header \"Name: Value\" (repeatable, or use DINEWAY_HEADERS env)"
768
+ },
769
+ json: {
770
+ type: "boolean",
771
+ description: "Output as JSON"
423
772
  }
424
- consola$1.log(typeof data === "string" ? data : JSON.stringify(data));
773
+ };
774
+ /**
775
+ * Create a DinewayClient from CLI args, env vars, and stored credentials.
776
+ *
777
+ * Auth resolution order:
778
+ * 1. --token flag
779
+ * 2. DINEWAY_TOKEN env var
780
+ * 3. Stored credentials (~/.config/dineway/auth.json)
781
+ * 4. Dev bypass (if URL is localhost)
782
+ *
783
+ * Custom headers are merged from (in priority order):
784
+ * 1. Stored credentials (persisted during `dineway login --header`)
785
+ * 2. DINEWAY_HEADERS env var
786
+ * 3. --header CLI flags
787
+ */
788
+ function createClientFromArgs(args) {
789
+ const baseUrl = resolveDinewayBaseUrl(args.url);
790
+ let token = resolveDinewayToken(args.token);
791
+ const isLocal = baseUrl.includes("localhost") || baseUrl.includes("127.0.0.1");
792
+ const cred = !token ? getCredentials(baseUrl) : null;
793
+ const customHeaders = {
794
+ ...cred?.customHeaders,
795
+ ...resolveCustomHeaders()
796
+ };
797
+ const extraInterceptors = [];
798
+ if (Object.keys(customHeaders).length > 0) extraInterceptors.push(customHeadersInterceptor(customHeaders));
799
+ if (!token && cred) if (new Date(cred.expiresAt) > /* @__PURE__ */ new Date()) token = cred.accessToken;
800
+ else return new DinewayClient({
801
+ baseUrl,
802
+ token: cred.accessToken,
803
+ refreshToken: cred.refreshToken,
804
+ onTokenRefresh: (newAccessToken, expiresIn) => {
805
+ saveCredentials(baseUrl, {
806
+ ...cred,
807
+ accessToken: newAccessToken,
808
+ expiresAt: new Date(Date.now() + expiresIn * 1e3).toISOString()
809
+ });
810
+ },
811
+ interceptors: extraInterceptors
812
+ });
813
+ return new DinewayClient({
814
+ baseUrl,
815
+ token,
816
+ devBypass: !token && isLocal,
817
+ interceptors: extraInterceptors
818
+ });
425
819
  }
426
820
 
427
821
  //#endregion
@@ -952,6 +1346,164 @@ const contentCommand = defineCommand({
952
1346
  }
953
1347
  });
954
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");
1371
+ }
1372
+ function isQuotaResource(resource) {
1373
+ const normalized = resource.toLowerCase();
1374
+ return normalized.includes("quota") || normalized.includes("place_search") || normalized.includes("place_get") || normalized.includes("/api/places");
1375
+ }
1376
+ function getCliPaywallRefreshStatus(paywall, account) {
1377
+ if (isHostedSitesResource(paywall.resource)) {
1378
+ const remainingHostedSites = account.sites?.remainingHostedSites;
1379
+ if (remainingHostedSites === null || (remainingHostedSites ?? 0) > 0) return {
1380
+ blocked: false,
1381
+ message: "Hosted capacity is now available. Re-run the blocked command."
1382
+ };
1383
+ return {
1384
+ blocked: true,
1385
+ message: "There is still no hosted capacity. Complete checkout in Dineway Web."
1386
+ };
1387
+ }
1388
+ if (isCreditResource(paywall.resource)) {
1389
+ if ((account.credits?.availableCredits ?? 0) > 0) return {
1390
+ blocked: false,
1391
+ message: "Provider credits are now available. Re-run the blocked command."
1392
+ };
1393
+ return {
1394
+ blocked: true,
1395
+ message: "There are still no provider credits. Complete checkout or top up credits in Dineway Web."
1396
+ };
1397
+ }
1398
+ if (isQuotaResource(paywall.resource)) return {
1399
+ blocked: false,
1400
+ message: "Account quota status refreshed. Re-run the blocked command when ready."
1401
+ };
1402
+ return {
1403
+ blocked: false,
1404
+ message: "Account status refreshed. Re-run the blocked command when ready."
1405
+ };
1406
+ }
1407
+ function normalizeCliPaywallError(input) {
1408
+ const error = input.error;
1409
+ const status = error?.status ?? error?.statusCode;
1410
+ const message = error?.message ?? (input.error instanceof Error ? input.error.message : "");
1411
+ const body = error?.body;
1412
+ const candidate = getNestedError(body) ?? getNestedError(input.error) ?? {};
1413
+ if (stringField(candidate, "code") && stringField(candidate, "resource") && stringField(candidate, "reason") && typeof candidate.handoffRequired === "boolean") return {
1414
+ code: stringField(candidate, "code") ?? "PAYWALL_REQUIRED",
1415
+ resource: stringField(candidate, "resource") ?? input.resource,
1416
+ reason: stringField(candidate, "reason") ?? input.reason ?? message,
1417
+ requiredPlan: stringField(candidate, "requiredPlan"),
1418
+ pricingUrl: stringField(candidate, "pricingUrl") ?? new URL("/pricing", normalizeDinewayWebUrl(input.webUrl)).toString(),
1419
+ handoffRequired: candidate.handoffRequired === true
1420
+ };
1421
+ if ((status === 402 || status === 403 || status === 429) && PAYWALL_MESSAGE_PATTERN.test(message)) return {
1422
+ code: status === 429 ? "QUOTA_EXCEEDED" : "PAYWALL_REQUIRED",
1423
+ resource: input.resource,
1424
+ reason: input.reason ?? message,
1425
+ pricingUrl: new URL("/pricing", normalizeDinewayWebUrl(input.webUrl)).toString(),
1426
+ handoffRequired: true
1427
+ };
1428
+ return null;
1429
+ }
1430
+ async function promptEnter(message) {
1431
+ const readline = createInterface({
1432
+ input: process.stdin,
1433
+ output: process.stdout
1434
+ });
1435
+ try {
1436
+ await readline.question(message);
1437
+ } finally {
1438
+ readline.close();
1439
+ }
1440
+ }
1441
+ async function createHandoff(input) {
1442
+ const credentials = await readStoredForgewayAccount({ platformApiUrl: input.platformApiUrl });
1443
+ if (!credentials) return null;
1444
+ const { credentials: refreshed } = await getForgewayDinewayAccount(credentials);
1445
+ const response = await fetch(new URL("/api/dineway-web/handoffs", input.webUrl), {
1446
+ method: "POST",
1447
+ headers: {
1448
+ Authorization: `Bearer ${refreshed.accessToken}`,
1449
+ "Content-Type": "application/json",
1450
+ "X-Dineway-Request": "1"
1451
+ },
1452
+ body: JSON.stringify({
1453
+ target: "pricing",
1454
+ reason: input.paywall.reason,
1455
+ context: {
1456
+ resource: input.paywall.resource,
1457
+ code: input.paywall.code,
1458
+ requiredPlan: input.paywall.requiredPlan,
1459
+ ...input.context
1460
+ }
1461
+ })
1462
+ });
1463
+ const payload = await response.json().catch(() => null);
1464
+ if (!response.ok || !payload?.success || !payload.data?.url) return null;
1465
+ return payload.data.url;
1466
+ }
1467
+ async function handleCliPaywall(input) {
1468
+ const paywall = normalizeCliPaywallError(input);
1469
+ if (!paywall) return false;
1470
+ const platformApiUrl = normalizeForgewayApiUrl(input.platformApiUrl);
1471
+ const webUrl = normalizeDinewayWebUrl(input.webUrl ?? process.env.DINEWAY_WEB_URL);
1472
+ let url = paywall.pricingUrl;
1473
+ let handoffFailed = false;
1474
+ try {
1475
+ const handoffUrl = await createHandoff({
1476
+ paywall,
1477
+ platformApiUrl,
1478
+ webUrl,
1479
+ context: input.context
1480
+ });
1481
+ if (handoffUrl) url = handoffUrl;
1482
+ else handoffFailed = true;
1483
+ } catch {
1484
+ handoffFailed = true;
1485
+ }
1486
+ consola$1.error(paywall.reason);
1487
+ if (handoffFailed) consola$1.info(`Log in first: ${pc.cyan("dineway account login")}`);
1488
+ consola$1.info(`Continue in Dineway Web: ${pc.cyan(url)}`);
1489
+ if (!input.interactive) return true;
1490
+ await promptEnter("Press Enter to continue after upgrading, or Ctrl-C to cancel.");
1491
+ const credentials = await readStoredForgewayAccount({ platformApiUrl });
1492
+ if (!credentials) {
1493
+ consola$1.error("Still not logged in. Run: dineway account login");
1494
+ return true;
1495
+ }
1496
+ try {
1497
+ const { account } = await getForgewayDinewayAccount(credentials);
1498
+ const status = getCliPaywallRefreshStatus(paywall, account);
1499
+ if (status.blocked) consola$1.error(status.message);
1500
+ else consola$1.info(status.message);
1501
+ } catch {
1502
+ consola$1.error("Account is still blocked. Complete checkout or top up credits in Dineway Web.");
1503
+ }
1504
+ return true;
1505
+ }
1506
+
955
1507
  //#endregion
956
1508
  //#region src/cli/commands/deploy/utils/astro-adapter.ts
957
1509
  const NODE_ADAPTER_PACKAGE = "@astrojs/node";
@@ -989,7 +1541,7 @@ function collectUploadIncludeFiles(directory = dinewayUploadsJoin(dinewayForgewa
989
1541
  \t});
990
1542
  }
991
1543
  `;
992
- async function fileExists$11(path) {
1544
+ async function fileExists$10(path) {
993
1545
  try {
994
1546
  await access(path);
995
1547
  return true;
@@ -1150,7 +1702,7 @@ function configurePackageJson(pkg, adapter) {
1150
1702
  }
1151
1703
  async function configureAstroConfig(cwd, adapter, dryRun) {
1152
1704
  const configPath = join(cwd, "astro.config.mjs");
1153
- if (!await fileExists$11(configPath)) return [];
1705
+ if (!await fileExists$10(configPath)) return [];
1154
1706
  const current = await readFile(configPath, "utf-8");
1155
1707
  const next = configureAstroConfigSource(current, adapter);
1156
1708
  if (next === current) return [{
@@ -1169,7 +1721,7 @@ async function configureAstroConfig(cwd, adapter, dryRun) {
1169
1721
  }
1170
1722
  async function configurePackage(cwd, adapter, dryRun) {
1171
1723
  const packagePath = join(cwd, "package.json");
1172
- if (!await fileExists$11(packagePath)) return [];
1724
+ if (!await fileExists$10(packagePath)) return [];
1173
1725
  const current = await readFile(packagePath, "utf-8");
1174
1726
  const nextPkg = configurePackageJson(JSON.parse(current), adapter);
1175
1727
  const next = JSON.stringify(nextPkg, null, " ") + "\n";
@@ -1188,7 +1740,7 @@ async function configurePackage(cwd, adapter, dryRun) {
1188
1740
  }];
1189
1741
  }
1190
1742
  async function configureAstroDeployAdapter(cwd, adapter, dryRun = false) {
1191
- if (!await fileExists$11(join(cwd, "astro.config.mjs"))) return [];
1743
+ if (!await fileExists$10(join(cwd, "astro.config.mjs"))) return [];
1192
1744
  return [...await configureAstroConfig(cwd, adapter, dryRun), ...await configurePackage(cwd, adapter, dryRun)];
1193
1745
  }
1194
1746
 
@@ -1278,7 +1830,7 @@ volumes:
1278
1830
 
1279
1831
  //#endregion
1280
1832
  //#region src/cli/commands/deploy/targets/docker.ts
1281
- async function fileExists$10(path) {
1833
+ async function fileExists$9(path) {
1282
1834
  try {
1283
1835
  await access(path);
1284
1836
  return true;
@@ -1288,7 +1840,7 @@ async function fileExists$10(path) {
1288
1840
  }
1289
1841
  async function writeGeneratedFile$2(cwd, relativePath, content, dryRun) {
1290
1842
  const path = join(cwd, relativePath);
1291
- if (await fileExists$10(path)) return {
1843
+ if (await fileExists$9(path)) return {
1292
1844
  path: relativePath,
1293
1845
  action: "exists"
1294
1846
  };
@@ -1378,7 +1930,7 @@ const EDGE_HYPHENS_RE$2 = /^-|-$/g;
1378
1930
  const LINE_SPLIT_RE = /\r?\n/;
1379
1931
  const DEFAULT_REGION$1 = "iad";
1380
1932
  const FLY_VOLUME_NAME = "dineway_data";
1381
- async function fileExists$9(path) {
1933
+ async function fileExists$8(path) {
1382
1934
  try {
1383
1935
  await access(path);
1384
1936
  return true;
@@ -1388,7 +1940,7 @@ async function fileExists$9(path) {
1388
1940
  }
1389
1941
  async function writeGeneratedFile$1(cwd, relativePath, content, dryRun) {
1390
1942
  const path = join(cwd, relativePath);
1391
- if (await fileExists$9(path)) return {
1943
+ if (await fileExists$8(path)) return {
1392
1944
  path: relativePath,
1393
1945
  action: "exists"
1394
1946
  };
@@ -1637,136 +2189,6 @@ async function writeForgewayDeployMetadata(cwd, metadata) {
1637
2189
  });
1638
2190
  }
1639
2191
 
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
2192
  //#endregion
1771
2193
  //#region src/cli/commands/deploy/targets/forgeway.ts
1772
2194
  const DEFAULT_DINEWAY_API_BASE_URL$1 = "https://api.dineway.ai";
@@ -1790,7 +2212,6 @@ const DINEWAY_PACKAGE_NAME = "dineway";
1790
2212
  const SEMVER_VERSION_PATTERN = /^\d+\.\d+\.\d+(?:[-+].*)?$/;
1791
2213
  const LOCAL_PACKAGE_SPEC_PATTERN = /^(?:workspace|file|link|portal):/;
1792
2214
  const SHADOW_EMAIL_PATTERN$1 = /^shadow_[a-f0-9]{16}@dineway\.ai$/i;
1793
- const OTP_PATTERN = /^\d{6}$/;
1794
2215
  const FOOD_TYPES = new Set([
1795
2216
  "restaurant",
1796
2217
  "cafe",
@@ -1850,7 +2271,7 @@ function normalizeForgewayUser$1(user) {
1850
2271
  function getFetch(deps) {
1851
2272
  return deps.fetch ?? fetch;
1852
2273
  }
1853
- async function fileExists$8(path) {
2274
+ async function fileExists$7(path) {
1854
2275
  try {
1855
2276
  await access(path);
1856
2277
  return true;
@@ -1875,7 +2296,7 @@ function formatDuration(ms) {
1875
2296
  if (ms < 1e3) return `${ms}ms`;
1876
2297
  return `${Math.round(ms / 100) / 10}s`;
1877
2298
  }
1878
- function formatBytes$1(bytes) {
2299
+ function formatBytes(bytes) {
1879
2300
  if (bytes < 1024) return `${bytes} B`;
1880
2301
  const units = [
1881
2302
  "KB",
@@ -1925,11 +2346,6 @@ async function parseErrorResponse(response) {
1925
2346
  function normalizeEmail$1(email) {
1926
2347
  return email.trim().toLowerCase();
1927
2348
  }
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
2349
  function isShadowEmail$1(email) {
1934
2350
  return Boolean(email && SHADOW_EMAIL_PATTERN$1.test(email));
1935
2351
  }
@@ -1948,8 +2364,7 @@ async function refreshFormalAccessToken(context, deps) {
1948
2364
  platformApiUrl: context.platformApiUrl,
1949
2365
  accessToken: payload.accessToken,
1950
2366
  refreshToken: payload.refreshToken ?? context.refreshToken,
1951
- ...user ? { user } : {},
1952
- source: "shadow-email-upgrade"
2367
+ ...user ? { user } : {}
1953
2368
  };
1954
2369
  context.accessToken = updated.accessToken;
1955
2370
  context.refreshToken = updated.refreshToken;
@@ -1961,30 +2376,6 @@ async function refreshFormalAccessToken(context, deps) {
1961
2376
  });
1962
2377
  return payload.accessToken;
1963
2378
  }
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
2379
  async function promptText(question, initialValue, deps) {
1989
2380
  if (deps.promptText) return await deps.promptText(question, initialValue);
1990
2381
  if (!process.stdin.isTTY) return "";
@@ -2047,112 +2438,17 @@ function validatePublisherEmail(rawEmail) {
2047
2438
  if (!email || isShadowEmail$1(email)) throw new Error("Dineway account email must be a real owner email, not a shadow user email.");
2048
2439
  return email;
2049
2440
  }
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
- function isStoredFormalCredentialForEmail(stored, email) {
2057
- if (!stored?.accessToken || !stored.user) return false;
2058
- if (email && normalizeEmail$1(stored.user.email) !== email) return false;
2059
- if (stored.user.emailVerified !== true) return false;
2060
- if (isShadowEmail$1(stored.user.email)) return false;
2061
- return true;
2062
- }
2063
- function assertVerifiedFormalAccountUser(user, expectedEmail) {
2064
- if (!user || user.emailVerified !== true || isShadowEmail$1(user.email)) throw new Error("Forgeway formal account credentials require a verified formal account.");
2065
- if (expectedEmail && normalizeEmail$1(user.email) !== normalizeEmail$1(expectedEmail)) throw new Error("Forgeway refresh returned credentials for a different email.");
2066
- return user;
2067
- }
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
- };
2441
+ function isStoredFormalCredentialForEmail(stored, email) {
2442
+ if (!stored?.accessToken || !stored.user) return false;
2443
+ if (email && normalizeEmail$1(stored.user.email) !== email) return false;
2444
+ if (stored.user.emailVerified !== true) return false;
2445
+ if (isShadowEmail$1(stored.user.email)) return false;
2446
+ return true;
2110
2447
  }
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
- };
2448
+ function assertVerifiedFormalAccountUser(user, expectedEmail) {
2449
+ if (!user || user.emailVerified !== true || isShadowEmail$1(user.email)) throw new Error("Forgeway formal account credentials require a verified formal account.");
2450
+ if (expectedEmail && normalizeEmail$1(user.email) !== normalizeEmail$1(expectedEmail)) throw new Error("Forgeway refresh returned credentials for a different email.");
2451
+ return user;
2156
2452
  }
2157
2453
  async function readCachedPublisherCredentials(cwd, platformApiUrl, email, deps) {
2158
2454
  const credentials = await (deps.readCredentials ?? readForgewayCredentials)({
@@ -2218,7 +2514,6 @@ async function resolveFormalProjectContext(cwd, options, deps) {
2218
2514
  const context = {
2219
2515
  projectDir: cwd,
2220
2516
  platformApiUrl,
2221
- authKind: "formal-account",
2222
2517
  accessToken: account.credentials.accessToken,
2223
2518
  refreshToken: account.credentials.refreshToken,
2224
2519
  user,
@@ -2232,7 +2527,7 @@ async function resolveFormalProjectContext(cwd, options, deps) {
2232
2527
  city: options.city
2233
2528
  };
2234
2529
  if (!context.placeId) {
2235
- const resolvedRestaurant = await resolveShadowRestaurantInfo(options, deps);
2530
+ const resolvedRestaurant = await resolveRequiredRestaurantInfo(options, deps);
2236
2531
  restaurant = resolvedRestaurant;
2237
2532
  context.placeId = await resolvePlaceIdWithFormalSearch({
2238
2533
  context,
@@ -2248,100 +2543,11 @@ async function resolveFormalProjectContext(cwd, options, deps) {
2248
2543
  restaurant
2249
2544
  };
2250
2545
  }
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
2546
  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;
2547
+ const formal = await resolveFormalProjectContext(cwd, options, deps);
2548
+ if (formal.status !== "missing") return formal;
2549
+ if (formal.email) throw new Error(`No verified Dineway account credentials were found for ${formal.email}. Run: dineway account login --email ${formal.email}`);
2550
+ throw new Error("No verified Dineway account credentials were found. Run: dineway account login");
2345
2551
  }
2346
2552
  function isRecord(value) {
2347
2553
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -2522,80 +2728,6 @@ function extractPlaceCandidates(payload) {
2522
2728
  if (!Array.isArray(places)) throw new Error("Dineway place search response did not include places/results.");
2523
2729
  return places.filter(isRecord);
2524
2730
  }
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
2731
  async function resolvePlaceIdWithFormalSearch(options) {
2600
2732
  const candidates = extractPlaceCandidates(await ossFetch(options.context, "/api/places/search", options.deps, {
2601
2733
  method: "POST",
@@ -2610,22 +2742,6 @@ async function resolvePlaceIdWithFormalSearch(options) {
2610
2742
  if (!PLACE_ID_PATTERN.test(finalPlaceId)) throw new Error("Could not resolve a valid Dineway place id for Forgeway deploy.");
2611
2743
  return finalPlaceId;
2612
2744
  }
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
2745
  async function ossFetch(context, path, deps, options = {}) {
2630
2746
  const request = async (token) => await forgewayRequest(`${context.ossHost.replace(TRAILING_SLASH_PATTERN$1, "")}${path}`, {
2631
2747
  ...options,
@@ -2638,7 +2754,7 @@ async function ossFetch(context, path, deps, options = {}) {
2638
2754
  const token = context.accessToken;
2639
2755
  if (!token) throw new Error("Forgeway deploy context is missing an authorization token.");
2640
2756
  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));
2757
+ if (response.status === 401) response = await request(await refreshFormalAccessToken(context, deps));
2642
2758
  if (!response.ok) throw new ForgewayApiError(await parseErrorResponse(response), response.status);
2643
2759
  return await response.json();
2644
2760
  }
@@ -2653,18 +2769,18 @@ function deriveForgewaySiteSlug(restaurantName, city) {
2653
2769
  async function resolveSeedPath$1(cwd, explicitSeedPath) {
2654
2770
  if (explicitSeedPath) {
2655
2771
  const resolved = resolve(cwd, explicitSeedPath);
2656
- if (!await fileExists$8(resolved)) throw new Error(`Seed file not found: ${explicitSeedPath}`);
2772
+ if (!await fileExists$7(resolved)) throw new Error(`Seed file not found: ${explicitSeedPath}`);
2657
2773
  return resolved;
2658
2774
  }
2659
2775
  const convention = resolve(cwd, ".dineway", "seed.json");
2660
- if (await fileExists$8(convention)) return convention;
2776
+ if (await fileExists$7(convention)) return convention;
2661
2777
  const pkg = await readDeployPackageJson(cwd).catch(() => null);
2662
2778
  if (typeof pkg?.dineway?.seed === "string") {
2663
2779
  const configured = resolve(cwd, pkg.dineway.seed);
2664
- if (await fileExists$8(configured)) return configured;
2780
+ if (await fileExists$7(configured)) return configured;
2665
2781
  }
2666
2782
  const legacyConvention = resolve(cwd, "seed", "seed.json");
2667
- if (await fileExists$8(legacyConvention)) return legacyConvention;
2783
+ if (await fileExists$7(legacyConvention)) return legacyConvention;
2668
2784
  return null;
2669
2785
  }
2670
2786
  async function readSeedTitle(seedPath) {
@@ -2689,7 +2805,7 @@ async function resolveRestaurantInfo(options, seedPath, deps, requireForSlug, us
2689
2805
  city
2690
2806
  };
2691
2807
  }
2692
- async function resolveShadowRestaurantInfo(options, deps) {
2808
+ async function resolveRequiredRestaurantInfo(options, deps) {
2693
2809
  return {
2694
2810
  name: options.restaurantName ?? await promptRequired("Restaurant name: ", void 0, deps, "Restaurant name is required. Pass --restaurant-name."),
2695
2811
  city: options.city ?? await promptRequired("City: ", void 0, deps, "City is required. Pass --city.")
@@ -3032,7 +3148,7 @@ async function deploySiteProject(options) {
3032
3148
  consola.start("Scanning deploy files");
3033
3149
  const localFiles = await (options.deps.collectDeploymentFiles ?? collectDeploymentFiles)(options.sourceDir);
3034
3150
  if (localFiles.length === 0) throw new Error("No deployable files found in the source directory.");
3035
- consola.success(`Scanned ${localFiles.length} files (${formatBytes$1(deploymentFileSize(localFiles))}) in ${formatDuration(Date.now() - scanStart)}`);
3151
+ consola.success(`Scanned ${localFiles.length} files (${formatBytes(deploymentFileSize(localFiles))}) in ${formatDuration(Date.now() - scanStart)}`);
3036
3152
  const createStart = Date.now();
3037
3153
  consola.start("Creating Forgeway deployment");
3038
3154
  const createResult = await ossFetch(options.context, `/api/deployments/sites/${encodeURIComponent(options.siteId)}/deploy`, options.deps, {
@@ -3051,7 +3167,7 @@ async function deploySiteProject(options) {
3051
3167
  const pendingFiles = createResult.files.filter((file) => !file.uploadedAt);
3052
3168
  const pendingSize = pendingFiles.reduce((total, file) => total + file.size, 0);
3053
3169
  if (pendingFiles.length === 0) consola.success("No file uploads needed");
3054
- else consola.start(`Uploading ${pendingFiles.length} changed files (${formatBytes$1(pendingSize)})`);
3170
+ else consola.start(`Uploading ${pendingFiles.length} changed files (${formatBytes(pendingSize)})`);
3055
3171
  let uploadedCount = 0;
3056
3172
  await runWithConcurrency(pendingFiles, DIRECT_UPLOAD_CONCURRENCY, async (manifestFile) => {
3057
3173
  const localFile = localFileByPath.get(manifestFile.path);
@@ -3094,15 +3210,6 @@ function formatDinewayAdminBootstrapMessage(bootstrap) {
3094
3210
  "CLI example: npx dineway whoami"
3095
3211
  ].join("\n");
3096
3212
  }
3097
- function formatForgewayOtpSentMessage(email, expiresAt) {
3098
- const lines = [
3099
- `Sent Forgeway email verification code to ${email}.`,
3100
- "Run the Forgeway deploy command again with the same restaurant/site options and --otp <code>.",
3101
- `Example: npx dineway deploy forgeway --email ${email} --otp 123456`
3102
- ];
3103
- if (expiresAt) lines.splice(1, 0, `Code expires at ${expiresAt}.`);
3104
- return lines.join("\n");
3105
- }
3106
3213
  async function deployForgeway(cwd, options, deps = {}) {
3107
3214
  if (options.dryRun) return { message: "[dry-run] Would resolve Forgeway project, create/reuse site, bind database, initialize Dineway, upload files, and start deployment." };
3108
3215
  const sourceDir = resolve(cwd);
@@ -3112,9 +3219,7 @@ async function deployForgeway(cwd, options, deps = {}) {
3112
3219
  if (database !== "none") await warnProjectDinewayRuntimeMismatch(cwd, deps.dinewayVersion ?? VERSION);
3113
3220
  await ensureProjectGitignoreDinewayLocalState(cwd);
3114
3221
  const verbose = isVerboseDeploy(options);
3115
- const project = await resolveProjectContext(cwd, options, deps);
3116
- if (project.status === "otp-sent") return { message: formatForgewayOtpSentMessage(project.email, project.expiresAt) };
3117
- const { context, restaurant } = project;
3222
+ const { context, restaurant } = await resolveProjectContext(cwd, options, deps);
3118
3223
  const seedPath = options.skipSeed ? null : await resolveSeedPath$1(cwd, options.seed);
3119
3224
  if (options.skipSeed) consola.info("Skipping seed initialization by request");
3120
3225
  await ensureRestaurantClaim(context, restaurant, deps);
@@ -3174,7 +3279,6 @@ const forgewayTarget = {
3174
3279
  remoteBuild: true,
3175
3280
  supportLevel: "stable",
3176
3281
  async generateConfig(cwd, options) {
3177
- if (options.sendOtp) return [];
3178
3282
  return await configureAstroDeployAdapter(cwd, "vercel", options.dryRun);
3179
3283
  },
3180
3284
  async deploy(cwd, options) {
@@ -3207,7 +3311,7 @@ pnpm-debug.log*
3207
3311
  yarn-debug.log*
3208
3312
  yarn-error.log*
3209
3313
  `;
3210
- async function fileExists$7(path) {
3314
+ async function fileExists$6(path) {
3211
3315
  try {
3212
3316
  await access(path);
3213
3317
  return true;
@@ -3217,7 +3321,7 @@ async function fileExists$7(path) {
3217
3321
  }
3218
3322
  async function writeGeneratedFile(cwd, relativePath, content, dryRun) {
3219
3323
  const path = join(cwd, relativePath);
3220
- if (await fileExists$7(path)) return {
3324
+ if (await fileExists$6(path)) return {
3221
3325
  path: relativePath,
3222
3326
  action: "exists"
3223
3327
  };
@@ -3350,7 +3454,7 @@ const gcpTarget = {
3350
3454
  env: options.env,
3351
3455
  stdio: "inherit"
3352
3456
  });
3353
- if (result.code !== 0 && !await fileExists$7(join(cwd, "Dockerfile"))) {
3457
+ if (result.code !== 0 && !await fileExists$6(join(cwd, "Dockerfile"))) {
3354
3458
  await writeFile(join(cwd, "Dockerfile"), generateDockerfile(), "utf-8");
3355
3459
  result = await runCommand$1("gcloud", deployArgs, {
3356
3460
  cwd,
@@ -3369,7 +3473,7 @@ const gcpTarget = {
3369
3473
 
3370
3474
  //#endregion
3371
3475
  //#region src/cli/commands/deploy/utils/build.ts
3372
- async function fileExists$6(path) {
3476
+ async function fileExists$5(path) {
3373
3477
  try {
3374
3478
  await access(path);
3375
3479
  return true;
@@ -3378,19 +3482,19 @@ async function fileExists$6(path) {
3378
3482
  }
3379
3483
  }
3380
3484
  async function detectBuildCommand(cwd) {
3381
- if (await fileExists$6(join(cwd, "pnpm-lock.yaml"))) return {
3485
+ if (await fileExists$5(join(cwd, "pnpm-lock.yaml"))) return {
3382
3486
  packageManager: "pnpm",
3383
3487
  command: "pnpm",
3384
3488
  args: ["build"],
3385
3489
  display: "pnpm build"
3386
3490
  };
3387
- if (await fileExists$6(join(cwd, "yarn.lock"))) return {
3491
+ if (await fileExists$5(join(cwd, "yarn.lock"))) return {
3388
3492
  packageManager: "yarn",
3389
3493
  command: "yarn",
3390
3494
  args: ["build"],
3391
3495
  display: "yarn build"
3392
3496
  };
3393
- if (await fileExists$6(join(cwd, "bun.lock")) || await fileExists$6(join(cwd, "bun.lockb"))) return {
3497
+ if (await fileExists$5(join(cwd, "bun.lock")) || await fileExists$5(join(cwd, "bun.lockb"))) return {
3394
3498
  packageManager: "bun",
3395
3499
  command: "bun",
3396
3500
  args: ["run", "build"],
@@ -3421,7 +3525,7 @@ const INVALID_RAILWAY_PROJECT_CHARS_RE = /[^a-z0-9-]+/g;
3421
3525
  const REPEATED_HYPHENS_RE = /-+/g;
3422
3526
  const EDGE_HYPHENS_RE = /^-|-$/g;
3423
3527
  const RAILWAY_BUILDER = "RAILPACK";
3424
- async function fileExists$5(path) {
3528
+ async function fileExists$4(path) {
3425
3529
  try {
3426
3530
  await access(path);
3427
3531
  return true;
@@ -3515,7 +3619,7 @@ const railwayTarget = {
3515
3619
  async generateConfig(cwd, options) {
3516
3620
  const generated = await configureAstroDeployAdapter(cwd, "node", options.dryRun);
3517
3621
  const railwayPath = join(cwd, "railway.json");
3518
- if (await fileExists$5(railwayPath)) return [...generated, {
3622
+ if (await fileExists$4(railwayPath)) return [...generated, {
3519
3623
  path: "railway.json",
3520
3624
  action: "exists"
3521
3625
  }];
@@ -3706,16 +3810,6 @@ const deployCommand = defineCommand({
3706
3810
  description: "Dineway account email for deploy authorization",
3707
3811
  required: false
3708
3812
  },
3709
- "send-otp": {
3710
- type: "boolean",
3711
- description: "Send a Forgeway email verification code and exit without prompting or deploying",
3712
- default: false
3713
- },
3714
- otp: {
3715
- type: "string",
3716
- description: "Forgeway email verification code for non-interactive deploy authorization",
3717
- required: false
3718
- },
3719
3813
  "restaurant-name": {
3720
3814
  type: "string",
3721
3815
  description: "Restaurant name for first Forgeway site creation",
@@ -3763,8 +3857,6 @@ const deployCommand = defineCommand({
3763
3857
  site: args.site,
3764
3858
  placeId: args["place-id"],
3765
3859
  email: args.email,
3766
- sendOtp: args["send-otp"],
3767
- otp: args.otp,
3768
3860
  restaurantName: args["restaurant-name"],
3769
3861
  city: args.city,
3770
3862
  database: args.database,
@@ -3773,8 +3865,6 @@ const deployCommand = defineCommand({
3773
3865
  forceDbInit: args["force-db-init"],
3774
3866
  verbose: args.verbose
3775
3867
  };
3776
- if ((options.sendOtp || options.otp) && target.name !== "forgeway") throw new Error("--send-otp and --otp are only supported for Forgeway deploys.");
3777
- if (options.sendOtp && options.otp) throw new Error("Use either --send-otp or --otp, not both.");
3778
3868
  consola.start(`Preparing ${target.label} deploy`);
3779
3869
  await ensureTargetCli(target, cwd, {
3780
3870
  yes: options.yes,
@@ -3808,7 +3898,21 @@ const deployCommand = defineCommand({
3808
3898
  consola.info("[dry-run] Would ensure Dineway local state entries in .gitignore");
3809
3899
  consola.info(`[dry-run] Would save .dineway/deploy.json target=${target.name}`);
3810
3900
  }
3811
- const result = await target.deploy(cwd, options);
3901
+ const result = await target.deploy(cwd, options).catch(async (error) => {
3902
+ if (await handleCliPaywall({
3903
+ error,
3904
+ resource: `deploy:${target.name}`,
3905
+ platformApiUrl: process.env.DINEWAY_FORGEWAY_API_URL,
3906
+ webUrl: process.env.DINEWAY_WEB_URL,
3907
+ interactive: process.stdin.isTTY && !options.yes,
3908
+ context: {
3909
+ target: target.name,
3910
+ site: options.site,
3911
+ placeId: options.placeId
3912
+ }
3913
+ })) process.exit(2);
3914
+ throw error;
3915
+ });
3812
3916
  if (result.url) consola.success(result.url);
3813
3917
  consola.success(result.message);
3814
3918
  }
@@ -3872,7 +3976,7 @@ async function readPackageJson$2(cwd) {
3872
3976
  return null;
3873
3977
  }
3874
3978
  }
3875
- async function fileExists$4(path) {
3979
+ async function fileExists$3(path) {
3876
3980
  try {
3877
3981
  await access(path);
3878
3982
  return true;
@@ -3919,7 +4023,7 @@ const devCommand = defineCommand({
3919
4023
  }
3920
4024
  const database = resolveCliDatabaseTarget(cwd, args.database);
3921
4025
  consola.info(`Database: ${database.display}`);
3922
- if (database.localPath && !await fileExists$4(database.localPath)) consola.start("Database not found, initializing...");
4026
+ if (database.localPath && !await fileExists$3(database.localPath)) consola.start("Database not found, initializing...");
3923
4027
  const db = createDatabase({ url: database.url });
3924
4028
  try {
3925
4029
  consola.start("Checking database migrations...");
@@ -3958,8 +4062,8 @@ const devCommand = defineCommand({
3958
4062
  "--port",
3959
4063
  args.port
3960
4064
  ];
3961
- const pnpmLockExists = await fileExists$4(resolve(cwd, "pnpm-lock.yaml"));
3962
- const yarnLockExists = await fileExists$4(resolve(cwd, "yarn.lock"));
4065
+ const pnpmLockExists = await fileExists$3(resolve(cwd, "pnpm-lock.yaml"));
4066
+ const yarnLockExists = await fileExists$3(resolve(cwd, "yarn.lock"));
3963
4067
  let cmd;
3964
4068
  let cmdArgs;
3965
4069
  if (pnpmLockExists) {
@@ -4003,7 +4107,7 @@ const devCommand = defineCommand({
4003
4107
  *
4004
4108
  * Diagnose database health: connection, migrations, schema integrity.
4005
4109
  */
4006
- async function fileExists$3(path) {
4110
+ async function fileExists$2(path) {
4007
4111
  try {
4008
4112
  await access(path);
4009
4113
  return true;
@@ -4016,7 +4120,7 @@ function printResult(result) {
4016
4120
  }
4017
4121
  async function checkDatabase(database) {
4018
4122
  const results = [];
4019
- if (database.localPath && !await fileExists$3(database.localPath)) {
4123
+ if (database.localPath && !await fileExists$2(database.localPath)) {
4020
4124
  results.push({
4021
4125
  name: "database",
4022
4126
  status: "fail",
@@ -4070,7 +4174,7 @@ async function checkDatabase(database) {
4070
4174
  });
4071
4175
  } catch {}
4072
4176
  try {
4073
- const count = (await sql`SELECT COUNT(id) as count FROM _dineway_users`.execute(db)).rows[0]?.count ?? 0;
4177
+ const count = (await sql`SELECT COUNT(id) as count FROM users`.execute(db)).rows[0]?.count ?? 0;
4074
4178
  results.push({
4075
4179
  name: "users",
4076
4180
  status: count > 0 ? "pass" : "warn",
@@ -4218,7 +4322,7 @@ async function exportSeed(db, withContent) {
4218
4322
  const { bylines, idToSeedId: bylineIdToSeedId } = await exportBylines(db);
4219
4323
  if (bylines.length > 0) seed.bylines = bylines;
4220
4324
  if (withContent !== void 0) {
4221
- const collections = withContent === "" || withContent === "true" ? null : withContent.split(",").map((s) => s.trim()).filter(Boolean);
4325
+ const collections = withContent === "" || withContent === "true" || withContent === "all" ? null : withContent.split(",").map((s) => s.trim()).filter(Boolean);
4222
4326
  seed.content = await exportContent(db, seed.collections || [], collections, bylineIdToSeedId, i18nEnabled);
4223
4327
  }
4224
4328
  return seed;
@@ -4348,8 +4452,8 @@ async function exportTaxonomies(db, i18nEnabled) {
4348
4452
  for (const def of defs) {
4349
4453
  const defSeedId = i18nEnabled && def.locale ? `tax:${def.name}:${def.locale}` : `tax:${def.name}`;
4350
4454
  const terms = await termRepo.findByName(def.name, { locale: def.locale });
4351
- const idToSlug = /* @__PURE__ */ new Map();
4352
- for (const term of terms) idToSlug.set(term.id, term.slug);
4455
+ const groupToSlug = /* @__PURE__ */ new Map();
4456
+ for (const term of terms) groupToSlug.set(term.translationGroup ?? term.id, term.slug);
4353
4457
  const termGroupToSeedId = /* @__PURE__ */ new Map();
4354
4458
  const seedTerms = [];
4355
4459
  for (const term of terms) {
@@ -4360,7 +4464,7 @@ async function exportTaxonomies(db, i18nEnabled) {
4360
4464
  label: term.label,
4361
4465
  description: typeof term.data?.description === "string" ? term.data.description : void 0
4362
4466
  };
4363
- if (term.parentId) seedTerm.parent = idToSlug.get(term.parentId);
4467
+ if (term.parentId) seedTerm.parent = groupToSlug.get(term.parentId);
4364
4468
  if (i18nEnabled && term.locale) {
4365
4469
  seedTerm.locale = term.locale;
4366
4470
  if (term.translationGroup) {
@@ -4649,7 +4753,7 @@ async function getTaxonomyAssignments(taxonomyRepo, collection, entryId) {
4649
4753
  *
4650
4754
  * Initialize database from template config in package.json
4651
4755
  */
4652
- async function fileExists$2(path) {
4756
+ async function fileExists$1(path) {
4653
4757
  try {
4654
4758
  await access(path);
4655
4759
  return true;
@@ -4749,7 +4853,7 @@ const initCommand = defineCommand({
4749
4853
  if (alreadyInitialized && args.force) consola.warn("Re-initializing (--force)...");
4750
4854
  if (config?.schema) {
4751
4855
  const schemaPath = resolve(cwd, config.schema);
4752
- if (await fileExists$2(schemaPath)) {
4856
+ if (await fileExists$1(schemaPath)) {
4753
4857
  consola.start(`Running schema: ${config.schema}`);
4754
4858
  try {
4755
4859
  await runSqlFile(db, schemaPath);
@@ -5292,593 +5396,6 @@ const menuCommand = defineCommand({
5292
5396
  }
5293
5397
  });
5294
5398
 
5295
- //#endregion
5296
- //#region src/cli/commands/bundle-utils.ts
5297
- /**
5298
- * Bundle utility functions
5299
- *
5300
- * Shared logic extracted from the bundle command so it can be tested
5301
- * without the CLI harness and tsdown dependency.
5302
- */
5303
- const MAX_BUNDLE_SIZE = 256 * 1024;
5304
- const MAX_FILE_SIZE = 128 * 1024;
5305
- const MAX_FILE_COUNT = 20;
5306
- const MAX_SCREENSHOTS = 5;
5307
- const MAX_SCREENSHOT_WIDTH = 1920;
5308
- const MAX_SCREENSHOT_HEIGHT = 1080;
5309
- const ICON_SIZE = 256;
5310
- function toFileImportSpecifier(filePath) {
5311
- return pathToFileURL(filePath).href;
5312
- }
5313
- /** Matches Node.js built-in imports in bundled output. */
5314
- const NODE_BUILTIN_IMPORT_RE = /(?:import|export|require)\s*(?:\(|[^(]*?\bfrom\s+)["'](?:node:)?([a-z_]+)(?:\/[^"']*)?\s*["']\)?/g;
5315
- const LEADING_DOT_SLASH_RE = /^\.\//;
5316
- const DIST_PREFIX_RE = /^dist\//;
5317
- const MJS_EXT_RE = /\.m?js$/;
5318
- const BUILD_OUTPUT_EXT_RE = /\.(?:mjs|js|cjs)$/;
5319
- const TS_TO_TSX_RE = /\.ts$/;
5320
- /** Node.js built-in modules that shouldn't appear in sandbox code */
5321
- const NODE_BUILTINS = new Set([
5322
- "assert",
5323
- "buffer",
5324
- "child_process",
5325
- "cluster",
5326
- "crypto",
5327
- "dgram",
5328
- "dns",
5329
- "domain",
5330
- "events",
5331
- "fs",
5332
- "http",
5333
- "http2",
5334
- "https",
5335
- "inspector",
5336
- "module",
5337
- "net",
5338
- "os",
5339
- "path",
5340
- "perf_hooks",
5341
- "process",
5342
- "punycode",
5343
- "querystring",
5344
- "readline",
5345
- "repl",
5346
- "stream",
5347
- "string_decoder",
5348
- "sys",
5349
- "timers",
5350
- "tls",
5351
- "trace_events",
5352
- "tty",
5353
- "url",
5354
- "util",
5355
- "v8",
5356
- "vm",
5357
- "wasi",
5358
- "worker_threads",
5359
- "zlib"
5360
- ]);
5361
- async function fileExists$1(path) {
5362
- try {
5363
- await access(path);
5364
- return true;
5365
- } catch {
5366
- return false;
5367
- }
5368
- }
5369
- /**
5370
- * Read image dimensions from a buffer.
5371
- * Returns [width, height] or null if the format is unrecognized.
5372
- */
5373
- function readImageDimensions(buf) {
5374
- try {
5375
- const result = imageSize(buf);
5376
- if (result.width != null && result.height != null) return [result.width, result.height];
5377
- return null;
5378
- } catch {
5379
- return null;
5380
- }
5381
- }
5382
- /**
5383
- * Extract manifest metadata from a ResolvedPlugin.
5384
- * Strips functions (hooks, route handlers) and keeps only serializable metadata.
5385
- */
5386
- function extractManifest(plugin) {
5387
- const hooks = [];
5388
- for (const [name, resolved] of Object.entries(plugin.hooks)) {
5389
- if (!resolved) continue;
5390
- if (resolved.exclusive || resolved.priority !== 100 || resolved.timeout !== 5e3) {
5391
- const entry = { name };
5392
- if (resolved.exclusive) entry.exclusive = true;
5393
- if (resolved.priority !== 100) entry.priority = resolved.priority;
5394
- if (resolved.timeout !== 5e3) entry.timeout = resolved.timeout;
5395
- hooks.push(entry);
5396
- } else hooks.push(name);
5397
- }
5398
- return {
5399
- id: plugin.id,
5400
- version: plugin.version,
5401
- capabilities: plugin.capabilities,
5402
- allowedHosts: plugin.allowedHosts,
5403
- storage: plugin.storage,
5404
- hooks,
5405
- routes: Object.keys(plugin.routes),
5406
- admin: {
5407
- settingsSchema: plugin.admin.settingsSchema,
5408
- pages: plugin.admin.pages,
5409
- widgets: plugin.admin.widgets
5410
- }
5411
- };
5412
- }
5413
- /**
5414
- * Scan bundled code for Node.js built-in imports.
5415
- * Matches require("node:xxx"), require("xxx"), import("node:xxx") — the patterns
5416
- * that appear in bundled ESM/CJS output (not source-level named imports).
5417
- * Returns deduplicated array of built-in module names found.
5418
- */
5419
- function findNodeBuiltinImports(code) {
5420
- const found = [];
5421
- NODE_BUILTIN_IMPORT_RE.lastIndex = 0;
5422
- let match;
5423
- while ((match = NODE_BUILTIN_IMPORT_RE.exec(code)) !== null) {
5424
- const mod = match[1];
5425
- if (NODE_BUILTINS.has(mod)) found.push(mod);
5426
- }
5427
- return [...new Set(found)];
5428
- }
5429
- /**
5430
- * Find a build output file by base name, checking common extensions.
5431
- * tsdown may output .mjs, .js, or .cjs depending on format and config.
5432
- */
5433
- async function findBuildOutput(dir, baseName) {
5434
- const normalizedBaseName = baseName.replace(BUILD_OUTPUT_EXT_RE, "");
5435
- for (const ext of [
5436
- ".mjs",
5437
- ".js",
5438
- ".cjs"
5439
- ]) {
5440
- const candidate = join(dir, `${normalizedBaseName}${ext}`);
5441
- if (await fileExists$1(candidate)) return candidate;
5442
- }
5443
- }
5444
- /**
5445
- * Resolve a dist/built path back to its source .ts/.tsx equivalent.
5446
- * E.g., "./dist/index.mjs" → "src/index.ts"
5447
- */
5448
- async function resolveSourceEntry(pluginDir, distPath) {
5449
- const cleaned = distPath.replace(LEADING_DOT_SLASH_RE, "");
5450
- const srcPath = cleaned.replace(DIST_PREFIX_RE, "src/").replace(MJS_EXT_RE, ".ts");
5451
- const srcFull = resolve(pluginDir, srcPath);
5452
- if (await fileExists$1(srcFull)) return srcFull;
5453
- const tsxFull = resolve(pluginDir, srcPath.replace(TS_TO_TSX_RE, ".tsx"));
5454
- if (await fileExists$1(tsxFull)) return tsxFull;
5455
- const direct = resolve(pluginDir, cleaned);
5456
- if (await fileExists$1(direct)) return direct;
5457
- }
5458
- const TS_SOURCE_EXPORT_RE = /\.(?:ts|tsx|mts|cts|jsx)$/;
5459
- /**
5460
- * Find package.json exports that point to source files instead of built output.
5461
- * Returns an array of `{ exportPath, resolvedPath }` for each offending export.
5462
- */
5463
- function findSourceExports(exports) {
5464
- const issues = [];
5465
- for (const [exportPath, exportValue] of Object.entries(exports)) {
5466
- const resolved = typeof exportValue === "string" ? exportValue : exportValue && typeof exportValue === "object" && "import" in exportValue ? exportValue.import : null;
5467
- if (resolved && TS_SOURCE_EXPORT_RE.test(resolved)) issues.push({
5468
- exportPath,
5469
- resolvedPath: resolved
5470
- });
5471
- }
5472
- return issues;
5473
- }
5474
- /**
5475
- * Recursively walk a staging directory and return all regular files with
5476
- * tarball-relative names.
5477
- */
5478
- async function collectBundleEntries(dir) {
5479
- const entries = [];
5480
- await walkBundle(dir, "", entries);
5481
- return entries;
5482
- }
5483
- async function walkBundle(dir, prefix, into) {
5484
- const items = await readdir(dir, { withFileTypes: true });
5485
- for (const item of items) {
5486
- const fullPath = join(dir, item.name);
5487
- const relPath = prefix ? `${prefix}/${item.name}` : item.name;
5488
- if (item.isFile()) {
5489
- const s = await stat(fullPath);
5490
- into.push({
5491
- name: relPath,
5492
- bytes: s.size
5493
- });
5494
- } else if (item.isDirectory()) await walkBundle(fullPath, relPath, into);
5495
- }
5496
- }
5497
- function totalBundleBytes(entries) {
5498
- let total = 0;
5499
- for (const entry of entries) total += entry.bytes;
5500
- return total;
5501
- }
5502
- /**
5503
- * Enforce sandboxed plugin caps against decompressed bundle files:
5504
- * total size, per-file size, and file count.
5505
- */
5506
- function validateBundleSize(entries) {
5507
- const violations = [];
5508
- const total = totalBundleBytes(entries);
5509
- if (total > MAX_BUNDLE_SIZE) violations.push(`Bundle size ${formatBytes(total)} exceeds maximum of ${formatBytes(MAX_BUNDLE_SIZE)}.`);
5510
- if (entries.length > MAX_FILE_COUNT) violations.push(`Bundle contains ${entries.length} files, exceeds maximum of ${MAX_FILE_COUNT}.`);
5511
- const oversized = entries.filter((entry) => entry.bytes > MAX_FILE_SIZE).toSorted((a, b) => a.name.localeCompare(b.name));
5512
- for (const entry of oversized) violations.push(`File ${entry.name} is ${formatBytes(entry.bytes)}, exceeds per-file maximum of ${formatBytes(MAX_FILE_SIZE)}.`);
5513
- return violations;
5514
- }
5515
- function formatBytes(bytes) {
5516
- if (bytes < 1024) return `${bytes} B`;
5517
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
5518
- return `${(bytes / 1024 / 1024).toFixed(2)} MB`;
5519
- }
5520
- /**
5521
- * Create a gzipped tarball from a directory.
5522
- */
5523
- async function createTarball(sourceDir, outputPath) {
5524
- const { createGzip } = await import("node:zlib");
5525
- await pipeline(packTar(sourceDir), createGzip({ level: 9 }), createWriteStream(outputPath));
5526
- }
5527
-
5528
- //#endregion
5529
- //#region src/cli/commands/bundle.ts
5530
- /**
5531
- * dineway plugin bundle
5532
- *
5533
- * Produces a publishable plugin tarball from a plugin source directory.
5534
- *
5535
- * Steps:
5536
- * 1. Resolve plugin entrypoint (finds definePlugin() export)
5537
- * 2. Bundle backend code with tsdown → backend.js (single ES module, tree-shaken)
5538
- * 3. Bundle admin code if present → admin.js
5539
- * 4. Extract manifest from definePlugin() → manifest.json
5540
- * 5. Collect assets (README.md, icon.png, screenshots/)
5541
- * 6. Validate bundle (manifest schema, size limits, no Node.js builtins)
5542
- * 7. Create tarball ({id}-{version}.tar.gz)
5543
- */
5544
- var bundle_exports = /* @__PURE__ */ __exportAll({ bundleCommand: () => bundleCommand });
5545
- const TS_EXT_RE = /\.tsx?$/;
5546
- const SLASH_RE = /\//g;
5547
- const LEADING_AT_RE = /^@/;
5548
- const DINEWAY_SCOPE_RE = /^@dineway-ai\//;
5549
- const bundleCommand = defineCommand({
5550
- meta: {
5551
- name: "bundle",
5552
- description: "Bundle a plugin for marketplace distribution"
5553
- },
5554
- args: {
5555
- dir: {
5556
- type: "string",
5557
- description: "Plugin directory (default: current directory)",
5558
- default: process.cwd()
5559
- },
5560
- outDir: {
5561
- type: "string",
5562
- alias: "o",
5563
- description: "Output directory for the tarball (default: ./dist)",
5564
- default: "dist"
5565
- },
5566
- validateOnly: {
5567
- type: "boolean",
5568
- description: "Run validation only, skip tarball creation",
5569
- default: false
5570
- }
5571
- },
5572
- async run({ args }) {
5573
- const pluginDir = resolve(args.dir);
5574
- const outDir = resolve(pluginDir, args.outDir);
5575
- const validateOnly = args.validateOnly;
5576
- consola.start(validateOnly ? "Validating plugin..." : "Bundling plugin...");
5577
- const pkgPath = join(pluginDir, "package.json");
5578
- if (!await fileExists$1(pkgPath)) {
5579
- consola.error("No package.json found in", pluginDir);
5580
- process.exit(1);
5581
- }
5582
- const pkg = JSON.parse(await readFile(pkgPath, "utf-8"));
5583
- let backendEntry;
5584
- let adminEntry;
5585
- if (pkg.exports) {
5586
- const sandboxExport = pkg.exports["./sandbox"];
5587
- if (typeof sandboxExport === "string") backendEntry = await resolveSourceEntry(pluginDir, sandboxExport);
5588
- else if (sandboxExport && typeof sandboxExport === "object" && "import" in sandboxExport) backendEntry = await resolveSourceEntry(pluginDir, sandboxExport.import);
5589
- const adminExport = pkg.exports["./admin"];
5590
- if (typeof adminExport === "string") adminEntry = await resolveSourceEntry(pluginDir, adminExport);
5591
- else if (adminExport && typeof adminExport === "object" && "import" in adminExport) adminEntry = await resolveSourceEntry(pluginDir, adminExport.import);
5592
- }
5593
- if (!backendEntry) {
5594
- const defaultSandbox = join(pluginDir, "src/sandbox-entry.ts");
5595
- if (await fileExists$1(defaultSandbox)) backendEntry = defaultSandbox;
5596
- }
5597
- let mainEntry;
5598
- if (pkg.exports?.["."] !== void 0) {
5599
- const mainExport = pkg.exports["."];
5600
- if (typeof mainExport === "string") mainEntry = await resolveSourceEntry(pluginDir, mainExport);
5601
- else if (mainExport && typeof mainExport === "object" && "import" in mainExport) mainEntry = await resolveSourceEntry(pluginDir, mainExport.import);
5602
- }
5603
- if (!mainEntry && pkg.main) mainEntry = await resolveSourceEntry(pluginDir, pkg.main);
5604
- if (!mainEntry) {
5605
- const defaultMain = join(pluginDir, "src/index.ts");
5606
- if (await fileExists$1(defaultMain)) mainEntry = defaultMain;
5607
- }
5608
- if (!mainEntry) {
5609
- consola.error("Cannot find plugin entrypoint. Expected src/index.ts or main/exports in package.json");
5610
- process.exit(1);
5611
- }
5612
- consola.info(`Main entry: ${mainEntry}`);
5613
- if (backendEntry) consola.info(`Backend entry: ${backendEntry}`);
5614
- if (adminEntry) consola.info(`Admin entry: ${adminEntry}`);
5615
- consola.start("Extracting plugin manifest...");
5616
- const { build } = await import("tsdown");
5617
- const tmpDir = join(pluginDir, ".dineway-bundle-tmp");
5618
- try {
5619
- await mkdir(tmpDir, { recursive: true });
5620
- await copyFile(pkgPath, join(tmpDir, "package.json"));
5621
- const mainOutDir = join(tmpDir, "main");
5622
- await build({
5623
- config: false,
5624
- entry: [mainEntry],
5625
- format: "esm",
5626
- outDir: mainOutDir,
5627
- dts: false,
5628
- platform: "node",
5629
- external: ["dineway", DINEWAY_SCOPE_RE]
5630
- });
5631
- const pluginNodeModules = join(pluginDir, "node_modules");
5632
- const tmpNodeModules = join(mainOutDir, "node_modules");
5633
- if (await fileExists$1(pluginNodeModules)) await symlink(pluginNodeModules, tmpNodeModules, "junction");
5634
- const mainOutputPath = await findBuildOutput(mainOutDir, basename(mainEntry).replace(TS_EXT_RE, ""));
5635
- if (!mainOutputPath) {
5636
- consola.error("Failed to build main entry — no output found in", mainOutDir);
5637
- process.exit(1);
5638
- }
5639
- const pluginModule = await import(toFileImportSpecifier(mainOutputPath));
5640
- let resolvedPlugin;
5641
- if (typeof pluginModule.createPlugin === "function") resolvedPlugin = pluginModule.createPlugin();
5642
- else if (typeof pluginModule.default === "function") resolvedPlugin = pluginModule.default();
5643
- else if (typeof pluginModule.default === "object" && pluginModule.default !== null) {
5644
- const defaultExport = pluginModule.default;
5645
- if ("id" in defaultExport && "version" in defaultExport) resolvedPlugin = defaultExport;
5646
- }
5647
- if (!resolvedPlugin) for (const [key, value] of Object.entries(pluginModule)) {
5648
- if (key === "default" || typeof value !== "function") continue;
5649
- try {
5650
- const result = value();
5651
- if (result && typeof result === "object" && "id" in result && "version" in result) {
5652
- resolvedPlugin = {
5653
- id: result.id,
5654
- version: result.version,
5655
- capabilities: result.capabilities ?? [],
5656
- allowedHosts: result.allowedHosts ?? [],
5657
- storage: result.storage ?? {},
5658
- hooks: {},
5659
- routes: {},
5660
- admin: {
5661
- pages: result.adminPages,
5662
- widgets: result.adminWidgets
5663
- }
5664
- };
5665
- if (backendEntry) {
5666
- const backendProbeDir = join(tmpDir, "backend-probe");
5667
- const probeShimDir = join(tmpDir, "probe-shims");
5668
- await mkdir(probeShimDir, { recursive: true });
5669
- await writeFile(join(probeShimDir, "dineway.mjs"), "export const definePlugin = (d) => d;\n");
5670
- await build({
5671
- config: false,
5672
- entry: [backendEntry],
5673
- format: "esm",
5674
- outDir: backendProbeDir,
5675
- dts: false,
5676
- platform: "neutral",
5677
- external: [],
5678
- alias: { dineway: join(probeShimDir, "dineway.mjs") },
5679
- treeshake: true
5680
- });
5681
- const backendProbePath = await findBuildOutput(backendProbeDir, basename(backendEntry).replace(TS_EXT_RE, ""));
5682
- if (backendProbePath) {
5683
- const standardDef = (await import(toFileImportSpecifier(backendProbePath))).default ?? {};
5684
- const hooks = standardDef.hooks;
5685
- const routes = standardDef.routes;
5686
- if (hooks) for (const hookName of Object.keys(hooks)) {
5687
- const hookEntry = hooks[hookName];
5688
- const isConfig = typeof hookEntry === "object" && hookEntry !== null && "handler" in hookEntry;
5689
- const config = isConfig ? hookEntry : {};
5690
- resolvedPlugin.hooks[hookName] = {
5691
- handler: isConfig ? hookEntry.handler : hookEntry,
5692
- priority: config.priority ?? 100,
5693
- timeout: config.timeout ?? 5e3,
5694
- dependencies: config.dependencies ?? [],
5695
- errorPolicy: config.errorPolicy ?? "abort",
5696
- exclusive: config.exclusive ?? false,
5697
- pluginId: result.id
5698
- };
5699
- }
5700
- if (routes) for (const [name, route] of Object.entries(routes)) {
5701
- const routeObj = route;
5702
- resolvedPlugin.routes[name] = {
5703
- handler: routeObj.handler,
5704
- public: routeObj.public
5705
- };
5706
- }
5707
- }
5708
- }
5709
- break;
5710
- }
5711
- } catch {}
5712
- }
5713
- if (!resolvedPlugin?.id || !resolvedPlugin?.version) {
5714
- consola.error("Could not extract plugin definition. Expected one of:\n - createPlugin() export (native format)\n - Descriptor factory function returning { id, version, ... } (standard format)");
5715
- process.exit(1);
5716
- }
5717
- const manifest = extractManifest(resolvedPlugin);
5718
- if (resolvedPlugin.admin?.entry) {
5719
- consola.error("Plugin declares adminEntry — React admin components require native/trusted mode. Use Block Kit for sandboxed admin pages, or remove adminEntry.");
5720
- process.exit(1);
5721
- }
5722
- if (resolvedPlugin.admin?.portableTextBlocks && resolvedPlugin.admin.portableTextBlocks.length > 0) {
5723
- consola.error("Plugin declares portableTextBlocks — these require native/trusted mode and cannot be bundled for the marketplace.");
5724
- process.exit(1);
5725
- }
5726
- consola.success(`Plugin: ${manifest.id}@${manifest.version}`);
5727
- consola.info(` Capabilities: ${manifest.capabilities.length > 0 ? manifest.capabilities.join(", ") : "(none)"}`);
5728
- consola.info(` Hooks: ${manifest.hooks.length > 0 ? manifest.hooks.map((h) => typeof h === "string" ? h : h.name).join(", ") : "(none)"}`);
5729
- consola.info(` Routes: ${manifest.routes.length > 0 ? manifest.routes.map((r) => typeof r === "string" ? r : r.name).join(", ") : "(none)"}`);
5730
- const bundleDir = join(tmpDir, "bundle");
5731
- await mkdir(bundleDir, { recursive: true });
5732
- if (backendEntry) {
5733
- consola.start("Bundling backend...");
5734
- const shimDir = join(tmpDir, "shims");
5735
- await mkdir(shimDir, { recursive: true });
5736
- await writeFile(join(shimDir, "dineway.mjs"), "export const definePlugin = (d) => d;\n");
5737
- await build({
5738
- config: false,
5739
- entry: [backendEntry],
5740
- format: "esm",
5741
- outDir: join(tmpDir, "backend"),
5742
- dts: false,
5743
- platform: "neutral",
5744
- external: [],
5745
- alias: { dineway: join(shimDir, "dineway.mjs") },
5746
- minify: true,
5747
- treeshake: true
5748
- });
5749
- const backendBaseName = basename(backendEntry).replace(TS_EXT_RE, "");
5750
- const backendOutputPath = await findBuildOutput(join(tmpDir, "backend"), backendBaseName);
5751
- if (backendOutputPath) {
5752
- await copyFile(backendOutputPath, join(bundleDir, "backend.js"));
5753
- consola.success("Built backend.js");
5754
- } else {
5755
- consola.error("Backend build produced no output");
5756
- process.exit(1);
5757
- }
5758
- } else {
5759
- consola.warn("No sandbox entry found — bundle will have no backend.js");
5760
- consola.warn(" Add a \"sandbox-entry.ts\" in src/ or a \"./sandbox\" export in package.json");
5761
- }
5762
- if (adminEntry) {
5763
- consola.start("Bundling admin...");
5764
- await build({
5765
- config: false,
5766
- entry: [adminEntry],
5767
- format: "esm",
5768
- outDir: join(tmpDir, "admin"),
5769
- dts: false,
5770
- platform: "neutral",
5771
- external: [],
5772
- minify: true,
5773
- treeshake: true
5774
- });
5775
- const adminBaseName = basename(adminEntry).replace(TS_EXT_RE, "");
5776
- const adminOutputPath = await findBuildOutput(join(tmpDir, "admin"), adminBaseName);
5777
- if (adminOutputPath) {
5778
- await copyFile(adminOutputPath, join(bundleDir, "admin.js"));
5779
- consola.success("Built admin.js");
5780
- }
5781
- }
5782
- await writeFile(join(bundleDir, "manifest.json"), JSON.stringify(manifest, null, 2));
5783
- consola.start("Collecting assets...");
5784
- const readmePath = join(pluginDir, "README.md");
5785
- if (await fileExists$1(readmePath)) {
5786
- await copyFile(readmePath, join(bundleDir, "README.md"));
5787
- consola.success("Included README.md");
5788
- }
5789
- const iconPath = join(pluginDir, "icon.png");
5790
- if (await fileExists$1(iconPath)) {
5791
- const dims = readImageDimensions(await readFile(iconPath));
5792
- if (!dims) consola.warn("icon.png is not a valid PNG — skipping");
5793
- else if (dims[0] !== ICON_SIZE || dims[1] !== ICON_SIZE) {
5794
- consola.warn(`icon.png is ${dims[0]}x${dims[1]}, expected ${ICON_SIZE}x${ICON_SIZE} — including anyway`);
5795
- await copyFile(iconPath, join(bundleDir, "icon.png"));
5796
- } else {
5797
- await copyFile(iconPath, join(bundleDir, "icon.png"));
5798
- consola.success("Included icon.png");
5799
- }
5800
- }
5801
- const screenshotsDir = join(pluginDir, "screenshots");
5802
- if (await fileExists$1(screenshotsDir)) {
5803
- const screenshotFiles = (await readdir(screenshotsDir)).filter((f) => {
5804
- const ext = extname(f).toLowerCase();
5805
- return ext === ".png" || ext === ".jpg" || ext === ".jpeg";
5806
- }).toSorted().slice(0, MAX_SCREENSHOTS);
5807
- if (screenshotFiles.length > 0) {
5808
- await mkdir(join(bundleDir, "screenshots"), { recursive: true });
5809
- for (const file of screenshotFiles) {
5810
- const filePath = join(screenshotsDir, file);
5811
- const dims = readImageDimensions(await readFile(filePath));
5812
- if (!dims) {
5813
- consola.warn(`screenshots/${file} — cannot read dimensions, skipping`);
5814
- continue;
5815
- }
5816
- if (dims[0] > MAX_SCREENSHOT_WIDTH || dims[1] > MAX_SCREENSHOT_HEIGHT) consola.warn(`screenshots/${file} is ${dims[0]}x${dims[1]}, max ${MAX_SCREENSHOT_WIDTH}x${MAX_SCREENSHOT_HEIGHT} — including anyway`);
5817
- await copyFile(filePath, join(bundleDir, "screenshots", file));
5818
- }
5819
- consola.success(`Included ${screenshotFiles.length} screenshot(s)`);
5820
- }
5821
- }
5822
- consola.start("Validating bundle...");
5823
- let hasErrors = false;
5824
- if (pkg.exports) for (const issue of findSourceExports(pkg.exports)) {
5825
- consola.error(`Export "${issue.exportPath}" points to source (${issue.resolvedPath}). Package exports must point to built files (e.g. dist/*.mjs). Add a build step and update the exports map.`);
5826
- hasErrors = true;
5827
- }
5828
- const backendPath = join(bundleDir, "backend.js");
5829
- if (await fileExists$1(backendPath)) {
5830
- const builtins = findNodeBuiltinImports(await readFile(backendPath, "utf-8"));
5831
- if (builtins.length > 0) {
5832
- consola.error(`backend.js imports Node.js built-in modules: ${builtins.join(", ")}`);
5833
- consola.error("Sandboxed plugins cannot use Node.js APIs");
5834
- hasErrors = true;
5835
- }
5836
- }
5837
- if (manifest.capabilities.includes("network:request:unrestricted")) consola.warn("Plugin declares unrestricted network access (network:request:unrestricted) — it can make requests to any host");
5838
- else if (manifest.capabilities.includes("network:request") && manifest.allowedHosts.length === 0) consola.warn("Plugin declares network:request capability but no allowedHosts — all fetch requests will be blocked");
5839
- if (resolvedPlugin.admin?.portableTextBlocks && resolvedPlugin.admin.portableTextBlocks.length > 0) consola.warn("Plugin declares portableTextBlocks — these require trusted mode and will be ignored in sandboxed plugins");
5840
- if (resolvedPlugin.admin?.entry) consola.warn("Plugin declares admin.entry — custom React components require trusted mode. Use Block Kit for sandboxed admin pages");
5841
- if (resolvedPlugin.hooks["page:fragments"]) consola.warn("Plugin declares page:fragments hook — this is trusted-only and will not work in sandboxed mode");
5842
- const hasAdminPages = (manifest.admin?.pages?.length ?? 0) > 0;
5843
- const hasAdminWidgets = (manifest.admin?.widgets?.length ?? 0) > 0;
5844
- if (hasAdminPages || hasAdminWidgets) {
5845
- if (!manifest.routes.map((r) => typeof r === "string" ? r : r.name).includes("admin")) {
5846
- consola.error(`Plugin declares ${hasAdminPages ? "adminPages" : ""}${hasAdminPages && hasAdminWidgets ? " and " : ""}${hasAdminWidgets ? "adminWidgets" : ""} but the sandbox entry has no "admin" route. Add an admin route handler to serve Block Kit pages.`);
5847
- hasErrors = true;
5848
- }
5849
- }
5850
- const bundleEntries = await collectBundleEntries(bundleDir);
5851
- const sizeViolations = validateBundleSize(bundleEntries);
5852
- if (sizeViolations.length > 0) {
5853
- for (const violation of sizeViolations) consola.error(violation);
5854
- hasErrors = true;
5855
- } else consola.info(`Bundle size: ${formatBytes(totalBundleBytes(bundleEntries))} across ${bundleEntries.length} file${bundleEntries.length === 1 ? "" : "s"}`);
5856
- if (hasErrors) {
5857
- consola.error("Bundle validation failed");
5858
- process.exit(1);
5859
- }
5860
- consola.success("Validation passed");
5861
- if (validateOnly) return;
5862
- await mkdir(outDir, { recursive: true });
5863
- const tarballName = `${manifest.id.replace(SLASH_RE, "-").replace(LEADING_AT_RE, "")}-${manifest.version}.tar.gz`;
5864
- const tarballPath = join(outDir, tarballName);
5865
- consola.start("Creating tarball...");
5866
- await createTarball(bundleDir, tarballPath);
5867
- const tarballSizeKB = ((await stat(tarballPath)).size / 1024).toFixed(1);
5868
- const tarballBuf = await readFile(tarballPath);
5869
- const checksum = createHash("sha256").update(tarballBuf).digest("hex");
5870
- consola.success(`Created ${tarballName} (${tarballSizeKB}KB)`);
5871
- consola.info(` SHA-256: ${checksum}`);
5872
- consola.info(` Path: ${tarballPath}`);
5873
- } finally {
5874
- if (tmpDir.endsWith(".dineway-bundle-tmp")) await rm(tmpDir, {
5875
- recursive: true,
5876
- force: true
5877
- });
5878
- }
5879
- }
5880
- });
5881
-
5882
5399
  //#endregion
5883
5400
  //#region src/cli/commands/plugin-init.ts
5884
5401
  /**
@@ -5954,7 +5471,7 @@ const pluginInitCommand = defineCommand({
5954
5471
  process.exit(1);
5955
5472
  }
5956
5473
  const srcDir = join(targetDir, "src");
5957
- if (await fileExists$1(join(targetDir, "package.json"))) {
5474
+ if (await fileExists$11(join(targetDir, "package.json"))) {
5958
5475
  consola.error(`package.json already exists in ${targetDir}`);
5959
5476
  process.exit(1);
5960
5477
  }
@@ -6320,6 +5837,7 @@ async function pollGitHubDeviceFlow(tokenEndpoint, clientId, deviceCode, interva
6320
5837
  const manifestSummarySchema = pluginManifestSchema.pick({
6321
5838
  id: true,
6322
5839
  version: true,
5840
+ declaredAccess: true,
6323
5841
  capabilities: true,
6324
5842
  allowedHosts: true
6325
5843
  });
@@ -6337,7 +5855,20 @@ async function readManifestFromTarball(tarballPath) {
6337
5855
  const parsed = JSON.parse(content);
6338
5856
  const result = manifestSummarySchema.safeParse(parsed);
6339
5857
  if (!result.success) throw new Error(`Invalid manifest.json: ${result.error.message}`);
6340
- return result.data;
5858
+ const reconciled = reconcileManifestAccess({
5859
+ ...result.data,
5860
+ storage: {},
5861
+ hooks: [],
5862
+ routes: [],
5863
+ admin: {}
5864
+ });
5865
+ return {
5866
+ id: reconciled.id,
5867
+ version: reconciled.version,
5868
+ declaredAccess: reconciled.declaredAccess,
5869
+ capabilities: reconciled.capabilities,
5870
+ allowedHosts: reconciled.allowedHosts
5871
+ };
6341
5872
  }
6342
5873
  const POLL_INTERVAL_MS = 3e3;
6343
5874
  const POLL_TIMEOUT_MS = 12e4;
@@ -6422,7 +5953,7 @@ const publishCommand = defineCommand({
6422
5953
  const pluginDir = resolve(args.dir);
6423
5954
  try {
6424
5955
  const { runCommand } = await import("citty");
6425
- const { bundleCommand } = await Promise.resolve().then(() => bundle_exports);
5956
+ const { bundleCommand } = await import("../bundle-7C_DpkEq.mjs").then((n) => n.n);
6426
5957
  await runCommand(bundleCommand, { rawArgs: ["--dir", pluginDir] });
6427
5958
  } catch {
6428
5959
  consola.error("Build failed");
@@ -7086,7 +6617,7 @@ const seedCommand = defineCommand({
7086
6617
  },
7087
6618
  "no-content": {
7088
6619
  type: "boolean",
7089
- description: "Skip sample content",
6620
+ description: "Skip sample data (content entries, bylines, taxonomy terms)",
7090
6621
  default: false
7091
6622
  },
7092
6623
  "on-conflict": {
@@ -7304,13 +6835,15 @@ var ForgewaySeoGatewayClient = class {
7304
6835
  }
7305
6836
  async request(path, body, init) {
7306
6837
  const credentials = await this.refreshAccessToken(await this.loadCredentials());
6838
+ const method = init?.method ?? "POST";
7307
6839
  const response = await this.fetchImpl(`${credentials.platformApiUrl}${path}`, {
7308
- method: init?.method ?? "POST",
6840
+ method,
7309
6841
  headers: {
7310
6842
  Authorization: `Bearer ${credentials.accessToken}`,
7311
- "Content-Type": "application/json"
6843
+ "Content-Type": "application/json",
6844
+ "Idempotency-Key": init?.idempotencyKey ?? randomUUID()
7312
6845
  },
7313
- body: init?.method === "GET" ? void 0 : JSON.stringify(body ?? {})
6846
+ body: method === "GET" ? void 0 : JSON.stringify(body ?? {})
7314
6847
  });
7315
6848
  const payload = await parseJsonResponse(response);
7316
6849
  if (!response.ok) throw new ForgewaySeoApiError(errorMessage(payload, `Forgeway SEO request failed with status ${response.status}.`), response.status, payload);
@@ -7375,6 +6908,11 @@ async function runSeoRequest(args, path, body) {
7375
6908
  try {
7376
6909
  output(await new ForgewaySeoGatewayClient().request(path, body), args);
7377
6910
  } catch (error) {
6911
+ if (await handleCliPaywall({
6912
+ error,
6913
+ resource: path,
6914
+ context: { providerPath: path }
6915
+ })) process.exit(2);
7378
6916
  consola$1.error(error instanceof Error ? error.message : "Unknown error");
7379
6917
  process.exit(1);
7380
6918
  }
@@ -7517,6 +7055,11 @@ const firecrawlCommand = defineCommand({
7517
7055
  try {
7518
7056
  output(await new ForgewaySeoGatewayClient().request(`/api/firecrawl/crawl/${encodeURIComponent(crawlId)}`, void 0, { method: "GET" }), args);
7519
7057
  } catch (error) {
7058
+ if (await handleCliPaywall({
7059
+ error,
7060
+ resource: `/api/firecrawl/crawl/${crawlId}`,
7061
+ context: { providerPath: `/api/firecrawl/crawl/${crawlId}` }
7062
+ })) process.exit(2);
7520
7063
  consola$1.error(error instanceof Error ? error.message : "Unknown error");
7521
7064
  process.exit(1);
7522
7065
  }
@@ -7972,6 +7515,7 @@ runMain(defineCommand({
7972
7515
  },
7973
7516
  subCommands: {
7974
7517
  init: initCommand,
7518
+ account: accountCommand,
7975
7519
  types: typesCommand,
7976
7520
  dev: devCommand,
7977
7521
  deploy: deployCommand,