@synteq/cli 0.2.0 → 1.1.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/api/client.d.ts +362 -5
- package/dist/api/client.js +559 -44
- package/dist/api/client.js.map +1 -1
- package/dist/api/factory.js +5 -2
- package/dist/api/factory.js.map +1 -1
- package/dist/api/types.d.ts +892 -3
- package/dist/apps-support/deploy.d.ts +197 -0
- package/dist/apps-support/deploy.js +639 -0
- package/dist/apps-support/deploy.js.map +1 -0
- package/dist/apps-support/dotenv.d.ts +67 -0
- package/dist/apps-support/dotenv.js +136 -0
- package/dist/apps-support/dotenv.js.map +1 -0
- package/dist/apps-support/env-rollout.d.ts +18 -0
- package/dist/apps-support/env-rollout.js +52 -0
- package/dist/apps-support/env-rollout.js.map +1 -0
- package/dist/apps-support/git.d.ts +14 -0
- package/dist/apps-support/git.js +25 -0
- package/dist/apps-support/git.js.map +1 -0
- package/dist/apps-support/link.d.ts +25 -0
- package/dist/apps-support/link.js +39 -0
- package/dist/apps-support/link.js.map +1 -0
- package/dist/apps-support/log-stream.d.ts +25 -0
- package/dist/apps-support/log-stream.js +85 -0
- package/dist/apps-support/log-stream.js.map +1 -0
- package/dist/apps-support/paid-app.d.ts +64 -0
- package/dist/apps-support/paid-app.js +195 -0
- package/dist/apps-support/paid-app.js.map +1 -0
- package/dist/apps-support/plans.d.ts +44 -0
- package/dist/apps-support/plans.js +43 -0
- package/dist/apps-support/plans.js.map +1 -0
- package/dist/apps-support/resolve.d.ts +10 -0
- package/dist/apps-support/resolve.js +53 -0
- package/dist/apps-support/resolve.js.map +1 -0
- package/dist/apps-support/time.d.ts +20 -0
- package/dist/apps-support/time.js +82 -0
- package/dist/apps-support/time.js.map +1 -0
- package/dist/auth/scope.js +4 -0
- package/dist/auth/scope.js.map +1 -1
- package/dist/auth/tokens.d.ts +3 -0
- package/dist/auth/tokens.js +6 -4
- package/dist/auth/tokens.js.map +1 -1
- package/dist/base/command.d.ts +35 -0
- package/dist/base/command.js +87 -4
- package/dist/base/command.js.map +1 -1
- package/dist/commands/agents.d.ts +10 -0
- package/dist/commands/agents.js +53 -0
- package/dist/commands/agents.js.map +1 -0
- package/dist/commands/api.d.ts +0 -1
- package/dist/commands/api.js +6 -5
- package/dist/commands/api.js.map +1 -1
- package/dist/commands/app/deployment/list.d.ts +14 -0
- package/dist/commands/app/deployment/list.js +45 -0
- package/dist/commands/app/deployment/list.js.map +1 -0
- package/dist/commands/app/deployment/rollback.d.ts +18 -0
- package/dist/commands/app/deployment/rollback.js +57 -0
- package/dist/commands/app/deployment/rollback.js.map +1 -0
- package/dist/commands/app/deployment/show.d.ts +26 -0
- package/dist/commands/app/deployment/show.js +98 -0
- package/dist/commands/app/deployment/show.js.map +1 -0
- package/dist/commands/app/domain/add.d.ts +17 -0
- package/dist/commands/app/domain/add.js +59 -0
- package/dist/commands/app/domain/add.js.map +1 -0
- package/dist/commands/app/domain/list.d.ts +14 -0
- package/dist/commands/app/domain/list.js +42 -0
- package/dist/commands/app/domain/list.js.map +1 -0
- package/dist/commands/app/domain/remove.d.ts +16 -0
- package/dist/commands/app/domain/remove.js +51 -0
- package/dist/commands/app/domain/remove.js.map +1 -0
- package/dist/commands/app/domain/verify.d.ts +15 -0
- package/dist/commands/app/domain/verify.js +39 -0
- package/dist/commands/app/domain/verify.js.map +1 -0
- package/dist/commands/app/env/add.d.ts +22 -0
- package/dist/commands/app/env/add.js +103 -0
- package/dist/commands/app/env/add.js.map +1 -0
- package/dist/commands/app/env/list.d.ts +17 -0
- package/dist/commands/app/env/list.js +40 -0
- package/dist/commands/app/env/list.js.map +1 -0
- package/dist/commands/app/env/reveal.d.ts +17 -0
- package/dist/commands/app/env/reveal.js +40 -0
- package/dist/commands/app/env/reveal.js.map +1 -0
- package/dist/commands/app/env/rm.d.ts +16 -0
- package/dist/commands/app/env/rm.js +48 -0
- package/dist/commands/app/env/rm.js.map +1 -0
- package/dist/commands/app/health.d.ts +14 -0
- package/dist/commands/app/health.js +40 -0
- package/dist/commands/app/health.js.map +1 -0
- package/dist/commands/app/index.d.ts +6 -0
- package/dist/commands/app/index.js +7 -0
- package/dist/commands/app/index.js.map +1 -0
- package/dist/commands/app/link.d.ts +22 -0
- package/dist/commands/app/link.js +31 -0
- package/dist/commands/app/link.js.map +1 -0
- package/dist/commands/app/logs.d.ts +25 -0
- package/dist/commands/app/logs.js +121 -0
- package/dist/commands/app/logs.js.map +1 -0
- package/dist/commands/app/metrics.d.ts +21 -0
- package/dist/commands/app/metrics.js +123 -0
- package/dist/commands/app/metrics.js.map +1 -0
- package/dist/commands/app/plan/change.d.ts +18 -0
- package/dist/commands/app/plan/change.js +79 -0
- package/dist/commands/app/plan/change.js.map +1 -0
- package/dist/commands/app/plan/show.d.ts +14 -0
- package/dist/commands/app/plan/show.js +40 -0
- package/dist/commands/app/plan/show.js.map +1 -0
- package/dist/commands/app/settings/set.d.ts +25 -0
- package/dist/commands/app/settings/set.js +96 -0
- package/dist/commands/app/settings/set.js.map +1 -0
- package/dist/commands/app/settings/show.d.ts +14 -0
- package/dist/commands/app/settings/show.js +48 -0
- package/dist/commands/app/settings/show.js.map +1 -0
- package/dist/commands/app/unlink.d.ts +8 -0
- package/dist/commands/app/unlink.js +25 -0
- package/dist/commands/app/unlink.js.map +1 -0
- package/dist/commands/apps/create.d.ts +26 -0
- package/dist/commands/apps/create.js +91 -0
- package/dist/commands/apps/create.js.map +1 -0
- package/dist/commands/apps/list.d.ts +16 -0
- package/dist/commands/apps/list.js +54 -0
- package/dist/commands/apps/list.js.map +1 -0
- package/dist/commands/baremetal/activity.d.ts +14 -0
- package/dist/commands/baremetal/activity.js +53 -0
- package/dist/commands/baremetal/activity.js.map +1 -0
- package/dist/commands/baremetal/bandwidth.d.ts +10 -0
- package/dist/commands/baremetal/bandwidth.js +86 -0
- package/dist/commands/baremetal/bandwidth.js.map +1 -0
- package/dist/commands/baremetal/console.d.ts +20 -0
- package/dist/commands/baremetal/console.js +72 -0
- package/dist/commands/baremetal/console.js.map +1 -0
- package/dist/commands/baremetal/details.d.ts +11 -0
- package/dist/commands/baremetal/details.js +116 -0
- package/dist/commands/baremetal/details.js.map +1 -0
- package/dist/commands/baremetal/index.d.ts +5 -0
- package/dist/commands/baremetal/index.js +6 -0
- package/dist/commands/baremetal/index.js.map +1 -0
- package/dist/commands/baremetal/install-password.d.ts +14 -0
- package/dist/commands/baremetal/install-password.js +80 -0
- package/dist/commands/baremetal/install-password.js.map +1 -0
- package/dist/commands/baremetal/list.d.ts +11 -0
- package/dist/commands/baremetal/list.js +59 -0
- package/dist/commands/baremetal/list.js.map +1 -0
- package/dist/commands/baremetal/order.d.ts +34 -0
- package/dist/commands/baremetal/order.js +394 -0
- package/dist/commands/baremetal/order.js.map +1 -0
- package/dist/commands/baremetal/power.d.ts +18 -0
- package/dist/commands/baremetal/power.js +168 -0
- package/dist/commands/baremetal/power.js.map +1 -0
- package/dist/commands/baremetal/reinstall.d.ts +21 -0
- package/dist/commands/baremetal/reinstall.js +168 -0
- package/dist/commands/baremetal/reinstall.js.map +1 -0
- package/dist/commands/config/profile/add.d.ts +11 -0
- package/dist/commands/config/profile/add.js +51 -0
- package/dist/commands/config/profile/add.js.map +1 -0
- package/dist/commands/config/profile/list.d.ts +7 -0
- package/dist/commands/config/profile/list.js +29 -0
- package/dist/commands/config/profile/list.js.map +1 -0
- package/dist/commands/config/profile/remove.d.ts +11 -0
- package/dist/commands/config/profile/remove.js +35 -0
- package/dist/commands/config/profile/remove.js.map +1 -0
- package/dist/commands/config/profile/use.d.ts +10 -0
- package/dist/commands/config/profile/use.js +44 -0
- package/dist/commands/config/profile/use.js.map +1 -0
- package/dist/commands/config/show.js +4 -1
- package/dist/commands/config/show.js.map +1 -1
- package/dist/commands/credits/add.js +2 -2
- package/dist/commands/credits/add.js.map +1 -1
- package/dist/commands/credits/index.js +5 -1
- package/dist/commands/credits/index.js.map +1 -1
- package/dist/commands/deploy.d.ts +51 -0
- package/dist/commands/deploy.js +515 -0
- package/dist/commands/deploy.js.map +1 -0
- package/dist/commands/function/create.d.ts +29 -0
- package/dist/commands/function/create.js +113 -0
- package/dist/commands/function/create.js.map +1 -0
- package/dist/commands/function/credits/add.d.ts +29 -0
- package/dist/commands/function/credits/add.js +209 -0
- package/dist/commands/function/credits/add.js.map +1 -0
- package/dist/commands/function/credits/auto-reload.d.ts +27 -0
- package/dist/commands/function/credits/auto-reload.js +107 -0
- package/dist/commands/function/credits/auto-reload.js.map +1 -0
- package/dist/commands/function/credits/index.d.ts +22 -0
- package/dist/commands/function/credits/index.js +80 -0
- package/dist/commands/function/credits/index.js.map +1 -0
- package/dist/commands/function/cron/add.d.ts +19 -0
- package/dist/commands/function/cron/add.js +74 -0
- package/dist/commands/function/cron/add.js.map +1 -0
- package/dist/commands/function/cron/list.d.ts +12 -0
- package/dist/commands/function/cron/list.js +55 -0
- package/dist/commands/function/cron/list.js.map +1 -0
- package/dist/commands/function/cron/rm.d.ts +17 -0
- package/dist/commands/function/cron/rm.js +73 -0
- package/dist/commands/function/cron/rm.js.map +1 -0
- package/dist/commands/function/cron/run.d.ts +16 -0
- package/dist/commands/function/cron/run.js +59 -0
- package/dist/commands/function/cron/run.js.map +1 -0
- package/dist/commands/function/cron/update.d.ts +21 -0
- package/dist/commands/function/cron/update.js +87 -0
- package/dist/commands/function/cron/update.js.map +1 -0
- package/dist/commands/function/delete.d.ts +23 -0
- package/dist/commands/function/delete.js +90 -0
- package/dist/commands/function/delete.js.map +1 -0
- package/dist/commands/function/deploy.d.ts +64 -0
- package/dist/commands/function/deploy.js +608 -0
- package/dist/commands/function/deploy.js.map +1 -0
- package/dist/commands/function/env/list.d.ts +12 -0
- package/dist/commands/function/env/list.js +46 -0
- package/dist/commands/function/env/list.js.map +1 -0
- package/dist/commands/function/env/reveal.d.ts +21 -0
- package/dist/commands/function/env/reveal.js +54 -0
- package/dist/commands/function/env/reveal.js.map +1 -0
- package/dist/commands/function/env/rm.d.ts +17 -0
- package/dist/commands/function/env/rm.js +62 -0
- package/dist/commands/function/env/rm.js.map +1 -0
- package/dist/commands/function/env/set.d.ts +28 -0
- package/dist/commands/function/env/set.js +124 -0
- package/dist/commands/function/env/set.js.map +1 -0
- package/dist/commands/function/index.d.ts +14 -0
- package/dist/commands/function/index.js +11 -0
- package/dist/commands/function/index.js.map +1 -0
- package/dist/commands/function/init.d.ts +47 -0
- package/dist/commands/function/init.js +269 -0
- package/dist/commands/function/init.js.map +1 -0
- package/dist/commands/function/invoke.d.ts +29 -0
- package/dist/commands/function/invoke.js +138 -0
- package/dist/commands/function/invoke.js.map +1 -0
- package/dist/commands/function/link.d.ts +23 -0
- package/dist/commands/function/link.js +80 -0
- package/dist/commands/function/link.js.map +1 -0
- package/dist/commands/function/list.d.ts +16 -0
- package/dist/commands/function/list.js +55 -0
- package/dist/commands/function/list.js.map +1 -0
- package/dist/commands/function/logs.d.ts +29 -0
- package/dist/commands/function/logs.js +171 -0
- package/dist/commands/function/logs.js.map +1 -0
- package/dist/commands/function/pause.d.ts +19 -0
- package/dist/commands/function/pause.js +50 -0
- package/dist/commands/function/pause.js.map +1 -0
- package/dist/commands/function/releases.d.ts +15 -0
- package/dist/commands/function/releases.js +62 -0
- package/dist/commands/function/releases.js.map +1 -0
- package/dist/commands/function/resume.d.ts +16 -0
- package/dist/commands/function/resume.js +47 -0
- package/dist/commands/function/resume.js.map +1 -0
- package/dist/commands/function/rollback.d.ts +18 -0
- package/dist/commands/function/rollback.js +69 -0
- package/dist/commands/function/rollback.js.map +1 -0
- package/dist/commands/function/settings/set.d.ts +23 -0
- package/dist/commands/function/settings/set.js +119 -0
- package/dist/commands/function/settings/set.js.map +1 -0
- package/dist/commands/function/show.d.ts +15 -0
- package/dist/commands/function/show.js +80 -0
- package/dist/commands/function/show.js.map +1 -0
- package/dist/commands/function/unlink.d.ts +9 -0
- package/dist/commands/function/unlink.js +34 -0
- package/dist/commands/function/unlink.js.map +1 -0
- package/dist/commands/link.d.ts +77 -0
- package/dist/commands/link.js +530 -0
- package/dist/commands/link.js.map +1 -0
- package/dist/commands/login.js +9 -0
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/order.js +3 -1
- package/dist/commands/order.js.map +1 -1
- package/dist/commands/payments/methods/delete.js +2 -2
- package/dist/commands/payments/methods/delete.js.map +1 -1
- package/dist/commands/resources.js +50 -7
- package/dist/commands/resources.js.map +1 -1
- package/dist/commands/status.d.ts +12 -0
- package/dist/commands/status.js +71 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/storage/detach.js +1 -1
- package/dist/commands/storage/detach.js.map +1 -1
- package/dist/commands/storage/list.js +6 -2
- package/dist/commands/storage/list.js.map +1 -1
- package/dist/commands/storage/order.d.ts +2 -0
- package/dist/commands/storage/order.js +100 -18
- package/dist/commands/storage/order.js.map +1 -1
- package/dist/commands/storage/resize.js +19 -6
- package/dist/commands/storage/resize.js.map +1 -1
- package/dist/commands/tickets/create.d.ts +2 -0
- package/dist/commands/tickets/create.js +40 -1
- package/dist/commands/tickets/create.js.map +1 -1
- package/dist/commands/tickets/download.d.ts +18 -0
- package/dist/commands/tickets/download.js +138 -0
- package/dist/commands/tickets/download.js.map +1 -0
- package/dist/commands/tickets/list.js +13 -7
- package/dist/commands/tickets/list.js.map +1 -1
- package/dist/commands/tickets/reply.d.ts +2 -0
- package/dist/commands/tickets/reply.js +33 -4
- package/dist/commands/tickets/reply.js.map +1 -1
- package/dist/commands/vds/order.js +72 -7
- package/dist/commands/vds/order.js.map +1 -1
- package/dist/commands/vps/console.js +14 -6
- package/dist/commands/vps/console.js.map +1 -1
- package/dist/commands/vps/details.js +7 -1
- package/dist/commands/vps/details.js.map +1 -1
- package/dist/commands/vps/ip/add.js +76 -9
- package/dist/commands/vps/ip/add.js.map +1 -1
- package/dist/commands/vps/list.js +13 -4
- package/dist/commands/vps/list.js.map +1 -1
- package/dist/commands/vps/order.d.ts +19 -0
- package/dist/commands/vps/order.js +179 -23
- package/dist/commands/vps/order.js.map +1 -1
- package/dist/commands/vps/power.js +2 -2
- package/dist/commands/vps/power.js.map +1 -1
- package/dist/commands/vps/reinstall.js +2 -2
- package/dist/commands/vps/reinstall.js.map +1 -1
- package/dist/commands/vps/resize.js +36 -13
- package/dist/commands/vps/resize.js.map +1 -1
- package/dist/commands/whoami.d.ts +5 -0
- package/dist/commands/whoami.js +8 -3
- package/dist/commands/whoami.js.map +1 -1
- package/dist/config/paths.d.ts +1 -1
- package/dist/config/paths.js +6 -1
- package/dist/config/paths.js.map +1 -1
- package/dist/config/store.d.ts +58 -0
- package/dist/config/store.js +84 -2
- package/dist/config/store.js.map +1 -1
- package/dist/functions-support/credits.d.ts +64 -0
- package/dist/functions-support/credits.js +181 -0
- package/dist/functions-support/credits.js.map +1 -0
- package/dist/functions-support/cron.d.ts +17 -0
- package/dist/functions-support/cron.js +99 -0
- package/dist/functions-support/cron.js.map +1 -0
- package/dist/functions-support/env.d.ts +23 -0
- package/dist/functions-support/env.js +44 -0
- package/dist/functions-support/env.js.map +1 -0
- package/dist/functions-support/link.d.ts +25 -0
- package/dist/functions-support/link.js +51 -0
- package/dist/functions-support/link.js.map +1 -0
- package/dist/functions-support/poll.d.ts +40 -0
- package/dist/functions-support/poll.js +109 -0
- package/dist/functions-support/poll.js.map +1 -0
- package/dist/functions-support/resolve.d.ts +3 -0
- package/dist/functions-support/resolve.js +31 -0
- package/dist/functions-support/resolve.js.map +1 -0
- package/dist/functions-support/runtime.d.ts +30 -0
- package/dist/functions-support/runtime.js +52 -0
- package/dist/functions-support/runtime.js.map +1 -0
- package/dist/functions-support/source.d.ts +92 -0
- package/dist/functions-support/source.js +343 -0
- package/dist/functions-support/source.js.map +1 -0
- package/dist/help/scope-aware-help.js +10 -1
- package/dist/help/scope-aware-help.js.map +1 -1
- package/dist/tui/App.js +10 -25
- package/dist/tui/App.js.map +1 -1
- package/dist/tui/components/Menu.d.ts +3 -1
- package/dist/tui/components/Menu.js +7 -3
- package/dist/tui/components/Menu.js.map +1 -1
- package/dist/tui/router.d.ts +1 -1
- package/dist/tui/router.js.map +1 -1
- package/dist/tui/screens/Billing.js +56 -4
- package/dist/tui/screens/Billing.js.map +1 -1
- package/dist/tui/screens/Dashboard.js +8 -7
- package/dist/tui/screens/Dashboard.js.map +1 -1
- package/dist/tui/screens/Deploy.d.ts +2 -0
- package/dist/tui/screens/Deploy.js +912 -0
- package/dist/tui/screens/Deploy.js.map +1 -0
- package/dist/tui/screens/Order.js +359 -26
- package/dist/tui/screens/Order.js.map +1 -1
- package/dist/tui/screens/Resources.js +273 -31
- package/dist/tui/screens/Resources.js.map +1 -1
- package/dist/tui/screens/Tickets.js +18 -6
- package/dist/tui/screens/Tickets.js.map +1 -1
- package/dist/tui/screens/deployPreset.d.ts +20 -0
- package/dist/tui/screens/deployPreset.js +11 -0
- package/dist/tui/screens/deployPreset.js.map +1 -0
- package/dist/tui/screens/resources/AppDetail.d.ts +7 -0
- package/dist/tui/screens/resources/AppDetail.js +810 -0
- package/dist/tui/screens/resources/AppDetail.js.map +1 -0
- package/dist/tui/screens/resources/FunctionDetail.d.ts +7 -0
- package/dist/tui/screens/resources/FunctionDetail.js +751 -0
- package/dist/tui/screens/resources/FunctionDetail.js.map +1 -0
- package/dist/ui/attach.d.ts +15 -0
- package/dist/ui/attach.js +63 -0
- package/dist/ui/attach.js.map +1 -0
- package/dist/ui/baremetal-resolve.d.ts +10 -0
- package/dist/ui/baremetal-resolve.js +50 -0
- package/dist/ui/baremetal-resolve.js.map +1 -0
- package/dist/ui/confirm.js +1 -1
- package/dist/ui/confirm.js.map +1 -1
- package/dist/ui/cycle.d.ts +66 -0
- package/dist/ui/cycle.js +96 -0
- package/dist/ui/cycle.js.map +1 -0
- package/dist/ui/deploy-ui.d.ts +75 -0
- package/dist/ui/deploy-ui.js +243 -0
- package/dist/ui/deploy-ui.js.map +1 -0
- package/dist/ui/order-result.d.ts +4 -0
- package/dist/ui/order-result.js +32 -0
- package/dist/ui/order-result.js.map +1 -0
- package/dist/ui/payment-gate.d.ts +26 -0
- package/dist/ui/payment-gate.js +70 -0
- package/dist/ui/payment-gate.js.map +1 -0
- package/dist/ui/payment.js +10 -3
- package/dist/ui/payment.js.map +1 -1
- package/dist/ui/portal.d.ts +1 -1
- package/dist/ui/portal.js +7 -2
- package/dist/ui/portal.js.map +1 -1
- package/dist/ui/project-resolve.d.ts +25 -0
- package/dist/ui/project-resolve.js +31 -0
- package/dist/ui/project-resolve.js.map +1 -0
- package/dist/ui/render-mode.d.ts +5 -0
- package/dist/ui/render-mode.js +1 -1
- package/dist/ui/render-mode.js.map +1 -1
- package/dist/ui/resource-detail.js +0 -3
- package/dist/ui/resource-detail.js.map +1 -1
- package/dist/ui/resource-resolve.d.ts +9 -2
- package/dist/ui/resource-resolve.js +11 -4
- package/dist/ui/resource-resolve.js.map +1 -1
- package/dist/ui/spinner.d.ts +10 -1
- package/dist/ui/spinner.js +12 -3
- package/dist/ui/spinner.js.map +1 -1
- package/dist/ui/table.d.ts +7 -0
- package/dist/ui/table.js +11 -0
- package/dist/ui/table.js.map +1 -1
- package/dist/ui/tax.d.ts +10 -0
- package/dist/ui/tax.js +31 -0
- package/dist/ui/tax.js.map +1 -0
- package/dist/ui/ticket-resolve.d.ts +9 -1
- package/dist/ui/ticket-resolve.js +13 -2
- package/dist/ui/ticket-resolve.js.map +1 -1
- package/dist/ui/volume-resolve.js +4 -1
- package/dist/ui/volume-resolve.js.map +1 -1
- package/dist/ui/wait.d.ts +4 -0
- package/dist/ui/wait.js +7 -2
- package/dist/ui/wait.js.map +1 -1
- package/dist/ui/wizard.d.ts +2 -1
- package/dist/ui/wizard.js +1 -1
- package/dist/ui/wizard.js.map +1 -1
- package/dist/version-check-bin.js +2 -2
- package/dist/version-check-bin.js.map +1 -1
- package/dist/version-check.d.ts +5 -0
- package/dist/version-check.js +6 -1
- package/dist/version-check.js.map +1 -1
- package/package.json +53 -6
|
@@ -0,0 +1,608 @@
|
|
|
1
|
+
import { Args, Flags } from "@oclif/core";
|
|
2
|
+
import { existsSync, statSync } from "node:fs";
|
|
3
|
+
import { resolve, basename } from "node:path";
|
|
4
|
+
import { BaseCommand } from "../../base/command.js";
|
|
5
|
+
import { resolveLinkedFunction, notLinkedFunctionError } from "../../functions-support/link.js";
|
|
6
|
+
import FunctionInit from "./init.js";
|
|
7
|
+
import { slugify } from "../link.js";
|
|
8
|
+
import { RUNTIMES } from "../../functions-support/runtime.js";
|
|
9
|
+
import { ensurePaymentMethod, PaymentMethodRequired } from "../../ui/payment-gate.js";
|
|
10
|
+
import { collectSourceFiles, tarballFromFiles, EDITOR_MAX_FILES, MAX_TOTAL_BYTES, SourceTooLargeError, SourceTooManyFilesError, } from "../../functions-support/source.js";
|
|
11
|
+
import { waitForBuild, waitForRelease, DeployTimeoutError } from "../../functions-support/poll.js";
|
|
12
|
+
import { inferRuntime } from "../../functions-support/runtime.js";
|
|
13
|
+
import { buildProgress, deployedCard, failedCard, deploymentUrl } from "../../ui/deploy-ui.js";
|
|
14
|
+
import { withSpinner } from "../../ui/spinner.js";
|
|
15
|
+
import { importDotenv, offerDotenv } from "../../apps-support/dotenv.js";
|
|
16
|
+
import { ApiError } from "../../api/errors.js";
|
|
17
|
+
import { portalUrl } from "../../ui/portal.js";
|
|
18
|
+
import { dim, ok, statusColor, G } from "../../ui/glyphs.js";
|
|
19
|
+
import { parseEnvAssignment } from "../../functions-support/env.js";
|
|
20
|
+
const ENV_KEY_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
21
|
+
import { normalizeSchedule, shortTriggerId } from "../../functions-support/cron.js";
|
|
22
|
+
import { isInteractive, confirmAction, pickFromCatalog, promptString } from "../../ui/wizard.js";
|
|
23
|
+
/** One-line function plan description: resources + the metered prices. */
|
|
24
|
+
function fnPlanLine(p) {
|
|
25
|
+
const cpu = p.cpuMillicores ? `${(p.cpuMillicores / 1000).toFixed(p.cpuMillicores % 1000 ? 1 : 0)} vCPU` : "";
|
|
26
|
+
const mem = p.memoryMib ? `${p.memoryMib} MiB` : "";
|
|
27
|
+
const inv = p.pricePerMillionInvocationsUsd != null ? `$${p.pricePerMillionInvocationsUsd}/M runs` : "";
|
|
28
|
+
const gbs = p.pricePerGbSecondUsd != null ? `$${p.pricePerGbSecondUsd}/GB·s` : "";
|
|
29
|
+
return [cpu, mem, inv, gbs].filter(Boolean).join(" · ");
|
|
30
|
+
}
|
|
31
|
+
/** Sentinel picker value for the "create a new function" row. */
|
|
32
|
+
const CREATE = "__create__";
|
|
33
|
+
/** Human wording for each reason collectSourceFiles reports a skip. */
|
|
34
|
+
const SKIP_REASON = {
|
|
35
|
+
binary: "binary file",
|
|
36
|
+
"too-large": "larger than the source limit on its own",
|
|
37
|
+
ignored: "excluded",
|
|
38
|
+
dotenv: "never packed — set variables with `synteq function env set`, `--env-file`, or the Environment tab",
|
|
39
|
+
symlink: "symlink (not followed)",
|
|
40
|
+
"bad-path": "path the backend won't accept",
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* `synteq function deploy` — upload this directory's source and roll it out,
|
|
44
|
+
* or roll out a pre-built image with `--image <ref>`.
|
|
45
|
+
*
|
|
46
|
+
* Backend: POST /functions/{id}/deploys/source — the files inline when the
|
|
47
|
+
* tree fits the editor's 32-file shape (so the portal editor can reopen it),
|
|
48
|
+
* else a gzipped tarball (`sourceB64`) bounded only by the function's source
|
|
49
|
+
* caps (`maxSourceBytes` / `maxSourceFiles` on the row). The server decides the build path (Dockerfile / bundle) itself and
|
|
50
|
+
* returns the build row. The deploy then has two phases the CLI follows: the
|
|
51
|
+
* BUILD reaches succeeded/failed, then the status cron mints a RELEASE and
|
|
52
|
+
* flips it current once the function is live. `--image` is the apps
|
|
53
|
+
* `deploy --image` route, function-owned (POST /functions/{id}/deploys): no
|
|
54
|
+
* source, a pull Build the same two phases follow.
|
|
55
|
+
*/
|
|
56
|
+
export default class FunctionDeploy extends BaseCommand {
|
|
57
|
+
static apiKeyScope = "none";
|
|
58
|
+
static description = [
|
|
59
|
+
"Deploy a function from a local source directory or a pre-built image.",
|
|
60
|
+
"",
|
|
61
|
+
"Uploads the directory's text files (node_modules, .git, build output, .env",
|
|
62
|
+
"files and anything a .synteqignore excludes are left out), then follows the build",
|
|
63
|
+
"and the release it produces, printing each status transition. Ctrl-C stops",
|
|
64
|
+
"watching; the deploy keeps running server-side. `--image <ref>` skips the",
|
|
65
|
+
"upload: the platform pulls the image and rolls it out the same way.",
|
|
66
|
+
"",
|
|
67
|
+
"First run (an unlinked directory on a TTY): pick one of the project's",
|
|
68
|
+
"functions to link, or create one — name, plan, location, then optional env",
|
|
69
|
+
"vars and a cron trigger. --env/--secret/--cron do the same from the command",
|
|
70
|
+
"line, with --create, --name or a linked directory; they are applied before",
|
|
71
|
+
"the build starts, so the release carries them. If one of those fails, the",
|
|
72
|
+
"deploy stops before the build; whatever was already set stays set.",
|
|
73
|
+
"",
|
|
74
|
+
"On a function that already has a release, --env/--secret reach the server",
|
|
75
|
+
"before the build, and the server rolls env changes out after 120 s. A build",
|
|
76
|
+
"that takes longer can first mint an \"Environment change\" release of the",
|
|
77
|
+
"old image, then the new release: two releases, two restarts. The first",
|
|
78
|
+
"deploy of a new function is unaffected.",
|
|
79
|
+
].join("\n");
|
|
80
|
+
static examples = [
|
|
81
|
+
"<%= config.bin %> function deploy # first run on a TTY: pick a function, or create one (name → plan → location → env → cron), then deploy",
|
|
82
|
+
"<%= config.bin %> function deploy --create my-fn --runtime node22 --plan nano --location dfw # scripted first run, no prompts",
|
|
83
|
+
'<%= config.bin %> function deploy --create my-fn --env LOG_LEVEL=info --secret API_KEY=sk-abc --cron "*/15 * * * *"',
|
|
84
|
+
"<%= config.bin %> function deploy # bare: this directory's linked function",
|
|
85
|
+
"<%= config.bin %> function deploy --name my-fn",
|
|
86
|
+
"<%= config.bin %> function deploy --name my-fn --dir ./api",
|
|
87
|
+
"<%= config.bin %> function deploy --env-file .env.production # import that file's variables onto the function first, no prompt",
|
|
88
|
+
"<%= config.bin %> function deploy --name my-fn --image docker.io/library/nginx:1.27-alpine # pre-built image, no upload",
|
|
89
|
+
"<%= config.bin %> function deploy --name my-fn --no-wait # fire-and-forget; returns the build row",
|
|
90
|
+
"<%= config.bin %> function deploy --name my-fn -o json",
|
|
91
|
+
];
|
|
92
|
+
static args = {
|
|
93
|
+
target: Args.string({ required: false, description: "Function slug or id (optional; default: the directory's linked function or --name)." }),
|
|
94
|
+
};
|
|
95
|
+
static flags = {
|
|
96
|
+
name: Flags.string({
|
|
97
|
+
description: "Function slug (or uuid) to deploy (default: the function this directory is linked to via `synteq function init`).",
|
|
98
|
+
}),
|
|
99
|
+
create: Flags.string({
|
|
100
|
+
description: "Create a function with this name (or reuse one of that name), link this directory to it, and deploy — the scripted first run. Pair with --runtime, --plan and --location.",
|
|
101
|
+
}),
|
|
102
|
+
runtime: Flags.string({
|
|
103
|
+
options: [...RUNTIMES],
|
|
104
|
+
description: `Runtime for --create: ${RUNTIMES.join(" or ")} (default: what the directory's files imply, else node22).`,
|
|
105
|
+
}),
|
|
106
|
+
plan: Flags.string({
|
|
107
|
+
description: "Plan tier for --create (default: the first tier in the catalog).",
|
|
108
|
+
}),
|
|
109
|
+
location: Flags.string({
|
|
110
|
+
description: "Location code for --create, e.g. dfw (default: the first location).",
|
|
111
|
+
}),
|
|
112
|
+
project: Flags.string({
|
|
113
|
+
description: "Project id for --create, and the project whose functions the first-run picker lists (default: the active project).",
|
|
114
|
+
}),
|
|
115
|
+
dir: Flags.string({
|
|
116
|
+
description: "Directory to upload as the function's source (default: the current directory).",
|
|
117
|
+
}),
|
|
118
|
+
image: Flags.string({
|
|
119
|
+
description: "Pre-built image reference to roll out, registry host included (mutually exclusive with --dir; no source is uploaded).",
|
|
120
|
+
}),
|
|
121
|
+
"no-wait": Flags.boolean({
|
|
122
|
+
description: "Return as soon as the build is triggered; don't follow it to completion.",
|
|
123
|
+
}),
|
|
124
|
+
"poll-interval": Flags.integer({
|
|
125
|
+
default: 3,
|
|
126
|
+
description: "Seconds between build/release polls (default: 3, min: 2).",
|
|
127
|
+
}),
|
|
128
|
+
timeout: Flags.integer({
|
|
129
|
+
default: 600,
|
|
130
|
+
description: "Max seconds to wait for the build and release (default: 600).",
|
|
131
|
+
}),
|
|
132
|
+
env: Flags.string({
|
|
133
|
+
multiple: true,
|
|
134
|
+
description: "Config env var KEY=VALUE to set before the build (repeatable). Works with --create, --name or a linked directory.",
|
|
135
|
+
}),
|
|
136
|
+
secret: Flags.string({
|
|
137
|
+
multiple: true,
|
|
138
|
+
description: "Secret env var KEY=VALUE to set before the build (repeatable; reveal is masked). Works with --create, --name or a linked directory.",
|
|
139
|
+
}),
|
|
140
|
+
cron: Flags.string({
|
|
141
|
+
description: 'Cron trigger to add before the build: a quoted 5-field expression in UTC, e.g. "*/15 * * * *".',
|
|
142
|
+
}),
|
|
143
|
+
yes: Flags.boolean({
|
|
144
|
+
char: "y",
|
|
145
|
+
description: "Deploy without confirming when the directory looks like a different runtime than the function is configured for (non-interactive runs never pause).",
|
|
146
|
+
}),
|
|
147
|
+
"env-file": Flags.string({
|
|
148
|
+
description: "Import this .env's KEY=VALUE lines as variables on the function before the build (runtime secrets unless a `# scope=… kind=…` comment above a line says otherwise); no question asked. A .env is never packed, and a plain deploy never asks about it.",
|
|
149
|
+
}),
|
|
150
|
+
};
|
|
151
|
+
/** The argv `function init` runs with on a first deploy: --create's values
|
|
152
|
+
* verbatim, else what the user picks. Runtime comes from the directory's
|
|
153
|
+
* files when they say (init infers it too; passing it keeps the two in
|
|
154
|
+
* step when the user overrides). */
|
|
155
|
+
async firstRunArgs(dir, flags, interactive) {
|
|
156
|
+
let name = flags.create ? slugify(flags.create) : "";
|
|
157
|
+
let plan = flags.plan;
|
|
158
|
+
let location = flags.location;
|
|
159
|
+
const runtime = flags.runtime;
|
|
160
|
+
if (!flags.create) {
|
|
161
|
+
name = slugify(await promptString("Function name", {
|
|
162
|
+
default: slugify(basename(dir)),
|
|
163
|
+
validate: (s) => (slugify(s).length >= 1 ? true : "Give it a name."),
|
|
164
|
+
}));
|
|
165
|
+
}
|
|
166
|
+
if (interactive && !plan) {
|
|
167
|
+
const plans = await this.clients.api.functions.plans().catch(() => []);
|
|
168
|
+
if (plans.length > 1) {
|
|
169
|
+
const items = plans.map((p) => ({
|
|
170
|
+
value: p.name,
|
|
171
|
+
name: p.displayName ?? p.name,
|
|
172
|
+
description: fnPlanLine(p),
|
|
173
|
+
}));
|
|
174
|
+
plan = await pickFromCatalog("Plan", items, { defaultValue: plans[0].name });
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
if (interactive && !location) {
|
|
178
|
+
const locations = await this.clients.api.functions.locations().catch(() => []);
|
|
179
|
+
if (locations.length > 1) {
|
|
180
|
+
location = await pickFromCatalog("Primary location", locations.map((l) => ({ value: l.code, name: l.city, description: l.code })));
|
|
181
|
+
}
|
|
182
|
+
else if (locations.length === 1) {
|
|
183
|
+
this.log(dim(`Primary location: ${locations[0].city} (${locations[0].code})`));
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
const argv = [name, "--dir", dir, "--from-deploy"];
|
|
187
|
+
if (flags.image)
|
|
188
|
+
argv.push("--no-scaffold");
|
|
189
|
+
if (runtime)
|
|
190
|
+
argv.push("--runtime", runtime);
|
|
191
|
+
if (plan)
|
|
192
|
+
argv.push("--plan", plan);
|
|
193
|
+
if (location)
|
|
194
|
+
argv.push("--location", location);
|
|
195
|
+
if (flags.project)
|
|
196
|
+
argv.push("--project", flags.project);
|
|
197
|
+
if (this.outputFormat === "json")
|
|
198
|
+
argv.push("-o", "json");
|
|
199
|
+
return argv;
|
|
200
|
+
}
|
|
201
|
+
/** Step 0 of the first run — the apps `pickOrCreateApp` shape: link one of
|
|
202
|
+
* the project's functions, or null for "Create a new function…". No
|
|
203
|
+
* functions at all goes straight to create. */
|
|
204
|
+
async pickExistingFunction(projectId) {
|
|
205
|
+
const fns = await withSpinner("Loading functions", () => this.clients.api.functions.list(projectId));
|
|
206
|
+
if (fns.length === 0)
|
|
207
|
+
return null;
|
|
208
|
+
const items = [
|
|
209
|
+
...fns.map((f) => ({
|
|
210
|
+
value: f.id,
|
|
211
|
+
name: f.slug,
|
|
212
|
+
description: `${f.status} · ${f.runtime} · ${f.region}`,
|
|
213
|
+
})),
|
|
214
|
+
{
|
|
215
|
+
value: CREATE,
|
|
216
|
+
name: "Create a new function…",
|
|
217
|
+
description: "Name, plan and location; optional env vars and a cron trigger.",
|
|
218
|
+
},
|
|
219
|
+
];
|
|
220
|
+
const choice = await pickFromCatalog("Which function should this directory deploy?", items);
|
|
221
|
+
return choice === CREATE ? null : fns.find((f) => f.id === choice);
|
|
222
|
+
}
|
|
223
|
+
/** The two optional steps after location on a created function: env vars
|
|
224
|
+
* (the apps walkthrough's shape — confirm, then name → value → secret?
|
|
225
|
+
* until a blank name) and a cron trigger (blank for none). Each is
|
|
226
|
+
* skipped when its flags already answered it. */
|
|
227
|
+
async promptFirstRunExtras(dir, have) {
|
|
228
|
+
const env = [];
|
|
229
|
+
// A .env in the directory first — this is the one place it is offered.
|
|
230
|
+
// Scope is runtime (what applySetup saves); kind follows the file.
|
|
231
|
+
if (!have.env) {
|
|
232
|
+
const rows = await offerDotenv({ dir, target: "the new function", log: (l) => this.log(l) });
|
|
233
|
+
env.push(...rows.map((r) => ({ key: r.key, value: r.value, kind: r.kind ?? "secret" })));
|
|
234
|
+
}
|
|
235
|
+
if (!have.env && (await confirmAction(env.length ? "Add more variables?" : "Set environment variables now?"))) {
|
|
236
|
+
this.log(dim("Secrets are masked after saving; config values can be revealed in full."));
|
|
237
|
+
for (;;) {
|
|
238
|
+
const key = await promptString("Variable name (blank to finish)", {
|
|
239
|
+
allowEmpty: true,
|
|
240
|
+
validate: (s) => ENV_KEY_RE.test(s.trim()) ? true : "Letters, digits and underscores; can't start with a digit.",
|
|
241
|
+
});
|
|
242
|
+
if (!key.trim())
|
|
243
|
+
break;
|
|
244
|
+
const value = await promptString(`Value for ${key.trim()}`, { allowEmpty: true });
|
|
245
|
+
const secret = await confirmAction(`Is ${key.trim()} a secret?`, false);
|
|
246
|
+
env.push({ key: key.trim(), value, kind: secret ? "secret" : "config" });
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
let cron;
|
|
250
|
+
if (!have.cron) {
|
|
251
|
+
const raw = await promptString("Cron trigger (5-field UTC, blank for none)", {
|
|
252
|
+
allowEmpty: true,
|
|
253
|
+
validate: (s) => {
|
|
254
|
+
try {
|
|
255
|
+
normalizeSchedule(s);
|
|
256
|
+
return true;
|
|
257
|
+
}
|
|
258
|
+
catch (e) {
|
|
259
|
+
return e.message;
|
|
260
|
+
}
|
|
261
|
+
},
|
|
262
|
+
});
|
|
263
|
+
if (raw.trim())
|
|
264
|
+
cron = normalizeSchedule(raw);
|
|
265
|
+
}
|
|
266
|
+
return { env, cron };
|
|
267
|
+
}
|
|
268
|
+
/** Set the env vars (same call `function env set` makes) and add the cron
|
|
269
|
+
* trigger (same call `function cron add` makes) — before the build, so
|
|
270
|
+
* the release it produces carries them. */
|
|
271
|
+
async applySetup(fn, env, cron) {
|
|
272
|
+
const table = this.outputFormat === "table";
|
|
273
|
+
for (const v of env) {
|
|
274
|
+
const saved = await withSpinner(`Setting ${v.key}`, () => this.clients.api.functions.setEnv(fn.id, { key: v.key, value: v.value, kind: v.kind, scope: "runtime" }));
|
|
275
|
+
if (table)
|
|
276
|
+
this.log(ok(`Set ${saved.key} on ${fn.slug} ${dim(`(${saved.kind} · ${saved.scope})`)}`));
|
|
277
|
+
}
|
|
278
|
+
if (cron) {
|
|
279
|
+
// Idempotent: a scripted deploy re-run on every push (or a linked dir
|
|
280
|
+
// deployed with --cron again) must not stack a second trigger on the
|
|
281
|
+
// same schedule — the backend doesn't dedupe, so each copy would fire
|
|
282
|
+
// (and bill) every tick until the per-function cap 422s the deploy.
|
|
283
|
+
const existing = await this.clients.api.functions.cronTriggers(fn.id);
|
|
284
|
+
const same = existing.find((t) => t.schedule.trim().replace(/\s+/g, " ") === cron);
|
|
285
|
+
if (same) {
|
|
286
|
+
if (table) {
|
|
287
|
+
this.log(dim(`Cron ${cron} (UTC) is already scheduled on ${fn.slug} (trigger ${shortTriggerId(same.id)}).`));
|
|
288
|
+
}
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
const trigger = await withSpinner("Adding cron trigger", () => this.clients.api.functions.createCronTrigger(fn.id, {
|
|
292
|
+
schedule: cron,
|
|
293
|
+
enabled: true,
|
|
294
|
+
retries: 0,
|
|
295
|
+
description: null,
|
|
296
|
+
}));
|
|
297
|
+
if (table) {
|
|
298
|
+
this.log(ok(`Added cron trigger ${shortTriggerId(trigger.id)} to ${fn.slug}: ${trigger.schedule} (UTC).`));
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
async run() {
|
|
303
|
+
await this.initClients();
|
|
304
|
+
const { args, flags: rawFlags } = await this.parse(FunctionDeploy);
|
|
305
|
+
const flags = { ...rawFlags, name: args.target ?? rawFlags.name };
|
|
306
|
+
try {
|
|
307
|
+
const dir = resolve(flags.dir && flags.dir !== "" ? flags.dir : ".");
|
|
308
|
+
if (!existsSync(dir) || !statSync(dir).isDirectory()) {
|
|
309
|
+
this.error(`Not a directory: ${dir}`, { exit: 1 });
|
|
310
|
+
}
|
|
311
|
+
if (flags.create && flags.name) {
|
|
312
|
+
this.error("Pass either --create <name> or --name <slug>, not both.", { exit: 1 });
|
|
313
|
+
}
|
|
314
|
+
if (flags.image && flags.dir) {
|
|
315
|
+
this.error("Pass either --image or --dir, not both.", { exit: 1 });
|
|
316
|
+
}
|
|
317
|
+
// --env / --secret / --cron are checked before anything is created, so
|
|
318
|
+
// a typo never leaves a half-set-up function behind.
|
|
319
|
+
let env = [];
|
|
320
|
+
let cron;
|
|
321
|
+
const parseFlag = (flag, raw, kind) => {
|
|
322
|
+
try {
|
|
323
|
+
return parseEnvAssignment(raw, kind);
|
|
324
|
+
}
|
|
325
|
+
catch (e) {
|
|
326
|
+
this.error(`--${flag}: ${e.message}`, { exit: 1 });
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
env = [
|
|
330
|
+
...(flags.env ?? []).map((a) => parseFlag("env", a, "config")),
|
|
331
|
+
...(flags.secret ?? []).map((a) => parseFlag("secret", a, "secret")),
|
|
332
|
+
];
|
|
333
|
+
try {
|
|
334
|
+
cron = flags.cron !== undefined ? normalizeSchedule(flags.cron) : undefined;
|
|
335
|
+
}
|
|
336
|
+
catch (e) {
|
|
337
|
+
this.error(`--cron: ${e.message}`, { exit: 1 });
|
|
338
|
+
}
|
|
339
|
+
// First run: nothing linked and no --name. On a TTY, pick one of the
|
|
340
|
+
// project's functions to link, or set a new one up right here (name →
|
|
341
|
+
// plan → location → env → cron; runtime from the files) and carry on
|
|
342
|
+
// into the deploy — one command. --create is the same thing with every
|
|
343
|
+
// answer on the command line, so scripts never prompt.
|
|
344
|
+
const interactive = isInteractive() && this.outputFormat === "table";
|
|
345
|
+
const linked = this.clients.config.linkFor(dir);
|
|
346
|
+
const firstRun = !flags.create && !flags.name && !linked && interactive;
|
|
347
|
+
let existing = null;
|
|
348
|
+
if (firstRun) {
|
|
349
|
+
this.log(dim("No function is linked to this directory yet — set it up, then the deploy runs."));
|
|
350
|
+
existing = await this.pickExistingFunction(flags.project ?? this.clients.config.get().default_project_id ?? undefined);
|
|
351
|
+
}
|
|
352
|
+
if (existing) {
|
|
353
|
+
// Link it exactly as `function init <slug>` would (init reuses an
|
|
354
|
+
// existing function and writes the same link record) — no scaffold:
|
|
355
|
+
// this directory's files are what gets deployed.
|
|
356
|
+
const argv = [existing.id, "--dir", dir, "--from-deploy", "--no-scaffold"];
|
|
357
|
+
if (flags.project)
|
|
358
|
+
argv.push("--project", flags.project);
|
|
359
|
+
await FunctionInit.run(argv, this.config);
|
|
360
|
+
this.clients.config.reload();
|
|
361
|
+
this.log("");
|
|
362
|
+
}
|
|
363
|
+
else if (flags.create || firstRun) {
|
|
364
|
+
const argv = await this.firstRunArgs(dir, flags, interactive);
|
|
365
|
+
if (firstRun) {
|
|
366
|
+
const extras = await this.promptFirstRunExtras(dir, {
|
|
367
|
+
env: env.length > 0,
|
|
368
|
+
cron: cron !== undefined,
|
|
369
|
+
});
|
|
370
|
+
env = [...env, ...extras.env];
|
|
371
|
+
cron = cron ?? extras.cron;
|
|
372
|
+
}
|
|
373
|
+
await FunctionInit.run(argv, this.config);
|
|
374
|
+
// init wrote the link through its own ConfigStore; pick it up here.
|
|
375
|
+
this.clients.config.reload();
|
|
376
|
+
if (interactive)
|
|
377
|
+
this.log("");
|
|
378
|
+
}
|
|
379
|
+
const { fn, clients } = await resolveLinkedFunction(this.clients, flags, dir).catch((e) => {
|
|
380
|
+
if (e instanceof Error && !("status" in e)) {
|
|
381
|
+
this.error(flags.create || interactive ? e.message : notLinkedFunctionError("--name <slug>, or --create <name>"), { exit: 1 });
|
|
382
|
+
}
|
|
383
|
+
throw e;
|
|
384
|
+
});
|
|
385
|
+
this.clients = clients;
|
|
386
|
+
// Every deploy needs a payment method on the team, free tier included.
|
|
387
|
+
// (A just-created function was gated at create; this is the cheap
|
|
388
|
+
// re-check for a directory linked long ago.)
|
|
389
|
+
await ensurePaymentMethod({
|
|
390
|
+
api: this.clients.api,
|
|
391
|
+
apiBaseUrl: this.clients.config.get().api_base_url,
|
|
392
|
+
interactive,
|
|
393
|
+
log: (l) => this.log(l),
|
|
394
|
+
}).catch((e) => {
|
|
395
|
+
if (e instanceof PaymentMethodRequired)
|
|
396
|
+
this.error(e.message, { exit: 1 });
|
|
397
|
+
throw e;
|
|
398
|
+
});
|
|
399
|
+
// --image: no tree to collect or check; the env/cron setup and the
|
|
400
|
+
// follow below are the same as for a source deploy.
|
|
401
|
+
if (flags.image) {
|
|
402
|
+
await this.applySetup(fn, env, cron);
|
|
403
|
+
const build = await withSpinner("Triggering deploy", () => this.clients.api.functions.deployImage(fn.id, flags.image));
|
|
404
|
+
await this.follow(fn, build, [], flags);
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
// 1. Collect the tree against the backend's LIVE caps (the row carries
|
|
408
|
+
// them; older backends don't, and the collector's fallbacks are the
|
|
409
|
+
// backend's defaults). A too-large tree is a user error with a
|
|
410
|
+
// message that already names the offenders.
|
|
411
|
+
let collected;
|
|
412
|
+
try {
|
|
413
|
+
collected = await withSpinner("Collecting source", () => collectSourceFiles(dir, {
|
|
414
|
+
maxTotalBytes: fn.maxSourceBytes ?? undefined,
|
|
415
|
+
maxFiles: fn.maxSourceFiles ?? undefined,
|
|
416
|
+
}));
|
|
417
|
+
}
|
|
418
|
+
catch (e) {
|
|
419
|
+
if (e instanceof SourceTooLargeError || e instanceof SourceTooManyFilesError) {
|
|
420
|
+
this.error(e.message, { exit: 1 });
|
|
421
|
+
}
|
|
422
|
+
throw e;
|
|
423
|
+
}
|
|
424
|
+
if (collected.files.length === 0) {
|
|
425
|
+
this.error(`No deployable files in ${dir}. Add a handler (\`synteq function init ${fn.slug}\` writes one).`, { exit: 1 });
|
|
426
|
+
}
|
|
427
|
+
// A skipped file is reported in EVERY output mode. In JSON mode the
|
|
428
|
+
// lines go to stderr so the JSON body stays parseable, and the body
|
|
429
|
+
// itself carries `skipped` (below) — a 6 MB data.json silently left out
|
|
430
|
+
// of a deploy is exactly the surprise -o json callers cannot see
|
|
431
|
+
// otherwise (2026-09-25).
|
|
432
|
+
const skipLines = collected.skipped.map((s) => `skipped ${s.path} — ${SKIP_REASON[s.reason] ?? s.reason}`);
|
|
433
|
+
if (this.outputFormat === "table") {
|
|
434
|
+
for (const line of skipLines)
|
|
435
|
+
this.log(dim(` ${line}`));
|
|
436
|
+
this.log(dim(`Uploading ${collected.files.length} file${collected.files.length === 1 ? "" : "s"} (${(collected.totalBytes / 1024).toFixed(0)} KiB) to ${fn.slug}.`));
|
|
437
|
+
}
|
|
438
|
+
// 2. A tree that looks like a different runtime than the function is
|
|
439
|
+
// configured for is the mismatch that fails LATE (the build uses the
|
|
440
|
+
// FUNCTION's runtime and finds no entry), so surface it now. On a
|
|
441
|
+
// TTY it is a confirm the user can decline; --yes and non-interactive
|
|
442
|
+
// runs get the warning and proceed, since a script cannot answer.
|
|
443
|
+
const inferred = inferRuntime(collected.files.map((f) => f.path));
|
|
444
|
+
const hasDockerfile = collected.files.some((f) => f.path === "Dockerfile");
|
|
445
|
+
if (inferred && !hasDockerfile && inferred !== fn.runtime && this.outputFormat === "table") {
|
|
446
|
+
this.log("");
|
|
447
|
+
// Advisory only; route to stderr so -o json stdout stays clean, and
|
|
448
|
+
// only prompt in table mode (json/non-TTY proceeds — the build uses
|
|
449
|
+
// fn.runtime either way).
|
|
450
|
+
this.info(`${G.dot} This directory looks like ${inferred}, but ${fn.slug} is configured for ${fn.runtime}.`);
|
|
451
|
+
this.info(dim(` The build will use ${fn.runtime}. Change the runtime in the portal (function → Settings) if that's wrong.`));
|
|
452
|
+
this.info("");
|
|
453
|
+
if (!flags.yes && interactive) {
|
|
454
|
+
const go = await confirmAction(`Deploy to ${fn.slug} as ${fn.runtime} anyway?`, false);
|
|
455
|
+
if (!go)
|
|
456
|
+
this.error("Deploy cancelled.", { exit: 1 });
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
// 3. The first release carries the env vars and the cron trigger:
|
|
460
|
+
// apply them now, after the function exists and before the build.
|
|
461
|
+
// --env-file lands the same way (a .env is never packed; a plain
|
|
462
|
+
// deploy never asks about it — the first-run create did).
|
|
463
|
+
await this.applySetup(fn, env, cron);
|
|
464
|
+
try {
|
|
465
|
+
await importDotenv({
|
|
466
|
+
dir,
|
|
467
|
+
envFile: flags["env-file"],
|
|
468
|
+
interactive: false,
|
|
469
|
+
target: `function ${fn.slug}`,
|
|
470
|
+
log: (l) => this.log(l),
|
|
471
|
+
save: (r) => this.clients.api.functions
|
|
472
|
+
.setEnv(fn.id, {
|
|
473
|
+
key: r.key,
|
|
474
|
+
value: r.value,
|
|
475
|
+
scope: r.scope ?? "runtime",
|
|
476
|
+
kind: r.kind ?? "secret",
|
|
477
|
+
...(r.note ? { note: r.note } : {}),
|
|
478
|
+
rollout: false,
|
|
479
|
+
})
|
|
480
|
+
.then(() => undefined),
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
catch (e) {
|
|
484
|
+
if (e instanceof ApiError)
|
|
485
|
+
throw e;
|
|
486
|
+
this.error(e.message, { exit: 1 });
|
|
487
|
+
}
|
|
488
|
+
// 4. Trigger. Past the editor's 32 files the tree goes up as a tarball,
|
|
489
|
+
// which the API bounds by the compressed size; refuse here rather
|
|
490
|
+
// than after the upload in the rare case tar overhead tips it over.
|
|
491
|
+
let tarball;
|
|
492
|
+
if (collected.files.length > EDITOR_MAX_FILES) {
|
|
493
|
+
tarball = tarballFromFiles(collected.files);
|
|
494
|
+
const limit = fn.maxSourceBytes ?? MAX_TOTAL_BYTES;
|
|
495
|
+
if (tarball.length > limit) {
|
|
496
|
+
this.error(`Source archive is ${(tarball.length / 1024).toFixed(0)} KiB; the limit is ${(limit / 1024).toFixed(0)} KiB. ` +
|
|
497
|
+
"Exclude files with a .synteqignore, or add a Dockerfile and deploy as a container.", { exit: 1 });
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
const build = await withSpinner("Uploading source", () => tarball
|
|
501
|
+
? this.clients.api.functions.deployTarball(fn.id, tarball)
|
|
502
|
+
: this.clients.api.functions.deployFiles(fn.id, collected.files));
|
|
503
|
+
await this.follow(fn, build, collected.skipped, flags);
|
|
504
|
+
}
|
|
505
|
+
catch (err) {
|
|
506
|
+
this.fail(err);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
/** Steps 5+: print the build row (--no-wait) or follow the build and the
|
|
510
|
+
* release it produces — in JSON mode too, with progress on stderr. Shared
|
|
511
|
+
* by the source and image paths. */
|
|
512
|
+
async follow(fn, build, skipped, flags) {
|
|
513
|
+
const skipLines = skipped.map((s) => `skipped ${s.path} — ${SKIP_REASON[s.reason] ?? s.reason}`);
|
|
514
|
+
const json = this.outputFormat === "json";
|
|
515
|
+
// Every emitted document carries the skip list; in JSON mode the lines go
|
|
516
|
+
// to stderr too, since a scripted caller never sees them otherwise (the
|
|
517
|
+
// skip report in run(), 2026-09-25).
|
|
518
|
+
const withSkipped = (doc) => (skipped.length ? { ...doc, skipped } : doc);
|
|
519
|
+
if (json)
|
|
520
|
+
for (const line of skipLines)
|
|
521
|
+
process.stderr.write(`${line}\n`);
|
|
522
|
+
if (flags["no-wait"]) {
|
|
523
|
+
this.emit(withSkipped(build), () => this.log(`${statusColor(build.status)} build ${build.id.slice(0, 8)} ${build.frontend}`));
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
526
|
+
// JSON mode follows the build like table mode — a CI job must see exit 1
|
|
527
|
+
// for a failed build or a release that never goes live (until 1.2.2 JSON
|
|
528
|
+
// returned the triggered build and exit 0, so the failure was invisible).
|
|
529
|
+
// The checklist takes an `out` stream and goes to stderr; stdout carries
|
|
530
|
+
// the final document only.
|
|
531
|
+
const out = json ? process.stderr : process.stdout;
|
|
532
|
+
// 5. Follow it. Ctrl-C stops watching, not the deploy.
|
|
533
|
+
const controller = new AbortController();
|
|
534
|
+
const onSigint = () => {
|
|
535
|
+
controller.abort();
|
|
536
|
+
};
|
|
537
|
+
process.on("SIGINT", onSigint);
|
|
538
|
+
const apiBaseUrl = this.clients.config.get().api_base_url;
|
|
539
|
+
const panelUrl = portalUrl(apiBaseUrl, `/functions/${fn.id}`);
|
|
540
|
+
const intervalMs = Math.max(2, flags["poll-interval"]) * 1000;
|
|
541
|
+
const deadline = Date.now() + flags.timeout * 1000;
|
|
542
|
+
const progress = buildProgress(`Deploying ${fn.slug}`, { out });
|
|
543
|
+
progress.update(build.status);
|
|
544
|
+
try {
|
|
545
|
+
const finalBuild = await waitForBuild(this.clients.api, fn.id, build.id, {
|
|
546
|
+
intervalMs,
|
|
547
|
+
timeoutMs: Math.max(0, deadline - Date.now()),
|
|
548
|
+
signal: controller.signal,
|
|
549
|
+
onStatus: (status) => progress.update(status),
|
|
550
|
+
});
|
|
551
|
+
if (finalBuild.status !== "succeeded") {
|
|
552
|
+
progress.failed();
|
|
553
|
+
this.emit(withSkipped(finalBuild), () => this.log(failedCard({ appSlug: fn.slug, buildId: finalBuild.id, panelUrl })));
|
|
554
|
+
this.exit(1);
|
|
555
|
+
}
|
|
556
|
+
const release = await waitForRelease(this.clients.api, fn.id, build.id, {
|
|
557
|
+
intervalMs,
|
|
558
|
+
timeoutMs: Math.max(0, deadline - Date.now()),
|
|
559
|
+
signal: controller.signal,
|
|
560
|
+
});
|
|
561
|
+
progress.done("succeeded");
|
|
562
|
+
const durationMs = finalBuild.startedAt && finalBuild.finishedAt
|
|
563
|
+
? new Date(finalBuild.finishedAt).getTime() - new Date(finalBuild.startedAt).getTime()
|
|
564
|
+
: null;
|
|
565
|
+
if (release.isCurrent) {
|
|
566
|
+
this.emit(withSkipped({ build: finalBuild, release }), () => this.log(deployedCard({
|
|
567
|
+
appSlug: fn.slug,
|
|
568
|
+
url: deploymentUrl(fn.hostname),
|
|
569
|
+
release: release.number,
|
|
570
|
+
digest: release.imageDigest,
|
|
571
|
+
durationMs,
|
|
572
|
+
panelUrl,
|
|
573
|
+
})));
|
|
574
|
+
}
|
|
575
|
+
else {
|
|
576
|
+
// The build produced a release that never went current — the image
|
|
577
|
+
// is fine, the rollout is not. Say so rather than claiming success.
|
|
578
|
+
this.emit(withSkipped({ build: finalBuild, release }), () => this.log(failedCard({ appSlug: fn.slug, buildId: finalBuild.id, panelUrl }) +
|
|
579
|
+
`\n${dim(` Release #${release.number} is ${statusColor(release.status)}.`)}`));
|
|
580
|
+
this.exit(1);
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
catch (e) {
|
|
584
|
+
if (controller.signal.aborted) {
|
|
585
|
+
progress.failed("Stopped watching");
|
|
586
|
+
// JSON stdout stays empty on an interrupt (nothing parseable to emit);
|
|
587
|
+
// the hint is for a human at a terminal only.
|
|
588
|
+
if (!json) {
|
|
589
|
+
this.log("");
|
|
590
|
+
this.log(`${G.dot} The deploy continues server-side. Watch it: ${panelUrl}, or run \`synteq function releases --name ${fn.slug}\`.`);
|
|
591
|
+
}
|
|
592
|
+
return;
|
|
593
|
+
}
|
|
594
|
+
if (e instanceof DeployTimeoutError) {
|
|
595
|
+
progress.failed(e.message);
|
|
596
|
+
// A timeout is "unknown", not a failure (exit 0). JSON still owes the
|
|
597
|
+
// caller a parseable document — the build row plus `timedOut`.
|
|
598
|
+
this.emit(withSkipped({ ...build, timedOut: true }), () => this.log(`${G.dot} Stopped waiting after ${flags.timeout}s — the deploy may still finish. Watch it: ${panelUrl}`));
|
|
599
|
+
return;
|
|
600
|
+
}
|
|
601
|
+
throw e;
|
|
602
|
+
}
|
|
603
|
+
finally {
|
|
604
|
+
process.removeListener("SIGINT", onSigint);
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
//# sourceMappingURL=deploy.js.map
|