@samebase/alchemy-convex 0.3.0 → 0.4.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/NOTICE +24 -0
- package/README.md +131 -280
- package/lib/index.d.ts +178 -346
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +754 -905
- package/lib/index.js.map +1 -1
- package/package.json +17 -16
- package/src/Credentials.ts +85 -27
- package/src/Deployment.ts +461 -122
- package/src/ManagementApi.ts +84 -64
- package/src/Project.ts +133 -16
- package/src/Providers.ts +5 -41
- package/src/Push.ts +646 -0
- package/src/index.ts +15 -47
- package/src/Code.ts +0 -463
- package/src/DefaultEnvironmentVariable.ts +0 -263
- package/src/Deploy.ts +0 -183
- package/src/DeployKey.ts +0 -332
- package/src/EnvironmentVariable.ts +0 -289
- package/src/PreviewDeployKey.ts +0 -153
package/NOTICE
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
@samebase/alchemy-convex
|
|
2
|
+
Copyright 2026 Samebase
|
|
3
|
+
|
|
4
|
+
This product follows patterns from Confect (https://github.com/rjdellecese/confect),
|
|
5
|
+
packages/alchemy, under the ISC license:
|
|
6
|
+
|
|
7
|
+
- the adoption check order in src/Adoption.ts (internal/Lifecycle.ts),
|
|
8
|
+
- the Convex CLI runner in src/Push.ts (internal/CommandRunner.ts),
|
|
9
|
+
- the deployment lookup rules in src/Deployment.ts and the project listing in src/Project.ts.
|
|
10
|
+
|
|
11
|
+
ISC License
|
|
12
|
+
|
|
13
|
+
Copyright 2024 RJ Dellecese
|
|
14
|
+
|
|
15
|
+
Permission to use, copy, modify, and/or distribute this software for any purpose with or without
|
|
16
|
+
fee is hereby granted, provided that the above copyright notice and this permission notice appear
|
|
17
|
+
in all copies.
|
|
18
|
+
|
|
19
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
|
|
20
|
+
SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
|
21
|
+
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
22
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
|
23
|
+
NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
|
24
|
+
THIS SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,53 +1,33 @@
|
|
|
1
1
|
# @samebase/alchemy-convex
|
|
2
2
|
|
|
3
|
-
Convex
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
your app installs keeps doing typecheck, codegen, bundling, and the
|
|
3
|
+
The Convex plane for [Alchemy v2](https://alchemy.run): projects, deployments, their environment
|
|
4
|
+
variables, and the push of the functions. One Alchemy stack owns a Convex app end to end. The
|
|
5
|
+
deployment resource pushes your `convex/` folder when its content changes and gives the deployment
|
|
6
|
+
URLs to a Cloudflare Worker or a Vite site as ordinary outputs. No deploy key goes from one resource
|
|
7
|
+
to another. The Convex CLI that your app installs keeps doing typecheck, codegen, bundling, and the
|
|
8
|
+
push.
|
|
8
9
|
|
|
9
10
|
Alchemy has no built-in Convex provider ([alchemy-run/alchemy-async#1306](https://github.com/alchemy-run/alchemy-async/issues/1306)).
|
|
10
|
-
This is a community provider, maintained by [Samebase](https://samebase.com).
|
|
11
|
+
This is a community provider, maintained by [Samebase](https://samebase.com). The resource model
|
|
12
|
+
follows the "Convex Plain" mode of [rjdellecese/confect#408](https://github.com/rjdellecese/confect/issues/408).
|
|
13
|
+
[docs/design/convex-plane.md](docs/design/convex-plane.md) records the decisions.
|
|
11
14
|
|
|
12
|
-
Status:
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
a Worker Preview per pull request, destroy on close. `Convex.Deployment` and `Convex.Code` are
|
|
16
|
-
verified by a live test with the real Convex CLI: a push to a production deployment and to a
|
|
17
|
-
preview deployment, then a delete of the preview.
|
|
15
|
+
Status: pinned to `alchemy@2.0.0-beta.83` and Effect 4. Alchemy ships breaking changes between
|
|
16
|
+
betas; upgrade this package and Alchemy together. A live test runs the full sequence with the real
|
|
17
|
+
Convex CLI: create, push, no-op, change, preview, deploy keys alone, and destroy.
|
|
18
18
|
|
|
19
19
|
## Install
|
|
20
20
|
|
|
21
21
|
```sh
|
|
22
|
-
pnpm add -D @samebase/alchemy-convex alchemy@2.0.0-beta.
|
|
22
|
+
pnpm add -D @samebase/alchemy-convex alchemy@2.0.0-beta.83 effect@^4.0.0 @effect/platform-node@^4.0.0 convex
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
The provider calls the [Convex Management API](https://docs.convex.dev/management-api) with a
|
|
28
|
-
bearer token. By default it reads `CONVEX_ACCESS_TOKEN` through the stack's config provider
|
|
29
|
-
(process env, `.env`, stack secrets) and then falls back to the token the Convex CLI saved after
|
|
30
|
-
`npx convex login` (`~/.convex/config.json`). A developer who is logged in needs no setup. CI sets
|
|
31
|
-
the variable to a team access token.
|
|
32
|
-
|
|
33
|
-
To pass a token explicitly:
|
|
34
|
-
|
|
35
|
-
```ts
|
|
36
|
-
Convex.providers(Convex.fromToken(Redacted.make(token)));
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
A team access token is team wide. The deploy keys this provider creates are scoped to one
|
|
40
|
-
deployment or one project, and those are what CI deploys with.
|
|
25
|
+
Use one version for `effect` and for each `@effect/*` package. A mix fails at load time, such as
|
|
26
|
+
`@effect/platform-node-shared` 4.0.5 next to `effect` 4.0.3.
|
|
41
27
|
|
|
42
28
|
## Example
|
|
43
29
|
|
|
44
30
|
```ts
|
|
45
|
-
import * as Alchemy from "alchemy";
|
|
46
|
-
import * as Cloudflare from "alchemy/Cloudflare";
|
|
47
|
-
import * as Effect from "effect/Effect";
|
|
48
|
-
import * as Layer from "effect/Layer";
|
|
49
|
-
import * as Convex from "@samebase/alchemy-convex";
|
|
50
|
-
|
|
51
31
|
export default Alchemy.Stack(
|
|
52
32
|
"MyApp",
|
|
53
33
|
{
|
|
@@ -55,251 +35,132 @@ export default Alchemy.Stack(
|
|
|
55
35
|
state: Cloudflare.state(),
|
|
56
36
|
},
|
|
57
37
|
Effect.gen(function* () {
|
|
58
|
-
const
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
38
|
+
const { stage } = yield* Alchemy.Stack;
|
|
39
|
+
const backend =
|
|
40
|
+
stage === "prod"
|
|
41
|
+
? yield* Convex.Deployment("Backend", {
|
|
42
|
+
// An existing project. A new one: { team: "my-team", name: "my-app" }.
|
|
43
|
+
project: yield* Convex.Project("Project", { team: "my-team", slug: "my-app" }),
|
|
44
|
+
type: "prod",
|
|
45
|
+
source: "./convex",
|
|
46
|
+
env: { AUTH_SECRET: Config.Redacted("AUTH_SECRET") },
|
|
47
|
+
})
|
|
48
|
+
: yield* Convex.Deployment("Backend", {
|
|
49
|
+
// The project that the stage "prod" owns, read from its state.
|
|
50
|
+
project: yield* Convex.Project.ref("Project", { stage: "prod" }),
|
|
51
|
+
type: "preview",
|
|
52
|
+
name: stage, // such as "pr-42"
|
|
53
|
+
source: "./convex",
|
|
54
|
+
}).pipe(RemovalPolicy.destroy());
|
|
72
55
|
const site = yield* Cloudflare.Website.Vite("Site", {
|
|
73
56
|
env: { VITE_CONVEX_URL: backend.url, VITE_CONVEX_SITE_URL: backend.siteUrl },
|
|
74
57
|
});
|
|
75
|
-
|
|
76
58
|
return { url: site.url, convexUrl: backend.url };
|
|
77
59
|
}),
|
|
78
60
|
);
|
|
79
61
|
```
|
|
80
62
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
`
|
|
63
|
+
The imports are `alchemy`, `alchemy/Cloudflare`, `alchemy/RemovalPolicy`, `effect/Config`,
|
|
64
|
+
`effect/Effect`, `effect/Layer`, and `@samebase/alchemy-convex` as `Convex`. Order follows the
|
|
65
|
+
outputs: the project exists before its deployment, and the push finishes before the site build. The
|
|
66
|
+
first `alchemy deploy --stage prod` takes over the existing project, and its production
|
|
67
|
+
deployment if it has code, only with `--adopt`.
|
|
68
|
+
`alchemy destroy --stage pr-42` deletes the preview deployment. Without `RemovalPolicy.destroy()`,
|
|
69
|
+
it stays until Convex deletes it at expiry (14 days by default).
|
|
70
|
+
[`examples/app/alchemy.run.ts`](examples/app/alchemy.run.ts) is the same stack.
|
|
85
71
|
|
|
86
|
-
|
|
72
|
+
## Credentials
|
|
87
73
|
|
|
88
|
-
|
|
89
|
-
|
|
74
|
+
Credentials are a layer, never props, so they do not go into Alchemy state. `Convex.providers()`
|
|
75
|
+
reads them through the stack's config provider (process env, `.env`, stack secrets):
|
|
76
|
+
|
|
77
|
+
- `CONVEX_ACCESS_TOKEN`, a team access token, for the Management API. Without it, the provider uses
|
|
78
|
+
the token that `npx convex login` saved (`~/.convex/config.json`). `Convex.Project` needs it, and
|
|
79
|
+
so does a deployment that the deploy key does not reach.
|
|
80
|
+
- `CONVEX_DEPLOY_KEY`, optional, the same variable that the Convex CLI reads:
|
|
81
|
+
- A deploy key of one deployment (`prod:<name>|...`) sets variables and pushes to that deployment.
|
|
82
|
+
That stage then needs no access token if it passes `project: { projectId }` or a
|
|
83
|
+
`Convex.Project.ref`. The key must have `deployment:data:view` (dashboard keys have all
|
|
84
|
+
actions), because the provider reads the project and type of its deployment first.
|
|
85
|
+
- A preview deploy key of a project (`preview:<team>:<project>|...`) creates, pushes to, and
|
|
86
|
+
deletes preview deployments of that project. It cannot change variables: with `env`, the
|
|
87
|
+
provider uses the access token, and without one it stops with `EnvironmentNeedsDeployKey`
|
|
88
|
+
before it creates anything. Use project default variables in the Convex dashboard for previews.
|
|
89
|
+
|
|
90
|
+
A key that does not fit the deployment is not used: the provider uses the access token. To pass
|
|
91
|
+
values explicitly: `Convex.providers(Convex.fromValues({ accessToken, deployKey }))`.
|
|
90
92
|
|
|
91
|
-
|
|
92
|
-
const stack = yield * Alchemy.Stack; // stack.stage, such as "pr-42"
|
|
93
|
-
// The project that the stage "prod" owns. A preview stage reads it and does not own it.
|
|
94
|
-
const project = yield * Convex.Project.ref("Project", { stage: "prod" });
|
|
95
|
-
const preview =
|
|
96
|
-
yield *
|
|
97
|
-
Convex.Deployment("Preview", {
|
|
98
|
-
projectId: project.projectId,
|
|
99
|
-
type: "preview",
|
|
100
|
-
name: stack.stage,
|
|
101
|
-
}).pipe(Alchemy.RemovalPolicy.destroy());
|
|
102
|
-
const previewKey =
|
|
103
|
-
yield *
|
|
104
|
-
Convex.PreviewDeployKey("PreviewDeployKey", {
|
|
105
|
-
projectId: project.projectId,
|
|
106
|
-
name: "alchemy",
|
|
107
|
-
});
|
|
108
|
-
const backend =
|
|
109
|
-
yield *
|
|
110
|
-
Convex.Code("Backend", {
|
|
111
|
-
deployment: preview,
|
|
112
|
-
deployKey: previewKey.previewDeployKey,
|
|
113
|
-
cwd: ".",
|
|
114
|
-
});
|
|
115
|
-
```
|
|
93
|
+
## Resources
|
|
116
94
|
|
|
117
|
-
`
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
`
|
|
95
|
+
- `Convex.Project`: `{ team, name, deploymentRegion?, deploymentType? }` creates a project with its
|
|
96
|
+
default deployment, or takes over one with that exact name with `--adopt`. A changed `name`
|
|
97
|
+
renames the project in place. `{ team, slug }` is an existing project, found by its slug and
|
|
98
|
+
taken over with `--adopt`; it never creates or renames a project. Outputs `projectId`, `slug`,
|
|
99
|
+
`name`, `teamId`, `prodDeploymentName`, `prodDeploymentUrl`.
|
|
100
|
+
- `Convex.Deployment`: `{ project, type: "prod" }` or `{ project, type: "dev" | "preview", name }`,
|
|
101
|
+
each with optional `source` and `env`. Outputs `name` (such as `happy-animal-123`), `url`,
|
|
102
|
+
`siteUrl`, `type`, `projectId`, `reference`, `previewName`, `hash`, and `envNames`.
|
|
103
|
+
- `prod` is the project's default production deployment (with a deploy key: the key's
|
|
104
|
+
production deployment). The resource never creates or deletes one. A production deployment
|
|
105
|
+
with code that is not in state is taken over only with `--adopt`.
|
|
106
|
+
- `dev` creates a dev deployment with `name` as its reference; `preview` creates a preview
|
|
107
|
+
deployment with `name` as its preview name. An expired preview is created again on the next
|
|
108
|
+
deploy.
|
|
109
|
+
- `source` is the Convex functions directory: `convex/`, or the `functions` field of
|
|
110
|
+
convex.json (`SourceMismatch`). The CLI runs in the nearest directory above it with a
|
|
111
|
+
package.json, with the Node.js that runs Alchemy, and is never downloaded (`ConvexCliNotFound`).
|
|
112
|
+
- The content identity is a hash of every file of that app directory that git does not ignore,
|
|
113
|
+
the nearest lockfile, the deployment name, and `env`. The same hash is a no-op. Otherwise the
|
|
114
|
+
update sets `env`, then pushes. A failed push sets the changed variables back, and deletes a
|
|
115
|
+
dev or preview deployment that the same run created.
|
|
116
|
+
- `env` values are strings or secrets such as `Config.Redacted("AUTH_SECRET")`. A name that
|
|
117
|
+
leaves `env` is removed from the deployment.
|
|
118
|
+
- `source: { path, command?, include? }` replaces `convex deploy` with `command`, run in the app
|
|
119
|
+
directory with the push key in `CONVEX_DEPLOY_KEY`, such as
|
|
120
|
+
`["node_modules/.bin/convex-hosting", "deploy", "--build", "node_modules/.bin/vp build", "--dist", "dist/client"]`.
|
|
121
|
+
The command must push with `convex deploy` (convex-hosting does, through `--cmd`). `include`
|
|
122
|
+
narrows the hash to `path`, package.json, convex.json, the lockfile, and the listed globs, such
|
|
123
|
+
as the build inputs `["src/**", "public/**", "vite.config.ts"]`. A minted key for a command
|
|
124
|
+
has every action, because the command can do more than a push.
|
|
122
125
|
|
|
123
126
|
## Data safety
|
|
124
127
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
`name` prop, a dash, and a hash of the resource identity. The provider deletes a key only by its
|
|
147
|
-
secret, so it cannot revoke the key of another resource. When the key list does not show
|
|
148
|
-
exactly one key with the requested name, the deploy stops with `DeployKeyRecoveryRequired`,
|
|
149
|
-
which lists the key ids. The provider never revokes a key on a failed create.
|
|
150
|
-
- With an OAuth token as the credential, Convex creates no new key: it returns the OAuth token
|
|
151
|
-
with a new prefix. The key resources then stop with `DeployKeyIsCredential` and do not keep that
|
|
152
|
-
value, because a delete would revoke the OAuth token. Use a team access token or the Convex CLI
|
|
153
|
-
login.
|
|
154
|
-
- `Convex.Deployment` has the removal policy `retain` for every type. It never deletes a
|
|
155
|
-
production deployment, also not with `RemovalPolicy.destroy()` and also not a dev deployment that
|
|
156
|
-
became a production deployment: delete the project for that. A
|
|
157
|
-
dev or preview deployment is deleted only with `RemovalPolicy.destroy()`.
|
|
158
|
-
- `Convex.Deployment` takes over the project's production deployment without `--adopt`: Convex
|
|
159
|
-
creates it with the project, and the resource never changes or deletes it. A dev or preview
|
|
160
|
-
deployment that exists but is not in state belongs to someone else, such as a preview that CI
|
|
161
|
-
made with `npx convex deploy --preview-name`. The resource takes it over only with `--adopt`.
|
|
162
|
-
It never creates over it: a Convex create for an existing preview name deletes that preview.
|
|
163
|
-
- A deployment keeps its `projectId`, `type`, and `name`. A change stops the deploy with
|
|
164
|
-
`DeploymentIdentityChange`. The resource is never replaced.
|
|
165
|
-
- `Convex.Code` checks before the push that the deploy key fits the deployment, and after the push
|
|
166
|
-
that the CLI pushed to that deployment. A production deploy key on a preview stage stops the deploy
|
|
167
|
-
before the push.
|
|
168
|
-
- An `EnvironmentVariable` or a `DefaultEnvironmentVariable` that exists but is not in state
|
|
169
|
-
belongs to someone else. The provider overwrites it only with `--adopt`. The same is true for a
|
|
170
|
-
`Convex.Code` `env` variable that exists with another value.
|
|
171
|
-
- A variable keeps its name and deployment (a default keeps its project, name, and deployment
|
|
172
|
-
type). A change stops the deploy with `VariableIdentityChange`. To rename or move a variable,
|
|
173
|
-
create a new resource with a new logical id and remove the old one. A rename in place would
|
|
174
|
-
need a cleanup step that can fail and leave a variable or a revoked deploy key behind.
|
|
128
|
+
- `Convex.Project` and `Convex.Deployment` have the removal policy `retain`. `alchemy destroy`
|
|
129
|
+
forgets them and Convex keeps them. Add `RemovalPolicy.destroy()` to delete with the resource.
|
|
130
|
+
- A project is never replaced. A change of `team`, `slug`, `deploymentType`, or `deploymentRegion`
|
|
131
|
+
stops the deploy with a typed error that names the fix.
|
|
132
|
+
- A deployment keeps its `project`, `type`, and `name`; a change stops the deploy with
|
|
133
|
+
`DeploymentIdentityChange`. A production deployment is never deleted, also not with
|
|
134
|
+
`RemovalPolicy.destroy()`, and also not a dev deployment that became one.
|
|
135
|
+
- A dev or preview deployment that exists but is not in state belongs to someone else, such as a
|
|
136
|
+
preview that CI made. The resource takes it over only with `--adopt`, and never creates over it:
|
|
137
|
+
a Convex create for an existing preview name deletes that preview.
|
|
138
|
+
- With the access token, each push uses a new deploy key with only `deployment:deploy`,
|
|
139
|
+
`deployment:env:view`, and `deployment:env:write`, which expires after two hours and is deleted
|
|
140
|
+
after the push, also after a failure. With an OAuth token, Convex returns the token itself as the
|
|
141
|
+
key, so the delete is skipped. No other key is created or revoked.
|
|
142
|
+
- The key reaches the CLI only in an env file with mode 0600, in a temporary home directory that is
|
|
143
|
+
removed after the run. Variables named `CONVEX_*` are not passed on. The CLI output stays out of
|
|
144
|
+
the logs; a failure (`CodePushFailed`) shows the last 20 lines with the key removed. A push to
|
|
145
|
+
another deployment stops the deploy with `PushTargetMismatch`.
|
|
146
|
+
- A variable in `env` that exists with another value and that the resource did not set stops the
|
|
147
|
+
deploy with `VariablesOwnedBySomeoneElse`. `--adopt` overwrites it. Destroy leaves variables in
|
|
148
|
+
place: they go with the deployment.
|
|
175
149
|
- A variable write runs again after a Convex write conflict or a 5xx answer, at most four more
|
|
176
|
-
times.
|
|
177
|
-
|
|
178
|
-
Upgrade from 0.2: `Convex.Deploy` keeps working. To move to `Convex.Code`, add a
|
|
179
|
-
`Convex.Deployment` and a `Convex.Code` with a new logical id and remove the `Convex.Deploy`.
|
|
180
|
-
Removing `Convex.Deploy` changes nothing in Convex. For a preview stage, use `previewName`, not
|
|
181
|
-
`previewCreate`, while you still use `Convex.Deploy`.
|
|
182
|
-
|
|
183
|
-
Upgrade from 0.1: state from 0.1 records the policy `destroy` for each project. Run
|
|
184
|
-
`alchemy deploy` one time with 0.2 while the stack still declares the project. That deploy records
|
|
185
|
-
`retain`. Do this before you remove a project from the stack or run `alchemy destroy`.
|
|
186
|
-
Deploy keys from 0.1 state keep working, but 0.2 does not delete them: their state cannot show that
|
|
187
|
-
the secret is a new key and not an OAuth token. When you remove or replace such a key, delete it in
|
|
188
|
-
the Convex dashboard.
|
|
189
|
-
|
|
190
|
-
## Resources
|
|
191
|
-
|
|
192
|
-
- `Convex.Project`: `{ team: slug | id, name, deploymentRegion?, deploymentType? }`. Creates a
|
|
193
|
-
project with its default deployment. Outputs `projectId`, `slug`, `teamId`,
|
|
194
|
-
`prodDeploymentName`, `prodDeploymentUrl`. A changed `name` renames the project in place. A
|
|
195
|
-
changed `team`, `deploymentRegion`, or `deploymentType` stops the deploy. An existing project
|
|
196
|
-
with the same name is adopted only with `--adopt`. The removal policy is `retain`: only a
|
|
197
|
-
resource with `RemovalPolicy.destroy()` deletes the project with its deployments and data.
|
|
198
|
-
- `Convex.Deployment`: `{ projectId, type: "prod" }` or
|
|
199
|
-
`{ projectId, type: "dev" | "preview", name }`. Outputs `name` (such as `happy-animal-123`),
|
|
200
|
-
`url` (`https://<name>.convex.cloud`, with the region outside US East), `siteUrl` (the same
|
|
201
|
-
host on `.convex.site`), `type`, `projectId`, `reference`, and `previewName`.
|
|
202
|
-
- `prod` takes over the project's default production deployment, and follows it when another
|
|
203
|
-
production deployment becomes the default. It never creates one: a project without one stops
|
|
204
|
-
the deploy with `ProductionDeploymentNotFound`.
|
|
205
|
-
- `dev` creates a dev deployment with `name` as its reference, through
|
|
206
|
-
`POST /projects/{project_id}/create_deployment`. Convex records the member of the access token
|
|
207
|
-
as its creator. It is not that member's default dev deployment, so `npx convex dev` does not
|
|
208
|
-
select it.
|
|
209
|
-
- `preview` creates a preview deployment with `name` as its preview name, through the same
|
|
210
|
-
call. `npx convex deploy --preview-name <name>` with a preview deploy key finds it.
|
|
211
|
-
- When the deployment in state is gone, such as an expired preview, the next deploy creates it
|
|
212
|
-
again. Two deployments with the name stop the deploy with `AmbiguousDeployment`.
|
|
213
|
-
- `Convex.Code`: `{ deployment, deployKey, cwd, command?, env?, typecheck?, codegen? }`. Pushes
|
|
214
|
-
the functions of the Convex app in `cwd` with `convex deploy`. Outputs `deploymentName`,
|
|
215
|
-
`url`, `siteUrl`, `deployedAt` (milliseconds since the Unix epoch), and `envNames`.
|
|
216
|
-
- `deployment` is a `Convex.Deployment` resource or a deployment name. `deployKey` is a
|
|
217
|
-
deploy key of that deployment, or, for a preview deployment, a preview deploy key of the
|
|
218
|
-
project: Code then runs `convex deploy --preview-name <name>`. Any other key stops the deploy
|
|
219
|
-
with `DeployKeyMismatch` before the push.
|
|
220
|
-
- Code pushes on every deploy. It does not hash the sources: a preview can expire, a push from
|
|
221
|
-
outside Alchemy can change the deployment, and a hash misses workspace packages. The CLI
|
|
222
|
-
uploads only the modules that changed.
|
|
223
|
-
- Code runs the `convex` package that `cwd` resolves, with the Node.js that runs Alchemy, and
|
|
224
|
-
never downloads one (`ConvexCliNotFound`). `command`, such as `["pnpm", "exec", "convex"]`,
|
|
225
|
-
replaces it.
|
|
226
|
-
- The key goes to the CLI only in an env file with mode 0600 (`--env-file`), in a temporary
|
|
227
|
-
directory that is removed after the run, also after a failure or an interruption. That
|
|
228
|
-
directory is the home directory of the CLI, so the CLI cannot use the Convex login of the
|
|
229
|
-
machine. Variables named `CONVEX_*` are not passed on.
|
|
230
|
-
- The CLI output stays out of the logs. A failure (`CodePushFailed`) shows the last 20 lines
|
|
231
|
-
with the key removed. A push to another deployment stops the deploy with
|
|
232
|
-
`PushTargetMismatch`.
|
|
233
|
-
- `env` sets variables on the deployment before the push, with the deploy key. A name that
|
|
234
|
-
leaves `env` is removed from the deployment. A preview deploy key cannot set variables
|
|
235
|
-
(`EnvironmentNeedsDeployKey`).
|
|
236
|
-
- `typecheck` (`enable`, `try`, `disable`) and `codegen` (`enable`, `disable`) go to
|
|
237
|
-
`convex deploy` as flags.
|
|
238
|
-
- Deleting the resource does nothing. The functions and the `env` variables stay: the deployment
|
|
239
|
-
runs them.
|
|
240
|
-
- `Convex.DeployKey`: `{ deployment, name, allowedActions? }`. Outputs `uniqueName`, `keyId`, and
|
|
241
|
-
the `deployKey` secret. Any change replaces the key. Delete revokes the key by its secret; a key
|
|
242
|
-
from 0.1 state stays. Keys are never adopted: a key without its secret is useless. The live test
|
|
243
|
-
pushes with `Convex.Code` and sets `env` with a key that has only `deployment:deploy`,
|
|
244
|
-
`deployment:env:view`, and `deployment:env:write`.
|
|
245
|
-
- `Convex.PreviewDeployKey`: `{ projectId, name }`. Project-level key for preview deployments.
|
|
246
|
-
Outputs `uniqueName`, `keyId`, and `previewDeployKey`.
|
|
247
|
-
- `Convex.EnvironmentVariable`: `{ deployment, deployKey, name, value }`. One variable on one
|
|
248
|
-
deployment, set through the deployment API with that deployment's key. An existing variable with
|
|
249
|
-
the same name is adopted and overwritten only with `--adopt`. A new `value` or `deployKey` is an
|
|
250
|
-
update in place. A new `name` or `deployment` stops the deploy with `VariableIdentityChange`:
|
|
251
|
-
use a new logical id. Outputs `deployment`, `name`, and `deployKey`. Read and delete use the
|
|
252
|
-
deploy key in the outputs, not the props.
|
|
253
|
-
- `Convex.DefaultEnvironmentVariable`: `{ projectId, name, value, deploymentType }`. A project
|
|
254
|
-
default that new deployments of that type inherit. Use it for preview and dev deployments. An
|
|
255
|
-
existing default with the same name and type is adopted and overwritten only with `--adopt`. A
|
|
256
|
-
new `value` is an update in place. A new `projectId`, `name`, or `deploymentType` stops the
|
|
257
|
-
deploy with `VariableIdentityChange`: use a new logical id.
|
|
258
|
-
- `Convex.Deploy` (deprecated since 0.3, use `Convex.Code`): `{ cwd?, env?, deployKey,
|
|
259
|
-
previewName?, previewCreate?, previewRun?, extraArgs?, memo?, timeout? }`. Runs
|
|
260
|
-
`npx convex deploy` with `CONVEX_DEPLOY_KEY` set and parses the deployment URL from the CLI
|
|
261
|
-
output. Outputs `url`, `deploymentName`, `hash`. It stays so that stacks and state from 0.1
|
|
262
|
-
and 0.2 keep working. Deleting the resource does nothing.
|
|
263
|
-
|
|
264
|
-
### Which Convex call each operation uses
|
|
265
|
-
|
|
266
|
-
| Operation | Path |
|
|
267
|
-
| ---------------------------------------- | ----------------------------------------------------------------------------------- |
|
|
268
|
-
| Find the production deployment | `GET /projects/{project_id}/list_deployments?deploymentType=prod&isDefault=true` |
|
|
269
|
-
| Find a dev or preview deployment by name | `GET /projects/{project_id}/list_deployments?deploymentType=<type>` |
|
|
270
|
-
| Create a dev or preview deployment | `POST /projects/{project_id}/create_deployment` with `type` and `reference` |
|
|
271
|
-
| Check that a deployment exists | `GET /deployments/{deployment_name}` |
|
|
272
|
-
| Delete a dev or preview deployment | `POST /deployments/{deployment_name}/delete` |
|
|
273
|
-
| Push to a deployment | `convex deploy --env-file <file>` with a deploy key of the deployment |
|
|
274
|
-
| Push to a preview deployment | `convex deploy --preview-name <name> --env-file <file>` with a preview deploy key |
|
|
275
|
-
| Set `env` variables | `POST https://<deployment>/api/v1/update_environment_variables` with the deploy key |
|
|
276
|
-
|
|
277
|
-
Code uses `--preview-name`, not `--preview-create`: `--preview-create` deletes and creates the
|
|
278
|
-
preview deployment again on every push, so every deploy would lose the preview data and change its
|
|
279
|
-
URL.
|
|
150
|
+
times.
|
|
280
151
|
|
|
281
152
|
## Limits
|
|
282
153
|
|
|
283
|
-
-
|
|
284
|
-
|
|
285
|
-
-
|
|
286
|
-
|
|
287
|
-
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
-
|
|
292
|
-
|
|
293
|
-
`--adopt` to take that deployment over.
|
|
294
|
-
- Between the lookup and the create of a preview deployment, another writer can create a preview
|
|
295
|
-
with the same name. The Convex create then replaces it. The Management API has no create that
|
|
296
|
-
fails for an existing preview name.
|
|
297
|
-
- `siteUrl` is the `.convex.site` URL. A custom domain is not used.
|
|
298
|
-
- When another production deployment becomes the default, a `DeployKey` with `deployment: prod.name`
|
|
299
|
-
gets a new key on the new deployment. Alchemy plans this as an update, not a replacement, so the
|
|
300
|
-
key on the old deployment stays. Delete it in the Convex dashboard.
|
|
301
|
-
- Variables that `Convex.Code` set on a deployment stay there when `deployment` changes to
|
|
302
|
-
another deployment, and when the resource is removed.
|
|
154
|
+
- `env` values are props, so Alchemy state holds them. Keep `.alchemy/` git-ignored, and use an
|
|
155
|
+
encrypted state store, such as `Cloudflare.state()`, in CI.
|
|
156
|
+
- The hash does not see a change in a workspace package outside the app directory, or a push from
|
|
157
|
+
outside Alchemy. Change a file of the app to push again.
|
|
158
|
+
- With a deploy key, the provider reaches the deployment at `https://<name>.convex.cloud`, so the
|
|
159
|
+
deployment must answer there.
|
|
160
|
+
- A run that stops between a deployment create and the state write leaves a deployment that state
|
|
161
|
+
does not know. The next run stops with `OwnedBySomeoneElse`; run it with `--adopt`.
|
|
162
|
+
- Team slugs for `{ team, name }` resolve through an unofficial dashboard endpoint. Pass the numeric
|
|
163
|
+
team id to avoid it. `{ team, slug }` uses the official endpoint.
|
|
303
164
|
- Not covered: deployment regions and classes, custom domains, log streams, teams and members,
|
|
304
165
|
components, snapshots.
|
|
305
166
|
|
|
@@ -312,26 +173,16 @@ pnpm run build # lib/ with declarations, then publint and attw
|
|
|
312
173
|
pnpm run test:live # real API calls, see below
|
|
313
174
|
```
|
|
314
175
|
|
|
315
|
-
Use Node 24 (`.node-version`) and pnpm 11.
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
`
|
|
323
|
-
the deploy test). They create resources named `tmp-alchemy-convex-*` and remove them again.
|
|
324
|
-
A file argument runs one live file only, for example
|
|
325
|
-
`pnpm run test:live test/live/safety.live.test.ts`. That test runs the data safety contract
|
|
326
|
-
through the Alchemy engine. It creates a project `tmp-alchemy-convex-<8 hex>` in
|
|
327
|
-
`ALCHEMY_CONVEX_LIVE_TEAM` and deletes it at the end, also after a failure. It refuses to delete a
|
|
328
|
-
project whose name does not start with `tmp-alchemy-convex-`.
|
|
329
|
-
`test/live/deployment-code.live.test.ts` does the same for `Convex.Deployment` and
|
|
330
|
-
`Convex.Code`: it pushes the app in `test/fixtures/convex-app` with the real Convex CLI to the
|
|
331
|
-
production deployment and to a preview deployment, and it also refuses to delete a deployment of
|
|
332
|
-
another project.
|
|
176
|
+
Use Node 24 (`.node-version`) and pnpm 11. Unit tests run against recorded Management API payloads
|
|
177
|
+
in `test/fixtures/management/` and a fake Convex CLI. Live tests run only with
|
|
178
|
+
`ALCHEMY_CONVEX_LIVE=1`, which `pnpm run test:live` sets. They need a Convex login or
|
|
179
|
+
`CONVEX_ACCESS_TOKEN` that can create projects in `ALCHEMY_CONVEX_LIVE_TEAM`. Each test creates a
|
|
180
|
+
project whose name starts with `ALCHEMY_CONVEX_LIVE_PREFIX` (default `tmp-alchemy-convex-`),
|
|
181
|
+
deletes it at the end, also after a failure, and refuses to delete a project, or a deployment of a
|
|
182
|
+
project, without that prefix. A file argument runs one live file only, for example
|
|
183
|
+
`pnpm run test:live test/live/plane.live.test.ts`.
|
|
333
184
|
|
|
334
185
|
Releases: change `version` in `package.json` in a pull request. After the merge,
|
|
335
186
|
`.github/workflows/release.yml` publishes that version from `main` with npm trusted publishing.
|
|
336
187
|
|
|
337
|
-
License: Apache 2.0.
|
|
188
|
+
License: Apache 2.0. Parts follow Confect; see [NOTICE](NOTICE).
|