dineway 0.2.0 → 0.2.1
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.
- package/dist/activity-DUaz_w7p.mjs +79 -0
- package/dist/{activity-events-y6eT8UW6.mjs → activity-events-CJDvE2uc.mjs} +1 -77
- package/dist/{actor-CrObAPV0.mjs → actor-0QJ1Gbtf.mjs} +1 -1
- package/dist/{allowed-origins-_oeyP6x-.mjs → allowed-origins--OwHHiY8.mjs} +1 -1
- package/dist/api/route-utils.d.mts +9 -10
- package/dist/api/route-utils.mjs +14 -14
- package/dist/api/schemas/index.d.mts +2 -2
- package/dist/api/schemas/index.mjs +5 -5
- package/dist/{api-ByrU2q-Z.mjs → api-B4PHIF4V.mjs} +51 -23
- package/dist/{api-tokens-CjVMQT-X.mjs → api-tokens-tbK_sORH.mjs} +1 -1
- package/dist/{apply-bZswmZPm.mjs → apply-DjTqq6Ae.mjs} +19 -19
- package/dist/astro/index.d.mts +10 -11
- package/dist/astro/index.mjs +10 -5
- package/dist/astro/middleware/auth.d.mts +9 -19
- package/dist/astro/middleware/auth.mjs +6 -6
- package/dist/astro/middleware/redirect.mjs +5 -5
- package/dist/astro/middleware/request-context.mjs +2 -2
- package/dist/astro/middleware/seed.d.mts +1 -1
- package/dist/astro/middleware/seed.mjs +1 -1
- package/dist/astro/middleware/setup.mjs +1 -1
- package/dist/astro/middleware.mjs +140 -98
- package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +6 -6
- package/dist/astro/routes/api/admin/allowed-domains/index.mjs +6 -6
- package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +4 -4
- package/dist/astro/routes/api/admin/api-tokens/index.mjs +6 -6
- package/dist/astro/routes/api/admin/briefing.mjs +18 -18
- package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +4 -4
- package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +9 -9
- package/dist/astro/routes/api/admin/byline-fields/index.mjs +9 -9
- package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +9 -9
- package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +16 -16
- package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +16 -16
- package/dist/astro/routes/api/admin/bylines/index.mjs +16 -16
- package/dist/astro/routes/api/admin/comments/_id_/status.mjs +12 -12
- package/dist/astro/routes/api/admin/comments/_id_.mjs +5 -5
- package/dist/astro/routes/api/admin/comments/bulk.mjs +10 -10
- package/dist/astro/routes/api/admin/comments/counts.mjs +5 -5
- package/dist/astro/routes/api/admin/comments/index.mjs +10 -10
- package/dist/astro/routes/api/admin/context/_id_/history.mjs +25 -24
- package/dist/astro/routes/api/admin/context/_id_/index.mjs +25 -24
- package/dist/astro/routes/api/admin/context/_id_/review.mjs +30 -29
- package/dist/astro/routes/api/admin/context/_id_/supersede.mjs +30 -29
- package/dist/astro/routes/api/admin/context/diff.mjs +29 -28
- package/dist/astro/routes/api/admin/context/index.mjs +30 -29
- package/dist/astro/routes/api/admin/context/stale.mjs +29 -28
- package/dist/astro/routes/api/admin/hitl-requests/_id_/index.mjs +25 -24
- package/dist/astro/routes/api/admin/hitl-requests/_id_/resolve.mjs +29 -28
- package/dist/astro/routes/api/admin/hitl-requests/index.mjs +29 -28
- package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +26 -25
- package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +2 -2
- package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +6 -6
- package/dist/astro/routes/api/admin/oauth-clients/index.mjs +6 -6
- package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +52 -51
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +52 -51
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +44 -44
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +51 -50
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +51 -50
- package/dist/astro/routes/api/admin/plugins/index.mjs +44 -44
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +2 -2
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +44 -44
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +51 -50
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +44 -44
- package/dist/astro/routes/api/admin/plugins/updates.mjs +44 -44
- package/dist/astro/routes/api/admin/review-requests/_id_/index.mjs +5 -5
- package/dist/astro/routes/api/admin/review-requests/_id_/resolve.mjs +30 -65
- package/dist/astro/routes/api/admin/review-requests/index.d.mts +2 -1
- package/dist/astro/routes/api/admin/review-requests/index.mjs +58 -11
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +44 -44
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +2 -2
- package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +44 -44
- package/dist/astro/routes/api/admin/users/_id_/disable.mjs +2 -2
- package/dist/astro/routes/api/admin/users/_id_/enable.mjs +1 -1
- package/dist/astro/routes/api/admin/users/_id_/index.mjs +7 -7
- package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +2 -2
- package/dist/astro/routes/api/admin/users/index.mjs +6 -6
- package/dist/astro/routes/api/auth/dev-bypass.mjs +4 -4
- package/dist/astro/routes/api/auth/invite/accept.mjs +1 -1
- package/dist/astro/routes/api/auth/invite/complete.mjs +10 -10
- package/dist/astro/routes/api/auth/invite/index.mjs +7 -7
- package/dist/astro/routes/api/auth/invite/register-options.mjs +9 -9
- package/dist/astro/routes/api/auth/logout.mjs +2 -2
- package/dist/astro/routes/api/auth/magic-link/send.mjs +9 -9
- package/dist/astro/routes/api/auth/magic-link/verify.mjs +2 -2
- package/dist/astro/routes/api/auth/me.mjs +8 -8
- package/dist/astro/routes/api/auth/mode.mjs +1 -1
- package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +2 -2
- package/dist/astro/routes/api/auth/oauth/_provider_.mjs +2 -2
- package/dist/astro/routes/api/auth/passkey/_id_.mjs +6 -6
- package/dist/astro/routes/api/auth/passkey/index.mjs +1 -1
- package/dist/astro/routes/api/auth/passkey/options.mjs +11 -11
- package/dist/astro/routes/api/auth/passkey/register/options.mjs +9 -9
- package/dist/astro/routes/api/auth/passkey/register/verify.mjs +10 -10
- package/dist/astro/routes/api/auth/passkey/verify.mjs +10 -10
- package/dist/astro/routes/api/auth/setup-token/index.mjs +5 -5
- package/dist/astro/routes/api/auth/setup-token/verify.mjs +2 -2
- package/dist/astro/routes/api/auth/signup/complete.mjs +10 -10
- package/dist/astro/routes/api/auth/signup/request.mjs +9 -9
- package/dist/astro/routes/api/auth/signup/verify.mjs +1 -1
- package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +13 -13
- package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +12 -12
- package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +6 -5
- package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +6 -5
- package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +6 -5
- package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +10 -10
- package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +49 -21
- package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +6 -5
- package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +67 -33
- package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +14 -14
- package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +6 -5
- package/dist/astro/routes/api/content/_collection_/_id_.mjs +11 -10
- package/dist/astro/routes/api/content/_collection_/authors.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/index.mjs +11 -10
- package/dist/astro/routes/api/content/_collection_/trash.mjs +7 -7
- package/dist/astro/routes/api/dashboard.mjs +8 -8
- package/dist/astro/routes/api/dev/emails.mjs +2 -2
- package/dist/astro/routes/api/health.mjs +1 -1
- package/dist/astro/routes/api/import/probe.d.mts +3 -3
- package/dist/astro/routes/api/import/probe.mjs +19 -19
- package/dist/astro/routes/api/import/wordpress/analyze.mjs +8 -8
- package/dist/astro/routes/api/import/wordpress/execute.d.mts +8 -9
- package/dist/astro/routes/api/import/wordpress/execute.mjs +35 -34
- package/dist/astro/routes/api/import/wordpress/media.d.mts +8 -9
- package/dist/astro/routes/api/import/wordpress/media.mjs +12 -12
- package/dist/astro/routes/api/import/wordpress/prepare.mjs +34 -33
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts +9 -10
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +31 -30
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +22 -22
- package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +8 -9
- package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +40 -39
- package/dist/astro/routes/api/manifest.mjs +4 -4
- package/dist/astro/routes/api/mcp.mjs +554 -167
- package/dist/astro/routes/api/media/_id_/confirm.mjs +10 -10
- package/dist/astro/routes/api/media/_id_.mjs +8 -8
- package/dist/astro/routes/api/media/file/_...key_.mjs +1 -1
- package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +2 -2
- package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +2 -2
- package/dist/astro/routes/api/media/providers/index.mjs +2 -2
- package/dist/astro/routes/api/media/upload-url.mjs +11 -11
- package/dist/astro/routes/api/media.mjs +14 -14
- package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +30 -29
- package/dist/astro/routes/api/menus/_name_/items.mjs +30 -29
- package/dist/astro/routes/api/menus/_name_/reorder.mjs +30 -29
- package/dist/astro/routes/api/menus/_name_/translations.mjs +30 -29
- package/dist/astro/routes/api/menus/_name_.mjs +30 -29
- package/dist/astro/routes/api/menus/index.mjs +30 -29
- package/dist/astro/routes/api/oauth/authorize.mjs +7 -7
- package/dist/astro/routes/api/oauth/device/authorize.mjs +6 -6
- package/dist/astro/routes/api/oauth/device/code.mjs +9 -9
- package/dist/astro/routes/api/oauth/device/token.mjs +8 -8
- package/dist/astro/routes/api/oauth/register.mjs +4 -4
- package/dist/astro/routes/api/oauth/token/refresh.mjs +6 -6
- package/dist/astro/routes/api/oauth/token/revoke.mjs +6 -6
- package/dist/astro/routes/api/oauth/token.mjs +6 -6
- package/dist/astro/routes/api/openapi.json.mjs +4 -4
- package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +20 -5
- package/dist/astro/routes/api/redirects/404s/index.mjs +10 -10
- package/dist/astro/routes/api/redirects/404s/summary.mjs +10 -10
- package/dist/astro/routes/api/redirects/_id_.mjs +31 -30
- package/dist/astro/routes/api/redirects/index.mjs +31 -30
- package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +2 -2
- package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +2 -2
- package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +46 -45
- package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +46 -45
- package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +46 -45
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +46 -45
- package/dist/astro/routes/api/schema/collections/index.mjs +46 -45
- package/dist/astro/routes/api/schema/index.mjs +8 -8
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs +44 -44
- package/dist/astro/routes/api/schema/orphans/index.mjs +44 -44
- package/dist/astro/routes/api/search/enable.mjs +11 -11
- package/dist/astro/routes/api/search/index.mjs +10 -10
- package/dist/astro/routes/api/search/rebuild.mjs +11 -11
- package/dist/astro/routes/api/search/stats.mjs +6 -6
- package/dist/astro/routes/api/search/suggest.mjs +10 -10
- package/dist/astro/routes/api/sections/_slug_.mjs +30 -29
- package/dist/astro/routes/api/sections/index.mjs +30 -29
- package/dist/astro/routes/api/settings/email.mjs +3 -3
- package/dist/astro/routes/api/settings.mjs +30 -29
- package/dist/astro/routes/api/setup/admin-verify.mjs +12 -12
- package/dist/astro/routes/api/setup/admin.mjs +10 -10
- package/dist/astro/routes/api/setup/dev-bypass.mjs +25 -25
- package/dist/astro/routes/api/setup/dev-reset.mjs +1 -1
- package/dist/astro/routes/api/setup/index.mjs +27 -27
- package/dist/astro/routes/api/setup/status.mjs +3 -3
- package/dist/astro/routes/api/snapshot.mjs +6 -6
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +33 -32
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +33 -32
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +33 -32
- package/dist/astro/routes/api/taxonomies/index.mjs +33 -32
- package/dist/astro/routes/api/themes/preview.mjs +4 -4
- package/dist/astro/routes/api/typegen.mjs +4 -4
- package/dist/astro/routes/api/well-known/auth.mjs +2 -2
- package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs +3 -3
- package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs +3 -3
- package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +29 -28
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +30 -29
- package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +30 -29
- package/dist/astro/routes/api/widget-areas/_name_.mjs +27 -26
- package/dist/astro/routes/api/widget-areas/index.mjs +30 -29
- package/dist/astro/routes/api/widget-components.mjs +2 -2
- package/dist/astro/routes/robots.txt.mjs +6 -6
- package/dist/astro/routes/sitemap-_collection_.xml.mjs +9 -9
- package/dist/astro/routes/sitemap.xml.mjs +7 -7
- package/dist/astro/session-driver.d.mts +1 -1
- package/dist/astro/session-driver.mjs +2 -2
- package/dist/astro/types.d.mts +13 -12
- package/dist/{audit-ByVKIwWF.mjs → audit-B2pRxZ20.mjs} +1 -1
- package/dist/auth/providers/github.d.mts +1 -1
- package/dist/auth/providers/google.d.mts +1 -1
- package/dist/{auth-control-guard-CqeUmQsv.mjs → auth-control-guard-D71jourk.mjs} +1 -1
- package/dist/{authorize-CcBxcHtz.mjs → authorize-ZXPGPwKn.mjs} +1 -1
- package/dist/{briefing-CawZ59CY.mjs → briefing-0rf-su3-.mjs} +7 -7
- package/dist/{briefing-BJaJI8dm.mjs → briefing-kRhegBoF.mjs} +1 -1
- package/dist/{bundle-7C_DpkEq.mjs → bundle-CEcdUa1s.mjs} +2 -2
- package/dist/{byline-e51-fWRs.mjs → byline-7xR185Ly.mjs} +6 -6
- package/dist/{byline-fields-D-N5qVIG.mjs → byline-fields-BKzA0fJU.mjs} +1 -1
- package/dist/{byline-fields-CUvbslGc.d.mts → byline-fields-Ckeqd1OY.d.mts} +57 -47
- package/dist/{byline-fields-DOJO16Gm.mjs → byline-fields-WN7RQT4q.mjs} +10 -4
- package/dist/{byline-registry-87nNnYl4.mjs → byline-registry-Ba54M74c.mjs} +2 -2
- package/dist/{bylines-CMQNCNFh.mjs → bylines-C-EL6dh3.mjs} +3 -3
- package/dist/{bylines-y4LO-dTj.mjs → bylines-CmZFCMr0.mjs} +5 -5
- package/dist/{cache-C-FNTFYK.mjs → cache-DkVCKGio.mjs} +2 -2
- package/dist/{chunks-CxBt-GxR.mjs → chunks-ChGNDY8r.mjs} +1 -1
- package/dist/cli/index.d.mts +29 -1
- package/dist/cli/index.mjs +1391 -1123
- package/dist/cli/plugin-kit.d.mts +75 -0
- package/dist/cli/plugin-kit.mjs +4 -0
- package/dist/client/external-auth-headers.d.mts +1 -1
- package/dist/client/index.d.mts +27 -52
- package/dist/client/index.mjs +34 -7
- package/dist/client-factory-BDD9azPJ.mjs +233 -0
- package/dist/{comment-DlA4iChg.mjs → comment-DFALgsJD.mjs} +1 -1
- package/dist/{comment-reaction-DfFao1ST.mjs → comment-reaction-C37bf99u.mjs} +1 -1
- package/dist/{comments-DApFGMsP.mjs → comments-B3NwDBxl.mjs} +1 -1
- package/dist/{content-Bh4BDjv8.mjs → content-DJcAYFhz.mjs} +2 -2
- package/dist/{content-refresh-CgutSUfO.mjs → content-refresh-B4ZCmxgd.mjs} +5 -5
- package/dist/{context-CK4ym2Sf.mjs → context-DnpXcp6Y.mjs} +2 -2
- package/dist/{context-C5W3G18y.mjs → context-fSCYLL3c.mjs} +24 -13
- package/dist/{context-route-helpers-MASyGgWf.mjs → context-route-helpers-CI8XzcsK.mjs} +2 -2
- package/dist/{dashboard-DQkVT7Ei.mjs → dashboard-D0nj5oWg.mjs} +4 -4
- package/dist/db/index.d.mts +3 -3
- package/dist/db/index.mjs +1 -1
- package/dist/db/libsql.d.mts +1 -1
- package/dist/db/postgres.d.mts +1 -1
- package/dist/db/sqlite.d.mts +1 -1
- package/dist/{device-flow-BnqRH-T9.mjs → device-flow-BJe6VEhP.mjs} +5 -5
- package/dist/{enrich-DIFIFA8O.mjs → enrich-Ck9tfMqe.mjs} +1 -1
- package/dist/{experimental-workflows-BMsUnIAw.mjs → experimental-workflows-GVhUgzEs.mjs} +1 -1
- package/dist/{field-defs-cache-DRNdhBJv.mjs → field-defs-cache-DL-T2XVS.mjs} +4 -4
- package/dist/forgeway-seo-client-G5ddhVHd.mjs +456 -0
- package/dist/{fts-manager-Crzypjqu.mjs → fts-manager-ewTGohf4.mjs} +1 -1
- package/dist/{hitl-requests-B4Vbcmaq.mjs → hitl-requests-DEFj8e6u.mjs} +2 -2
- package/dist/{hitl-route-helpers-hEVzvP8l.mjs → hitl-route-helpers-C23JHaWz.mjs} +5 -5
- package/dist/{import-Bh9biJfx.mjs → import-CXXL5pip.mjs} +7 -7
- package/dist/{index-D4y6NGiy.d.mts → index-DcnOCD1e.d.mts} +79 -3
- package/dist/index.d.mts +15 -17
- package/dist/index.mjs +81 -78
- package/dist/{jsonld-Dq0gsnOH.d.mts → jsonld-DzKbhRZ4.d.mts} +2 -2
- package/dist/{load-DmYeniXl.mjs → load-CFtJRT3c.mjs} +1 -1
- package/dist/{loader-CjWqjweO.mjs → loader-aWkkc1_o.mjs} +2 -2
- package/dist/{manifest-schema-BxVPYMJR.mjs → manifest-schema-uA6pRFXi.mjs} +6 -2
- package/dist/{mcp-reviewed-executor-TwVbMzG6.mjs → mcp-reviewed-executor-Dn52L_yY.mjs} +6 -3
- package/dist/media/image-endpoint.mjs +1 -1
- package/dist/media/index.d.mts +1 -1
- package/dist/media/index.mjs +2 -2
- package/dist/media/local-runtime.d.mts +10 -11
- package/dist/media/local-runtime.mjs +2 -2
- package/dist/{media-DMj0grzC.mjs → media-CVMOoywq.mjs} +1 -1
- package/dist/{media-allowlist-BlVCSzHx.mjs → media-allowlist-zDNJmXCo.mjs} +1 -1
- package/dist/{menus-xvsnVZXw.mjs → menus-CCG2z5um.mjs} +6 -6
- package/dist/{menus-TaW1gKnk.mjs → menus-CmyIkRG5.mjs} +2 -2
- package/dist/{oauth-authorization-DiaGvRVz.mjs → oauth-authorization-B9H7X85L.mjs} +5 -5
- package/dist/{oauth-clients-Dl9E8dEM.mjs → oauth-clients-Dwl32-Uj.mjs} +2 -2
- package/dist/object-cache/memory.d.mts +1 -1
- package/dist/output-DhBe5_Pi.mjs +68 -0
- package/dist/page/index.d.mts +9 -3
- package/dist/page/index.mjs +1 -1
- package/dist/{parse-CbymENaR.mjs → parse-i15EFSAE.mjs} +1 -1
- package/dist/plugin-utils.d.mts +8 -9
- package/dist/plugins/adapt-sandbox-entry.d.mts +8 -9
- package/dist/plugins/adapt-sandbox-entry.mjs +3 -1
- package/dist/{plugins-BolVa-tl.mjs → plugins-CPA2PtfY.mjs} +95 -10
- package/dist/portable-text-E79LyjGo.d.mts +45 -0
- package/dist/{preview-vSVg6fwG.mjs → preview-BjedZm8G.mjs} +2 -2
- package/dist/project-env-DKibmuP8.mjs +95 -0
- package/dist/{provider-loader-MD8zAbnH.d.mts → provider-loader-DC2JdWeO.d.mts} +1 -1
- package/dist/{public-url-gsp3oUbu.d.mts → public-url-DQJCnYi9.d.mts} +1 -1
- package/dist/publication-authorization-RKiHXKtq.mjs +985 -0
- package/dist/{query-jaAmw8E1.mjs → query-C2U5u5_p.mjs} +3 -3
- package/dist/{query-CfRCdaL3.mjs → query-DEv5x6yB.mjs} +13 -13
- package/dist/{rate-limit-ZLdyWoZF.mjs → rate-limit-DglsAJSw.mjs} +2 -2
- package/dist/{redirect-BAjt4Z6b.mjs → redirect-ubhEqQCQ.mjs} +2 -2
- package/dist/{redirects-CA-xylPG.mjs → redirects-Bhpm8bRe.mjs} +18 -10
- package/dist/{redirects-BTdwpQtE.mjs → redirects-xs2yahLq.mjs} +4 -4
- package/dist/{registry-CtyVedcN.mjs → registry-BYYyb2tF.mjs} +24 -10
- package/dist/{request-meta-CUypToDJ.mjs → request-meta-CFe1tW2M.mjs} +1 -1
- package/dist/review-payload-BysRWpxS.mjs +111 -0
- package/dist/{review-requests-DUyEmtmG.mjs → review-requests-CTWGnWUt.mjs} +1 -1
- package/dist/review-requests-D42VEP1l.mjs +142 -0
- package/dist/review-route-helpers-C31vO6SI.mjs +41 -0
- package/dist/{runner-DB7CRfOF.mjs → runner-BgmttQmD.mjs} +1151 -447
- package/dist/{runner-1tC2tIRV.d.mts → runner-D6hzs8L9.d.mts} +1 -1
- package/dist/runtime.d.mts +9 -10
- package/dist/runtime.mjs +3 -3
- package/dist/schema-DUtnZxjZ.mjs +8 -0
- package/dist/{search-DSaLgEFI.mjs → search-DUKgZUlm.mjs} +3 -3
- package/dist/{secrets-CDZo2k8L.mjs → secrets-ZV5rd8yV.mjs} +1 -1
- package/dist/{sections-PVVXHGfp.mjs → sections-DvFgsnda.mjs} +2 -2
- package/dist/seed/index.d.mts +2 -2
- package/dist/seed/index.mjs +19 -19
- package/dist/seo/index.d.mts +1 -1
- package/dist/seo/index.mjs +1 -1
- package/dist/{seo-CQG3GCHQ.mjs → seo-BU8MLCS9.mjs} +1 -1
- package/dist/{service-DiN4ZuPp.mjs → service-FL3fB0Rx.mjs} +2 -2
- package/dist/{settings-BbqgHWpU.mjs → settings-BECcAIRH.mjs} +5 -5
- package/dist/{settings-i4VPP8bT.mjs → settings-EzADu-dd.mjs} +2 -2
- package/dist/{site-activity-Dy3FROs0.mjs → site-activity-h8smOlYI.mjs} +1 -1
- package/dist/{site-context-DQiL8Fl5.mjs → site-context-B8T1kpUP.mjs} +565 -129
- package/dist/stable-hash-DshcXvRE.mjs +19 -0
- package/dist/storage/local.d.mts +1 -1
- package/dist/storage/local.mjs +1 -1
- package/dist/storage/s3.d.mts +1 -1
- package/dist/storage/s3.mjs +1 -1
- package/dist/{taxonomies-9s-v03H-.mjs → taxonomies-BiM9NtgW.mjs} +3 -3
- package/dist/{taxonomies-DRiixp_E.mjs → taxonomies-DSnY5nOa.mjs} +6 -6
- package/dist/{taxonomy-Dvsw6BOs.mjs → taxonomy-0k_vRVsD.mjs} +2 -2
- package/dist/{types-4garmdWa.mjs → types-A8fPOJnl.mjs} +5 -2
- package/dist/{types-DW_-sFyz.d.mts → types-B_FlxIIl.d.mts} +2 -0
- package/dist/{types-Dq1qT19x.mjs → types-ChxYDRvx.mjs} +1 -1
- package/dist/{types-DU0bU2Wu.d.mts → types-DuQn1G7-.d.mts} +583 -2
- package/dist/{runtime-BOeiQsCv.d.mts → types-DwoUifGE.d.mts} +3560 -1355
- package/dist/{types-C_ly5eTp.d.mts → types-opjX_kz6.d.mts} +1 -1
- package/dist/ui/server-runtime.d.mts +12 -14
- package/dist/ui/server-runtime.mjs +21 -21
- package/dist/{user-BIZPzCb9.mjs → user-BH-n01y3.mjs} +2 -2
- package/dist/{utils-CMDhr5Xd.mjs → utils-D1SrKGtP.mjs} +1 -1
- package/dist/{validate-CZvb-BKB.d.mts → validate-CbVFoJgc.d.mts} +59 -5
- package/dist/{validate-DNs0pTSc.mjs → validate-D1HL-oLR.mjs} +2 -2
- package/dist/version-C3iVRuaF.mjs +6 -0
- package/dist/{widgets-f0ibZUIq.mjs → widgets-BZrLrNgS.mjs} +3 -3
- package/dist/{wordpress-slugs-BhHJX8XE.mjs → wordpress-slugs-C3PWcowq.mjs} +1 -1
- package/dist/{zod-generator-B7TMjyFJ.mjs → zod-generator-C7AsLpSB.mjs} +2 -2
- package/package.json +13 -5
- package/dist/hitl-Hw1RmWOq.mjs +0 -677
- package/dist/review-requests-C9Ff11Vq.mjs +0 -79
- package/dist/schema-DXdYj4R3.mjs +0 -8
- package/dist/types-C46EvNdc.d.mts +0 -56
- package/dist/types-C8XW6L19.d.mts +0 -1468
- package/dist/version-BTvfRGc6.mjs +0 -6
- /package/dist/{adapters-NVSs4UH7.d.mts → adapters-BiRymx02.d.mts} +0 -0
- /package/dist/{api-tokens-2r7OWi_I.mjs → api-tokens-Ypaly90d.mjs} +0 -0
- /package/dist/{challenge-store-Bjlepa2E.mjs → challenge-store-D5pSY2S1.mjs} +0 -0
- /package/dist/{components-Bclf98Be.mjs → components-DImzlLhb.mjs} +0 -0
- /package/dist/{context-types-DqTo6C79.mjs → context-types-eBuMDAg-.mjs} +0 -0
- /package/dist/{cron-cKcNTix_.mjs → cron-B1SL_lsb.mjs} +0 -0
- /package/dist/{default--K40jqm0.mjs → default-D4Vygcy_.mjs} +0 -0
- /package/dist/{email-console-ChgKFO8-.mjs → email-console-Bp0r68iF.mjs} +0 -0
- /package/dist/{error-CytFlgcd.mjs → error-CSVaQNZy.mjs} +0 -0
- /package/dist/{escape-Bd4P_xKg.mjs → escape-DN4Qmjsl.mjs} +0 -0
- /package/dist/{hash-BPmX6P8I.mjs → hash-mxxx2oPW.mjs} +0 -0
- /package/dist/{media-url-lEKSrpr9.mjs → media-url-BdoLPvg8.mjs} +0 -0
- /package/dist/{mime-CA7Lgovc.mjs → mime-C0vOHFm7.mjs} +0 -0
- /package/dist/{mode-C4CIyjtR.mjs → mode-C8yZnIlR.mjs} +0 -0
- /package/dist/{normalize-5ek_z7de.mjs → normalize-Cyt7JdF7.mjs} +0 -0
- /package/dist/{oauth-state-store-CNoXafF7.mjs → oauth-state-store-CndT35iw.mjs} +0 -0
- /package/dist/{oauth-user-lookup-Ygw4bNyt.mjs → oauth-user-lookup-CMehAaKs.mjs} +0 -0
- /package/dist/{parser-C1nYd-81.mjs → parser-06LLLL4E.mjs} +0 -0
- /package/dist/{passkey-config-BUwu8BA3.mjs → passkey-config-NYukYGed.mjs} +0 -0
- /package/dist/{patterns-BhAvqO0S.mjs → patterns-CoqlXUvk.mjs} +0 -0
- /package/dist/{placeholder-uvNRZBX9.d.mts → placeholder-DkWkXfDI.d.mts} +0 -0
- /package/dist/{portable-text-dA_UlJwW.mjs → portable-text-BASHceim.mjs} +0 -0
- /package/dist/{process-cache-7xgAO9JY.mjs → process-cache-CCDgti7j.mjs} +0 -0
- /package/dist/{provider-loader-D0w9dqjm.mjs → provider-loader-BtfrrzfD.mjs} +0 -0
- /package/dist/{public-url-BEz_sM9n.mjs → public-url-Cp6hyjVR.mjs} +0 -0
- /package/dist/{redirect-wphRBv4y.mjs → redirect-DrbEmU9a.mjs} +0 -0
- /package/dist/{request-cache-D9GQBxMP.mjs → request-cache-CBFjCwSt.mjs} +0 -0
- /package/dist/{resolve-Cb6Dbz-C.mjs → resolve-DE71WcL9.mjs} +0 -0
- /package/dist/{seo-qa7Dn0jK.mjs → seo-BLszyJxd.mjs} +0 -0
- /package/dist/{seo-contributions-C1EnikHB.mjs → seo-contributions-GnCuL1ML.mjs} +0 -0
- /package/dist/{session-user-CAKImna3.mjs → session-user-Ct6GBLvn.mjs} +0 -0
- /package/dist/{setup-complete-B8fl-mjV.mjs → setup-complete-Da0axZEE.mjs} +0 -0
- /package/dist/{setup-nonce-CoyjILvW.mjs → setup-nonce-BtkKnvxQ.mjs} +0 -0
- /package/dist/{sidecar-client-C3mqXg4C.mjs → sidecar-client-Ctzfyyp-.mjs} +0 -0
- /package/dist/{site-url-BML3GQYm.mjs → site-url-DJEid0ml.mjs} +0 -0
- /package/dist/{ssrf-DWe8jwAp.mjs → ssrf-FJqwQzj4.mjs} +0 -0
- /package/dist/{status-DANd8ERo.mjs → status-NqWOSFAD.mjs} +0 -0
- /package/dist/{tokens-1RK1n6ED.mjs → tokens-BDQU29Vd.mjs} +0 -0
- /package/dist/{transaction-C2EOMTJA.mjs → transaction-0LEAAy8R.mjs} +0 -0
- /package/dist/{transport-BNmCqLu7.mjs → transport-C46KHLMP.mjs} +0 -0
- /package/dist/{transport-CcJu3Co8.d.mts → transport-D9pKAzFP.d.mts} +0 -0
- /package/dist/{trusted-proxy-DTXQ2IMv.mjs → trusted-proxy-Dm7Mxvt6.mjs} +0 -0
- /package/dist/{types-B3t5cxhU.mjs → types-B7TDDFMG.mjs} +0 -0
- /package/dist/{types-DF7ZuGGk.d.mts → types-BLQCz46p.d.mts} +0 -0
- /package/dist/{types-CDpH6MA4.d.mts → types-Cw0PeCT_.d.mts} +0 -0
- /package/dist/{types-Rc3gQqqw.d.mts → types-g0zMtraY.d.mts} +0 -0
- /package/dist/{types-C5CVgwsV.mjs → types-mVVgRPaU.mjs} +0 -0
- /package/dist/{types-POH8PQZh.d.mts → types-wFu80FrO.d.mts} +0 -0
- /package/dist/{url-CpyFDFpO.mjs → url-EMAguGVk.mjs} +0 -0
- /package/dist/{url-Cac7a9QZ.mjs → url-guoXQQcV.mjs} +0 -0
package/dist/cli/index.mjs
CHANGED
|
@@ -1,150 +1,74 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { i as runMigrations, n as getMigrationStatus, t as getMigrationFingerprint } from "../runner-BgmttQmD.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
7
|
import { i as encodeBase64url } from "../base64-F8-DUraK.mjs";
|
|
8
|
-
import "../types-
|
|
9
|
-
import { o as isMissingTableError } from "../loader-
|
|
8
|
+
import "../types-ChxYDRvx.mjs";
|
|
9
|
+
import { o as isMissingTableError } from "../loader-aWkkc1_o.mjs";
|
|
10
10
|
import "../object-cache-D51qOseS.mjs";
|
|
11
11
|
import { n as slugify } from "../slugify-KSsVD_D3.mjs";
|
|
12
|
-
import { t as ContentRepository } from "../content-
|
|
13
|
-
import { t as MediaRepository } from "../media-
|
|
14
|
-
import { t as TaxonomyRepository } from "../taxonomy-
|
|
12
|
+
import { t as ContentRepository } from "../content-DJcAYFhz.mjs";
|
|
13
|
+
import { t as MediaRepository } from "../media-CVMOoywq.mjs";
|
|
14
|
+
import { t as TaxonomyRepository } from "../taxonomy-0k_vRVsD.mjs";
|
|
15
15
|
import { t as OptionsRepository } from "../options-DQPTH5n0.mjs";
|
|
16
|
-
import "../redirect-
|
|
17
|
-
import "../request-cache-
|
|
18
|
-
import "../byline-registry-
|
|
19
|
-
import "../field-defs-cache-
|
|
20
|
-
import { t as BylineRepository } from "../byline-
|
|
21
|
-
import "../content-refresh-
|
|
22
|
-
import "../fts-manager-
|
|
23
|
-
import { n as SchemaRegistry } from "../registry-
|
|
24
|
-
import "../settings-
|
|
25
|
-
import { n as VERSION } from "../version-
|
|
26
|
-
import { a as reconcileManifestAccess, i as pluginManifestSchema } from "../manifest-schema-
|
|
27
|
-
import "../ssrf-
|
|
28
|
-
import { n as fingerprintKey, r as generateEncryptionKey, t as DinewaySecretsError } from "../secrets-
|
|
29
|
-
import { t as validateSeed } from "../validate-
|
|
30
|
-
import { t as applySeed } from "../apply-
|
|
31
|
-
import {
|
|
32
|
-
import { t as
|
|
33
|
-
import {
|
|
16
|
+
import "../redirect-ubhEqQCQ.mjs";
|
|
17
|
+
import "../request-cache-CBFjCwSt.mjs";
|
|
18
|
+
import "../byline-registry-Ba54M74c.mjs";
|
|
19
|
+
import "../field-defs-cache-DL-T2XVS.mjs";
|
|
20
|
+
import { t as BylineRepository } from "../byline-7xR185Ly.mjs";
|
|
21
|
+
import "../content-refresh-B4ZCmxgd.mjs";
|
|
22
|
+
import "../fts-manager-ewTGohf4.mjs";
|
|
23
|
+
import { n as SchemaRegistry } from "../registry-BYYyb2tF.mjs";
|
|
24
|
+
import "../settings-BECcAIRH.mjs";
|
|
25
|
+
import { n as VERSION } from "../version-C3iVRuaF.mjs";
|
|
26
|
+
import { a as reconcileManifestAccess, i as pluginManifestSchema } from "../manifest-schema-uA6pRFXi.mjs";
|
|
27
|
+
import { n as resolveAndValidateExternalUrl, t as SsrfError } from "../ssrf-FJqwQzj4.mjs";
|
|
28
|
+
import { n as fingerprintKey, r as generateEncryptionKey, t as DinewaySecretsError } from "../secrets-ZV5rd8yV.mjs";
|
|
29
|
+
import { t as validateSeed } from "../validate-D1HL-oLR.mjs";
|
|
30
|
+
import { t as applySeed } from "../apply-DjTqq6Ae.mjs";
|
|
31
|
+
import { a as readSavedDeployTarget, c as listForgewayCredentials, i as readForgewayDeployMetadata, l as readForgewayCredentials, n as SeoProviderEvidenceService, o as writeDeployTarget, r as readDeployPackageJson, s as writeForgewayDeployMetadata, t as ForgewaySeoGatewayClient, u as writeForgewayCredentials } from "../forgeway-seo-client-G5ddhVHd.mjs";
|
|
32
|
+
import { n as output, t as configureOutputMode } from "../output-DhBe5_Pi.mjs";
|
|
33
|
+
import { createHeaderAwareFetch, isRedirectResponse, resolveCustomHeaders } from "../client/external-auth-headers.mjs";
|
|
34
|
+
import { t as convertDataForRead } from "../portable-text-BASHceim.mjs";
|
|
35
|
+
import { a as getMarketplaceCredential, c as resolveCredentialKey, i as getCredentials, l as saveCredentials, n as connectionArgs, o as removeCredentials, r as createClientFromArgs, s as removeMarketplaceCredential, u as saveMarketplaceCredential } from "../client-factory-BDD9azPJ.mjs";
|
|
36
|
+
import { a as resolveDinewayBaseUrl, n as ensureProjectGitignoreDinewayLocalState, o as resolveDinewayToken, r as ensureProjectGitignoreEntry, s as upsertProjectEnv, t as DEFAULT_DINEWAY_URL } from "../project-env-DKibmuP8.mjs";
|
|
34
37
|
import { LocalStorage } from "../storage/local.mjs";
|
|
35
|
-
import { r as fileExists$11, t as bundleCommand } from "../bundle-
|
|
36
|
-
import {
|
|
38
|
+
import { r as fileExists$11, t as bundleCommand } from "../bundle-CEcdUa1s.mjs";
|
|
39
|
+
import { createRequire } from "node:module";
|
|
40
|
+
import { createHash } from "node:crypto";
|
|
37
41
|
import { sql } from "kysely";
|
|
38
42
|
import { createGzipDecoder, unpackTar } from "modern-tar";
|
|
39
|
-
import { createReadStream, existsSync,
|
|
43
|
+
import { createReadStream, existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
40
44
|
import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
45
|
+
import sax from "sax";
|
|
46
|
+
import { pathToFileURL } from "node:url";
|
|
41
47
|
import { defineCommand, runCommand, runMain } from "citty";
|
|
42
48
|
import { createInterface } from "node:readline/promises";
|
|
43
49
|
import consola, { consola as consola$1 } from "consola";
|
|
44
50
|
import pc from "picocolors";
|
|
45
51
|
import { ForgewayClient } from "@forgeway/sdk";
|
|
46
|
-
import { access,
|
|
47
|
-
import { homedir } from "node:os";
|
|
52
|
+
import { access, mkdir, readFile, readdir, stat, writeFile } from "node:fs/promises";
|
|
48
53
|
import { spawn } from "node:child_process";
|
|
54
|
+
import { parse } from "parse5";
|
|
49
55
|
|
|
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
56
|
//#region src/cli/forgeway-account.ts
|
|
133
|
-
const TRAILING_SLASH_PATTERN$
|
|
134
|
-
const SHADOW_EMAIL_PATTERN$
|
|
57
|
+
const TRAILING_SLASH_PATTERN$1 = /\/$/;
|
|
58
|
+
const SHADOW_EMAIL_PATTERN$1 = /^shadow_[a-f0-9]{16}@dineway\.ai$/i;
|
|
135
59
|
const DEFAULT_FORGEWAY_API_BASE_URL = "https://api.dineway.ai";
|
|
136
60
|
const DEFAULT_DINEWAY_WEB_URL = "https://dineway.ai";
|
|
137
61
|
function normalizeForgewayApiUrl(value) {
|
|
138
|
-
return (value || DEFAULT_FORGEWAY_API_BASE_URL).replace(TRAILING_SLASH_PATTERN$
|
|
62
|
+
return (value || DEFAULT_FORGEWAY_API_BASE_URL).replace(TRAILING_SLASH_PATTERN$1, "");
|
|
139
63
|
}
|
|
140
64
|
function normalizeDinewayWebUrl(value) {
|
|
141
|
-
return (value || DEFAULT_DINEWAY_WEB_URL).replace(TRAILING_SLASH_PATTERN$
|
|
65
|
+
return (value || DEFAULT_DINEWAY_WEB_URL).replace(TRAILING_SLASH_PATTERN$1, "");
|
|
142
66
|
}
|
|
143
67
|
function normalizeForgewayEmail(value) {
|
|
144
68
|
return value?.trim().toLowerCase() ?? "";
|
|
145
69
|
}
|
|
146
70
|
function isShadowForgewayEmail(email) {
|
|
147
|
-
return Boolean(email && SHADOW_EMAIL_PATTERN$
|
|
71
|
+
return Boolean(email && SHADOW_EMAIL_PATTERN$1.test(email));
|
|
148
72
|
}
|
|
149
73
|
function createForgewayAccountClient(platformApiUrl, accessToken) {
|
|
150
74
|
return new ForgewayClient({
|
|
@@ -154,7 +78,7 @@ function createForgewayAccountClient(platformApiUrl, accessToken) {
|
|
|
154
78
|
auth: { detectOAuthCallback: false }
|
|
155
79
|
});
|
|
156
80
|
}
|
|
157
|
-
function normalizeForgewayUser$
|
|
81
|
+
function normalizeForgewayUser$1(user) {
|
|
158
82
|
if (!user?.id || !user.email) throw new Error("Forgeway session response did not include a user email.");
|
|
159
83
|
return {
|
|
160
84
|
id: user.id,
|
|
@@ -192,7 +116,7 @@ async function refreshForgewayAccountCredentials(credentials) {
|
|
|
192
116
|
if (!credentials.refreshToken) throw new Error("Stored Forgeway account is missing a refresh token. Run `dineway account login`.");
|
|
193
117
|
const { data, error } = await createForgewayAccountClient(credentials.platformApiUrl).auth.refreshSession({ refreshToken: credentials.refreshToken });
|
|
194
118
|
if (error || !data?.accessToken) throw new Error(error?.message || "Failed to refresh Forgeway account. Run `dineway account login`.");
|
|
195
|
-
const refreshedUser = normalizeForgewayUser$
|
|
119
|
+
const refreshedUser = normalizeForgewayUser$1(data.user);
|
|
196
120
|
if (normalizeForgewayEmail(refreshedUser.email) !== normalizeForgewayEmail(user.email)) throw new Error("Forgeway refresh returned credentials for a different account.");
|
|
197
121
|
const updated = {
|
|
198
122
|
...credentials,
|
|
@@ -224,7 +148,7 @@ async function completeForgewayAccountLogin(input) {
|
|
|
224
148
|
const platformApiUrl = normalizeForgewayApiUrl(input.platformApiUrl);
|
|
225
149
|
const { data, error } = await createForgewayAccountClient(platformApiUrl).auth.signInWithPasswordlessToken({ token: input.token });
|
|
226
150
|
if (error || !data?.accessToken || !data.refreshToken) throw new Error(error?.message || "Forgeway sign-in token is invalid or expired.");
|
|
227
|
-
const user = normalizeForgewayUser$
|
|
151
|
+
const user = normalizeForgewayUser$1(data.user);
|
|
228
152
|
if (input.email && normalizeForgewayEmail(user.email) !== normalizeForgewayEmail(input.email)) throw new Error("Forgeway sign-in returned credentials for a different email.");
|
|
229
153
|
const credentials = {
|
|
230
154
|
platformApiUrl,
|
|
@@ -251,71 +175,6 @@ async function getForgewayDinewayAccount(credentials) {
|
|
|
251
175
|
};
|
|
252
176
|
}
|
|
253
177
|
|
|
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
178
|
//#endregion
|
|
320
179
|
//#region src/cli/commands/account.ts
|
|
321
180
|
async function promptLine(question) {
|
|
@@ -504,320 +363,6 @@ const accountCommand = defineCommand({
|
|
|
504
363
|
}
|
|
505
364
|
});
|
|
506
365
|
|
|
507
|
-
//#endregion
|
|
508
|
-
//#region src/cli/credentials.ts
|
|
509
|
-
/**
|
|
510
|
-
* Credential storage for CLI auth tokens.
|
|
511
|
-
*
|
|
512
|
-
* Stores OAuth tokens in ~/.config/dineway/auth.json.
|
|
513
|
-
* Remote URLs are keyed by origin, local dev by project path.
|
|
514
|
-
*/
|
|
515
|
-
function getConfigDir() {
|
|
516
|
-
const xdg = process.env["XDG_CONFIG_HOME"];
|
|
517
|
-
if (xdg) return join(xdg, "dineway");
|
|
518
|
-
return join(homedir(), ".config", "dineway");
|
|
519
|
-
}
|
|
520
|
-
function getCredentialPath() {
|
|
521
|
-
return join(getConfigDir(), "auth.json");
|
|
522
|
-
}
|
|
523
|
-
/**
|
|
524
|
-
* Resolve the credential key for a given URL.
|
|
525
|
-
*
|
|
526
|
-
* Remote URLs are keyed by origin (e.g. "https://my-site.pages.dev").
|
|
527
|
-
* Local dev instances are keyed by project path (e.g. "path:/Users/matt/sites/blog").
|
|
528
|
-
*/
|
|
529
|
-
function resolveCredentialKey(baseUrl) {
|
|
530
|
-
try {
|
|
531
|
-
const url = new URL(baseUrl);
|
|
532
|
-
if (url.hostname === "localhost" || url.hostname === "127.0.0.1" || url.hostname === "[::1]") {
|
|
533
|
-
const projectPath = findProjectRoot(process.cwd());
|
|
534
|
-
if (projectPath) return `path:${projectPath}`;
|
|
535
|
-
return url.origin;
|
|
536
|
-
}
|
|
537
|
-
return url.origin;
|
|
538
|
-
} catch {
|
|
539
|
-
return baseUrl;
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
/**
|
|
543
|
-
* Walk up from cwd to find the project root (directory containing astro.config.*).
|
|
544
|
-
*/
|
|
545
|
-
function findProjectRoot(from) {
|
|
546
|
-
let dir = resolve(from);
|
|
547
|
-
const root = resolve("/");
|
|
548
|
-
while (dir !== root) {
|
|
549
|
-
for (const name of [
|
|
550
|
-
"astro.config.ts",
|
|
551
|
-
"astro.config.mts",
|
|
552
|
-
"astro.config.js",
|
|
553
|
-
"astro.config.mjs"
|
|
554
|
-
]) if (existsSync(join(dir, name))) return dir;
|
|
555
|
-
const parent = resolve(dir, "..");
|
|
556
|
-
if (parent === dir) break;
|
|
557
|
-
dir = parent;
|
|
558
|
-
}
|
|
559
|
-
return null;
|
|
560
|
-
}
|
|
561
|
-
function readStore() {
|
|
562
|
-
const path = getCredentialPath();
|
|
563
|
-
try {
|
|
564
|
-
if (existsSync(path)) {
|
|
565
|
-
const content = readFileSync(path, "utf-8");
|
|
566
|
-
return JSON.parse(content);
|
|
567
|
-
}
|
|
568
|
-
} catch {}
|
|
569
|
-
return {};
|
|
570
|
-
}
|
|
571
|
-
function writeStore(store) {
|
|
572
|
-
mkdirSync(getConfigDir(), {
|
|
573
|
-
recursive: true,
|
|
574
|
-
mode: 448
|
|
575
|
-
});
|
|
576
|
-
writeFileSync(getCredentialPath(), JSON.stringify(store, null, " "), {
|
|
577
|
-
encoding: "utf-8",
|
|
578
|
-
mode: 384
|
|
579
|
-
});
|
|
580
|
-
}
|
|
581
|
-
/**
|
|
582
|
-
* Get stored credentials for a URL.
|
|
583
|
-
*/
|
|
584
|
-
function getCredentials(baseUrl) {
|
|
585
|
-
const key = resolveCredentialKey(baseUrl);
|
|
586
|
-
const cred = readStore()[key];
|
|
587
|
-
if (!cred || !("accessToken" in cred)) return null;
|
|
588
|
-
return cred;
|
|
589
|
-
}
|
|
590
|
-
/**
|
|
591
|
-
* Save credentials for a URL.
|
|
592
|
-
*/
|
|
593
|
-
function saveCredentials(baseUrl, cred) {
|
|
594
|
-
const key = resolveCredentialKey(baseUrl);
|
|
595
|
-
const store = readStore();
|
|
596
|
-
store[key] = cred;
|
|
597
|
-
writeStore(store);
|
|
598
|
-
}
|
|
599
|
-
/**
|
|
600
|
-
* Remove credentials for a URL.
|
|
601
|
-
*/
|
|
602
|
-
function removeCredentials(baseUrl) {
|
|
603
|
-
const key = resolveCredentialKey(baseUrl);
|
|
604
|
-
const store = readStore();
|
|
605
|
-
if (key in store) {
|
|
606
|
-
delete store[key];
|
|
607
|
-
writeStore(store);
|
|
608
|
-
return true;
|
|
609
|
-
}
|
|
610
|
-
return false;
|
|
611
|
-
}
|
|
612
|
-
function marketplaceKey(registryUrl) {
|
|
613
|
-
try {
|
|
614
|
-
return `marketplace:${new URL(registryUrl).origin}`;
|
|
615
|
-
} catch {
|
|
616
|
-
return `marketplace:${registryUrl}`;
|
|
617
|
-
}
|
|
618
|
-
}
|
|
619
|
-
/**
|
|
620
|
-
* Get stored marketplace credential for a registry URL.
|
|
621
|
-
*/
|
|
622
|
-
function getMarketplaceCredential(registryUrl) {
|
|
623
|
-
const key = marketplaceKey(registryUrl);
|
|
624
|
-
const cred = readStore()[key];
|
|
625
|
-
if (!cred || !("token" in cred)) return null;
|
|
626
|
-
if (new Date(cred.expiresAt) < /* @__PURE__ */ new Date()) return null;
|
|
627
|
-
return cred;
|
|
628
|
-
}
|
|
629
|
-
/**
|
|
630
|
-
* Save marketplace credential for a registry URL.
|
|
631
|
-
*/
|
|
632
|
-
function saveMarketplaceCredential(registryUrl, cred) {
|
|
633
|
-
const key = marketplaceKey(registryUrl);
|
|
634
|
-
const store = readStore();
|
|
635
|
-
store[key] = cred;
|
|
636
|
-
writeStore(store);
|
|
637
|
-
}
|
|
638
|
-
/**
|
|
639
|
-
* Remove marketplace credential for a registry URL.
|
|
640
|
-
*/
|
|
641
|
-
function removeMarketplaceCredential(registryUrl) {
|
|
642
|
-
const key = marketplaceKey(registryUrl);
|
|
643
|
-
const store = readStore();
|
|
644
|
-
if (key in store) {
|
|
645
|
-
delete store[key];
|
|
646
|
-
writeStore(store);
|
|
647
|
-
return true;
|
|
648
|
-
}
|
|
649
|
-
return false;
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
//#endregion
|
|
653
|
-
//#region src/cli/project-env.ts
|
|
654
|
-
const DEFAULT_DINEWAY_URL = "http://localhost:4321";
|
|
655
|
-
const ENV_KEY_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
656
|
-
const LINE_SPLIT_PATTERN = /\r?\n/;
|
|
657
|
-
const DINEWAY_LOCAL_STATE_GITIGNORE_COMMENT = "# Dineway local state";
|
|
658
|
-
const DINEWAY_LOCAL_STATE_GITIGNORE_ENTRIES = [
|
|
659
|
-
".dineway/deploy.json",
|
|
660
|
-
".dineway/forgeway.json",
|
|
661
|
-
".dineway/types.ts",
|
|
662
|
-
".dineway/schema.json",
|
|
663
|
-
".dineway/uploads/"
|
|
664
|
-
];
|
|
665
|
-
const NEWLINE_PATTERN = /\r?\n/g;
|
|
666
|
-
function parseDotenvValue(value) {
|
|
667
|
-
const trimmed = value.trim();
|
|
668
|
-
if (trimmed.startsWith("\"") && trimmed.endsWith("\"") || trimmed.startsWith("'") && trimmed.endsWith("'")) return trimmed.slice(1, -1);
|
|
669
|
-
return trimmed;
|
|
670
|
-
}
|
|
671
|
-
function parseDotenv(text) {
|
|
672
|
-
const env = {};
|
|
673
|
-
for (const line of text.split(LINE_SPLIT_PATTERN)) {
|
|
674
|
-
const trimmed = line.trim();
|
|
675
|
-
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
676
|
-
const normalized = trimmed.startsWith("export ") ? trimmed.slice(7).trim() : trimmed;
|
|
677
|
-
const equalsIndex = normalized.indexOf("=");
|
|
678
|
-
if (equalsIndex <= 0) continue;
|
|
679
|
-
const key = normalized.slice(0, equalsIndex).trim();
|
|
680
|
-
if (!ENV_KEY_PATTERN.test(key)) continue;
|
|
681
|
-
env[key] = parseDotenvValue(normalized.slice(equalsIndex + 1));
|
|
682
|
-
}
|
|
683
|
-
return env;
|
|
684
|
-
}
|
|
685
|
-
function readProjectEnv(cwd = process.cwd()) {
|
|
686
|
-
const envPath = join(cwd, ".env");
|
|
687
|
-
if (!existsSync(envPath)) return {};
|
|
688
|
-
return parseDotenv(readFileSync(envPath, "utf-8"));
|
|
689
|
-
}
|
|
690
|
-
function getProjectEnvValue(name, cwd = process.cwd()) {
|
|
691
|
-
return process.env[name] ?? readProjectEnv(cwd)[name];
|
|
692
|
-
}
|
|
693
|
-
function resolveDinewayBaseUrl(url, cwd = process.cwd()) {
|
|
694
|
-
if (url && url !== DEFAULT_DINEWAY_URL) return url;
|
|
695
|
-
const projectEnv = readProjectEnv(cwd);
|
|
696
|
-
return process.env["DINEWAY_URL"] ?? process.env["DINEWAY_SITE_URL"] ?? projectEnv["DINEWAY_SITE_URL"] ?? projectEnv["DINEWAY_URL"] ?? url ?? DEFAULT_DINEWAY_URL;
|
|
697
|
-
}
|
|
698
|
-
function resolveDinewayToken(token, cwd = process.cwd()) {
|
|
699
|
-
return token ?? getProjectEnvValue("DINEWAY_TOKEN", cwd);
|
|
700
|
-
}
|
|
701
|
-
function formatEnvValue(value) {
|
|
702
|
-
return value.replace(NEWLINE_PATTERN, "");
|
|
703
|
-
}
|
|
704
|
-
async function upsertProjectEnv(cwd, values) {
|
|
705
|
-
const envPath = join(cwd, ".env");
|
|
706
|
-
const existing = await readFile(envPath, "utf-8").catch(() => "");
|
|
707
|
-
const lines = existing ? existing.split(LINE_SPLIT_PATTERN) : [];
|
|
708
|
-
const seen = /* @__PURE__ */ new Set();
|
|
709
|
-
const nextLines = lines.map((line) => {
|
|
710
|
-
const trimmed = line.trim();
|
|
711
|
-
const normalized = trimmed.startsWith("export ") ? trimmed.slice(7).trim() : trimmed;
|
|
712
|
-
const equalsIndex = normalized.indexOf("=");
|
|
713
|
-
if (equalsIndex <= 0) return line;
|
|
714
|
-
const key = normalized.slice(0, equalsIndex).trim();
|
|
715
|
-
const value = values[key];
|
|
716
|
-
if (!(key in values) || value === void 0) return line;
|
|
717
|
-
seen.add(key);
|
|
718
|
-
return `${key}=${formatEnvValue(value)}`;
|
|
719
|
-
});
|
|
720
|
-
for (const [key, value] of Object.entries(values)) {
|
|
721
|
-
if (value === void 0 || seen.has(key)) continue;
|
|
722
|
-
nextLines.push(`${key}=${formatEnvValue(value)}`);
|
|
723
|
-
}
|
|
724
|
-
await writeFile(envPath, `${nextLines.filter((line, index) => line || index < nextLines.length - 1).join("\n")}\n`, "utf-8");
|
|
725
|
-
}
|
|
726
|
-
async function ensureProjectGitignoreEntry(cwd, entry) {
|
|
727
|
-
const gitignorePath = join(cwd, ".gitignore");
|
|
728
|
-
const existing = await readFile(gitignorePath, "utf-8").catch(() => "");
|
|
729
|
-
if (existing.split(LINE_SPLIT_PATTERN).map((line) => line.trim()).includes(entry)) return;
|
|
730
|
-
await writeFile(gitignorePath, `${existing}${existing && !existing.endsWith("\n") ? "\n" : ""}${entry}\n`, "utf-8");
|
|
731
|
-
}
|
|
732
|
-
async function ensureProjectGitignoreDinewayLocalState(cwd) {
|
|
733
|
-
const gitignorePath = join(cwd, ".gitignore");
|
|
734
|
-
const existing = await readFile(gitignorePath, "utf-8").catch(() => "");
|
|
735
|
-
const lines = new Set(existing.split(LINE_SPLIT_PATTERN).map((line) => line.trim()));
|
|
736
|
-
const missingEntries = DINEWAY_LOCAL_STATE_GITIGNORE_ENTRIES.filter((entry) => !lines.has(entry));
|
|
737
|
-
if (missingEntries.length === 0) return;
|
|
738
|
-
const block = [DINEWAY_LOCAL_STATE_GITIGNORE_COMMENT, ...missingEntries].join("\n");
|
|
739
|
-
await writeFile(gitignorePath, `${existing}${existing.trim() ? existing.endsWith("\n") ? "\n" : "\n\n" : ""}${block}\n`, "utf-8");
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
//#endregion
|
|
743
|
-
//#region src/cli/client-factory.ts
|
|
744
|
-
var client_factory_exports = /* @__PURE__ */ __exportAll({
|
|
745
|
-
connectionArgs: () => connectionArgs,
|
|
746
|
-
createClientFromArgs: () => createClientFromArgs
|
|
747
|
-
});
|
|
748
|
-
/**
|
|
749
|
-
* Shared connection args for all CLI commands that talk to a Dineway instance.
|
|
750
|
-
* Spread into each command's `args` definition.
|
|
751
|
-
*/
|
|
752
|
-
const connectionArgs = {
|
|
753
|
-
url: {
|
|
754
|
-
type: "string",
|
|
755
|
-
alias: "u",
|
|
756
|
-
description: "Dineway instance URL",
|
|
757
|
-
default: DEFAULT_DINEWAY_URL
|
|
758
|
-
},
|
|
759
|
-
token: {
|
|
760
|
-
type: "string",
|
|
761
|
-
alias: "t",
|
|
762
|
-
description: "Auth token"
|
|
763
|
-
},
|
|
764
|
-
header: {
|
|
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"
|
|
772
|
-
}
|
|
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
|
-
});
|
|
819
|
-
}
|
|
820
|
-
|
|
821
366
|
//#endregion
|
|
822
367
|
//#region src/cli/commands/auth.ts
|
|
823
368
|
/**
|
|
@@ -1064,7 +609,7 @@ const createCommand$1 = defineCommand({
|
|
|
1064
609
|
},
|
|
1065
610
|
draft: {
|
|
1066
611
|
type: "boolean",
|
|
1067
|
-
description: "
|
|
612
|
+
description: "Explicitly create as Draft (the only supported creation mode)"
|
|
1068
613
|
},
|
|
1069
614
|
...connectionArgs
|
|
1070
615
|
},
|
|
@@ -1079,7 +624,6 @@ const createCommand$1 = defineCommand({
|
|
|
1079
624
|
locale: args.locale,
|
|
1080
625
|
translationOf: args["translation-of"]
|
|
1081
626
|
});
|
|
1082
|
-
if (!args.draft) await client.publish(args.collection, item.id);
|
|
1083
627
|
output(await client.get(args.collection, item.id), args);
|
|
1084
628
|
} catch (error) {
|
|
1085
629
|
consola$1.error(error instanceof Error ? error.message : "Unknown error");
|
|
@@ -1122,7 +666,7 @@ const updateCommand = defineCommand({
|
|
|
1122
666
|
},
|
|
1123
667
|
draft: {
|
|
1124
668
|
type: "boolean",
|
|
1125
|
-
description: "
|
|
669
|
+
description: "Explicitly update the Draft (the only supported update mode)"
|
|
1126
670
|
},
|
|
1127
671
|
...connectionArgs
|
|
1128
672
|
},
|
|
@@ -1136,7 +680,6 @@ const updateCommand = defineCommand({
|
|
|
1136
680
|
_rev: args.rev,
|
|
1137
681
|
locale: args.locale
|
|
1138
682
|
});
|
|
1139
|
-
if (!args.draft && updated.draftRevisionId) await client.publish(args.collection, updated.id);
|
|
1140
683
|
output(await client.get(args.collection, updated.id), args);
|
|
1141
684
|
} catch (error) {
|
|
1142
685
|
consola$1.error(error instanceof Error ? error.message : "Unknown error");
|
|
@@ -1190,12 +733,25 @@ const publishCommand$1 = defineCommand({
|
|
|
1190
733
|
description: "Content item ID or slug",
|
|
1191
734
|
required: true
|
|
1192
735
|
},
|
|
736
|
+
"review-request": {
|
|
737
|
+
type: "string",
|
|
738
|
+
description: "Approved editorial Review Request ID for the exact Draft",
|
|
739
|
+
required: true
|
|
740
|
+
},
|
|
741
|
+
"release-authorization": {
|
|
742
|
+
type: "string",
|
|
743
|
+
description: "Approved release authorization ID for this token action",
|
|
744
|
+
required: true
|
|
745
|
+
},
|
|
1193
746
|
...connectionArgs
|
|
1194
747
|
},
|
|
1195
748
|
async run({ args }) {
|
|
1196
749
|
configureOutputMode(args);
|
|
1197
750
|
try {
|
|
1198
|
-
await createClientFromArgs(args).publish(args.collection, args.id
|
|
751
|
+
await createClientFromArgs(args).publish(args.collection, args.id, {
|
|
752
|
+
reviewRequestId: args["review-request"],
|
|
753
|
+
releaseAuthorizationId: args["release-authorization"]
|
|
754
|
+
});
|
|
1199
755
|
output({ success: true }, args);
|
|
1200
756
|
consola$1.success(`Published ${args.collection}/${args.id}`);
|
|
1201
757
|
} catch (error) {
|
|
@@ -1255,12 +811,26 @@ const scheduleCommand = defineCommand({
|
|
|
1255
811
|
description: "ISO 8601 datetime to publish at",
|
|
1256
812
|
required: true
|
|
1257
813
|
},
|
|
814
|
+
"review-request": {
|
|
815
|
+
type: "string",
|
|
816
|
+
description: "Approved editorial Review Request ID for the exact Draft",
|
|
817
|
+
required: true
|
|
818
|
+
},
|
|
819
|
+
"release-authorization": {
|
|
820
|
+
type: "string",
|
|
821
|
+
description: "Approved release authorization ID for this token action",
|
|
822
|
+
required: true
|
|
823
|
+
},
|
|
1258
824
|
...connectionArgs
|
|
1259
825
|
},
|
|
1260
826
|
async run({ args }) {
|
|
1261
827
|
configureOutputMode(args);
|
|
1262
828
|
try {
|
|
1263
|
-
await createClientFromArgs(args).schedule(args.collection, args.id, {
|
|
829
|
+
await createClientFromArgs(args).schedule(args.collection, args.id, {
|
|
830
|
+
at: args.at,
|
|
831
|
+
reviewRequestId: args["review-request"],
|
|
832
|
+
releaseAuthorizationId: args["release-authorization"]
|
|
833
|
+
});
|
|
1264
834
|
output({ success: true }, args);
|
|
1265
835
|
consola$1.success(`Scheduled ${args.collection}/${args.id} for ${args.at}`);
|
|
1266
836
|
} catch (error) {
|
|
@@ -1349,7 +919,7 @@ const contentCommand = defineCommand({
|
|
|
1349
919
|
//#endregion
|
|
1350
920
|
//#region src/cli/paywall.ts
|
|
1351
921
|
const PAYWALL_MESSAGE_PATTERN = /\b(quota|credit|credits|upgrade|plan|billing|subscription|slot)\b/i;
|
|
1352
|
-
function isRecord$
|
|
922
|
+
function isRecord$2(value) {
|
|
1353
923
|
return typeof value === "object" && value !== null;
|
|
1354
924
|
}
|
|
1355
925
|
function stringField(record, key) {
|
|
@@ -1357,9 +927,9 @@ function stringField(record, key) {
|
|
|
1357
927
|
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
1358
928
|
}
|
|
1359
929
|
function getNestedError(value) {
|
|
1360
|
-
if (!isRecord$
|
|
930
|
+
if (!isRecord$2(value)) return null;
|
|
1361
931
|
const nested = value.error;
|
|
1362
|
-
return isRecord$
|
|
932
|
+
return isRecord$2(nested) ? nested : value;
|
|
1363
933
|
}
|
|
1364
934
|
function isHostedSitesResource(resource) {
|
|
1365
935
|
const normalized = resource.toLowerCase();
|
|
@@ -1927,7 +1497,7 @@ const FLY_HOST_RE = /\b[a-z0-9][a-z0-9-]*\.fly\.dev\b/;
|
|
|
1927
1497
|
const INVALID_FLY_APP_CHARS_RE = /[^a-z0-9-]+/g;
|
|
1928
1498
|
const REPEATED_HYPHENS_RE$2 = /-+/g;
|
|
1929
1499
|
const EDGE_HYPHENS_RE$2 = /^-|-$/g;
|
|
1930
|
-
const LINE_SPLIT_RE = /\r?\n/;
|
|
1500
|
+
const LINE_SPLIT_RE$1 = /\r?\n/;
|
|
1931
1501
|
const DEFAULT_REGION$1 = "iad";
|
|
1932
1502
|
const FLY_VOLUME_NAME = "dineway_data";
|
|
1933
1503
|
async function fileExists$8(path) {
|
|
@@ -2019,7 +1589,7 @@ primary_region = "${region}"
|
|
|
2019
1589
|
function parseFlyUrl(stdout) {
|
|
2020
1590
|
const direct = stdout.match(FLY_URL_RE);
|
|
2021
1591
|
if (direct) return direct[0];
|
|
2022
|
-
for (const line of stdout.split(LINE_SPLIT_RE).filter(Boolean)) try {
|
|
1592
|
+
for (const line of stdout.split(LINE_SPLIT_RE$1).filter(Boolean)) try {
|
|
2023
1593
|
const url = findFlyUrl(JSON.parse(line));
|
|
2024
1594
|
if (url) return url;
|
|
2025
1595
|
} catch {
|
|
@@ -2129,69 +1699,9 @@ const flyTarget = {
|
|
|
2129
1699
|
}
|
|
2130
1700
|
};
|
|
2131
1701
|
|
|
2132
|
-
//#endregion
|
|
2133
|
-
//#region src/cli/commands/deploy/utils/config.ts
|
|
2134
|
-
const DINEWAY_DIR_NAME = ".dineway";
|
|
2135
|
-
const DEPLOY_STATE_FILE_NAME = "deploy.json";
|
|
2136
|
-
function deployStatePath(cwd) {
|
|
2137
|
-
return join(cwd, DINEWAY_DIR_NAME, DEPLOY_STATE_FILE_NAME);
|
|
2138
|
-
}
|
|
2139
|
-
function emptyDeployState() {
|
|
2140
|
-
return { version: 1 };
|
|
2141
|
-
}
|
|
2142
|
-
async function readDeployPackageJson(cwd) {
|
|
2143
|
-
const content = await readFile(join(cwd, "package.json"), "utf-8");
|
|
2144
|
-
return JSON.parse(content);
|
|
2145
|
-
}
|
|
2146
|
-
async function readDeployState(cwd) {
|
|
2147
|
-
try {
|
|
2148
|
-
const content = await readFile(deployStatePath(cwd), "utf-8");
|
|
2149
|
-
return {
|
|
2150
|
-
...emptyDeployState(),
|
|
2151
|
-
...JSON.parse(content),
|
|
2152
|
-
version: 1
|
|
2153
|
-
};
|
|
2154
|
-
} catch (error) {
|
|
2155
|
-
if (error && typeof error === "object" && error.code === "ENOENT") return emptyDeployState();
|
|
2156
|
-
throw error;
|
|
2157
|
-
}
|
|
2158
|
-
}
|
|
2159
|
-
async function writeDeployState(cwd, state) {
|
|
2160
|
-
await mkdir(join(cwd, DINEWAY_DIR_NAME), { recursive: true });
|
|
2161
|
-
await writeFile(deployStatePath(cwd), JSON.stringify({
|
|
2162
|
-
...state,
|
|
2163
|
-
version: 1
|
|
2164
|
-
}, null, " ") + "\n", "utf-8");
|
|
2165
|
-
}
|
|
2166
|
-
async function readSavedDeployTarget(cwd) {
|
|
2167
|
-
return (await readDeployState(cwd)).target;
|
|
2168
|
-
}
|
|
2169
|
-
async function writeDeployTarget(cwd, target) {
|
|
2170
|
-
await writeDeployState(cwd, {
|
|
2171
|
-
...await readDeployState(cwd),
|
|
2172
|
-
target
|
|
2173
|
-
});
|
|
2174
|
-
}
|
|
2175
|
-
async function readForgewayDeployMetadata(cwd) {
|
|
2176
|
-
return (await readDeployState(cwd)).targets?.forgeway ?? {};
|
|
2177
|
-
}
|
|
2178
|
-
async function writeForgewayDeployMetadata(cwd, metadata) {
|
|
2179
|
-
const state = await readDeployState(cwd);
|
|
2180
|
-
await writeDeployState(cwd, {
|
|
2181
|
-
...state,
|
|
2182
|
-
targets: {
|
|
2183
|
-
...state.targets,
|
|
2184
|
-
forgeway: {
|
|
2185
|
-
...state.targets?.forgeway,
|
|
2186
|
-
...metadata
|
|
2187
|
-
}
|
|
2188
|
-
}
|
|
2189
|
-
});
|
|
2190
|
-
}
|
|
2191
|
-
|
|
2192
1702
|
//#endregion
|
|
2193
1703
|
//#region src/cli/commands/deploy/targets/forgeway.ts
|
|
2194
|
-
const DEFAULT_DINEWAY_API_BASE_URL
|
|
1704
|
+
const DEFAULT_DINEWAY_API_BASE_URL = "https://api.dineway.ai";
|
|
2195
1705
|
const DATABASE_ENV_VAR_NAMES = ["DINEWAY_DATABASE_URL", "DINEWAY_DATABASE_AUTH_TOKEN"];
|
|
2196
1706
|
const POLL_INTERVAL_MS$1 = 5e3;
|
|
2197
1707
|
const POLL_TIMEOUT_MS$1 = 3e5;
|
|
@@ -2206,12 +1716,12 @@ const NON_COMPARE_PATTERN = /[^\p{Letter}\p{Number}]+/gu;
|
|
|
2206
1716
|
const LOCATION_PARTS_PATTERN = /[,;|/]+|\s+-\s+/u;
|
|
2207
1717
|
const JWT_PATTERN = /[A-Za-z0-9_-]{32,}\.[A-Za-z0-9_-]{16,}\.[A-Za-z0-9_-]{16,}/g;
|
|
2208
1718
|
const TOKEN_ASSIGNMENT_PATTERN = /(DINEWAY_DATABASE_AUTH_TOKEN|DATABASE_AUTH_TOKEN|AUTH_TOKEN)=\S+/gi;
|
|
2209
|
-
const TRAILING_SLASH_PATTERN
|
|
1719
|
+
const TRAILING_SLASH_PATTERN = /\/$/;
|
|
2210
1720
|
const BACKSLASH_PATTERN = /\\/g;
|
|
2211
1721
|
const DINEWAY_PACKAGE_NAME = "dineway";
|
|
2212
1722
|
const SEMVER_VERSION_PATTERN = /^\d+\.\d+\.\d+(?:[-+].*)?$/;
|
|
2213
1723
|
const LOCAL_PACKAGE_SPEC_PATTERN = /^(?:workspace|file|link|portal):/;
|
|
2214
|
-
const SHADOW_EMAIL_PATTERN
|
|
1724
|
+
const SHADOW_EMAIL_PATTERN = /^shadow_[a-f0-9]{16}@dineway\.ai$/i;
|
|
2215
1725
|
const FOOD_TYPES = new Set([
|
|
2216
1726
|
"restaurant",
|
|
2217
1727
|
"cafe",
|
|
@@ -2259,7 +1769,7 @@ var ForgewayApiError = class extends Error {
|
|
|
2259
1769
|
this.name = "ForgewayApiError";
|
|
2260
1770
|
}
|
|
2261
1771
|
};
|
|
2262
|
-
function normalizeForgewayUser
|
|
1772
|
+
function normalizeForgewayUser(user) {
|
|
2263
1773
|
return {
|
|
2264
1774
|
id: user.id,
|
|
2265
1775
|
name: user.profile?.name ?? user.name ?? user.email,
|
|
@@ -2280,7 +1790,7 @@ async function fileExists$7(path) {
|
|
|
2280
1790
|
}
|
|
2281
1791
|
}
|
|
2282
1792
|
function normalizePlatformApiUrl(value) {
|
|
2283
|
-
return (value || DEFAULT_DINEWAY_API_BASE_URL
|
|
1793
|
+
return (value || DEFAULT_DINEWAY_API_BASE_URL).replace(TRAILING_SLASH_PATTERN, "");
|
|
2284
1794
|
}
|
|
2285
1795
|
function resolvePlatformApiUrl(savedPlatformApiUrl) {
|
|
2286
1796
|
return normalizePlatformApiUrl(getEnv("DINEWAY_API_BASE_URL") ?? (typeof savedPlatformApiUrl === "string" ? savedPlatformApiUrl : void 0));
|
|
@@ -2343,11 +1853,11 @@ async function parseErrorResponse(response) {
|
|
|
2343
1853
|
}
|
|
2344
1854
|
return `Forgeway request failed: ${response.status}`;
|
|
2345
1855
|
}
|
|
2346
|
-
function normalizeEmail
|
|
1856
|
+
function normalizeEmail(email) {
|
|
2347
1857
|
return email.trim().toLowerCase();
|
|
2348
1858
|
}
|
|
2349
|
-
function isShadowEmail
|
|
2350
|
-
return Boolean(email && SHADOW_EMAIL_PATTERN
|
|
1859
|
+
function isShadowEmail(email) {
|
|
1860
|
+
return Boolean(email && SHADOW_EMAIL_PATTERN.test(email));
|
|
2351
1861
|
}
|
|
2352
1862
|
async function refreshFormalAccessToken(context, deps) {
|
|
2353
1863
|
if (!context.refreshToken) throw new Error("Forgeway formal account refresh token is missing. Run dineway deploy again.");
|
|
@@ -2359,7 +1869,7 @@ async function refreshFormalAccessToken(context, deps) {
|
|
|
2359
1869
|
if (!response.ok) throw new Error("Failed to refresh Forgeway formal account credentials. Run dineway deploy again.");
|
|
2360
1870
|
const payload = await response.json();
|
|
2361
1871
|
if (!payload.accessToken) throw new Error("Forgeway refresh response was missing accessToken.");
|
|
2362
|
-
const user = assertVerifiedFormalAccountUser(payload.user ? normalizeForgewayUser
|
|
1872
|
+
const user = assertVerifiedFormalAccountUser(payload.user ? normalizeForgewayUser(payload.user) : context.user, context.user?.email);
|
|
2363
1873
|
const updated = {
|
|
2364
1874
|
platformApiUrl: context.platformApiUrl,
|
|
2365
1875
|
accessToken: payload.accessToken,
|
|
@@ -2406,7 +1916,7 @@ function getDependencySpec(pkg, name) {
|
|
|
2406
1916
|
if (typeof value === "string" && value.trim()) return value.trim();
|
|
2407
1917
|
}
|
|
2408
1918
|
}
|
|
2409
|
-
async function readProjectPackage(cwd) {
|
|
1919
|
+
async function readProjectPackage$1(cwd) {
|
|
2410
1920
|
try {
|
|
2411
1921
|
return await readDeployPackageJson(cwd);
|
|
2412
1922
|
} catch {
|
|
@@ -2420,7 +1930,7 @@ function isDinewayDependencySpecCompatible(dependencySpec, cliVersion) {
|
|
|
2420
1930
|
}
|
|
2421
1931
|
async function warnProjectDinewayRuntimeMismatch(cwd, cliVersion = VERSION) {
|
|
2422
1932
|
if (!SEMVER_VERSION_PATTERN.test(cliVersion)) return;
|
|
2423
|
-
const pkg = await readProjectPackage(cwd);
|
|
1933
|
+
const pkg = await readProjectPackage$1(cwd);
|
|
2424
1934
|
if (!pkg) return;
|
|
2425
1935
|
const dependencySpec = getDependencySpec(pkg, DINEWAY_PACKAGE_NAME);
|
|
2426
1936
|
if (!dependencySpec) return;
|
|
@@ -2434,20 +1944,20 @@ function savedPublisherEmail(saved) {
|
|
|
2434
1944
|
return typeof saved.publisherEmail === "string" && saved.publisherEmail.trim() ? saved.publisherEmail : void 0;
|
|
2435
1945
|
}
|
|
2436
1946
|
function validatePublisherEmail(rawEmail) {
|
|
2437
|
-
const email = normalizeEmail
|
|
2438
|
-
if (!email || isShadowEmail
|
|
1947
|
+
const email = normalizeEmail(rawEmail);
|
|
1948
|
+
if (!email || isShadowEmail(email)) throw new Error("Dineway account email must be a real owner email, not a shadow user email.");
|
|
2439
1949
|
return email;
|
|
2440
1950
|
}
|
|
2441
1951
|
function isStoredFormalCredentialForEmail(stored, email) {
|
|
2442
1952
|
if (!stored?.accessToken || !stored.user) return false;
|
|
2443
|
-
if (email && normalizeEmail
|
|
1953
|
+
if (email && normalizeEmail(stored.user.email) !== email) return false;
|
|
2444
1954
|
if (stored.user.emailVerified !== true) return false;
|
|
2445
|
-
if (isShadowEmail
|
|
1955
|
+
if (isShadowEmail(stored.user.email)) return false;
|
|
2446
1956
|
return true;
|
|
2447
1957
|
}
|
|
2448
1958
|
function assertVerifiedFormalAccountUser(user, expectedEmail) {
|
|
2449
|
-
if (!user || user.emailVerified !== true || isShadowEmail
|
|
2450
|
-
if (expectedEmail && normalizeEmail
|
|
1959
|
+
if (!user || user.emailVerified !== true || isShadowEmail(user.email)) throw new Error("Forgeway formal account credentials require a verified formal account.");
|
|
1960
|
+
if (expectedEmail && normalizeEmail(user.email) !== normalizeEmail(expectedEmail)) throw new Error("Forgeway refresh returned credentials for a different email.");
|
|
2451
1961
|
return user;
|
|
2452
1962
|
}
|
|
2453
1963
|
async function readCachedPublisherCredentials(cwd, platformApiUrl, email, deps) {
|
|
@@ -2480,14 +1990,14 @@ async function resolveCachedPublisherAccount(cwd, options, saved, platformApiUrl
|
|
|
2480
1990
|
platformApiUrl
|
|
2481
1991
|
});
|
|
2482
1992
|
if (isStoredFormalCredentialForEmail(singleCredentials)) return {
|
|
2483
|
-
email: normalizeEmail
|
|
1993
|
+
email: normalizeEmail(singleCredentials.user.email),
|
|
2484
1994
|
credentials: singleCredentials
|
|
2485
1995
|
};
|
|
2486
1996
|
const accounts = (await (deps.listCredentials ?? listForgewayCredentials)(platformApiUrl)).filter((credentials) => isStoredFormalCredentialForEmail(credentials));
|
|
2487
1997
|
if (accounts.length === 1) {
|
|
2488
1998
|
const credentials = accounts[0];
|
|
2489
1999
|
return {
|
|
2490
|
-
email: normalizeEmail
|
|
2000
|
+
email: normalizeEmail(credentials.user.email),
|
|
2491
2001
|
credentials
|
|
2492
2002
|
};
|
|
2493
2003
|
}
|
|
@@ -2549,7 +2059,7 @@ async function resolveProjectContext(cwd, options, deps) {
|
|
|
2549
2059
|
if (formal.email) throw new Error(`No verified Dineway account credentials were found for ${formal.email}. Run: dineway account login --email ${formal.email}`);
|
|
2550
2060
|
throw new Error("No verified Dineway account credentials were found. Run: dineway account login");
|
|
2551
2061
|
}
|
|
2552
|
-
function isRecord(value) {
|
|
2062
|
+
function isRecord$1(value) {
|
|
2553
2063
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2554
2064
|
}
|
|
2555
2065
|
function scalarText(value) {
|
|
@@ -2562,7 +2072,7 @@ function uniqueStrings(values) {
|
|
|
2562
2072
|
function displayText(value) {
|
|
2563
2073
|
if (typeof value === "string" || typeof value === "number") return String(value);
|
|
2564
2074
|
if (Array.isArray(value)) return value.map(displayText).filter(Boolean).join(" ");
|
|
2565
|
-
if (isRecord(value)) return displayText(value.text) || displayText(value.name) || displayText(value.displayName) || displayText(value.longText) || displayText(value.shortText) || displayText(value.long_name) || displayText(value.short_name) || displayText(value.value);
|
|
2075
|
+
if (isRecord$1(value)) return displayText(value.text) || displayText(value.name) || displayText(value.displayName) || displayText(value.longText) || displayText(value.shortText) || displayText(value.long_name) || displayText(value.short_name) || displayText(value.value);
|
|
2566
2076
|
return "";
|
|
2567
2077
|
}
|
|
2568
2078
|
function normalizeCompare(value) {
|
|
@@ -2580,7 +2090,7 @@ function candidateNameTexts(candidate) {
|
|
|
2580
2090
|
]);
|
|
2581
2091
|
}
|
|
2582
2092
|
function candidateAddressTexts(candidate) {
|
|
2583
|
-
const addressComponents = Array.isArray(candidate.addressComponents) ? candidate.addressComponents.flatMap((component) => isRecord(component) ? [
|
|
2093
|
+
const addressComponents = Array.isArray(candidate.addressComponents) ? candidate.addressComponents.flatMap((component) => isRecord$1(component) ? [
|
|
2584
2094
|
displayText(component.longText),
|
|
2585
2095
|
displayText(component.shortText),
|
|
2586
2096
|
displayText(component.long_name),
|
|
@@ -2722,11 +2232,11 @@ function selectPlaceCandidate(candidates, context) {
|
|
|
2722
2232
|
} : null;
|
|
2723
2233
|
}
|
|
2724
2234
|
function extractPlaceCandidates(payload) {
|
|
2725
|
-
const root = isRecord(payload) ? payload : {};
|
|
2726
|
-
const nestedData = isRecord(root.data) ? root.data : {};
|
|
2235
|
+
const root = isRecord$1(payload) ? payload : {};
|
|
2236
|
+
const nestedData = isRecord$1(root.data) ? root.data : {};
|
|
2727
2237
|
const places = root.places ?? root.results ?? nestedData.places ?? nestedData.results;
|
|
2728
2238
|
if (!Array.isArray(places)) throw new Error("Dineway place search response did not include places/results.");
|
|
2729
|
-
return places.filter(isRecord);
|
|
2239
|
+
return places.filter(isRecord$1);
|
|
2730
2240
|
}
|
|
2731
2241
|
async function resolvePlaceIdWithFormalSearch(options) {
|
|
2732
2242
|
const candidates = extractPlaceCandidates(await ossFetch(options.context, "/api/places/search", options.deps, {
|
|
@@ -2743,7 +2253,7 @@ async function resolvePlaceIdWithFormalSearch(options) {
|
|
|
2743
2253
|
return finalPlaceId;
|
|
2744
2254
|
}
|
|
2745
2255
|
async function ossFetch(context, path, deps, options = {}) {
|
|
2746
|
-
const request = async (token) => await forgewayRequest(`${context.ossHost.replace(TRAILING_SLASH_PATTERN
|
|
2256
|
+
const request = async (token) => await forgewayRequest(`${context.ossHost.replace(TRAILING_SLASH_PATTERN, "")}${path}`, {
|
|
2747
2257
|
...options,
|
|
2748
2258
|
headers: {
|
|
2749
2259
|
"Content-Type": "application/json",
|
|
@@ -3258,7 +2768,7 @@ async function deployForgeway(cwd, options, deps = {}) {
|
|
|
3258
2768
|
deps,
|
|
3259
2769
|
verbose
|
|
3260
2770
|
});
|
|
3261
|
-
if (context.user?.email) await writeForgewayDeployMetadata(cwd, { publisherEmail: normalizeEmail
|
|
2771
|
+
if (context.user?.email) await writeForgewayDeployMetadata(cwd, { publisherEmail: normalizeEmail(context.user.email) });
|
|
3262
2772
|
const url = deployment.liveUrl ?? `https://${site.domain}`;
|
|
3263
2773
|
await (deps.writeProjectEnv ?? persistForgewayCliEnv)(cwd, {
|
|
3264
2774
|
siteUrl: url,
|
|
@@ -4040,7 +3550,7 @@ const devCommand = defineCommand({
|
|
|
4040
3550
|
const remoteUrl = pkg.dineway?.url || process.env.DINEWAY_URL;
|
|
4041
3551
|
if (!remoteUrl) consola.warn("No remote URL configured. Set DINEWAY_URL or dineway.url in package.json");
|
|
4042
3552
|
else try {
|
|
4043
|
-
const { createClientFromArgs } = await
|
|
3553
|
+
const { createClientFromArgs } = await import("../client-factory-BDD9azPJ.mjs").then((n) => n.t);
|
|
4044
3554
|
const client = createClientFromArgs({ url: remoteUrl });
|
|
4045
3555
|
const schema = await client.schemaExport();
|
|
4046
3556
|
const types = await client.schemaTypes();
|
|
@@ -5953,7 +5463,7 @@ const publishCommand = defineCommand({
|
|
|
5953
5463
|
const pluginDir = resolve(args.dir);
|
|
5954
5464
|
try {
|
|
5955
5465
|
const { runCommand } = await import("citty");
|
|
5956
|
-
const { bundleCommand } = await import("../bundle-
|
|
5466
|
+
const { bundleCommand } = await import("../bundle-CEcdUa1s.mjs").then((n) => n.n);
|
|
5957
5467
|
await runCommand(bundleCommand, { rawArgs: ["--dir", pluginDir] });
|
|
5958
5468
|
} catch {
|
|
5959
5469
|
consola.error("Build failed");
|
|
@@ -6723,141 +6233,714 @@ const seedCommand = defineCommand({
|
|
|
6723
6233
|
});
|
|
6724
6234
|
|
|
6725
6235
|
//#endregion
|
|
6726
|
-
//#region src/
|
|
6727
|
-
const
|
|
6728
|
-
const
|
|
6729
|
-
const
|
|
6730
|
-
|
|
6731
|
-
|
|
6732
|
-
|
|
6733
|
-
|
|
6734
|
-
|
|
6735
|
-
|
|
6736
|
-
|
|
6737
|
-
|
|
6738
|
-
|
|
6739
|
-
|
|
6236
|
+
//#region src/seo/local-crawl.ts
|
|
6237
|
+
const CONTRACT_VERSION = 1;
|
|
6238
|
+
const USER_AGENT = "DinewayContentCrawler/1.0";
|
|
6239
|
+
const DEFAULT_PAGE_LIMIT = 100;
|
|
6240
|
+
const MAX_PAGE_LIMIT = 500;
|
|
6241
|
+
const DEFAULT_MAX_DEPTH = 3;
|
|
6242
|
+
const MAX_DEPTH = 10;
|
|
6243
|
+
const DEFAULT_CONCURRENCY = 4;
|
|
6244
|
+
const MAX_CONCURRENCY = 10;
|
|
6245
|
+
const DEFAULT_TIMEOUT_MS = 1e4;
|
|
6246
|
+
const MAX_TIMEOUT_MS = 6e4;
|
|
6247
|
+
const DEFAULT_MAX_BYTES = 1e6;
|
|
6248
|
+
const MAX_RESOURCE_BYTES = 1e7;
|
|
6249
|
+
const MAX_SITEMAPS = 20;
|
|
6250
|
+
const MAX_REDIRECTS = 5;
|
|
6251
|
+
const MAX_TEXT_EXCERPT = 2e4;
|
|
6252
|
+
const LINE_SPLIT_RE = /\r?\n/;
|
|
6253
|
+
const COMMENT_RE = /#.*$/;
|
|
6254
|
+
const WHITESPACE_RE = /\s+/g;
|
|
6255
|
+
const WORD_RE = /[\p{L}\p{N}]+(?:['’-][\p{L}\p{N}]+)*/gu;
|
|
6256
|
+
const REGEXP_SPECIAL_RE = /[.*+?^${}()|[\]\\]/g;
|
|
6257
|
+
async function crawlLocalSite(options) {
|
|
6258
|
+
const normalized = normalizeOptions(options);
|
|
6259
|
+
if (!normalized.allowPrivateNetwork) await resolveAndValidateExternalUrl(normalized.startUrl.href, { resolver: normalized.dnsResolver });
|
|
6260
|
+
const origin = normalized.startUrl.origin;
|
|
6261
|
+
const skipped = /* @__PURE__ */ new Map();
|
|
6262
|
+
const robots = await loadRobots(normalized);
|
|
6263
|
+
const sitemapResult = normalized.sitemap === "skip" ? {
|
|
6264
|
+
sources: [],
|
|
6265
|
+
urls: []
|
|
6266
|
+
} : await loadSitemaps(normalized, robots.sitemaps);
|
|
6267
|
+
const queue = [];
|
|
6268
|
+
const queued = /* @__PURE__ */ new Set();
|
|
6269
|
+
const enqueue = (candidate, depth, discoveredFrom) => {
|
|
6270
|
+
const url = normalizeUrl(candidate, normalized.startUrl, normalized.keepQuery);
|
|
6271
|
+
if (!url || url.origin !== origin || queued.has(url.href)) return;
|
|
6272
|
+
const pathDecision = pathEligibility(url, normalized);
|
|
6273
|
+
if (pathDecision) {
|
|
6274
|
+
skipped.set(url.href, {
|
|
6275
|
+
url: url.href,
|
|
6276
|
+
reason: pathDecision
|
|
6277
|
+
});
|
|
6278
|
+
return;
|
|
6279
|
+
}
|
|
6280
|
+
if (!robotsAllows(url, robots.rules)) {
|
|
6281
|
+
skipped.set(url.href, {
|
|
6282
|
+
url: url.href,
|
|
6283
|
+
reason: "robots_disallowed"
|
|
6284
|
+
});
|
|
6285
|
+
return;
|
|
6286
|
+
}
|
|
6287
|
+
queued.add(url.href);
|
|
6288
|
+
queue.push({
|
|
6289
|
+
url: url.href,
|
|
6290
|
+
depth,
|
|
6291
|
+
discoveredFrom
|
|
6292
|
+
});
|
|
6293
|
+
};
|
|
6294
|
+
if (normalized.sitemap !== "only") enqueue(normalized.startUrl.href, 0, "start");
|
|
6295
|
+
for (const url of sitemapResult.urls) enqueue(url, 0, "sitemap");
|
|
6296
|
+
const pages = [];
|
|
6297
|
+
let cursor = 0;
|
|
6298
|
+
while (cursor < queue.length && pages.length < normalized.pageLimit) {
|
|
6299
|
+
const remaining = normalized.pageLimit - pages.length;
|
|
6300
|
+
const batch = queue.slice(cursor, cursor + Math.min(normalized.concurrency, remaining));
|
|
6301
|
+
cursor += batch.length;
|
|
6302
|
+
const resources = await Promise.all(batch.map(async (item) => ({
|
|
6303
|
+
item,
|
|
6304
|
+
resource: await fetchResource(item.url, normalized)
|
|
6305
|
+
})));
|
|
6306
|
+
for (const { item, resource } of resources) {
|
|
6307
|
+
const page = pageFromResource(item, resource, normalized);
|
|
6308
|
+
pages.push(page);
|
|
6309
|
+
if (normalized.sitemap !== "only" && !page.error && page.contentType?.includes("text/html") && item.depth < normalized.maxDepth) for (const link of page.internalLinks) enqueue(link.url, item.depth + 1, item.url);
|
|
6310
|
+
}
|
|
6311
|
+
}
|
|
6312
|
+
const edges = pages.flatMap((page) => page.internalLinks.map((link) => ({
|
|
6313
|
+
from: page.url,
|
|
6314
|
+
...link
|
|
6315
|
+
})));
|
|
6316
|
+
const brokenInternalUrls = uniqueSorted(pages.filter((page) => page.httpStatus !== null && page.httpStatus >= 400).filter((page) => edges.some((edge) => edge.url === page.url)).map((page) => page.url));
|
|
6317
|
+
const incoming = new Set(edges.map((edge) => edge.url));
|
|
6318
|
+
const orphanUrls = uniqueSorted(pages.filter((page) => page.url !== normalized.startUrl.href && page.httpStatus !== null && page.httpStatus < 400 && page.contentType?.includes("text/html") && !incoming.has(page.url)).map((page) => page.url));
|
|
6319
|
+
const successfulHtml = pages.filter((page) => page.httpStatus !== null && page.httpStatus < 400 && page.contentType?.includes("text/html"));
|
|
6320
|
+
return {
|
|
6321
|
+
contractVersion: CONTRACT_VERSION,
|
|
6322
|
+
startUrl: normalized.startUrl.href,
|
|
6323
|
+
origin,
|
|
6324
|
+
crawledAt: normalized.now().toISOString(),
|
|
6325
|
+
options: {
|
|
6326
|
+
pageLimit: normalized.pageLimit,
|
|
6327
|
+
maxDepth: normalized.maxDepth,
|
|
6328
|
+
concurrency: normalized.concurrency,
|
|
6329
|
+
include: normalized.includeValues,
|
|
6330
|
+
exclude: normalized.excludeValues,
|
|
6331
|
+
timeoutMs: normalized.timeoutMs,
|
|
6332
|
+
maxBytesPerResource: normalized.maxBytesPerResource,
|
|
6333
|
+
sitemap: normalized.sitemap,
|
|
6334
|
+
keepQuery: normalized.keepQuery,
|
|
6335
|
+
allowPrivateNetwork: normalized.allowPrivateNetwork
|
|
6336
|
+
},
|
|
6337
|
+
sources: {
|
|
6338
|
+
robots: robots.source,
|
|
6339
|
+
sitemaps: sitemapResult.sources
|
|
6340
|
+
},
|
|
6341
|
+
pages,
|
|
6342
|
+
skipped: [...skipped.values()].toSorted((left, right) => left.url.localeCompare(right.url)),
|
|
6343
|
+
linkGraph: {
|
|
6344
|
+
edges,
|
|
6345
|
+
orphanUrls,
|
|
6346
|
+
brokenInternalUrls,
|
|
6347
|
+
duplicateTitles: duplicateGroups(successfulHtml, "title"),
|
|
6348
|
+
duplicateDescriptions: duplicateGroups(successfulHtml, "description"),
|
|
6349
|
+
duplicateContent: duplicateGroups(successfulHtml, "contentSha256")
|
|
6350
|
+
},
|
|
6351
|
+
summary: {
|
|
6352
|
+
fetchedPages: pages.length,
|
|
6353
|
+
htmlPages: pages.filter((page) => page.contentType?.includes("text/html")).length,
|
|
6354
|
+
brokenPages: pages.filter((page) => page.httpStatus !== null && page.httpStatus >= 400).length,
|
|
6355
|
+
orphanPages: orphanUrls.length,
|
|
6356
|
+
skippedUrls: skipped.size,
|
|
6357
|
+
errorPages: pages.filter((page) => page.error).length,
|
|
6358
|
+
pageLimitReached: pages.length === normalized.pageLimit && cursor < queue.length
|
|
6359
|
+
}
|
|
6360
|
+
};
|
|
6740
6361
|
}
|
|
6741
|
-
function
|
|
6742
|
-
|
|
6362
|
+
function normalizeOptions(options) {
|
|
6363
|
+
const startUrl = normalizeUrl(options.startUrl, void 0, options.keepQuery === true);
|
|
6364
|
+
if (!startUrl) throw new Error("startUrl must be an absolute HTTP or HTTPS URL without credentials");
|
|
6365
|
+
const pageLimit = boundedInteger(options.pageLimit, DEFAULT_PAGE_LIMIT, 1, MAX_PAGE_LIMIT, "pageLimit");
|
|
6366
|
+
const maxDepth = boundedInteger(options.maxDepth, DEFAULT_MAX_DEPTH, 0, MAX_DEPTH, "maxDepth");
|
|
6367
|
+
const concurrency = boundedInteger(options.concurrency, DEFAULT_CONCURRENCY, 1, MAX_CONCURRENCY, "concurrency");
|
|
6368
|
+
const timeoutMs = boundedInteger(options.timeoutMs, DEFAULT_TIMEOUT_MS, 100, MAX_TIMEOUT_MS, "timeoutMs");
|
|
6369
|
+
const maxBytesPerResource = boundedInteger(options.maxBytesPerResource, DEFAULT_MAX_BYTES, 1024, MAX_RESOURCE_BYTES, "maxBytesPerResource");
|
|
6370
|
+
const sitemap = options.sitemap ?? "include";
|
|
6371
|
+
if (![
|
|
6372
|
+
"include",
|
|
6373
|
+
"skip",
|
|
6374
|
+
"only"
|
|
6375
|
+
].includes(sitemap)) throw new Error("sitemap must be include, skip, or only");
|
|
6376
|
+
const includeValues = normalizePatterns(options.include ?? []);
|
|
6377
|
+
const excludeValues = normalizePatterns(options.exclude ?? []);
|
|
6378
|
+
return {
|
|
6379
|
+
startUrl,
|
|
6380
|
+
pageLimit,
|
|
6381
|
+
maxDepth,
|
|
6382
|
+
concurrency,
|
|
6383
|
+
include: includeValues.map(pathMatcher),
|
|
6384
|
+
exclude: excludeValues.map(pathMatcher),
|
|
6385
|
+
includeValues,
|
|
6386
|
+
excludeValues,
|
|
6387
|
+
timeoutMs,
|
|
6388
|
+
maxBytesPerResource,
|
|
6389
|
+
sitemap,
|
|
6390
|
+
keepQuery: options.keepQuery === true,
|
|
6391
|
+
allowPrivateNetwork: options.allowPrivateNetwork === true,
|
|
6392
|
+
dnsResolver: options.dnsResolver,
|
|
6393
|
+
fetch: options.fetch ?? globalThis.fetch,
|
|
6394
|
+
now: options.now ?? (() => /* @__PURE__ */ new Date())
|
|
6395
|
+
};
|
|
6743
6396
|
}
|
|
6744
|
-
function
|
|
6745
|
-
|
|
6397
|
+
function boundedInteger(value, fallback, minimum, maximum, name) {
|
|
6398
|
+
const normalized = value ?? fallback;
|
|
6399
|
+
if (!Number.isInteger(normalized) || normalized < minimum || normalized > maximum) throw new Error(`${name} must be an integer from ${minimum} to ${maximum}`);
|
|
6400
|
+
return normalized;
|
|
6746
6401
|
}
|
|
6747
|
-
function
|
|
6748
|
-
return
|
|
6402
|
+
function normalizePatterns(values) {
|
|
6403
|
+
return uniqueSorted(values.map((value) => value.trim()).filter((value) => {
|
|
6404
|
+
if (!value.startsWith("/") || value.length > 255) throw new Error("include and exclude patterns must be path globs starting with /");
|
|
6405
|
+
return true;
|
|
6406
|
+
}));
|
|
6749
6407
|
}
|
|
6750
|
-
function
|
|
6751
|
-
|
|
6752
|
-
|
|
6408
|
+
function pathMatcher(value) {
|
|
6409
|
+
let source = "^";
|
|
6410
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
6411
|
+
const character = value[index];
|
|
6412
|
+
if (character === "*" && value[index + 1] === "*") {
|
|
6413
|
+
source += ".*";
|
|
6414
|
+
index += 1;
|
|
6415
|
+
} else if (character === "*") source += "[^/]*";
|
|
6416
|
+
else source += escapeRegExp(character ?? "");
|
|
6417
|
+
}
|
|
6418
|
+
return {
|
|
6419
|
+
value,
|
|
6420
|
+
pattern: new RegExp(`${source}$`)
|
|
6421
|
+
};
|
|
6422
|
+
}
|
|
6423
|
+
function pathEligibility(url, options) {
|
|
6424
|
+
const path = url.pathname;
|
|
6425
|
+
if (options.include.length > 0 && !options.include.some((item) => item.pattern.test(path))) return "not_included";
|
|
6426
|
+
if (options.exclude.some((item) => item.pattern.test(path))) return "excluded";
|
|
6427
|
+
return null;
|
|
6753
6428
|
}
|
|
6754
|
-
function
|
|
6755
|
-
|
|
6429
|
+
async function loadRobots(options) {
|
|
6430
|
+
const url = new URL("/robots.txt", options.startUrl.origin).href;
|
|
6431
|
+
const resource = await fetchResource(url, options);
|
|
6432
|
+
if (!resource.response) return {
|
|
6433
|
+
source: {
|
|
6434
|
+
url,
|
|
6435
|
+
status: "temporarily_unavailable",
|
|
6436
|
+
httpStatus: null,
|
|
6437
|
+
error: resource.error ?? "fetch_failed"
|
|
6438
|
+
},
|
|
6439
|
+
rules: [],
|
|
6440
|
+
sitemaps: []
|
|
6441
|
+
};
|
|
6442
|
+
if (resource.response.status === 404) return {
|
|
6443
|
+
source: {
|
|
6444
|
+
url,
|
|
6445
|
+
status: "not_found",
|
|
6446
|
+
httpStatus: 404
|
|
6447
|
+
},
|
|
6448
|
+
rules: [],
|
|
6449
|
+
sitemaps: []
|
|
6450
|
+
};
|
|
6451
|
+
if (!resource.response.ok || resource.error) return {
|
|
6452
|
+
source: {
|
|
6453
|
+
url,
|
|
6454
|
+
status: "temporarily_unavailable",
|
|
6455
|
+
httpStatus: resource.response.status,
|
|
6456
|
+
error: resource.error ?? `http_${resource.response.status}`
|
|
6457
|
+
},
|
|
6458
|
+
rules: [],
|
|
6459
|
+
sitemaps: []
|
|
6460
|
+
};
|
|
6461
|
+
const parsed = parseRobots(resource.body);
|
|
6756
6462
|
return {
|
|
6757
|
-
|
|
6758
|
-
|
|
6759
|
-
|
|
6760
|
-
|
|
6761
|
-
|
|
6463
|
+
source: {
|
|
6464
|
+
url,
|
|
6465
|
+
status: "available",
|
|
6466
|
+
httpStatus: resource.response.status
|
|
6467
|
+
},
|
|
6468
|
+
rules: parsed.rules,
|
|
6469
|
+
sitemaps: parsed.sitemaps
|
|
6762
6470
|
};
|
|
6763
6471
|
}
|
|
6764
|
-
|
|
6765
|
-
const
|
|
6766
|
-
|
|
6767
|
-
|
|
6768
|
-
|
|
6769
|
-
|
|
6770
|
-
|
|
6771
|
-
|
|
6772
|
-
|
|
6773
|
-
|
|
6774
|
-
|
|
6775
|
-
|
|
6776
|
-
|
|
6777
|
-
|
|
6778
|
-
|
|
6779
|
-
|
|
6780
|
-
|
|
6781
|
-
|
|
6782
|
-
|
|
6783
|
-
|
|
6784
|
-
|
|
6785
|
-
|
|
6786
|
-
|
|
6787
|
-
|
|
6788
|
-
|
|
6789
|
-
|
|
6790
|
-
|
|
6791
|
-
|
|
6792
|
-
|
|
6793
|
-
|
|
6794
|
-
|
|
6795
|
-
|
|
6796
|
-
async loadCredentials() {
|
|
6797
|
-
const metadata = await readForgewayDeployMetadata(this.cwd).catch(() => ({}));
|
|
6798
|
-
const platformApiUrl = resolveForgewaySeoApiUrl(metadata.platformApiUrl, this.cwd);
|
|
6799
|
-
const credentials = await this.readCredentials({
|
|
6800
|
-
cwd: this.cwd,
|
|
6801
|
-
platformApiUrl,
|
|
6802
|
-
email: typeof metadata.publisherEmail === "string" ? metadata.publisherEmail : void 0
|
|
6472
|
+
function parseRobots(body) {
|
|
6473
|
+
const groups = [];
|
|
6474
|
+
const sitemaps = [];
|
|
6475
|
+
let current = {
|
|
6476
|
+
agents: [],
|
|
6477
|
+
rules: []
|
|
6478
|
+
};
|
|
6479
|
+
for (const rawLine of body.split(LINE_SPLIT_RE)) {
|
|
6480
|
+
const line = rawLine.replace(COMMENT_RE, "").trim();
|
|
6481
|
+
if (!line) continue;
|
|
6482
|
+
const separator = line.indexOf(":");
|
|
6483
|
+
if (separator < 0) continue;
|
|
6484
|
+
const field = line.slice(0, separator).trim().toLowerCase();
|
|
6485
|
+
const value = line.slice(separator + 1).trim();
|
|
6486
|
+
if (field === "sitemap" && value) {
|
|
6487
|
+
sitemaps.push(value);
|
|
6488
|
+
continue;
|
|
6489
|
+
}
|
|
6490
|
+
if (field === "user-agent") {
|
|
6491
|
+
if (current.rules.length > 0) {
|
|
6492
|
+
groups.push(current);
|
|
6493
|
+
current = {
|
|
6494
|
+
agents: [],
|
|
6495
|
+
rules: []
|
|
6496
|
+
};
|
|
6497
|
+
}
|
|
6498
|
+
current.agents.push(value.toLowerCase());
|
|
6499
|
+
continue;
|
|
6500
|
+
}
|
|
6501
|
+
if ((field === "allow" || field === "disallow") && current.agents.length > 0 && value) current.rules.push({
|
|
6502
|
+
type: field,
|
|
6503
|
+
path: value
|
|
6803
6504
|
});
|
|
6804
|
-
if (!credentials?.accessToken) throw new Error("Forgeway SEO provider access requires stored Forgeway credentials. Run `dineway deploy forgeway` first.");
|
|
6805
|
-
assertFormalUser(credentials.user);
|
|
6806
|
-
if (!credentials.refreshToken) throw new Error("Forgeway SEO provider access requires a stored formal-account refresh token. Run `dineway deploy forgeway` again.");
|
|
6807
|
-
return {
|
|
6808
|
-
...credentials,
|
|
6809
|
-
platformApiUrl: resolveForgewaySeoApiUrl(credentials.platformApiUrl, this.cwd)
|
|
6810
|
-
};
|
|
6811
6505
|
}
|
|
6812
|
-
|
|
6813
|
-
|
|
6814
|
-
|
|
6815
|
-
|
|
6816
|
-
|
|
6817
|
-
|
|
6818
|
-
|
|
6819
|
-
|
|
6820
|
-
|
|
6821
|
-
|
|
6822
|
-
|
|
6823
|
-
|
|
6824
|
-
|
|
6825
|
-
|
|
6826
|
-
|
|
6827
|
-
|
|
6506
|
+
if (current.agents.length > 0 || current.rules.length > 0) groups.push(current);
|
|
6507
|
+
const crawlerName = USER_AGENT.split("/")[0]?.toLowerCase() ?? "dinewaycontentcrawler";
|
|
6508
|
+
const exact = groups.filter((group) => group.agents.includes(crawlerName));
|
|
6509
|
+
return {
|
|
6510
|
+
rules: (exact.length > 0 ? exact : groups.filter((group) => group.agents.includes("*"))).flatMap((group) => group.rules),
|
|
6511
|
+
sitemaps: uniqueSorted(sitemaps)
|
|
6512
|
+
};
|
|
6513
|
+
}
|
|
6514
|
+
function robotsAllows(url, rules) {
|
|
6515
|
+
const path = `${url.pathname}${url.search}`;
|
|
6516
|
+
const matching = rules.filter((rule) => robotsRuleMatches(path, rule.path)).toSorted((left, right) => right.path.length - left.path.length);
|
|
6517
|
+
if (matching.length === 0) return true;
|
|
6518
|
+
const longest = matching[0]?.path.length ?? 0;
|
|
6519
|
+
return matching.some((rule) => rule.path.length === longest && rule.type === "allow");
|
|
6520
|
+
}
|
|
6521
|
+
function robotsRuleMatches(path, rulePath) {
|
|
6522
|
+
const anchored = rulePath.endsWith("$");
|
|
6523
|
+
const pattern = escapeRegExp(anchored ? rulePath.slice(0, -1) : rulePath).replaceAll("\\*", ".*");
|
|
6524
|
+
return new RegExp(`^${pattern}${anchored ? "$" : ""}`).test(path);
|
|
6525
|
+
}
|
|
6526
|
+
async function loadSitemaps(options, robotsSitemaps) {
|
|
6527
|
+
const queue = (robotsSitemaps.length > 0 ? robotsSitemaps : [new URL("/sitemap.xml", options.startUrl.origin).href]).map((value) => normalizeUrl(value, options.startUrl, options.keepQuery)).filter((value) => value !== null && value.origin === options.startUrl.origin).map((value) => value.href);
|
|
6528
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6529
|
+
const sources = [];
|
|
6530
|
+
const urls = [];
|
|
6531
|
+
while (queue.length > 0 && seen.size < MAX_SITEMAPS) {
|
|
6532
|
+
const url = queue.shift();
|
|
6533
|
+
if (!url || seen.has(url)) continue;
|
|
6534
|
+
seen.add(url);
|
|
6535
|
+
const resource = await fetchResource(url, options);
|
|
6536
|
+
if (!resource.response) {
|
|
6537
|
+
sources.push({
|
|
6538
|
+
url,
|
|
6539
|
+
status: "temporarily_unavailable",
|
|
6540
|
+
httpStatus: null,
|
|
6541
|
+
error: resource.error ?? "fetch_failed"
|
|
6542
|
+
});
|
|
6543
|
+
continue;
|
|
6544
|
+
}
|
|
6545
|
+
if (resource.response.status === 404) {
|
|
6546
|
+
sources.push({
|
|
6547
|
+
url,
|
|
6548
|
+
status: "not_found",
|
|
6549
|
+
httpStatus: 404
|
|
6550
|
+
});
|
|
6551
|
+
continue;
|
|
6552
|
+
}
|
|
6553
|
+
if (!resource.response.ok || resource.error) {
|
|
6554
|
+
sources.push({
|
|
6555
|
+
url,
|
|
6556
|
+
status: "temporarily_unavailable",
|
|
6557
|
+
httpStatus: resource.response.status,
|
|
6558
|
+
error: resource.error ?? `http_${resource.response.status}`
|
|
6559
|
+
});
|
|
6560
|
+
continue;
|
|
6561
|
+
}
|
|
6562
|
+
try {
|
|
6563
|
+
const parsed = parseSitemap(resource.body);
|
|
6564
|
+
sources.push({
|
|
6565
|
+
url,
|
|
6566
|
+
status: "available",
|
|
6567
|
+
httpStatus: resource.response.status
|
|
6568
|
+
});
|
|
6569
|
+
for (const location of parsed.locations) {
|
|
6570
|
+
const normalized = normalizeUrl(location, options.startUrl, options.keepQuery);
|
|
6571
|
+
if (!normalized || normalized.origin !== options.startUrl.origin) continue;
|
|
6572
|
+
if (parsed.kind === "index") queue.push(normalized.href);
|
|
6573
|
+
else urls.push(normalized.href);
|
|
6574
|
+
}
|
|
6575
|
+
} catch {
|
|
6576
|
+
sources.push({
|
|
6577
|
+
url,
|
|
6578
|
+
status: "invalid",
|
|
6579
|
+
httpStatus: resource.response.status,
|
|
6580
|
+
error: "invalid_sitemap_xml"
|
|
6581
|
+
});
|
|
6582
|
+
}
|
|
6583
|
+
}
|
|
6584
|
+
return {
|
|
6585
|
+
sources,
|
|
6586
|
+
urls: uniqueSorted(urls)
|
|
6587
|
+
};
|
|
6588
|
+
}
|
|
6589
|
+
function parseSitemap(body) {
|
|
6590
|
+
const parser = sax.parser(true, {
|
|
6591
|
+
trim: true,
|
|
6592
|
+
normalize: true
|
|
6593
|
+
});
|
|
6594
|
+
let root = null;
|
|
6595
|
+
let inLocation = false;
|
|
6596
|
+
let location = "";
|
|
6597
|
+
const locations = [];
|
|
6598
|
+
parser.onopentag = (node) => {
|
|
6599
|
+
const name = node.name.toLowerCase();
|
|
6600
|
+
root ??= name;
|
|
6601
|
+
if (name === "loc") {
|
|
6602
|
+
inLocation = true;
|
|
6603
|
+
location = "";
|
|
6604
|
+
}
|
|
6605
|
+
};
|
|
6606
|
+
parser.ontext = (text) => {
|
|
6607
|
+
if (inLocation) location += text;
|
|
6608
|
+
};
|
|
6609
|
+
parser.oncdata = (text) => {
|
|
6610
|
+
if (inLocation) location += text;
|
|
6611
|
+
};
|
|
6612
|
+
parser.onclosetag = (name) => {
|
|
6613
|
+
if (name.toLowerCase() !== "loc") return;
|
|
6614
|
+
inLocation = false;
|
|
6615
|
+
if (location.trim()) locations.push(location.trim());
|
|
6616
|
+
};
|
|
6617
|
+
parser.write(body).close();
|
|
6618
|
+
if (root !== "urlset" && root !== "sitemapindex") throw new Error("Unsupported sitemap root");
|
|
6619
|
+
return {
|
|
6620
|
+
kind: root === "sitemapindex" ? "index" : "urls",
|
|
6621
|
+
locations
|
|
6622
|
+
};
|
|
6623
|
+
}
|
|
6624
|
+
async function fetchResource(url, options) {
|
|
6625
|
+
const controller = new AbortController();
|
|
6626
|
+
const timeout = setTimeout(() => controller.abort(), options.timeoutMs);
|
|
6627
|
+
try {
|
|
6628
|
+
let currentUrl = url;
|
|
6629
|
+
let response = null;
|
|
6630
|
+
for (let redirects = 0; redirects <= MAX_REDIRECTS; redirects += 1) {
|
|
6631
|
+
if (!options.allowPrivateNetwork) await resolveAndValidateExternalUrl(currentUrl, { resolver: options.dnsResolver });
|
|
6632
|
+
response = await options.fetch(currentUrl, {
|
|
6633
|
+
headers: {
|
|
6634
|
+
accept: "text/html,application/xml,text/xml,text/plain;q=0.8",
|
|
6635
|
+
"user-agent": USER_AGENT
|
|
6636
|
+
},
|
|
6637
|
+
redirect: "manual",
|
|
6638
|
+
signal: controller.signal
|
|
6639
|
+
});
|
|
6640
|
+
const location = response.headers.get("location");
|
|
6641
|
+
if (response.status < 300 || response.status >= 400 || !location) break;
|
|
6642
|
+
const next = normalizeUrl(location, new URL(currentUrl), options.keepQuery);
|
|
6643
|
+
if (!next) return {
|
|
6644
|
+
response,
|
|
6645
|
+
finalUrl: currentUrl,
|
|
6646
|
+
contentType: response.headers.get("content-type"),
|
|
6647
|
+
body: "",
|
|
6648
|
+
bytes: 0,
|
|
6649
|
+
error: "invalid_redirect"
|
|
6650
|
+
};
|
|
6651
|
+
if (next.origin !== options.startUrl.origin) return {
|
|
6652
|
+
response,
|
|
6653
|
+
finalUrl: next.href,
|
|
6654
|
+
contentType: response.headers.get("content-type"),
|
|
6655
|
+
body: "",
|
|
6656
|
+
bytes: 0,
|
|
6657
|
+
error: "cross_origin_redirect"
|
|
6658
|
+
};
|
|
6659
|
+
if (redirects === MAX_REDIRECTS) return {
|
|
6660
|
+
response,
|
|
6661
|
+
finalUrl: next.href,
|
|
6662
|
+
contentType: response.headers.get("content-type"),
|
|
6663
|
+
body: "",
|
|
6664
|
+
bytes: 0,
|
|
6665
|
+
error: "too_many_redirects"
|
|
6666
|
+
};
|
|
6667
|
+
currentUrl = next.href;
|
|
6668
|
+
}
|
|
6669
|
+
if (!response) throw new Error("No response");
|
|
6670
|
+
const finalUrl = response.url || currentUrl;
|
|
6671
|
+
const contentType = response.headers.get("content-type");
|
|
6672
|
+
const declaredLength = Number(response.headers.get("content-length"));
|
|
6673
|
+
if (Number.isFinite(declaredLength) && declaredLength > options.maxBytesPerResource) return {
|
|
6674
|
+
response,
|
|
6675
|
+
finalUrl,
|
|
6676
|
+
contentType,
|
|
6677
|
+
body: "",
|
|
6678
|
+
bytes: 0,
|
|
6679
|
+
error: "resource_too_large"
|
|
6828
6680
|
};
|
|
6829
|
-
await
|
|
6830
|
-
|
|
6831
|
-
|
|
6832
|
-
|
|
6833
|
-
|
|
6834
|
-
|
|
6681
|
+
const body = await readBoundedBody(response, options.maxBytesPerResource);
|
|
6682
|
+
return {
|
|
6683
|
+
response,
|
|
6684
|
+
finalUrl,
|
|
6685
|
+
contentType,
|
|
6686
|
+
body: body.text,
|
|
6687
|
+
bytes: body.bytes
|
|
6688
|
+
};
|
|
6689
|
+
} catch (error) {
|
|
6690
|
+
return {
|
|
6691
|
+
response: null,
|
|
6692
|
+
finalUrl: url,
|
|
6693
|
+
contentType: null,
|
|
6694
|
+
body: "",
|
|
6695
|
+
bytes: 0,
|
|
6696
|
+
error: error instanceof ResourceTooLargeError ? "resource_too_large" : fetchError(error)
|
|
6697
|
+
};
|
|
6698
|
+
} finally {
|
|
6699
|
+
clearTimeout(timeout);
|
|
6835
6700
|
}
|
|
6836
|
-
|
|
6837
|
-
|
|
6838
|
-
|
|
6839
|
-
|
|
6840
|
-
|
|
6841
|
-
|
|
6842
|
-
|
|
6843
|
-
|
|
6844
|
-
|
|
6845
|
-
|
|
6846
|
-
|
|
6847
|
-
|
|
6848
|
-
|
|
6849
|
-
if (
|
|
6850
|
-
|
|
6701
|
+
}
|
|
6702
|
+
async function readBoundedBody(response, limit) {
|
|
6703
|
+
if (!response.body) return {
|
|
6704
|
+
text: "",
|
|
6705
|
+
bytes: 0
|
|
6706
|
+
};
|
|
6707
|
+
const reader = response.body.getReader();
|
|
6708
|
+
const chunks = [];
|
|
6709
|
+
let bytes = 0;
|
|
6710
|
+
while (true) {
|
|
6711
|
+
const result = await reader.read();
|
|
6712
|
+
if (result.done) break;
|
|
6713
|
+
bytes += result.value.byteLength;
|
|
6714
|
+
if (bytes > limit) {
|
|
6715
|
+
await reader.cancel();
|
|
6716
|
+
throw new ResourceTooLargeError();
|
|
6717
|
+
}
|
|
6718
|
+
chunks.push(result.value);
|
|
6719
|
+
}
|
|
6720
|
+
const combined = new Uint8Array(bytes);
|
|
6721
|
+
let offset = 0;
|
|
6722
|
+
for (const chunk of chunks) {
|
|
6723
|
+
combined.set(chunk, offset);
|
|
6724
|
+
offset += chunk.byteLength;
|
|
6851
6725
|
}
|
|
6852
|
-
|
|
6726
|
+
return {
|
|
6727
|
+
text: new TextDecoder().decode(combined),
|
|
6728
|
+
bytes
|
|
6729
|
+
};
|
|
6730
|
+
}
|
|
6731
|
+
var ResourceTooLargeError = class extends Error {};
|
|
6732
|
+
function fetchError(error) {
|
|
6733
|
+
if (error instanceof SsrfError) return "private_network_blocked";
|
|
6734
|
+
if (error instanceof Error && error.name === "AbortError") return "timeout";
|
|
6735
|
+
return "fetch_failed";
|
|
6736
|
+
}
|
|
6737
|
+
function pageFromResource(item, resource, options) {
|
|
6738
|
+
const base = {
|
|
6739
|
+
url: item.url,
|
|
6740
|
+
finalUrl: resource.finalUrl,
|
|
6741
|
+
depth: item.depth,
|
|
6742
|
+
discoveredFrom: item.discoveredFrom,
|
|
6743
|
+
httpStatus: resource.response?.status ?? null,
|
|
6744
|
+
contentType: resource.contentType,
|
|
6745
|
+
bytes: resource.bytes
|
|
6746
|
+
};
|
|
6747
|
+
const empty = {
|
|
6748
|
+
title: null,
|
|
6749
|
+
description: null,
|
|
6750
|
+
canonicalUrl: null,
|
|
6751
|
+
robots: null,
|
|
6752
|
+
language: null,
|
|
6753
|
+
headings: {
|
|
6754
|
+
h1: [],
|
|
6755
|
+
h2: [],
|
|
6756
|
+
h3: []
|
|
6757
|
+
},
|
|
6758
|
+
wordCount: 0,
|
|
6759
|
+
contentSha256: null,
|
|
6760
|
+
textExcerpt: "",
|
|
6761
|
+
textTruncated: false,
|
|
6762
|
+
internalLinks: [],
|
|
6763
|
+
externalLinks: [],
|
|
6764
|
+
structuredDataBlocks: 0,
|
|
6765
|
+
renderingRecommended: false
|
|
6766
|
+
};
|
|
6767
|
+
if (resource.error) return {
|
|
6768
|
+
...base,
|
|
6769
|
+
...empty,
|
|
6770
|
+
error: resource.error
|
|
6771
|
+
};
|
|
6772
|
+
const final = normalizeUrl(resource.finalUrl, void 0, options.keepQuery);
|
|
6773
|
+
if (!final || final.origin !== options.startUrl.origin) return {
|
|
6774
|
+
...base,
|
|
6775
|
+
...empty,
|
|
6776
|
+
error: "cross_origin_redirect"
|
|
6777
|
+
};
|
|
6778
|
+
if (!resource.contentType?.includes("text/html")) return {
|
|
6779
|
+
...base,
|
|
6780
|
+
...empty
|
|
6781
|
+
};
|
|
6782
|
+
try {
|
|
6783
|
+
return {
|
|
6784
|
+
...base,
|
|
6785
|
+
...parseHtml(resource.body, final, options.keepQuery)
|
|
6786
|
+
};
|
|
6787
|
+
} catch {
|
|
6788
|
+
return {
|
|
6789
|
+
...base,
|
|
6790
|
+
...empty,
|
|
6791
|
+
error: "invalid_html"
|
|
6792
|
+
};
|
|
6793
|
+
}
|
|
6794
|
+
}
|
|
6795
|
+
function parseHtml(body, pageUrl, keepQuery) {
|
|
6796
|
+
const document = parse(body);
|
|
6797
|
+
let title = null;
|
|
6798
|
+
let description = null;
|
|
6799
|
+
let canonicalUrl = null;
|
|
6800
|
+
let robots = null;
|
|
6801
|
+
let language = null;
|
|
6802
|
+
let structuredDataBlocks = 0;
|
|
6803
|
+
let scriptBlocks = 0;
|
|
6804
|
+
const headings = {
|
|
6805
|
+
h1: [],
|
|
6806
|
+
h2: [],
|
|
6807
|
+
h3: []
|
|
6808
|
+
};
|
|
6809
|
+
const internalLinks = [];
|
|
6810
|
+
const externalLinks = [];
|
|
6811
|
+
walk(document, (element) => {
|
|
6812
|
+
const attributes = new Map(element.attrs.map((attribute) => [attribute.name, attribute.value]));
|
|
6813
|
+
if (element.tagName === "html") language = cleanText(attributes.get("lang")) || language;
|
|
6814
|
+
if (element.tagName === "title" && title === null) title = cleanText(textContent(element));
|
|
6815
|
+
if (element.tagName === "meta") {
|
|
6816
|
+
const name = attributes.get("name")?.toLowerCase();
|
|
6817
|
+
if (name === "description" && description === null) description = cleanText(attributes.get("content"));
|
|
6818
|
+
if ((name === "robots" || name === "googlebot") && robots === null) robots = cleanText(attributes.get("content"));
|
|
6819
|
+
}
|
|
6820
|
+
if (element.tagName === "link") {
|
|
6821
|
+
if ((attributes.get("rel")?.toLowerCase().split(WHITESPACE_RE) ?? []).includes("canonical") && canonicalUrl === null) canonicalUrl = normalizeUrl(attributes.get("href") ?? "", pageUrl, keepQuery)?.href ?? null;
|
|
6822
|
+
}
|
|
6823
|
+
if (element.tagName === "h1" || element.tagName === "h2" || element.tagName === "h3") {
|
|
6824
|
+
const value = cleanText(textContent(element));
|
|
6825
|
+
if (value) headings[element.tagName].push(value);
|
|
6826
|
+
}
|
|
6827
|
+
if (element.tagName === "script") {
|
|
6828
|
+
scriptBlocks += 1;
|
|
6829
|
+
if (attributes.get("type")?.toLowerCase() === "application/ld+json") structuredDataBlocks += 1;
|
|
6830
|
+
}
|
|
6831
|
+
if (element.tagName === "a") {
|
|
6832
|
+
const link = normalizeUrl(attributes.get("href") ?? "", pageUrl, keepQuery);
|
|
6833
|
+
if (!link) return;
|
|
6834
|
+
const item = {
|
|
6835
|
+
url: link.href,
|
|
6836
|
+
anchor: cleanText(textContent(element)) ?? ""
|
|
6837
|
+
};
|
|
6838
|
+
if (link.origin === pageUrl.origin) internalLinks.push(item);
|
|
6839
|
+
else externalLinks.push(item);
|
|
6840
|
+
}
|
|
6841
|
+
});
|
|
6842
|
+
const visibleText = cleanText(textContent(document)) ?? "";
|
|
6843
|
+
const wordCount = countWords(visibleText);
|
|
6844
|
+
const textExcerpt = visibleText.slice(0, MAX_TEXT_EXCERPT);
|
|
6845
|
+
return {
|
|
6846
|
+
title,
|
|
6847
|
+
description,
|
|
6848
|
+
canonicalUrl,
|
|
6849
|
+
robots,
|
|
6850
|
+
language,
|
|
6851
|
+
headings,
|
|
6852
|
+
wordCount,
|
|
6853
|
+
contentSha256: createHash("sha256").update(visibleText).digest("hex"),
|
|
6854
|
+
textExcerpt,
|
|
6855
|
+
textTruncated: textExcerpt.length < visibleText.length,
|
|
6856
|
+
internalLinks: uniqueLinks(internalLinks),
|
|
6857
|
+
externalLinks: uniqueLinks(externalLinks),
|
|
6858
|
+
structuredDataBlocks,
|
|
6859
|
+
renderingRecommended: wordCount < 20 && scriptBlocks > 0
|
|
6860
|
+
};
|
|
6861
|
+
}
|
|
6862
|
+
function walk(node, visit) {
|
|
6863
|
+
if (isElement(node)) visit(node);
|
|
6864
|
+
if (!("childNodes" in node)) return;
|
|
6865
|
+
for (const child of node.childNodes) walk(child, visit);
|
|
6866
|
+
}
|
|
6867
|
+
function textContent(node, hidden = false) {
|
|
6868
|
+
if ("value" in node) return hidden ? "" : node.value;
|
|
6869
|
+
const nextHidden = hidden || isElement(node) && [
|
|
6870
|
+
"script",
|
|
6871
|
+
"style",
|
|
6872
|
+
"noscript",
|
|
6873
|
+
"template",
|
|
6874
|
+
"svg",
|
|
6875
|
+
"head"
|
|
6876
|
+
].includes(node.tagName);
|
|
6877
|
+
if (!("childNodes" in node)) return "";
|
|
6878
|
+
return node.childNodes.map((child) => textContent(child, nextHidden)).join(" ");
|
|
6879
|
+
}
|
|
6880
|
+
function isElement(node) {
|
|
6881
|
+
return "tagName" in node;
|
|
6882
|
+
}
|
|
6883
|
+
function normalizeUrl(value, base, keepQuery = false) {
|
|
6884
|
+
try {
|
|
6885
|
+
const url = base ? new URL(value, base) : new URL(value);
|
|
6886
|
+
if (url.protocol !== "http:" && url.protocol !== "https:" || url.username || url.password) return null;
|
|
6887
|
+
url.hash = "";
|
|
6888
|
+
if (!keepQuery) url.search = "";
|
|
6889
|
+
if (!url.pathname) url.pathname = "/";
|
|
6890
|
+
return url;
|
|
6891
|
+
} catch {
|
|
6892
|
+
return null;
|
|
6893
|
+
}
|
|
6894
|
+
}
|
|
6895
|
+
function cleanText(value) {
|
|
6896
|
+
if (!value) return null;
|
|
6897
|
+
return value.replaceAll(WHITESPACE_RE, " ").trim() || null;
|
|
6898
|
+
}
|
|
6899
|
+
function countWords(value) {
|
|
6900
|
+
return value.match(WORD_RE)?.length ?? 0;
|
|
6901
|
+
}
|
|
6902
|
+
function uniqueLinks(links) {
|
|
6903
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6904
|
+
return links.filter((link) => {
|
|
6905
|
+
const key = `${link.url}\u0000${link.anchor}`;
|
|
6906
|
+
if (seen.has(key)) return false;
|
|
6907
|
+
seen.add(key);
|
|
6908
|
+
return true;
|
|
6909
|
+
});
|
|
6910
|
+
}
|
|
6911
|
+
function duplicateGroups(pages, field) {
|
|
6912
|
+
const groups = /* @__PURE__ */ new Map();
|
|
6913
|
+
for (const page of pages) {
|
|
6914
|
+
const value = page[field];
|
|
6915
|
+
if (!value) continue;
|
|
6916
|
+
const key = field === "contentSha256" ? value : value.toLocaleLowerCase();
|
|
6917
|
+
const group = groups.get(key) ?? {
|
|
6918
|
+
value,
|
|
6919
|
+
urls: []
|
|
6920
|
+
};
|
|
6921
|
+
group.urls.push(page.url);
|
|
6922
|
+
groups.set(key, group);
|
|
6923
|
+
}
|
|
6924
|
+
return [...groups.values()].filter((group) => group.urls.length > 1).map((group) => ({
|
|
6925
|
+
value: group.value,
|
|
6926
|
+
urls: uniqueSorted(group.urls)
|
|
6927
|
+
})).toSorted((left, right) => left.value.localeCompare(right.value));
|
|
6928
|
+
}
|
|
6929
|
+
function uniqueSorted(values) {
|
|
6930
|
+
return [...new Set(values)].toSorted((left, right) => left.localeCompare(right));
|
|
6931
|
+
}
|
|
6932
|
+
function escapeRegExp(value) {
|
|
6933
|
+
return value.replace(REGEXP_SPECIAL_RE, "\\$&");
|
|
6934
|
+
}
|
|
6853
6935
|
|
|
6854
6936
|
//#endregion
|
|
6855
6937
|
//#region src/cli/commands/seo.ts
|
|
6938
|
+
const jsonArgs = { json: {
|
|
6939
|
+
type: "boolean",
|
|
6940
|
+
description: "Output as JSON"
|
|
6941
|
+
} };
|
|
6856
6942
|
const hostedProviderArgs = {
|
|
6857
|
-
|
|
6858
|
-
type: "boolean",
|
|
6859
|
-
description: "Output as JSON"
|
|
6860
|
-
},
|
|
6943
|
+
...jsonArgs,
|
|
6861
6944
|
"force-refresh": {
|
|
6862
6945
|
type: "boolean",
|
|
6863
6946
|
description: "Bypass Forgeway SEO provider cache"
|
|
@@ -6903,416 +6986,515 @@ function requireArg(value, name) {
|
|
|
6903
6986
|
if (!normalized) throw new Error(`${name} is required.`);
|
|
6904
6987
|
return normalized;
|
|
6905
6988
|
}
|
|
6906
|
-
|
|
6907
|
-
|
|
6908
|
-
|
|
6909
|
-
|
|
6910
|
-
} catch (error) {
|
|
6911
|
-
if (await handleCliPaywall({
|
|
6912
|
-
error,
|
|
6913
|
-
resource: path,
|
|
6914
|
-
context: { providerPath: path }
|
|
6915
|
-
})) process.exit(2);
|
|
6916
|
-
consola$1.error(error instanceof Error ? error.message : "Unknown error");
|
|
6917
|
-
process.exit(1);
|
|
6918
|
-
}
|
|
6989
|
+
function sitemapMode(value) {
|
|
6990
|
+
const mode = toStringValue(value) ?? "include";
|
|
6991
|
+
if (mode === "include" || mode === "skip" || mode === "only") return mode;
|
|
6992
|
+
throw new Error("sitemap must be include, skip, or only.");
|
|
6919
6993
|
}
|
|
6920
|
-
const
|
|
6994
|
+
const crawlCommand = defineCommand({
|
|
6921
6995
|
meta: {
|
|
6922
|
-
name: "
|
|
6923
|
-
description: "
|
|
6996
|
+
name: "crawl",
|
|
6997
|
+
description: "Deterministic site crawl controls"
|
|
6924
6998
|
},
|
|
6925
|
-
subCommands: {
|
|
6926
|
-
|
|
6927
|
-
|
|
6928
|
-
|
|
6929
|
-
|
|
6999
|
+
subCommands: { local: defineCommand({
|
|
7000
|
+
meta: {
|
|
7001
|
+
name: "local",
|
|
7002
|
+
description: "Crawl one site locally and return bounded structural evidence"
|
|
7003
|
+
},
|
|
7004
|
+
args: {
|
|
7005
|
+
url: {
|
|
7006
|
+
type: "positional",
|
|
7007
|
+
description: "First-party site URL",
|
|
7008
|
+
required: true
|
|
6930
7009
|
},
|
|
6931
|
-
|
|
6932
|
-
|
|
6933
|
-
|
|
6934
|
-
|
|
6935
|
-
|
|
6936
|
-
},
|
|
6937
|
-
...hostedProviderArgs,
|
|
6938
|
-
formats: {
|
|
6939
|
-
type: "string",
|
|
6940
|
-
description: "Comma-separated Firecrawl formats",
|
|
6941
|
-
default: "markdown"
|
|
6942
|
-
},
|
|
6943
|
-
"only-main-content": {
|
|
6944
|
-
type: "boolean",
|
|
6945
|
-
description: "Return main content only",
|
|
6946
|
-
default: true
|
|
6947
|
-
},
|
|
6948
|
-
"timeout-ms": {
|
|
6949
|
-
type: "string",
|
|
6950
|
-
description: "Provider timeout in milliseconds",
|
|
6951
|
-
default: "60000"
|
|
6952
|
-
}
|
|
7010
|
+
...jsonArgs,
|
|
7011
|
+
limit: {
|
|
7012
|
+
type: "string",
|
|
7013
|
+
description: "Maximum pages",
|
|
7014
|
+
default: "100"
|
|
6953
7015
|
},
|
|
6954
|
-
|
|
6955
|
-
|
|
6956
|
-
|
|
6957
|
-
|
|
6958
|
-
onlyMainContent: args["only-main-content"] !== false,
|
|
6959
|
-
timeoutMs: toNumberValue(args["timeout-ms"], 6e4),
|
|
6960
|
-
forceRefresh: forceRefresh(args)
|
|
6961
|
-
});
|
|
6962
|
-
}
|
|
6963
|
-
}),
|
|
6964
|
-
map: defineCommand({
|
|
6965
|
-
meta: {
|
|
6966
|
-
name: "map",
|
|
6967
|
-
description: "Map URLs through Forgeway-hosted Firecrawl"
|
|
7016
|
+
"max-depth": {
|
|
7017
|
+
type: "string",
|
|
7018
|
+
description: "Maximum link discovery depth",
|
|
7019
|
+
default: "3"
|
|
6968
7020
|
},
|
|
6969
|
-
|
|
6970
|
-
|
|
6971
|
-
|
|
6972
|
-
|
|
6973
|
-
required: true
|
|
6974
|
-
},
|
|
6975
|
-
...hostedProviderArgs,
|
|
6976
|
-
search: {
|
|
6977
|
-
type: "string",
|
|
6978
|
-
description: "Optional relevance search term"
|
|
6979
|
-
},
|
|
6980
|
-
sitemap: {
|
|
6981
|
-
type: "string",
|
|
6982
|
-
description: "Sitemap mode: skip, include, or only",
|
|
6983
|
-
default: "include"
|
|
6984
|
-
},
|
|
6985
|
-
limit: {
|
|
6986
|
-
type: "string",
|
|
6987
|
-
description: "Maximum URLs",
|
|
6988
|
-
default: "100"
|
|
6989
|
-
},
|
|
6990
|
-
"include-subdomains": {
|
|
6991
|
-
type: "boolean",
|
|
6992
|
-
description: "Include subdomains"
|
|
6993
|
-
},
|
|
6994
|
-
"ignore-query-parameters": {
|
|
6995
|
-
type: "boolean",
|
|
6996
|
-
description: "Ignore query parameters",
|
|
6997
|
-
default: true
|
|
6998
|
-
}
|
|
7021
|
+
concurrency: {
|
|
7022
|
+
type: "string",
|
|
7023
|
+
description: "Maximum concurrent page requests",
|
|
7024
|
+
default: "4"
|
|
6999
7025
|
},
|
|
7000
|
-
|
|
7001
|
-
|
|
7002
|
-
|
|
7003
|
-
search: toStringValue(args.search),
|
|
7004
|
-
sitemap: toStringValue(args.sitemap) ?? "include",
|
|
7005
|
-
limit: toNumberValue(args.limit, 100),
|
|
7006
|
-
includeSubdomains: args["include-subdomains"] === true,
|
|
7007
|
-
ignoreQueryParameters: args["ignore-query-parameters"] !== false,
|
|
7008
|
-
forceRefresh: forceRefresh(args)
|
|
7009
|
-
});
|
|
7010
|
-
}
|
|
7011
|
-
}),
|
|
7012
|
-
crawl: defineCommand({
|
|
7013
|
-
meta: {
|
|
7014
|
-
name: "crawl",
|
|
7015
|
-
description: "Start a bounded Firecrawl crawl, or check status with --id"
|
|
7026
|
+
include: {
|
|
7027
|
+
type: "string",
|
|
7028
|
+
description: "Comma-separated path globs to include"
|
|
7016
7029
|
},
|
|
7017
|
-
|
|
7018
|
-
|
|
7019
|
-
|
|
7020
|
-
description: "Base URL to crawl"
|
|
7021
|
-
},
|
|
7022
|
-
...hostedProviderArgs,
|
|
7023
|
-
id: {
|
|
7024
|
-
type: "string",
|
|
7025
|
-
description: "Existing Firecrawl crawl id to check"
|
|
7026
|
-
},
|
|
7027
|
-
limit: {
|
|
7028
|
-
type: "string",
|
|
7029
|
-
description: "Maximum pages",
|
|
7030
|
-
default: "25"
|
|
7031
|
-
},
|
|
7032
|
-
"max-depth": {
|
|
7033
|
-
type: "string",
|
|
7034
|
-
description: "Maximum discovery depth",
|
|
7035
|
-
default: "3"
|
|
7036
|
-
},
|
|
7037
|
-
"allow-subdomains": {
|
|
7038
|
-
type: "boolean",
|
|
7039
|
-
description: "Allow subdomains"
|
|
7040
|
-
},
|
|
7041
|
-
"allow-external-links": {
|
|
7042
|
-
type: "boolean",
|
|
7043
|
-
description: "Allow external links"
|
|
7044
|
-
},
|
|
7045
|
-
formats: {
|
|
7046
|
-
type: "string",
|
|
7047
|
-
description: "Comma-separated scrape formats",
|
|
7048
|
-
default: "markdown"
|
|
7049
|
-
}
|
|
7030
|
+
exclude: {
|
|
7031
|
+
type: "string",
|
|
7032
|
+
description: "Comma-separated path globs to exclude"
|
|
7050
7033
|
},
|
|
7051
|
-
|
|
7052
|
-
|
|
7053
|
-
|
|
7054
|
-
|
|
7055
|
-
try {
|
|
7056
|
-
output(await new ForgewaySeoGatewayClient().request(`/api/firecrawl/crawl/${encodeURIComponent(crawlId)}`, void 0, { method: "GET" }), args);
|
|
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);
|
|
7063
|
-
consola$1.error(error instanceof Error ? error.message : "Unknown error");
|
|
7064
|
-
process.exit(1);
|
|
7065
|
-
}
|
|
7066
|
-
return;
|
|
7067
|
-
}
|
|
7068
|
-
await runSeoRequest(args, "/api/firecrawl/crawl", {
|
|
7069
|
-
url: requireArg(args.url, "url"),
|
|
7070
|
-
limit: toNumberValue(args.limit, 25),
|
|
7071
|
-
maxDiscoveryDepth: toNumberValue(args["max-depth"], 3),
|
|
7072
|
-
allowExternalLinks: args["allow-external-links"] === true,
|
|
7073
|
-
allowSubdomains: args["allow-subdomains"] === true,
|
|
7074
|
-
scrapeFormats: formats(args.formats),
|
|
7075
|
-
forceRefresh: forceRefresh(args)
|
|
7076
|
-
});
|
|
7077
|
-
}
|
|
7078
|
-
}),
|
|
7079
|
-
search: defineCommand({
|
|
7080
|
-
meta: {
|
|
7081
|
-
name: "search",
|
|
7082
|
-
description: "Search through Forgeway-hosted Firecrawl"
|
|
7034
|
+
"timeout-ms": {
|
|
7035
|
+
type: "string",
|
|
7036
|
+
description: "Per-resource timeout in milliseconds",
|
|
7037
|
+
default: "10000"
|
|
7083
7038
|
},
|
|
7084
|
-
|
|
7085
|
-
|
|
7086
|
-
|
|
7087
|
-
|
|
7088
|
-
required: true
|
|
7089
|
-
},
|
|
7090
|
-
...hostedProviderArgs,
|
|
7091
|
-
limit: {
|
|
7092
|
-
type: "string",
|
|
7093
|
-
description: "Maximum results",
|
|
7094
|
-
default: "10"
|
|
7095
|
-
},
|
|
7096
|
-
scrape: {
|
|
7097
|
-
type: "boolean",
|
|
7098
|
-
description: "Scrape result markdown"
|
|
7099
|
-
}
|
|
7039
|
+
"max-bytes": {
|
|
7040
|
+
type: "string",
|
|
7041
|
+
description: "Maximum bytes per fetched resource",
|
|
7042
|
+
default: "1000000"
|
|
7100
7043
|
},
|
|
7101
|
-
|
|
7102
|
-
|
|
7103
|
-
|
|
7104
|
-
|
|
7105
|
-
|
|
7106
|
-
|
|
7107
|
-
|
|
7044
|
+
sitemap: {
|
|
7045
|
+
type: "string",
|
|
7046
|
+
description: "Sitemap mode: include, skip, or only",
|
|
7047
|
+
default: "include"
|
|
7048
|
+
},
|
|
7049
|
+
"keep-query": {
|
|
7050
|
+
type: "boolean",
|
|
7051
|
+
description: "Keep query parameters in page identity"
|
|
7052
|
+
},
|
|
7053
|
+
"allow-private-network": {
|
|
7054
|
+
type: "boolean",
|
|
7055
|
+
description: "Allow an explicitly selected localhost or private origin"
|
|
7108
7056
|
}
|
|
7109
|
-
}
|
|
7110
|
-
|
|
7057
|
+
},
|
|
7058
|
+
async run({ args }) {
|
|
7059
|
+
configureOutputMode(args);
|
|
7060
|
+
try {
|
|
7061
|
+
output(await crawlLocalSite({
|
|
7062
|
+
startUrl: requireArg(args.url, "url"),
|
|
7063
|
+
pageLimit: toNumberValue(args.limit, 100),
|
|
7064
|
+
maxDepth: toNumberValue(args["max-depth"], 3),
|
|
7065
|
+
concurrency: toNumberValue(args.concurrency, 4),
|
|
7066
|
+
include: formats(args.include) ?? [],
|
|
7067
|
+
exclude: formats(args.exclude) ?? [],
|
|
7068
|
+
timeoutMs: toNumberValue(args["timeout-ms"], 1e4),
|
|
7069
|
+
maxBytesPerResource: toNumberValue(args["max-bytes"], 1e6),
|
|
7070
|
+
sitemap: sitemapMode(args.sitemap),
|
|
7071
|
+
keepQuery: args["keep-query"] === true,
|
|
7072
|
+
allowPrivateNetwork: args["allow-private-network"] === true
|
|
7073
|
+
}), args);
|
|
7074
|
+
} catch (error) {
|
|
7075
|
+
consola$1.error(error instanceof Error ? error.message : "Local site crawl failed");
|
|
7076
|
+
process.exit(1);
|
|
7077
|
+
}
|
|
7078
|
+
}
|
|
7079
|
+
}) }
|
|
7111
7080
|
});
|
|
7081
|
+
function dataForSeoDevice(value) {
|
|
7082
|
+
const normalized = toStringValue(value) ?? "desktop";
|
|
7083
|
+
if (normalized === "desktop" || normalized === "mobile") return normalized;
|
|
7084
|
+
throw new Error("device must be desktop or mobile.");
|
|
7085
|
+
}
|
|
7086
|
+
function aiScrapePlatform(value) {
|
|
7087
|
+
const normalized = toStringValue(value) ?? "chat_gpt";
|
|
7088
|
+
if (normalized === "chat_gpt" || normalized === "gemini" || normalized === "perplexity") return normalized;
|
|
7089
|
+
throw new Error("platform must be chat_gpt, gemini, or perplexity.");
|
|
7090
|
+
}
|
|
7091
|
+
function aiMentionPlatform(value) {
|
|
7092
|
+
const normalized = toStringValue(value) ?? "google";
|
|
7093
|
+
if (normalized === "google" || normalized === "chat_gpt") return normalized;
|
|
7094
|
+
throw new Error("platform must be google or chat_gpt.");
|
|
7095
|
+
}
|
|
7112
7096
|
function dataForSeoBase(args) {
|
|
7113
7097
|
return {
|
|
7114
7098
|
locationCode: toNumberValue(args["location-code"], 2840),
|
|
7115
7099
|
languageCode: toStringValue(args["language-code"]) ?? "en",
|
|
7116
|
-
device:
|
|
7100
|
+
device: dataForSeoDevice(args.device),
|
|
7117
7101
|
forceRefresh: forceRefresh(args)
|
|
7118
7102
|
};
|
|
7119
7103
|
}
|
|
7120
|
-
|
|
7121
|
-
|
|
7122
|
-
|
|
7123
|
-
|
|
7124
|
-
|
|
7125
|
-
|
|
7126
|
-
|
|
7127
|
-
|
|
7128
|
-
|
|
7129
|
-
|
|
7130
|
-
|
|
7131
|
-
|
|
7132
|
-
|
|
7133
|
-
|
|
7134
|
-
description: "SERP depth",
|
|
7135
|
-
default: "10"
|
|
7104
|
+
function createSeoCommand(options = {}) {
|
|
7105
|
+
const providerService = options.providerService ?? new SeoProviderEvidenceService(new ForgewaySeoGatewayClient());
|
|
7106
|
+
async function runSeoRequest(args, resource, request) {
|
|
7107
|
+
configureOutputMode(args);
|
|
7108
|
+
try {
|
|
7109
|
+
output(await request(), args);
|
|
7110
|
+
} catch (error) {
|
|
7111
|
+
if (await handleCliPaywall({
|
|
7112
|
+
error,
|
|
7113
|
+
resource,
|
|
7114
|
+
context: { providerPath: resource }
|
|
7115
|
+
})) process.exit(2);
|
|
7116
|
+
consola$1.error(error instanceof Error ? error.message : "Unknown error");
|
|
7117
|
+
process.exit(1);
|
|
7136
7118
|
}
|
|
7137
|
-
},
|
|
7138
|
-
async run({ args }) {
|
|
7139
|
-
await runSeoRequest(args, "/api/dataforseo/serp", {
|
|
7140
|
-
keyword: requireArg(args.keyword, "keyword"),
|
|
7141
|
-
depth: toNumberValue(args.depth, 10),
|
|
7142
|
-
...dataForSeoBase(args)
|
|
7143
|
-
});
|
|
7144
7119
|
}
|
|
7145
|
-
|
|
7146
|
-
|
|
7147
|
-
|
|
7148
|
-
|
|
7149
|
-
|
|
7150
|
-
|
|
7151
|
-
|
|
7152
|
-
|
|
7153
|
-
|
|
7154
|
-
|
|
7155
|
-
|
|
7156
|
-
|
|
7157
|
-
|
|
7158
|
-
|
|
7159
|
-
|
|
7160
|
-
|
|
7161
|
-
|
|
7120
|
+
const firecrawlCommand = defineCommand({
|
|
7121
|
+
meta: {
|
|
7122
|
+
name: "firecrawl",
|
|
7123
|
+
description: "Forgeway-hosted Firecrawl workflows"
|
|
7124
|
+
},
|
|
7125
|
+
subCommands: {
|
|
7126
|
+
scrape: defineCommand({
|
|
7127
|
+
meta: {
|
|
7128
|
+
name: "scrape",
|
|
7129
|
+
description: "Scrape one URL through Forgeway-hosted Firecrawl"
|
|
7130
|
+
},
|
|
7131
|
+
args: {
|
|
7132
|
+
url: {
|
|
7133
|
+
type: "positional",
|
|
7134
|
+
description: "URL to scrape",
|
|
7135
|
+
required: true
|
|
7136
|
+
},
|
|
7137
|
+
...hostedProviderArgs,
|
|
7138
|
+
formats: {
|
|
7139
|
+
type: "string",
|
|
7140
|
+
description: "Comma-separated Firecrawl formats",
|
|
7141
|
+
default: "markdown"
|
|
7142
|
+
},
|
|
7143
|
+
"only-main-content": {
|
|
7144
|
+
type: "boolean",
|
|
7145
|
+
description: "Return main content only",
|
|
7146
|
+
default: true
|
|
7147
|
+
},
|
|
7148
|
+
"timeout-ms": {
|
|
7149
|
+
type: "string",
|
|
7150
|
+
description: "Provider timeout in milliseconds",
|
|
7151
|
+
default: "60000"
|
|
7152
|
+
}
|
|
7153
|
+
},
|
|
7154
|
+
async run({ args }) {
|
|
7155
|
+
await runSeoRequest(args, "/api/firecrawl/scrape", () => providerService.firecrawlScrape({
|
|
7156
|
+
url: requireArg(args.url, "url"),
|
|
7157
|
+
formats: formats(args.formats) ?? ["markdown"],
|
|
7158
|
+
onlyMainContent: args["only-main-content"] !== false,
|
|
7159
|
+
timeoutMs: toNumberValue(args["timeout-ms"], 6e4),
|
|
7160
|
+
forceRefresh: forceRefresh(args)
|
|
7161
|
+
}));
|
|
7162
|
+
}
|
|
7163
|
+
}),
|
|
7164
|
+
map: defineCommand({
|
|
7165
|
+
meta: {
|
|
7166
|
+
name: "map",
|
|
7167
|
+
description: "Map URLs through Forgeway-hosted Firecrawl"
|
|
7168
|
+
},
|
|
7169
|
+
args: {
|
|
7170
|
+
url: {
|
|
7171
|
+
type: "positional",
|
|
7172
|
+
description: "Base URL to map",
|
|
7173
|
+
required: true
|
|
7174
|
+
},
|
|
7175
|
+
...hostedProviderArgs,
|
|
7176
|
+
search: {
|
|
7177
|
+
type: "string",
|
|
7178
|
+
description: "Optional relevance search term"
|
|
7179
|
+
},
|
|
7180
|
+
sitemap: {
|
|
7181
|
+
type: "string",
|
|
7182
|
+
description: "Sitemap mode: skip, include, or only",
|
|
7183
|
+
default: "include"
|
|
7184
|
+
},
|
|
7185
|
+
limit: {
|
|
7186
|
+
type: "string",
|
|
7187
|
+
description: "Maximum URLs",
|
|
7188
|
+
default: "100"
|
|
7189
|
+
},
|
|
7190
|
+
"include-subdomains": {
|
|
7191
|
+
type: "boolean",
|
|
7192
|
+
description: "Include subdomains"
|
|
7193
|
+
},
|
|
7194
|
+
"ignore-query-parameters": {
|
|
7195
|
+
type: "boolean",
|
|
7196
|
+
description: "Ignore query parameters",
|
|
7197
|
+
default: true
|
|
7198
|
+
}
|
|
7199
|
+
},
|
|
7200
|
+
async run({ args }) {
|
|
7201
|
+
await runSeoRequest(args, "/api/firecrawl/map", () => providerService.firecrawlMap({
|
|
7202
|
+
url: requireArg(args.url, "url"),
|
|
7203
|
+
search: toStringValue(args.search),
|
|
7204
|
+
sitemap: sitemapMode(args.sitemap),
|
|
7205
|
+
limit: toNumberValue(args.limit, 100),
|
|
7206
|
+
includeSubdomains: args["include-subdomains"] === true,
|
|
7207
|
+
ignoreQueryParameters: args["ignore-query-parameters"] !== false,
|
|
7208
|
+
forceRefresh: forceRefresh(args)
|
|
7209
|
+
}));
|
|
7210
|
+
}
|
|
7211
|
+
}),
|
|
7212
|
+
crawl: defineCommand({
|
|
7213
|
+
meta: {
|
|
7214
|
+
name: "crawl",
|
|
7215
|
+
description: "Start a bounded Firecrawl crawl, or check status with --id"
|
|
7216
|
+
},
|
|
7217
|
+
args: {
|
|
7218
|
+
url: {
|
|
7219
|
+
type: "positional",
|
|
7220
|
+
description: "Base URL to crawl",
|
|
7221
|
+
required: false
|
|
7222
|
+
},
|
|
7223
|
+
...hostedProviderArgs,
|
|
7224
|
+
id: {
|
|
7225
|
+
type: "string",
|
|
7226
|
+
description: "Existing Firecrawl crawl id to check"
|
|
7227
|
+
},
|
|
7228
|
+
limit: {
|
|
7229
|
+
type: "string",
|
|
7230
|
+
description: "Maximum pages",
|
|
7231
|
+
default: "25"
|
|
7232
|
+
},
|
|
7233
|
+
"max-depth": {
|
|
7234
|
+
type: "string",
|
|
7235
|
+
description: "Maximum discovery depth",
|
|
7236
|
+
default: "3"
|
|
7237
|
+
},
|
|
7238
|
+
"allow-subdomains": {
|
|
7239
|
+
type: "boolean",
|
|
7240
|
+
description: "Allow subdomains"
|
|
7241
|
+
},
|
|
7242
|
+
"allow-external-links": {
|
|
7243
|
+
type: "boolean",
|
|
7244
|
+
description: "Allow external links"
|
|
7245
|
+
},
|
|
7246
|
+
formats: {
|
|
7247
|
+
type: "string",
|
|
7248
|
+
description: "Comma-separated scrape formats",
|
|
7249
|
+
default: "markdown"
|
|
7250
|
+
}
|
|
7251
|
+
},
|
|
7252
|
+
async run({ args }) {
|
|
7253
|
+
const crawlId = toStringValue(args.id);
|
|
7254
|
+
if (crawlId) {
|
|
7255
|
+
await runSeoRequest(args, `/api/firecrawl/crawl/${crawlId}`, () => providerService.firecrawlCrawlStatus({ id: crawlId }));
|
|
7256
|
+
return;
|
|
7257
|
+
}
|
|
7258
|
+
await runSeoRequest(args, "/api/firecrawl/crawl", () => providerService.firecrawlCrawlStart({
|
|
7259
|
+
url: requireArg(args.url, "url"),
|
|
7260
|
+
limit: toNumberValue(args.limit, 25),
|
|
7261
|
+
maxDiscoveryDepth: toNumberValue(args["max-depth"], 3),
|
|
7262
|
+
allowExternalLinks: args["allow-external-links"] === true,
|
|
7263
|
+
allowSubdomains: args["allow-subdomains"] === true,
|
|
7264
|
+
scrapeFormats: formats(args.formats) ?? ["markdown"],
|
|
7265
|
+
forceRefresh: forceRefresh(args)
|
|
7266
|
+
}));
|
|
7267
|
+
}
|
|
7268
|
+
}),
|
|
7269
|
+
search: defineCommand({
|
|
7270
|
+
meta: {
|
|
7271
|
+
name: "search",
|
|
7272
|
+
description: "Search through Forgeway-hosted Firecrawl"
|
|
7273
|
+
},
|
|
7274
|
+
args: {
|
|
7275
|
+
query: {
|
|
7276
|
+
type: "positional",
|
|
7277
|
+
description: "Search query",
|
|
7278
|
+
required: true
|
|
7279
|
+
},
|
|
7280
|
+
...hostedProviderArgs,
|
|
7281
|
+
limit: {
|
|
7282
|
+
type: "string",
|
|
7283
|
+
description: "Maximum results",
|
|
7284
|
+
default: "10"
|
|
7285
|
+
},
|
|
7286
|
+
scrape: {
|
|
7287
|
+
type: "boolean",
|
|
7288
|
+
description: "Scrape result markdown"
|
|
7289
|
+
}
|
|
7290
|
+
},
|
|
7291
|
+
async run({ args }) {
|
|
7292
|
+
await runSeoRequest(args, "/api/firecrawl/search", () => providerService.firecrawlSearch({
|
|
7293
|
+
query: requireArg(args.query, "query"),
|
|
7294
|
+
limit: toNumberValue(args.limit, 10),
|
|
7295
|
+
scrape: args.scrape === true,
|
|
7296
|
+
forceRefresh: forceRefresh(args)
|
|
7297
|
+
}));
|
|
7298
|
+
}
|
|
7299
|
+
})
|
|
7162
7300
|
}
|
|
7163
|
-
}
|
|
7164
|
-
|
|
7165
|
-
|
|
7166
|
-
|
|
7167
|
-
|
|
7168
|
-
|
|
7169
|
-
|
|
7170
|
-
|
|
7171
|
-
|
|
7172
|
-
|
|
7173
|
-
|
|
7174
|
-
|
|
7175
|
-
|
|
7176
|
-
|
|
7177
|
-
|
|
7178
|
-
|
|
7179
|
-
|
|
7180
|
-
|
|
7181
|
-
required: true
|
|
7301
|
+
});
|
|
7302
|
+
const dataForSeoSerpCommand = defineCommand({
|
|
7303
|
+
meta: {
|
|
7304
|
+
name: "serp",
|
|
7305
|
+
description: "Fetch Google organic SERP data"
|
|
7306
|
+
},
|
|
7307
|
+
args: {
|
|
7308
|
+
keyword: {
|
|
7309
|
+
type: "positional",
|
|
7310
|
+
description: "Keyword",
|
|
7311
|
+
required: true
|
|
7312
|
+
},
|
|
7313
|
+
...dataForSeoCommonArgs,
|
|
7314
|
+
depth: {
|
|
7315
|
+
type: "string",
|
|
7316
|
+
description: "SERP depth",
|
|
7317
|
+
default: "10"
|
|
7318
|
+
}
|
|
7182
7319
|
},
|
|
7183
|
-
|
|
7184
|
-
|
|
7185
|
-
|
|
7186
|
-
|
|
7187
|
-
|
|
7320
|
+
async run({ args }) {
|
|
7321
|
+
await runSeoRequest(args, "/api/dataforseo/serp", () => providerService.dataForSeoSerp({
|
|
7322
|
+
keyword: requireArg(args.keyword, "keyword"),
|
|
7323
|
+
depth: toNumberValue(args.depth, 10),
|
|
7324
|
+
...dataForSeoBase(args)
|
|
7325
|
+
}));
|
|
7188
7326
|
}
|
|
7189
|
-
}
|
|
7190
|
-
|
|
7191
|
-
|
|
7192
|
-
|
|
7193
|
-
|
|
7194
|
-
|
|
7195
|
-
|
|
7196
|
-
|
|
7197
|
-
|
|
7198
|
-
|
|
7199
|
-
|
|
7200
|
-
|
|
7201
|
-
|
|
7202
|
-
|
|
7203
|
-
|
|
7204
|
-
|
|
7205
|
-
|
|
7206
|
-
|
|
7207
|
-
type: "positional",
|
|
7208
|
-
description: "Target domain",
|
|
7209
|
-
required: true
|
|
7327
|
+
});
|
|
7328
|
+
const dataForSeoMapsCommand = defineCommand({
|
|
7329
|
+
meta: {
|
|
7330
|
+
name: "maps",
|
|
7331
|
+
description: "Fetch Google Maps SERP data"
|
|
7332
|
+
},
|
|
7333
|
+
args: {
|
|
7334
|
+
keyword: {
|
|
7335
|
+
type: "positional",
|
|
7336
|
+
description: "Keyword",
|
|
7337
|
+
required: true
|
|
7338
|
+
},
|
|
7339
|
+
...dataForSeoCommonArgs,
|
|
7340
|
+
depth: {
|
|
7341
|
+
type: "string",
|
|
7342
|
+
description: "Maps depth",
|
|
7343
|
+
default: "10"
|
|
7344
|
+
}
|
|
7210
7345
|
},
|
|
7211
|
-
|
|
7212
|
-
|
|
7213
|
-
|
|
7214
|
-
|
|
7215
|
-
|
|
7346
|
+
async run({ args }) {
|
|
7347
|
+
await runSeoRequest(args, "/api/dataforseo/maps", () => providerService.dataForSeoMaps({
|
|
7348
|
+
keyword: requireArg(args.keyword, "keyword"),
|
|
7349
|
+
depth: toNumberValue(args.depth, 10),
|
|
7350
|
+
...dataForSeoBase(args)
|
|
7351
|
+
}));
|
|
7216
7352
|
}
|
|
7217
|
-
}
|
|
7218
|
-
|
|
7219
|
-
|
|
7220
|
-
|
|
7221
|
-
|
|
7222
|
-
|
|
7223
|
-
|
|
7224
|
-
|
|
7225
|
-
|
|
7226
|
-
|
|
7227
|
-
|
|
7228
|
-
|
|
7229
|
-
|
|
7230
|
-
|
|
7231
|
-
|
|
7232
|
-
|
|
7233
|
-
|
|
7234
|
-
|
|
7235
|
-
required: true
|
|
7353
|
+
});
|
|
7354
|
+
const dataForSeoKeywordsCommand = defineCommand({
|
|
7355
|
+
meta: {
|
|
7356
|
+
name: "keywords",
|
|
7357
|
+
description: "Fetch keyword suggestions"
|
|
7358
|
+
},
|
|
7359
|
+
args: {
|
|
7360
|
+
keyword: {
|
|
7361
|
+
type: "positional",
|
|
7362
|
+
description: "Seed keyword",
|
|
7363
|
+
required: true
|
|
7364
|
+
},
|
|
7365
|
+
...dataForSeoCommonArgs,
|
|
7366
|
+
limit: {
|
|
7367
|
+
type: "string",
|
|
7368
|
+
description: "Maximum suggestions",
|
|
7369
|
+
default: "20"
|
|
7370
|
+
}
|
|
7236
7371
|
},
|
|
7237
|
-
|
|
7238
|
-
|
|
7239
|
-
|
|
7240
|
-
|
|
7241
|
-
|
|
7372
|
+
async run({ args }) {
|
|
7373
|
+
await runSeoRequest(args, "/api/dataforseo/keywords", () => providerService.dataForSeoKeywords({
|
|
7374
|
+
keyword: requireArg(args.keyword, "keyword"),
|
|
7375
|
+
limit: toNumberValue(args.limit, 20),
|
|
7376
|
+
...dataForSeoBase(args)
|
|
7377
|
+
}));
|
|
7242
7378
|
}
|
|
7243
|
-
}
|
|
7244
|
-
|
|
7245
|
-
|
|
7246
|
-
|
|
7247
|
-
|
|
7248
|
-
|
|
7249
|
-
|
|
7250
|
-
|
|
7251
|
-
|
|
7252
|
-
|
|
7253
|
-
|
|
7254
|
-
|
|
7255
|
-
|
|
7256
|
-
|
|
7257
|
-
|
|
7258
|
-
|
|
7259
|
-
|
|
7260
|
-
|
|
7261
|
-
description: "Target domain"
|
|
7379
|
+
});
|
|
7380
|
+
const dataForSeoCompetitorsCommand = defineCommand({
|
|
7381
|
+
meta: {
|
|
7382
|
+
name: "competitors",
|
|
7383
|
+
description: "Fetch competitor-domain data"
|
|
7384
|
+
},
|
|
7385
|
+
args: {
|
|
7386
|
+
domain: {
|
|
7387
|
+
type: "positional",
|
|
7388
|
+
description: "Target domain",
|
|
7389
|
+
required: true
|
|
7390
|
+
},
|
|
7391
|
+
...dataForSeoCommonArgs,
|
|
7392
|
+
limit: {
|
|
7393
|
+
type: "string",
|
|
7394
|
+
description: "Maximum competitors",
|
|
7395
|
+
default: "20"
|
|
7396
|
+
}
|
|
7262
7397
|
},
|
|
7263
|
-
|
|
7264
|
-
|
|
7265
|
-
|
|
7398
|
+
async run({ args }) {
|
|
7399
|
+
await runSeoRequest(args, "/api/dataforseo/competitors", () => providerService.dataForSeoCompetitors({
|
|
7400
|
+
domain: requireArg(args.domain, "domain"),
|
|
7401
|
+
limit: toNumberValue(args.limit, 20),
|
|
7402
|
+
...dataForSeoBase(args)
|
|
7403
|
+
}));
|
|
7404
|
+
}
|
|
7405
|
+
});
|
|
7406
|
+
const dataForSeoAiScrapeCommand = defineCommand({
|
|
7407
|
+
meta: {
|
|
7408
|
+
name: "ai-scrape",
|
|
7409
|
+
description: "Fetch DataForSEO AI scraper response data"
|
|
7410
|
+
},
|
|
7411
|
+
args: {
|
|
7412
|
+
keyword: {
|
|
7413
|
+
type: "positional",
|
|
7414
|
+
description: "AI search keyword",
|
|
7415
|
+
required: true
|
|
7416
|
+
},
|
|
7417
|
+
...dataForSeoCommonArgs,
|
|
7418
|
+
platform: {
|
|
7419
|
+
type: "string",
|
|
7420
|
+
description: "AI platform: chat_gpt, gemini, or perplexity",
|
|
7421
|
+
default: "chat_gpt"
|
|
7422
|
+
}
|
|
7266
7423
|
},
|
|
7267
|
-
|
|
7268
|
-
|
|
7269
|
-
|
|
7270
|
-
|
|
7424
|
+
async run({ args }) {
|
|
7425
|
+
await runSeoRequest(args, "/api/dataforseo/ai-scrape", () => providerService.dataForSeoAiScrape({
|
|
7426
|
+
keyword: requireArg(args.keyword, "keyword"),
|
|
7427
|
+
platform: aiScrapePlatform(args.platform),
|
|
7428
|
+
...dataForSeoBase(args)
|
|
7429
|
+
}));
|
|
7430
|
+
}
|
|
7431
|
+
});
|
|
7432
|
+
const dataForSeoAiMentionsCommand = defineCommand({
|
|
7433
|
+
meta: {
|
|
7434
|
+
name: "ai-mentions",
|
|
7435
|
+
description: "Fetch DataForSEO LLM mention data"
|
|
7436
|
+
},
|
|
7437
|
+
args: {
|
|
7438
|
+
...dataForSeoCommonArgs,
|
|
7439
|
+
domain: {
|
|
7440
|
+
type: "string",
|
|
7441
|
+
description: "Target domain"
|
|
7442
|
+
},
|
|
7443
|
+
keyword: {
|
|
7444
|
+
type: "string",
|
|
7445
|
+
description: "Target keyword"
|
|
7446
|
+
},
|
|
7447
|
+
platform: {
|
|
7448
|
+
type: "string",
|
|
7449
|
+
description: "Mention platform: google or chat_gpt",
|
|
7450
|
+
default: "google"
|
|
7451
|
+
},
|
|
7452
|
+
limit: {
|
|
7453
|
+
type: "string",
|
|
7454
|
+
description: "Maximum mentions",
|
|
7455
|
+
default: "20"
|
|
7456
|
+
}
|
|
7271
7457
|
},
|
|
7272
|
-
|
|
7273
|
-
|
|
7274
|
-
|
|
7275
|
-
|
|
7458
|
+
async run({ args }) {
|
|
7459
|
+
if (!toStringValue(args.domain) && !toStringValue(args.keyword)) {
|
|
7460
|
+
consola$1.error("domain or keyword is required.");
|
|
7461
|
+
process.exit(1);
|
|
7462
|
+
}
|
|
7463
|
+
await runSeoRequest(args, "/api/dataforseo/ai-mentions", () => providerService.dataForSeoAiMentions({
|
|
7464
|
+
domain: toStringValue(args.domain),
|
|
7465
|
+
keyword: toStringValue(args.keyword),
|
|
7466
|
+
platform: aiMentionPlatform(args.platform),
|
|
7467
|
+
limit: toNumberValue(args.limit, 20),
|
|
7468
|
+
...dataForSeoBase(args)
|
|
7469
|
+
}));
|
|
7276
7470
|
}
|
|
7277
|
-
}
|
|
7278
|
-
|
|
7279
|
-
|
|
7280
|
-
|
|
7281
|
-
|
|
7471
|
+
});
|
|
7472
|
+
return defineCommand({
|
|
7473
|
+
meta: {
|
|
7474
|
+
name: "seo",
|
|
7475
|
+
description: "Local site evidence and hosted SEO provider workflows"
|
|
7476
|
+
},
|
|
7477
|
+
subCommands: {
|
|
7478
|
+
crawl: crawlCommand,
|
|
7479
|
+
firecrawl: firecrawlCommand,
|
|
7480
|
+
dataforseo: defineCommand({
|
|
7481
|
+
meta: {
|
|
7482
|
+
name: "dataforseo",
|
|
7483
|
+
description: "Forgeway-hosted DataForSEO workflows"
|
|
7484
|
+
},
|
|
7485
|
+
subCommands: {
|
|
7486
|
+
serp: dataForSeoSerpCommand,
|
|
7487
|
+
maps: dataForSeoMapsCommand,
|
|
7488
|
+
keywords: dataForSeoKeywordsCommand,
|
|
7489
|
+
competitors: dataForSeoCompetitorsCommand,
|
|
7490
|
+
"ai-scrape": dataForSeoAiScrapeCommand,
|
|
7491
|
+
"ai-mentions": dataForSeoAiMentionsCommand
|
|
7492
|
+
}
|
|
7493
|
+
})
|
|
7282
7494
|
}
|
|
7283
|
-
|
|
7284
|
-
|
|
7285
|
-
|
|
7286
|
-
platform: toStringValue(args.platform) ?? "google",
|
|
7287
|
-
limit: toNumberValue(args.limit, 20),
|
|
7288
|
-
...dataForSeoBase(args)
|
|
7289
|
-
});
|
|
7290
|
-
}
|
|
7291
|
-
});
|
|
7292
|
-
const dataForSeoCommand = defineCommand({
|
|
7293
|
-
meta: {
|
|
7294
|
-
name: "dataforseo",
|
|
7295
|
-
description: "Forgeway-hosted DataForSEO workflows"
|
|
7296
|
-
},
|
|
7297
|
-
subCommands: {
|
|
7298
|
-
serp: dataForSeoSerpCommand,
|
|
7299
|
-
maps: dataForSeoMapsCommand,
|
|
7300
|
-
keywords: dataForSeoKeywordsCommand,
|
|
7301
|
-
competitors: dataForSeoCompetitorsCommand,
|
|
7302
|
-
"ai-scrape": dataForSeoAiScrapeCommand,
|
|
7303
|
-
"ai-mentions": dataForSeoAiMentionsCommand
|
|
7304
|
-
}
|
|
7305
|
-
});
|
|
7306
|
-
const seoCommand = defineCommand({
|
|
7307
|
-
meta: {
|
|
7308
|
-
name: "seo",
|
|
7309
|
-
description: "Hosted SEO provider workflows through Forgeway"
|
|
7310
|
-
},
|
|
7311
|
-
subCommands: {
|
|
7312
|
-
firecrawl: firecrawlCommand,
|
|
7313
|
-
dataforseo: dataForSeoCommand
|
|
7314
|
-
}
|
|
7315
|
-
});
|
|
7495
|
+
});
|
|
7496
|
+
}
|
|
7497
|
+
const seoCommand = createSeoCommand();
|
|
7316
7498
|
|
|
7317
7499
|
//#endregion
|
|
7318
7500
|
//#region src/cli/commands/taxonomy.ts
|
|
@@ -7482,6 +7664,88 @@ const typesCommand = defineCommand({
|
|
|
7482
7664
|
}
|
|
7483
7665
|
});
|
|
7484
7666
|
|
|
7667
|
+
//#endregion
|
|
7668
|
+
//#region src/cli/contributions.ts
|
|
7669
|
+
const DINEWAY_PLUGIN_PACKAGE = /^(?:@dineway-ai\/plugin-|dineway-plugin-)/;
|
|
7670
|
+
const CLI_COMMAND_NAME = /^[a-z][a-z0-9-]*$/;
|
|
7671
|
+
async function discoverDinewayCliContributions(cwd = process.cwd()) {
|
|
7672
|
+
const projectPackage = await findProjectPackage(cwd);
|
|
7673
|
+
if (!projectPackage) return [];
|
|
7674
|
+
const { packagePath, project } = projectPackage;
|
|
7675
|
+
const requireFromProject = createRequire(packagePath);
|
|
7676
|
+
const packageNames = new Set([
|
|
7677
|
+
...Object.keys(project.dependencies ?? {}),
|
|
7678
|
+
...Object.keys(project.devDependencies ?? {}),
|
|
7679
|
+
...Object.keys(project.optionalDependencies ?? {})
|
|
7680
|
+
]);
|
|
7681
|
+
const contributions = [];
|
|
7682
|
+
for (const packageName of [...packageNames].filter(isDinewayPluginPackage).toSorted()) {
|
|
7683
|
+
const specifier = `${packageName}/cli`;
|
|
7684
|
+
let modulePath;
|
|
7685
|
+
try {
|
|
7686
|
+
modulePath = requireFromProject.resolve(specifier);
|
|
7687
|
+
} catch (error) {
|
|
7688
|
+
if (isMissingContribution(error)) continue;
|
|
7689
|
+
throw error;
|
|
7690
|
+
}
|
|
7691
|
+
const loaded = await import(pathToFileURL(modulePath).href);
|
|
7692
|
+
const value = loaded.dinewayCliContribution ?? loaded.default;
|
|
7693
|
+
if (!isDinewayCliContribution(value)) throw new Error(`${specifier} does not export a valid Dineway CLI contribution`);
|
|
7694
|
+
contributions.push({
|
|
7695
|
+
packageName,
|
|
7696
|
+
commands: value.commands
|
|
7697
|
+
});
|
|
7698
|
+
}
|
|
7699
|
+
return contributions;
|
|
7700
|
+
}
|
|
7701
|
+
async function findProjectPackage(from) {
|
|
7702
|
+
let directory = resolve(from);
|
|
7703
|
+
while (true) {
|
|
7704
|
+
const packagePath = join(directory, "package.json");
|
|
7705
|
+
const project = await readProjectPackage(packagePath);
|
|
7706
|
+
if (project) return {
|
|
7707
|
+
packagePath,
|
|
7708
|
+
project
|
|
7709
|
+
};
|
|
7710
|
+
const parent = dirname(directory);
|
|
7711
|
+
if (parent === directory) return null;
|
|
7712
|
+
directory = parent;
|
|
7713
|
+
}
|
|
7714
|
+
}
|
|
7715
|
+
function mergeDinewayCliContributions(builtIns, contributions) {
|
|
7716
|
+
const commands = { ...builtIns };
|
|
7717
|
+
for (const contribution of contributions) for (const [name, command] of Object.entries(contribution.commands).toSorted(([left], [right]) => left.localeCompare(right))) {
|
|
7718
|
+
if (commands[name]) throw new Error(`Dineway CLI command "${name}" from ${contribution.packageName} conflicts with an existing command`);
|
|
7719
|
+
commands[name] = command;
|
|
7720
|
+
}
|
|
7721
|
+
return commands;
|
|
7722
|
+
}
|
|
7723
|
+
async function readProjectPackage(path) {
|
|
7724
|
+
try {
|
|
7725
|
+
const parsed = JSON.parse(await readFile(path, "utf8"));
|
|
7726
|
+
return isRecord(parsed) ? parsed : null;
|
|
7727
|
+
} catch (error) {
|
|
7728
|
+
if (isFileNotFound(error)) return null;
|
|
7729
|
+
throw error;
|
|
7730
|
+
}
|
|
7731
|
+
}
|
|
7732
|
+
function isDinewayPluginPackage(packageName) {
|
|
7733
|
+
return DINEWAY_PLUGIN_PACKAGE.test(packageName);
|
|
7734
|
+
}
|
|
7735
|
+
function isDinewayCliContribution(value) {
|
|
7736
|
+
if (!isRecord(value) || !isRecord(value.commands)) return false;
|
|
7737
|
+
return Object.entries(value.commands).every(([name, command]) => CLI_COMMAND_NAME.test(name) && isRecord(command));
|
|
7738
|
+
}
|
|
7739
|
+
function isRecord(value) {
|
|
7740
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7741
|
+
}
|
|
7742
|
+
function isMissingContribution(error) {
|
|
7743
|
+
return error instanceof Error && "code" in error && (error.code === "MODULE_NOT_FOUND" || error.code === "ERR_PACKAGE_PATH_NOT_EXPORTED");
|
|
7744
|
+
}
|
|
7745
|
+
function isFileNotFound(error) {
|
|
7746
|
+
return error instanceof Error && "code" in error && error.code === "ENOENT";
|
|
7747
|
+
}
|
|
7748
|
+
|
|
7485
7749
|
//#endregion
|
|
7486
7750
|
//#region src/cli/index.ts
|
|
7487
7751
|
/**
|
|
@@ -7507,36 +7771,40 @@ const typesCommand = defineCommand({
|
|
|
7507
7771
|
* - deploy: Deploy a standard Dineway Node server through a provider CLI
|
|
7508
7772
|
* - plugin: Plugin management (init, bundle, validate, publish, login, logout)
|
|
7509
7773
|
*/
|
|
7510
|
-
|
|
7511
|
-
|
|
7512
|
-
|
|
7513
|
-
|
|
7514
|
-
|
|
7515
|
-
|
|
7516
|
-
|
|
7517
|
-
|
|
7518
|
-
|
|
7519
|
-
|
|
7520
|
-
|
|
7521
|
-
|
|
7522
|
-
|
|
7523
|
-
|
|
7524
|
-
|
|
7525
|
-
|
|
7526
|
-
|
|
7527
|
-
|
|
7528
|
-
|
|
7529
|
-
|
|
7530
|
-
|
|
7531
|
-
|
|
7532
|
-
|
|
7533
|
-
|
|
7534
|
-
|
|
7535
|
-
|
|
7536
|
-
|
|
7537
|
-
|
|
7538
|
-
|
|
7539
|
-
}
|
|
7774
|
+
const builtInCommands = {
|
|
7775
|
+
init: initCommand,
|
|
7776
|
+
account: accountCommand,
|
|
7777
|
+
types: typesCommand,
|
|
7778
|
+
dev: devCommand,
|
|
7779
|
+
deploy: deployCommand,
|
|
7780
|
+
doctor: doctorCommand,
|
|
7781
|
+
seed: seedCommand,
|
|
7782
|
+
"export-seed": exportSeedCommand,
|
|
7783
|
+
secrets: secretsCommand,
|
|
7784
|
+
auth: authCommand,
|
|
7785
|
+
login: loginCommand,
|
|
7786
|
+
logout: logoutCommand,
|
|
7787
|
+
whoami: whoamiCommand,
|
|
7788
|
+
content: contentCommand,
|
|
7789
|
+
schema: schemaCommand,
|
|
7790
|
+
media: mediaCommand,
|
|
7791
|
+
search: searchCommand,
|
|
7792
|
+
seo: seoCommand,
|
|
7793
|
+
taxonomy: taxonomyCommand,
|
|
7794
|
+
menu: menuCommand,
|
|
7795
|
+
plugin: pluginCommand
|
|
7796
|
+
};
|
|
7797
|
+
async function createDinewayCliCommand(cwd = process.cwd()) {
|
|
7798
|
+
return defineCommand({
|
|
7799
|
+
meta: {
|
|
7800
|
+
name: "dineway",
|
|
7801
|
+
version: "0.0.0",
|
|
7802
|
+
description: "CLI for Dineway Agentic Web builder"
|
|
7803
|
+
},
|
|
7804
|
+
subCommands: mergeDinewayCliContributions(builtInCommands, await discoverDinewayCliContributions(cwd))
|
|
7805
|
+
});
|
|
7806
|
+
}
|
|
7807
|
+
createDinewayCliCommand().then((main) => runMain(main));
|
|
7540
7808
|
|
|
7541
7809
|
//#endregion
|
|
7542
|
-
export {
|
|
7810
|
+
export { createDinewayCliCommand };
|