insta 0.0.23-rc.1 → 0.0.24
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/README.md +172 -127
- package/dist/commands/compute.js +17 -0
- package/dist/commands/db.js +27 -0
- package/dist/commands/services.js +3 -0
- package/dist/index.js +9 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,175 +1,220 @@
|
|
|
1
1
|
# insta-cli
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/insta)
|
|
4
|
+
[](LICENSE)
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
The InstaCloud CLI. Provision Postgres, object storage and compute, fork the whole
|
|
7
|
+
environment per branch, and give your coding agent scoped credentials without pasting
|
|
8
|
+
secrets into a chat window.
|
|
7
9
|
|
|
8
|
-
|
|
10
|
+
`insta` is a thin client over the InstaCloud control-plane API. Every command is one API
|
|
11
|
+
call, so anything you can do, an agent can do.
|
|
9
12
|
|
|
10
|
-
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
Native binary, no Node required (macOS / Linux / WSL). Installs to `~/.insta/bin` and
|
|
16
|
+
verifies the download against `SHA256SUMS`:
|
|
11
17
|
|
|
12
18
|
```bash
|
|
13
19
|
curl -fsSL https://raw.githubusercontent.com/InsForge/insta-cli/main/install.sh | sh
|
|
14
|
-
# Installs to ~/.insta/bin/insta (override with INSTA_INSTALL_DIR); verifies SHA256SUMS.
|
|
15
|
-
# Pin a version: curl -fsSL .../install.sh | INSTA_VERSION=v0.1.0 sh
|
|
16
|
-
# Windows: download insta-windows-x64.exe from the releases page.
|
|
17
20
|
```
|
|
18
21
|
|
|
19
|
-
|
|
22
|
+
From npm:
|
|
20
23
|
|
|
21
24
|
```bash
|
|
22
|
-
|
|
23
|
-
curl -fsSL agents.staging.instacloud.com | sh # staging
|
|
25
|
+
npm install -g insta
|
|
24
26
|
```
|
|
25
27
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
> The staging host serves this repo's `agents-staging.sh` from `main`, so it returns 404 until that
|
|
30
|
-
> file is on `main`. Equivalent, and works regardless:
|
|
31
|
-
>
|
|
32
|
-
> ```bash
|
|
33
|
-
> curl -fsSL https://raw.githubusercontent.com/InsForge/insta-cli/main/install.sh | sh -s -- --agents --staging -y
|
|
34
|
-
> ```
|
|
35
|
-
>
|
|
36
|
-
> If the environment can't be applied (a CLI predating `insta env`), the installer exits non-zero
|
|
37
|
-
> rather than silently leaving you on production.
|
|
38
|
-
|
|
39
|
-
**Build from source (requires node):**
|
|
28
|
+
For coding agents. Installs the CLI, the `insta` skill for every agent on the machine, and
|
|
29
|
+
registers the MCP server:
|
|
40
30
|
|
|
41
31
|
```bash
|
|
42
|
-
|
|
43
|
-
npm run build # -> dist/index.js (bin: insta; pure JS, requires node to run)
|
|
44
|
-
node dist/index.js --help
|
|
32
|
+
curl -fsSL agents.instacloud.com | sh
|
|
45
33
|
```
|
|
46
34
|
|
|
47
|
-
|
|
35
|
+
On Windows, download `insta-windows-x64.exe` from the
|
|
36
|
+
[releases page](https://github.com/InsForge/insta-cli/releases).
|
|
48
37
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
38
|
+
Pin a version with `INSTA_VERSION=v0.0.22`; change the install directory with
|
|
39
|
+
`INSTA_INSTALL_DIR`. While the CLI is pre-1.0 it updates itself on new releases. Turn that
|
|
40
|
+
off with `insta autoupdate off`.
|
|
41
|
+
|
|
42
|
+
## Quickstart
|
|
52
43
|
|
|
53
44
|
```bash
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
45
|
+
insta login --oauth github
|
|
46
|
+
insta project create my-app
|
|
47
|
+
insta services add postgres db
|
|
48
|
+
insta services add compute api
|
|
49
|
+
insta secrets
|
|
50
|
+
insta deploy .
|
|
57
51
|
```
|
|
58
52
|
|
|
59
|
-
|
|
60
|
-
|
|
53
|
+
`project create` makes an empty project and links the current directory. Services are
|
|
54
|
+
opt-in, so you add only what you need. `secrets` writes the current branch's credentials to
|
|
55
|
+
`./.env`. `deploy .` builds the directory remotely and ships it to the branch's compute
|
|
56
|
+
service; it needs a `Dockerfile`, but no local Docker.
|
|
61
57
|
|
|
62
|
-
##
|
|
58
|
+
## Authentication
|
|
63
59
|
|
|
64
60
|
```bash
|
|
65
|
-
|
|
66
|
-
insta login --
|
|
67
|
-
insta
|
|
68
|
-
insta services add postgres db # add services on demand (postgres/storage/compute)
|
|
69
|
-
insta services add compute api # compute is used to deploy images
|
|
70
|
-
insta secrets # write the current branch's credentials to ./.env (secret seam)
|
|
71
|
-
insta deploy --image <registry/img> # deploy a container image to the current branch's compute service
|
|
72
|
-
insta status # login state + linked project/branch
|
|
61
|
+
insta login --email you@example.com # password from $INSTA_PASSWORD or a prompt
|
|
62
|
+
insta login --oauth github # or google, through the browser
|
|
63
|
+
insta login --env staging --oauth github # log in to a specific deployment
|
|
73
64
|
```
|
|
74
65
|
|
|
66
|
+
Tokens are stored in `~/.insta/config.json` and refresh automatically.
|
|
67
|
+
|
|
68
|
+
`--oauth` starts a loopback listener on `127.0.0.1`, opens the browser at the control
|
|
69
|
+
plane's `/auth/cli/authorize`, and receives the token back on that listener once the
|
|
70
|
+
provider has authorized you. Nothing is pasted by hand.
|
|
71
|
+
|
|
72
|
+
If you operate your own control plane, the provider's OAuth app needs
|
|
73
|
+
`GITHUB_OAUTH_CLIENT_ID` / `GITHUB_OAUTH_CLIENT_SECRET` (or the `GOOGLE_*` equivalents), and
|
|
74
|
+
its callback URL must be `{INSTA_API_BASE_URL}/api/auth/callback/<provider>` — the control
|
|
75
|
+
plane's address, not the CLI's loopback address.
|
|
76
|
+
|
|
77
|
+
## How it works
|
|
78
|
+
|
|
79
|
+
### Services are branch-scoped
|
|
80
|
+
|
|
81
|
+
A project holds services (`postgres`, `storage`, `compute`) and each branch owns its own
|
|
82
|
+
set. `insta branch create feature-x` forks the parent's services: a Neon branch per
|
|
83
|
+
Postgres, a copy-on-write bucket per storage, a clone of every compute service. From there
|
|
84
|
+
the two branches diverge independently. A project is capped at 10 branches.
|
|
85
|
+
|
|
86
|
+
### Credentials come from the secret seam, not a file you maintain
|
|
87
|
+
|
|
88
|
+
`insta secrets` fetches the current branch's bundle and writes `./.env`. `insta run <cmd>`
|
|
89
|
+
does the same without touching disk, injecting the bundle into the child process only.
|
|
90
|
+
Credential names are per service — `DATABASE_URL`, `BUCKET_NAME`, `AWS_ACCESS_KEY_ID` —
|
|
91
|
+
suffixed with the service name when a project has more than one service of a type.
|
|
92
|
+
|
|
93
|
+
### Destructive actions can require approval
|
|
94
|
+
|
|
95
|
+
Reading secrets, deploying, deleting a project or branch, and changing services are
|
|
96
|
+
governed by a per-project policy. Where the policy says `approve`, the command stops and
|
|
97
|
+
prints an approval id for an admin to grant with `insta approvals approve <id>`. Run
|
|
98
|
+
`insta policy get` for the live policy.
|
|
99
|
+
|
|
100
|
+
### Agents get the same surface
|
|
101
|
+
|
|
102
|
+
`insta manifest` prints an agent-legible view of every branch and its URLs. `insta setup
|
|
103
|
+
agent` installs the InstaCloud skill and registers the remote MCP server for the coding
|
|
104
|
+
agents on the machine.
|
|
105
|
+
|
|
75
106
|
## Environments
|
|
76
107
|
|
|
77
|
-
`prod` and `staging` are
|
|
78
|
-
different auth. A session
|
|
79
|
-
stored session and you log in again.
|
|
108
|
+
`prod` and `staging` are separate deployments, in different regions, with different
|
|
109
|
+
databases and different auth. A session minted by one cannot authenticate against the
|
|
110
|
+
other, so switching environments drops the stored session and you log in again.
|
|
80
111
|
|
|
81
112
|
| | `prod` (default) | `staging` |
|
|
82
113
|
|---|---|---|
|
|
83
|
-
| control plane | `api.instacloud.com`
|
|
114
|
+
| control plane | `api.instacloud.com` | `api.staging.instacloud.com` |
|
|
84
115
|
| MCP server | `mcp.instacloud.com/mcp` | `mcp.staging.instacloud.com/mcp` |
|
|
85
|
-
| registers as | `insta-cloud` | `insta-cloud-staging` |
|
|
86
|
-
| agent skills | `InsForge/insta-skills` | `InsForge/insta-skills
|
|
87
|
-
| CLI channel | latest stable release | newest prerelease
|
|
116
|
+
| MCP registers as | `insta-cloud` | `insta-cloud-staging` |
|
|
117
|
+
| agent skills | `InsForge/insta-skills` | `InsForge/insta-skills#devel` |
|
|
118
|
+
| CLI channel | latest stable release | newest prerelease, else stable |
|
|
88
119
|
|
|
89
120
|
```bash
|
|
90
|
-
insta env
|
|
91
|
-
insta env use staging
|
|
92
|
-
insta login --env staging --oauth github
|
|
121
|
+
insta env # current environment and everything derived from it
|
|
122
|
+
insta env use staging # switch; persisted to ~/.insta/config.json
|
|
93
123
|
```
|
|
94
124
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
Resolution order, most specific first:
|
|
100
|
-
|
|
101
|
-
1. `INSTA_API_URL` — a literal URL. The only way to reach a host no environment name covers
|
|
102
|
-
(`insta-oss` on localhost, a preview deployment). `INSTA_MCP_URL` and `INSTA_SKILLS_REPO` do the
|
|
103
|
-
same for the MCP host and the skill source.
|
|
104
|
-
2. `INSTA_ENV` — `prod` | `staging`. An unrecognised value is an error, never a silent fallback.
|
|
105
|
-
3. the persisted `apiUrl` in `~/.insta/config.json`.
|
|
106
|
-
4. `prod`.
|
|
107
|
-
|
|
108
|
-
Prereleases never take the `latest` GitHub release or the `latest` npm dist-tag — they publish with
|
|
109
|
-
`--prerelease` and under npm's `next` tag — so a staging build can't reach production installers.
|
|
110
|
-
|
|
111
|
-
## Commands
|
|
125
|
+
The control plane, the MCP host and the skill source all resolve from that one switch, so a
|
|
126
|
+
machine cannot end up running staging while its agents read production's skill text. The
|
|
127
|
+
two MCP registrations use different names, so both environments can be installed side by
|
|
128
|
+
side.
|
|
112
129
|
|
|
113
|
-
|
|
114
|
-
|------|------|
|
|
115
|
-
| `insta login [--email --password --api-url --env]` | Log in (email/password; tokens auto-refresh) |
|
|
116
|
-
| `insta env [--json]` / `insta env use <prod\|staging>` | Show or switch deployment environment |
|
|
117
|
-
| `insta login --oauth <github\|google>` | Browser OAuth login (starts a local loopback port; the token is carried back automatically after browser authorization) |
|
|
118
|
-
| `insta logout` / `insta status [--json]` | Log out / show status |
|
|
119
|
-
| `insta org list [--json]` / `org create <name>` | Organizations (each user may own only one free org) |
|
|
120
|
-
| `insta project create <name> [--org]` | Create an empty project and link it (no services by default) |
|
|
121
|
-
| `insta project list [--org] [--json]` / `link <id>` / `delete` | Project management |
|
|
122
|
-
| `insta services add <postgres\|storage\|compute> <name>` | Provision a service on demand (postgres/compute get a default access domain) |
|
|
123
|
-
| `insta services list [--json]` / `services remove <type> <name>` | List / remove services |
|
|
124
|
-
| `insta services scale compute <name> <number> [region]` | Set the compute machine count (paid tiers; rejected on free) |
|
|
125
|
-
| `insta services upgrade <compute\|postgres> <name> <spec>` | Upgrade the spec (paid tiers; upgrade only, no downgrade) |
|
|
126
|
-
| `insta branch create <name> [--from]` | Create a branch environment (materializes the project's current services; up to 10 branches per project) |
|
|
127
|
-
| `insta branch list [--json]` / `switch <name>` / `delete <name>` | Branch management |
|
|
128
|
-
| `insta secrets [--branch -o --print --json]` | Secret seam: write credentials to `.env` |
|
|
129
|
-
| `insta secrets list [--branch]` | List secret names only |
|
|
130
|
-
| `insta deploy --image <url> [--branch --group --port]` | Deploy an image |
|
|
131
|
-
| `insta manifest [--json]` | Agent-readable environment manifest |
|
|
132
|
-
| `insta metrics <db\|compute> [group] [--branch --from --to --step --json]` | Resource metrics (compute=Fly; db limited) |
|
|
133
|
-
| `insta logs <db\|compute> [group] [--branch --limit --region --instance --json]` | Runtime logs (compute=Fly; db limited) |
|
|
134
|
-
| `insta events [--branch --limit --json]` | Audit + agent event timeline |
|
|
135
|
-
| `insta usage [--from --to --json]` | Resource usage aggregated by meter (includes costUsd) |
|
|
136
|
-
| `insta billing [--org --json]` | Current billing-cycle summary (tier / quota / used / overage / status) |
|
|
137
|
-
| `insta billing upgrade <pro\|enterprise> [--org --no-open --json]` | Subscribe to a paid tier via Stripe Checkout; returns and opens the payment link |
|
|
138
|
-
| `insta billing portal [--org --no-open --json]` | Open the Stripe Customer Portal (change plan / card / cancel) |
|
|
139
|
-
| `insta approvals list [--status] [--json]` | Governance approval list |
|
|
140
|
-
| `insta approvals approve <id> [--always]` / `deny <id>` | Approve / deny (admin) |
|
|
141
|
-
| `insta policy get [--json]` / `policy set <action> <decision>` | Governance policy (actions include `service.add/remove/scale/upgrade`) |
|
|
142
|
-
|
|
143
|
-
When a governance-gated operation (`secrets.read`/`deploy`/`project.delete`/`branch.delete`/`service.add`/`service.remove`/`service.scale`/`service.upgrade`) hits an approval,
|
|
144
|
-
the CLI prompts `approval required — run: insta approvals approve <id>`.
|
|
145
|
-
|
|
146
|
-
## Configuration locations
|
|
147
|
-
|
|
148
|
-
- Global: `~/.insta/config.json` (apiUrl + access/refresh token + user)
|
|
149
|
-
- Project: `./.insta/project.json` (projectId / orgId / current branch)
|
|
150
|
-
|
|
151
|
-
## Local end-to-end run
|
|
152
|
-
|
|
153
|
-
The platform provides a `dev:fake` mode (fake provider adapters, no Neon/Fly/Tigris credentials required):
|
|
130
|
+
To install against staging directly:
|
|
154
131
|
|
|
155
132
|
```bash
|
|
156
|
-
|
|
157
|
-
docker run -d --name pg -e POSTGRES_PASSWORD=insta -e POSTGRES_DB=insta_dev -p 55432:5432 postgres:16-alpine
|
|
158
|
-
cd ../platform && DATABASE_URL='postgres://postgres:insta@localhost:55432/insta_dev' PORT=8899 npm run dev:fake
|
|
159
|
-
|
|
160
|
-
# 2) Run the full flow with the CLI (signup goes through /auth/signup + /auth/verify-email; in dev mode the verification code is printed in the server logs)
|
|
161
|
-
INSTA_API_URL=http://localhost:8899 insta login --email you@x.com --password ...
|
|
133
|
+
curl -fsSL agents.staging.instacloud.com | sh
|
|
162
134
|
```
|
|
163
135
|
|
|
164
|
-
|
|
136
|
+
That host is a CloudFront cache, so after a change to the installer it can serve the
|
|
137
|
+
previous copy for up to about a day. This form is equivalent and always current:
|
|
165
138
|
|
|
166
139
|
```bash
|
|
167
|
-
insta
|
|
168
|
-
# CLI starts a local loopback port → opens the browser to /auth/cli/authorize → Better Auth runs provider authorization →
|
|
169
|
-
# the platform reads the session cookie to exchange for a bearer token → carries it back to the loopback port → CLI stores it as login state
|
|
140
|
+
curl -fsSL https://raw.githubusercontent.com/InsForge/insta-cli/main/install.sh | sh -s -- --agents --staging -y
|
|
170
141
|
```
|
|
171
142
|
|
|
172
|
-
|
|
173
|
-
|
|
143
|
+
If the environment cannot be applied — an installed CLI older than 0.0.23 has no `insta
|
|
144
|
+
env` — the installer exits non-zero and says so, rather than leaving you silently pointed
|
|
145
|
+
at production. The canonical usage is `curl … | sh && insta project create`, often run
|
|
146
|
+
unattended by an agent, and a silent fallback there would provision real production
|
|
147
|
+
infrastructure.
|
|
148
|
+
|
|
149
|
+
Resolution order, most specific first:
|
|
150
|
+
|
|
151
|
+
1. `INSTA_API_URL` — a literal URL, and the only way to reach a host no environment name
|
|
152
|
+
covers, such as a local daemon or a preview deployment. `INSTA_MCP_URL` and
|
|
153
|
+
`INSTA_SKILLS_REPO` do the same for the MCP host and the skill source.
|
|
154
|
+
2. `INSTA_ENV` — `prod` or `staging`. An unrecognised value is an error, never a fallback.
|
|
155
|
+
3. The `apiUrl` persisted in `~/.insta/config.json`.
|
|
156
|
+
4. `prod`.
|
|
157
|
+
|
|
158
|
+
Prereleases publish with `--prerelease` on GitHub and under npm's `next` tag, so a staging
|
|
159
|
+
build never reaches a production installer.
|
|
160
|
+
|
|
161
|
+
## Commands
|
|
174
162
|
|
|
175
|
-
|
|
163
|
+
`insta --help` is the authoritative list. For flags, approval gates and plan limits, see the
|
|
164
|
+
[full command reference](https://github.com/InsForge/insta-skills/blob/main/insta/cli-reference.md).
|
|
165
|
+
|
|
166
|
+
| Command | What it covers |
|
|
167
|
+
|---|---|
|
|
168
|
+
| `insta login` · `logout` · `status` | Email/password or `--oauth github\|google`; `status` shows the environment, login and linked project/branch |
|
|
169
|
+
| `insta env` | `show` · `use <prod\|staging>` |
|
|
170
|
+
| `insta setup` | `agent` — install the skill and register MCP for every coding agent |
|
|
171
|
+
| `insta mcp` | `install` — register the remote MCP server only |
|
|
172
|
+
| `insta org` | `list` · `create` (one free org per user) |
|
|
173
|
+
| `insta project` | `create` · `list` · `link` · `delete` |
|
|
174
|
+
| `insta branch` | `create` · `list` · `switch` · `delete` · `merge` |
|
|
175
|
+
| `insta services` | `add` · `list` · `remove` · `rename` · `set-access` · `scale` · `upgrade` · `secrets` |
|
|
176
|
+
| `insta secrets` | Write `.env`, plus `list` · `set` · `unset` · `tree` |
|
|
177
|
+
| `insta run <cmd>` | Run a command with the branch bundle injected, nothing written to disk |
|
|
178
|
+
| `insta deploy [dir]` | Deploy a source directory (built remotely) or `--image <url>` |
|
|
179
|
+
| `insta compute` | `start` · `stop` · `suspend` · `status` · `set-domain` · `check-domain` · `remove-domain` |
|
|
180
|
+
| `insta regions` | Regions available for postgres and compute |
|
|
181
|
+
| `insta manifest` | Agent-legible view of every branch and its URLs |
|
|
182
|
+
| `insta metrics` · `logs` · `events` | Service metrics; runtime logs (`--deploy` for deploy events); audit timeline |
|
|
183
|
+
| `insta usage` · `billing` | Usage by billing dimension; `billing upgrade` · `billing portal` |
|
|
184
|
+
| `insta approvals` | `list` · `approve` · `deny` |
|
|
185
|
+
| `insta policy` | `get` · `set <action> <decision>` |
|
|
186
|
+
| `insta observe` | `install` · `uninstall` · `report` · `sync` — local credential audit |
|
|
187
|
+
| `insta upgrade` · `autoupdate` | Update the CLI; show or set auto-update |
|
|
188
|
+
|
|
189
|
+
## Configuration
|
|
190
|
+
|
|
191
|
+
| Location | Contents |
|
|
192
|
+
|---|---|
|
|
193
|
+
| `~/.insta/config.json` | API URL, access and refresh tokens, user, auto-update preference |
|
|
194
|
+
| `./.insta/project.json` | Project id, org id, current branch |
|
|
195
|
+
|
|
196
|
+
| Variable | Effect |
|
|
197
|
+
|---|---|
|
|
198
|
+
| `INSTA_API_URL` | Control-plane URL; outranks every other source |
|
|
199
|
+
| `INSTA_ENV` | `prod` or `staging` |
|
|
200
|
+
| `INSTA_MCP_URL` · `INSTA_SKILLS_REPO` | Override the MCP host and the agent-skill source |
|
|
201
|
+
| `INSTA_PROJECT_ID` · `INSTA_ORG_ID` · `INSTA_BRANCH` | Target a project, org or branch without linking |
|
|
202
|
+
| `INSTA_PASSWORD` | Password for non-interactive login |
|
|
203
|
+
| `INSTA_NO_AUTOUPDATE` | Disable self-update |
|
|
204
|
+
|
|
205
|
+
## Agent skills
|
|
206
|
+
|
|
207
|
+
The `insta` skill and its task guides live in
|
|
208
|
+
[InsForge/insta-skills](https://github.com/InsForge/insta-skills). `insta setup agent`
|
|
209
|
+
installs it user-globally for every coding agent on the machine. `insta project create` and
|
|
210
|
+
`insta project link` additionally install the stack skills (Neon Postgres, Tigris, Better
|
|
211
|
+
Auth) into the project, along with the `insta observe` credential-audit hook.
|
|
212
|
+
|
|
213
|
+
## Contributing
|
|
214
|
+
|
|
215
|
+
Dev loop, architecture, cross-compilation and the release process are in
|
|
216
|
+
[CONTRIBUTING.md](CONTRIBUTING.md). Issues and pull requests are welcome.
|
|
217
|
+
|
|
218
|
+
## License
|
|
219
|
+
|
|
220
|
+
Apache 2.0. See [LICENSE](LICENSE).
|
package/dist/commands/compute.js
CHANGED
|
@@ -70,4 +70,21 @@ export async function computeStatus(serviceName, opts) {
|
|
|
70
70
|
return printJson(r);
|
|
71
71
|
info(`compute ${serviceName ?? id}: desired=${r.desiredState} live=${r.state}`);
|
|
72
72
|
}
|
|
73
|
+
// ---- always-on (opt out of scale-to-zero; all plans; billing is actual usage either way) ----
|
|
74
|
+
export async function computeAlwaysOn(mode, serviceName, opts) {
|
|
75
|
+
if (mode !== 'on' && mode !== 'off')
|
|
76
|
+
throw new Error('mode must be on|off');
|
|
77
|
+
const api = await ApiClient.load();
|
|
78
|
+
const p = await requireProject();
|
|
79
|
+
const branch = opts.branch ?? p.branch;
|
|
80
|
+
const { services } = await api.request('GET', `/projects/${p.projectId}/services${q(branch)}`);
|
|
81
|
+
const id = resolveComputeServiceId(services, serviceName);
|
|
82
|
+
const res = await api.rawRequest('PUT', `/projects/${p.projectId}/services/${id}/always-on`, { enabled: mode === 'on' });
|
|
83
|
+
if (handleApproval(res))
|
|
84
|
+
return;
|
|
85
|
+
if (opts.json)
|
|
86
|
+
return printJson(res.body);
|
|
87
|
+
const on = res.body.service?.always_on;
|
|
88
|
+
info(`compute ${res.body.service?.name ?? id}: always-on ${on ? 'ENABLED — machines stay warm (no cold starts; idle RAM bills at actual usage)' : 'disabled — scales to zero when idle (default)'}`);
|
|
89
|
+
}
|
|
73
90
|
//# sourceMappingURL=compute.js.map
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ApiClient, requireProject } from '../api.js';
|
|
2
|
+
import { info, printJson, handleApproval } from '../util.js';
|
|
3
|
+
// Toggle a postgres service between scale-to-zero (the default: instance suspends when idle,
|
|
4
|
+
// cold-starts on the next connection) and always-on (instance stays warm; idle RAM bills at
|
|
5
|
+
// actual usage). Thin wrapper over PATCH /database/settings {scaleToZero} — insta-db-backed
|
|
6
|
+
// postgres only; Neon-backed services manage their own autosuspend and the platform returns an
|
|
7
|
+
// error for them.
|
|
8
|
+
export async function dbAlwaysOn(mode, opts) {
|
|
9
|
+
if (mode !== 'on' && mode !== 'off')
|
|
10
|
+
throw new Error('mode must be on|off');
|
|
11
|
+
const api = await ApiClient.load();
|
|
12
|
+
const p = await requireProject();
|
|
13
|
+
const qs = new URLSearchParams();
|
|
14
|
+
const branch = opts.branch ?? p.branch;
|
|
15
|
+
if (branch)
|
|
16
|
+
qs.set('branch', branch);
|
|
17
|
+
if (opts.group)
|
|
18
|
+
qs.set('group', opts.group);
|
|
19
|
+
const res = await api.rawRequest('PATCH', `/projects/${p.projectId}/database/settings${qs.toString() ? `?${qs}` : ''}`, { scaleToZero: mode !== 'on' });
|
|
20
|
+
if (handleApproval(res))
|
|
21
|
+
return;
|
|
22
|
+
if (opts.json)
|
|
23
|
+
return printJson(res.body);
|
|
24
|
+
const s2z = res.body?.scaleToZero;
|
|
25
|
+
info(`postgres ${opts.group ?? 'default'}: always-on ${s2z === false ? 'ENABLED — instance stays warm (no cold starts; idle RAM bills at actual usage)' : 'disabled — scales to zero when idle (default; first connection after idle cold-starts)'}`);
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=db.js.map
|
|
@@ -53,6 +53,7 @@ export function servicesAddRequestBody(type, name, branch, opts) {
|
|
|
53
53
|
type, name, ...(branch ? { branch } : {}), public: !!opts.public,
|
|
54
54
|
...(opts.image ? { image: opts.image } : {}), ...(opts.port ? { port: Number(opts.port) } : {}),
|
|
55
55
|
...(opts.region ? { region: opts.region } : {}),
|
|
56
|
+
...(opts.alwaysOn ? { alwaysOn: true } : {}),
|
|
56
57
|
};
|
|
57
58
|
}
|
|
58
59
|
export async function servicesAdd(type, name, opts = {}) {
|
|
@@ -65,6 +66,8 @@ export async function servicesAdd(type, name, opts = {}) {
|
|
|
65
66
|
throw new Error('--image is only valid for compute services');
|
|
66
67
|
if (opts.port && type !== 'compute')
|
|
67
68
|
throw new Error('--port is only valid for compute services');
|
|
69
|
+
if (opts.alwaysOn && type !== 'compute')
|
|
70
|
+
throw new Error('--always-on is only valid for compute services (for postgres, use `insta db always-on on` after creation)');
|
|
68
71
|
const api = await ApiClient.load();
|
|
69
72
|
const p = await requireProject();
|
|
70
73
|
const branch = opts.branch ?? p.branch;
|
package/dist/index.js
CHANGED
|
@@ -17,6 +17,7 @@ import * as regions from './commands/regions.js';
|
|
|
17
17
|
import * as secretsCmd from './commands/secrets.js';
|
|
18
18
|
import { deploy } from './commands/deploy.js';
|
|
19
19
|
import * as computeCmd from './commands/compute.js';
|
|
20
|
+
import * as dbCmd from './commands/db.js';
|
|
20
21
|
import { manifest } from './commands/manifest.js';
|
|
21
22
|
import * as govern from './commands/govern.js';
|
|
22
23
|
import * as observe from './commands/observe.js';
|
|
@@ -111,6 +112,7 @@ svc.command('add <type> <name>').description('Provision a service on demand (ass
|
|
|
111
112
|
.option('--public', 'storage only: serve the bucket with anonymous public-read (default private)')
|
|
112
113
|
.option('--image <url>', 'compute only: run this container image at creation')
|
|
113
114
|
.option('--port <n>', 'compute only: port the image listens on (default 8080)')
|
|
115
|
+
.option('--always-on', 'compute only: create as always-on — never scales to zero (all plans; billing is actual usage either way)')
|
|
114
116
|
.action(guard((type, name, o) => services.servicesAdd(type, name, o)));
|
|
115
117
|
svc.command('list').option('--json').option('--branch <branch>', 'branch (default: current)')
|
|
116
118
|
.action(guard((o) => services.servicesList(o)));
|
|
@@ -161,6 +163,13 @@ compute.command('suspend [service]').description('Suspend a compute service (RAM
|
|
|
161
163
|
.option('--json').option('--branch <branch>', 'branch (default: current)').action(guard((service, o) => computeCmd.computeSuspend(service, o)));
|
|
162
164
|
compute.command('status [service]').description("Show a compute service's desired vs. live state")
|
|
163
165
|
.option('--json').option('--branch <branch>', 'branch (default: current)').action(guard((service, o) => computeCmd.computeStatus(service, o)));
|
|
166
|
+
compute.command('always-on <mode> [service]').description('Set a compute service always-on (mode: on|off). on = machines never scale to zero; off = default scale-to-zero. All plans; billing is actual usage either way')
|
|
167
|
+
.option('--json').option('--branch <branch>', 'branch (default: current)').action(guard((mode, service, o) => computeCmd.computeAlwaysOn(mode, service, o)));
|
|
168
|
+
// ---- db (postgres service controls) ----
|
|
169
|
+
const db = program.command('db').description('Postgres service controls (always-on / scale-to-zero)');
|
|
170
|
+
db.command('always-on <mode>').description('Set a postgres service always-on (mode: on|off). on = instance stays warm, no cold starts; off = default scale-to-zero (idle instance suspends; first connection cold-starts). insta-db-backed services only')
|
|
171
|
+
.option('--json').option('--branch <branch>', 'branch (default: current)').option('--group <g>', 'postgres service name (default: the sole/default one)')
|
|
172
|
+
.action(guard((mode, o) => dbCmd.dbAlwaysOn(mode, o)));
|
|
164
173
|
// ---- manifest ----
|
|
165
174
|
program.command('manifest').description('Print an agent-legible view of the project environments').option('--json').action(guard((o) => manifest(o)));
|
|
166
175
|
// ---- regions ----
|