@samebase/alchemy-convex 0.7.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +50 -15
- package/lib/index.d.ts +49 -11
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +126 -66
- package/lib/index.js.map +1 -1
- package/package.json +3 -3
- package/src/Deployment.ts +97 -18
- package/src/Providers.ts +2 -2
- package/src/Push.ts +58 -48
- package/src/State.ts +35 -29
- package/src/index.ts +2 -0
- package/src/store/convex/_generated/api.d.ts +4 -0
- package/src/store/convex/auth.config.ts +14 -0
- package/src/store/convex/reader.ts +131 -0
- package/src/store/convex/runRecord.ts +41 -0
- package/src/store/convex/schema.ts +3 -1
- package/src/store/convex/state.ts +47 -21
- package/src/store/convex/version.ts +6 -4
- package/src/store/package.json +1 -1
package/README.md
CHANGED
|
@@ -69,6 +69,28 @@ deployment if it has code, only with `--adopt`.
|
|
|
69
69
|
it stays until Convex deletes it at expiry (14 days by default).
|
|
70
70
|
[`examples/app/alchemy.run.ts`](examples/app/alchemy.run.ts) is the same stack.
|
|
71
71
|
|
|
72
|
+
### The stack file at the repository root
|
|
73
|
+
|
|
74
|
+
`rootDir` is the app directory, relative to the directory where `alchemy deploy` runs, which is
|
|
75
|
+
the directory of the stack file. The default is `"."`. The push runs in `rootDir`, and `source` is
|
|
76
|
+
relative to it:
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
Effect.gen(function* () {
|
|
80
|
+
const project = yield* Convex.Project("Project", { team: "my-team", slug: "my-app" });
|
|
81
|
+
const backend = yield* Convex.Deployment("Backend", {
|
|
82
|
+
project,
|
|
83
|
+
type: "prod",
|
|
84
|
+
rootDir: "apps/web", // the Convex app, with its package.json
|
|
85
|
+
source: "./convex", // apps/web/convex
|
|
86
|
+
});
|
|
87
|
+
return { convexUrl: backend.url };
|
|
88
|
+
});
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
State always holds `rootDir`, `"."` included, so a reader of the state finds the app directory of
|
|
92
|
+
each deployment.
|
|
93
|
+
|
|
72
94
|
## Credentials
|
|
73
95
|
|
|
74
96
|
Credentials are a layer, never props, so they do not go into Alchemy state. `Convex.providers()`
|
|
@@ -113,11 +135,20 @@ is set must be the slug of that team, checked against its projects, and a token
|
|
|
113
135
|
fails the run. The Convex CLI login needs the slug or the id. The first run of a team creates
|
|
114
136
|
the project `alchemy-state` and pushes the store functions to its
|
|
115
137
|
production deployment with the Convex CLI of the app; a later version of this package pushes a
|
|
116
|
-
newer store when it finds an older one
|
|
138
|
+
newer store when it finds an older one. A store that is newer than the package fails the run with
|
|
139
|
+
both versions, so the repositories of a team upgrade the package together. Each run makes a
|
|
117
140
|
deploy key of that deployment that can only run the store's internal functions, and deletes it at
|
|
118
141
|
the end. Rows are in the tables `resources` and `outputs` in the dashboard, under the stack name.
|
|
119
142
|
The store has no lock: run one deploy of a stage at a time, such as with a CI concurrency group.
|
|
120
|
-
The
|
|
143
|
+
The store and its readers (Samebase) are released and upgraded together.
|
|
144
|
+
|
|
145
|
+
Store version 3 supports native subscriptions. A trusted server checks repository access, then
|
|
146
|
+
calls internal `reader:authorize({ repository, subject })` with a deployment credential. It gives
|
|
147
|
+
the returned token to a separate `ConvexClient` connected to the state deployment. The client
|
|
148
|
+
subscribes to `reader:repository({})`; the verified token selects the repository. The token has a
|
|
149
|
+
five-minute lifetime and permits redacted reads only. The server checks access again on renewal.
|
|
150
|
+
The store uses its own native signing key and JWKS, so no extra signing secret is required.
|
|
151
|
+
See [the reader contract](docs/design/convex-state.md#repository-subscriptions-090).
|
|
121
152
|
|
|
122
153
|
### What the output records about a run
|
|
123
154
|
|
|
@@ -160,25 +191,29 @@ call.
|
|
|
160
191
|
taken over with `--adopt`; it never creates or renames a project. Outputs `projectId`, `slug`,
|
|
161
192
|
`name`, `teamId`, `prodDeploymentName`, `prodDeploymentUrl`.
|
|
162
193
|
- `Convex.Deployment`: `{ project, type: "prod" }` or `{ project, type: "dev" | "preview", name }`,
|
|
163
|
-
each with optional `source
|
|
164
|
-
`siteUrl`, `type`, `projectId`, `reference`, `previewName`, `hash`, and `envNames`.
|
|
194
|
+
each with optional `rootDir`, `source`, and `env`. Outputs `name` (such as `happy-animal-123`),
|
|
195
|
+
`url`, `siteUrl`, `type`, `projectId`, `reference`, `previewName`, `hash`, and `envNames`.
|
|
165
196
|
- `prod` is the project's default production deployment (with a deploy key: the key's
|
|
166
197
|
production deployment). The resource never creates or deletes one. A production deployment
|
|
167
198
|
with code that is not in state is taken over only with `--adopt`.
|
|
168
199
|
- `dev` creates a dev deployment with `name` as its reference; `preview` creates a preview
|
|
169
200
|
deployment with `name` as its preview name. An expired preview is created again on the next
|
|
170
201
|
deploy.
|
|
171
|
-
- `
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
202
|
+
- `rootDir` is the app directory, relative to the directory where the deploy runs, `"."` by
|
|
203
|
+
default. It must be relative (`AbsoluteRootDir`) and have a package.json (`ConvexAppNotFound`).
|
|
204
|
+
There is no search in the directories above it. When convex.json puts the functions outside
|
|
205
|
+
`rootDir`, the hash covers them too.
|
|
206
|
+
- `source` is the Convex functions directory relative to `rootDir`: `convex/`, or the `functions`
|
|
207
|
+
field of convex.json (`SourceMismatch`). The CLI runs in `rootDir`, with the Node.js that runs
|
|
208
|
+
Alchemy, and is never downloaded (`ConvexCliNotFound`).
|
|
209
|
+
- The content identity is a hash of every file of `rootDir` that git does not ignore, the nearest
|
|
210
|
+
lockfile, the deployment name, and `env`. The same hash is a no-op. Otherwise the update sets
|
|
211
|
+
`env`, then pushes. A failed push sets the changed variables back, and deletes a dev or preview
|
|
212
|
+
deployment that the same run created.
|
|
178
213
|
- `env` values are strings or secrets such as `Config.Redacted("AUTH_SECRET")`. A name that
|
|
179
214
|
leaves `env` is removed from the deployment.
|
|
180
|
-
- `source: { path, command?, include? }` replaces `convex deploy` with `command`, run in
|
|
181
|
-
|
|
215
|
+
- `source: { path, command?, include? }` replaces `convex deploy` with `command`, run in `rootDir`
|
|
216
|
+
with the push key in `CONVEX_DEPLOY_KEY`, such as
|
|
182
217
|
`["node_modules/.bin/convex-hosting", "deploy", "--build", "node_modules/.bin/vp build", "--dist", "dist/client"]`.
|
|
183
218
|
The command must push with `convex deploy` (convex-hosting does, through `--cmd`). `include`
|
|
184
219
|
narrows the hash to `path`, package.json, convex.json, the lockfile, and the listed globs, such
|
|
@@ -215,8 +250,8 @@ call.
|
|
|
215
250
|
|
|
216
251
|
- `env` values are props, so Alchemy state holds them. Keep `.alchemy/` git-ignored, and use an
|
|
217
252
|
encrypted state store, such as `Cloudflare.state()`, in CI.
|
|
218
|
-
- The hash does not see a change in a workspace package outside
|
|
219
|
-
|
|
253
|
+
- The hash does not see a change in a workspace package outside `rootDir`, or a push from outside
|
|
254
|
+
Alchemy. Change a file of the app to push again.
|
|
220
255
|
- With a deploy key, the provider reaches the deployment at `https://<name>.convex.cloud`, so the
|
|
221
256
|
deployment must answer there.
|
|
222
257
|
- A run that stops between a deployment create and the state write leaves a deployment that state
|
package/lib/index.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ import * as ChildProcessSpawner from "effect/process/ChildProcessSpawner";
|
|
|
9
9
|
import { createDeploymentClient, createManagementClient } from "@convex-dev/platform";
|
|
10
10
|
import "effect/Scope";
|
|
11
11
|
import { State, StateStoreError } from "alchemy/State";
|
|
12
|
+
import { InputProps } from "alchemy/Input";
|
|
12
13
|
import { components } from "@convex-dev/platform/managementApi";
|
|
13
14
|
//#region src/Credentials.d.ts
|
|
14
15
|
interface ResolvedCredentials {
|
|
@@ -117,11 +118,12 @@ export declare const providers: (credentials?: Layer.Layer<Credentials>) => Laye
|
|
|
117
118
|
/** A value of the `env` prop: a string, or a secret such as `Config.Redacted("AUTH_SECRET")`. */
|
|
118
119
|
type EnvValue = string | Redacted.Redacted<string>;
|
|
119
120
|
/**
|
|
120
|
-
* The `source` prop: the Convex functions directory
|
|
121
|
-
*
|
|
121
|
+
* The `source` prop: the Convex functions directory relative to the app
|
|
122
|
+
* directory (`rootDir`), such as `./convex`, or that directory with a push
|
|
123
|
+
* command and more files for the content identity.
|
|
122
124
|
*/
|
|
123
125
|
type Source = string | {
|
|
124
|
-
/** The Convex functions directory, such as `./convex`. */
|
|
126
|
+
/** The Convex functions directory relative to the app directory, such as `./convex`. */
|
|
125
127
|
readonly path: string;
|
|
126
128
|
/**
|
|
127
129
|
* Replaces `convex deploy`: a program and its arguments, run in the app
|
|
@@ -147,9 +149,10 @@ export declare class ConvexCliNotFound extends ConvexCliNotFound_base {
|
|
|
147
149
|
get message(): string;
|
|
148
150
|
}
|
|
149
151
|
declare const ConvexAppNotFound_base: Schema.Class<ConvexAppNotFound, Schema.TaggedStruct<"ConvexAppNotFound", {
|
|
150
|
-
|
|
152
|
+
/** The app directory, resolved against the working directory of the deploy. */
|
|
153
|
+
readonly rootDir: Schema.String;
|
|
151
154
|
}>, import("effect/Cause").YieldableError>;
|
|
152
|
-
/**
|
|
155
|
+
/** The app directory (`rootDir`) has no package.json. */
|
|
153
156
|
export declare class ConvexAppNotFound extends ConvexAppNotFound_base {
|
|
154
157
|
get message(): string;
|
|
155
158
|
}
|
|
@@ -199,10 +202,16 @@ interface DeploymentInputs {
|
|
|
199
202
|
readonly projectId: number;
|
|
200
203
|
};
|
|
201
204
|
/**
|
|
202
|
-
* The
|
|
203
|
-
*
|
|
204
|
-
*
|
|
205
|
-
*
|
|
205
|
+
* The app directory, relative to the directory where the deploy runs (the
|
|
206
|
+
* directory of the stack file), such as `apps/web`. Default ".". It must
|
|
207
|
+
* have a package.json. The push runs in it, and `source` is relative to
|
|
208
|
+
* it. State from 0.7 has no `rootDir`.
|
|
209
|
+
*/
|
|
210
|
+
readonly rootDir?: string;
|
|
211
|
+
/**
|
|
212
|
+
* The Convex functions directory relative to `rootDir`, such as
|
|
213
|
+
* `./convex`, or that directory with a push command and more hashed
|
|
214
|
+
* files. Without `source`, the resource pushes nothing.
|
|
206
215
|
*/
|
|
207
216
|
readonly source?: Source;
|
|
208
217
|
/** Environment variables to set on the deployment before the push. */
|
|
@@ -242,7 +251,36 @@ interface DeploymentAttributes extends DeploymentTarget {
|
|
|
242
251
|
readonly envNames: readonly string[];
|
|
243
252
|
}
|
|
244
253
|
export type Deployment = Resource<"Convex.Deployment", DeploymentProps, DeploymentAttributes, never, Providers>;
|
|
245
|
-
|
|
254
|
+
/** The props of a `Convex.Deployment` call: Alchemy inputs, with `rootDir` a plain string. */
|
|
255
|
+
type DeploymentInput = DeploymentProps extends (infer P) ? P extends DeploymentProps ? InputProps<P, "rootDir"> : never : never;
|
|
256
|
+
declare const AbsoluteRootDir_base: Schema.Class<AbsoluteRootDir, Schema.TaggedStruct<"AbsoluteRootDir", {
|
|
257
|
+
readonly rootDir: Schema.String;
|
|
258
|
+
}>, import("effect/Cause").YieldableError>;
|
|
259
|
+
/** `rootDir` is an absolute path. The declaration stops with it as a defect, before the plan. */
|
|
260
|
+
export declare class AbsoluteRootDir extends AbsoluteRootDir_base {
|
|
261
|
+
get message(): string;
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* `Convex.Deployment("id", props)`. The props go to state with `rootDir` in
|
|
265
|
+
* POSIX form, and with "." when it is not set, so that every row names the
|
|
266
|
+
* app directory of its deployment. An absolute `rootDir` stops the
|
|
267
|
+
* declaration, so it never reaches the plan or state. The check dies,
|
|
268
|
+
* because the program of `Alchemy.Stack` can fail only with a ConfigError.
|
|
269
|
+
* `win32.isAbsolute` also answers true for a POSIX absolute path. The other
|
|
270
|
+
* fields keep it usable where Alchemy takes a resource class, such as
|
|
271
|
+
* `Provider.collection`.
|
|
272
|
+
*/
|
|
273
|
+
export declare const Deployment: ((id: string, props: DeploymentInput) => Effect.Effect<Deployment, never, Providers>) & {
|
|
274
|
+
Type: "Convex.Deployment";
|
|
275
|
+
Props: DeploymentProps;
|
|
276
|
+
Self: import("alchemy/Self").Self<Deployment>;
|
|
277
|
+
Provider: Provider.Provider<Deployment>;
|
|
278
|
+
Aliases: readonly string[] | undefined;
|
|
279
|
+
ref: (id: string, options?: {
|
|
280
|
+
stage?: string;
|
|
281
|
+
stack?: string;
|
|
282
|
+
}) => Effect.Effect<Deployment, never, never>;
|
|
283
|
+
};
|
|
246
284
|
declare const DeploymentIdentityChange_base: Schema.Class<DeploymentIdentityChange, Schema.TaggedStruct<"DeploymentIdentityChange", {
|
|
247
285
|
/** Name of the deployment in state, such as `happy-animal-123`. */
|
|
248
286
|
readonly deployment: Schema.String;
|
|
@@ -410,5 +448,5 @@ export declare const state: (options?: {
|
|
|
410
448
|
readonly team?: string | number;
|
|
411
449
|
}) => Layer.Layer<State, never, ChildProcessSpawner.ChildProcessSpawner>;
|
|
412
450
|
//#endregion
|
|
413
|
-
export type { DeploymentAttributes, DeploymentProps, DeploymentRegion, EnvValue, ProjectAttributes, ProjectProps, RunRecord, Source };
|
|
451
|
+
export type { DeploymentAttributes, DeploymentInput, DeploymentProps, DeploymentRegion, EnvValue, ProjectAttributes, ProjectProps, RunRecord, Source };
|
|
414
452
|
//# sourceMappingURL=index.d.ts.map
|
package/lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/Credentials.ts","../src/ManagementApi.ts","../src/Providers.ts","../src/Push.ts","../src/Deployment.ts","../src/Project.ts","../src/RunRecord.ts","../src/State.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/Credentials.ts","../src/ManagementApi.ts","../src/Providers.ts","../src/Push.ts","../src/Deployment.ts","../src/Project.ts","../src/RunRecord.ts","../src/State.ts"],"mappings":"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"}
|
package/lib/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
2
|
import { access, mkdtemp, readFile, realpath, rm, writeFile } from "node:fs/promises";
|
|
3
3
|
import { homedir, tmpdir } from "node:os";
|
|
4
|
-
import { dirname, join, relative, resolve, sep } from "node:path";
|
|
4
|
+
import { dirname, join, posix, relative, resolve, sep, win32 } from "node:path";
|
|
5
5
|
import * as Config from "effect/Config";
|
|
6
6
|
import * as Context from "effect/Context";
|
|
7
7
|
import * as Effect from "effect/Effect";
|
|
@@ -282,13 +282,15 @@ const EnvironmentVariableList = Schema.Struct({ environmentVariables: Schema.Rec
|
|
|
282
282
|
/** No `convex` package resolves from the app directory. */
|
|
283
283
|
var ConvexCliNotFound = class extends Schema.TaggedError()("ConvexCliNotFound", { cwd: Schema.String }) {
|
|
284
284
|
get message() {
|
|
285
|
-
return `Convex.Deployment found no installed convex package from ${this.cwd}, and it does not download one. Install convex in the app (npm install convex), or set
|
|
285
|
+
return `Convex.Deployment found no installed convex package from ${this.cwd}, and it does not download one. Install convex in the app (npm install convex), or set rootDir to the directory of the app.`;
|
|
286
286
|
}
|
|
287
287
|
};
|
|
288
|
-
/**
|
|
289
|
-
var ConvexAppNotFound = class extends Schema.TaggedError()("ConvexAppNotFound", {
|
|
288
|
+
/** The app directory (`rootDir`) has no package.json. */
|
|
289
|
+
var ConvexAppNotFound = class extends Schema.TaggedError()("ConvexAppNotFound", {
|
|
290
|
+
/** The app directory, resolved against the working directory of the deploy. */
|
|
291
|
+
rootDir: Schema.String }) {
|
|
290
292
|
get message() {
|
|
291
|
-
return `Convex.Deployment found no package.json
|
|
293
|
+
return `Convex.Deployment found no package.json in ${this.rootDir}. Set rootDir to the directory of the Convex app, relative to the directory where the deploy runs, such as "apps/web".`;
|
|
292
294
|
}
|
|
293
295
|
};
|
|
294
296
|
/** The Convex CLI failed, or exited 0 without the deployment URL. The output tail never contains the key. */
|
|
@@ -372,28 +374,26 @@ const parseDeployOutput = (text) => {
|
|
|
372
374
|
/** The last non-empty lines of `text`, without escape codes and with every secret replaced. */
|
|
373
375
|
const outputTail = (text, secrets) => secrets.reduce((redacted, secret) => redacted.split(secret).join("[REDACTED]"), stripVTControlCharacters(text)).split(/\r?\n|\r/).filter((line) => line.trim() !== "").slice(-20).join("\n");
|
|
374
376
|
const valueOf$1 = (value) => Redacted.isRedacted(value) ? Redacted.value(value) : value;
|
|
375
|
-
/**
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
},
|
|
388
|
-
catch: () => new ConvexAppNotFound({ source })
|
|
389
|
-
});
|
|
390
|
-
/** `source` is not the functions directory that the Convex CLI pushes from this app. */
|
|
377
|
+
/**
|
|
378
|
+
* The app directory: `rootDir` resolved against the working directory of the
|
|
379
|
+
* deploy. It must have a package.json. There is no search above it.
|
|
380
|
+
*/
|
|
381
|
+
const appDirectoryOf = (rootDir) => {
|
|
382
|
+
const directory = resolve(rootDir);
|
|
383
|
+
return Effect.tryPromise({
|
|
384
|
+
try: () => access(join(directory, "package.json")).then(() => directory),
|
|
385
|
+
catch: () => new ConvexAppNotFound({ rootDir: directory })
|
|
386
|
+
});
|
|
387
|
+
};
|
|
388
|
+
/** `source` is not the functions directory that the Convex CLI pushes from the app directory. */
|
|
391
389
|
var SourceMismatch = class extends Schema.TaggedError()("SourceMismatch", {
|
|
390
|
+
/** The app directory, resolved. */
|
|
391
|
+
rootDir: Schema.String,
|
|
392
392
|
source: Schema.String,
|
|
393
393
|
functions: Schema.String
|
|
394
394
|
}) {
|
|
395
395
|
get message() {
|
|
396
|
-
return `Convex.Deployment source is ${this.source}, but the Convex CLI pushes ${this.functions}
|
|
396
|
+
return `Convex.Deployment source is ${this.source}, but the Convex CLI pushes ${this.functions} from the app directory ${this.rootDir} (the "functions" field of convex.json, or convex/ by default). Set rootDir to the directory of the Convex app, and source to its functions directory relative to rootDir, such as "./convex".`;
|
|
397
397
|
}
|
|
398
398
|
};
|
|
399
399
|
const ConvexJson = Schema.Struct({ functions: Schema.optionalKey(Schema.String) });
|
|
@@ -402,8 +402,9 @@ const checkFunctionsDirectory = (cwd, path) => Effect.gen(function* () {
|
|
|
402
402
|
const text = yield* Effect.promise(() => readFile(join(cwd, "convex.json"), "utf8").catch(() => void 0));
|
|
403
403
|
const configured = text === void 0 ? void 0 : Schema.decodeUnknownSync(Schema.fromJsonString(ConvexJson))(text).functions;
|
|
404
404
|
const functions = resolve(cwd, configured ?? "convex");
|
|
405
|
-
if (functions !==
|
|
406
|
-
|
|
405
|
+
if (functions !== path) return yield* new SourceMismatch({
|
|
406
|
+
rootDir: cwd,
|
|
407
|
+
source: path,
|
|
407
408
|
functions
|
|
408
409
|
});
|
|
409
410
|
});
|
|
@@ -427,18 +428,24 @@ const installedCli = (cwd) => Effect.tryPromise({
|
|
|
427
428
|
*/
|
|
428
429
|
const pushHash = (options) => Effect.gen(function* () {
|
|
429
430
|
const source = options.source === void 0 ? void 0 : sourceOf(options.source);
|
|
430
|
-
const files = source === void 0 ? void 0 : yield* appDirectoryOf(
|
|
431
|
-
cwd,
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
431
|
+
const files = source === void 0 ? void 0 : yield* appDirectoryOf(options.rootDir).pipe(Effect.flatMap((cwd) => {
|
|
432
|
+
const functions = relative(cwd, resolve(cwd, source.path)).split("\\").join("/");
|
|
433
|
+
return hashDirectory({
|
|
434
|
+
cwd,
|
|
435
|
+
memo: source.include !== void 0 ? {
|
|
436
|
+
include: [
|
|
437
|
+
`${functions}/**`,
|
|
438
|
+
"package.json",
|
|
439
|
+
"convex.json",
|
|
440
|
+
...source.include
|
|
441
|
+
],
|
|
442
|
+
lockfile: true
|
|
443
|
+
} : functions === ".." || functions.startsWith("../") ? {
|
|
444
|
+
include: ["**/*", `${functions}/**`],
|
|
445
|
+
lockfile: true
|
|
446
|
+
} : {}
|
|
447
|
+
});
|
|
448
|
+
}));
|
|
442
449
|
const env = Object.entries(options.env).map(([name, value]) => [name, valueOf$1(value)]).sort(([a], [b]) => a < b ? -1 : 1);
|
|
443
450
|
return createHash("sha256").update(JSON.stringify({
|
|
444
451
|
files,
|
|
@@ -510,13 +517,13 @@ const writeVariables = (url, key, changes) => settleVoid("update environment var
|
|
|
510
517
|
})) } }));
|
|
511
518
|
/**
|
|
512
519
|
* The app directory and the program of a push. Fails before any change when
|
|
513
|
-
* `source` is not the functions directory
|
|
514
|
-
* installed Convex CLI and no push command.
|
|
520
|
+
* `rootDir` has no package.json, when `source` is not the functions directory
|
|
521
|
+
* of the app, or when the app has no installed Convex CLI and no push command.
|
|
515
522
|
*/
|
|
516
|
-
const checkSource = (input) => Effect.gen(function* () {
|
|
523
|
+
const checkSource = (rootDir, input) => Effect.gen(function* () {
|
|
517
524
|
const source = sourceOf(input);
|
|
518
|
-
const cwd = yield* appDirectoryOf(
|
|
519
|
-
yield* checkFunctionsDirectory(cwd, source.path);
|
|
525
|
+
const cwd = yield* appDirectoryOf(rootDir);
|
|
526
|
+
yield* checkFunctionsDirectory(cwd, resolve(cwd, source.path));
|
|
520
527
|
return {
|
|
521
528
|
cwd,
|
|
522
529
|
program: source.command ?? (yield* installedCli(cwd))
|
|
@@ -530,7 +537,7 @@ const checkSource = (input) => Effect.gen(function* () {
|
|
|
530
537
|
*/
|
|
531
538
|
const push = (spawner, key, options) => Effect.gen(function* () {
|
|
532
539
|
const source = options.source === void 0 ? void 0 : sourceOf(options.source);
|
|
533
|
-
const resolved = options.source === void 0 ? void 0 : yield* checkSource(options.source);
|
|
540
|
+
const resolved = options.source === void 0 ? void 0 : yield* checkSource(options.rootDir, options.source);
|
|
534
541
|
const cwd = resolved?.cwd;
|
|
535
542
|
const program = resolved?.program;
|
|
536
543
|
const env = Object.entries(options.env).sort(([a], [b]) => a < b ? -1 : 1);
|
|
@@ -628,7 +635,43 @@ const runPush = (spawner, key, options) => Effect.gen(function* () {
|
|
|
628
635
|
});
|
|
629
636
|
//#endregion
|
|
630
637
|
//#region src/Deployment.ts
|
|
631
|
-
|
|
638
|
+
/** The resource class. Stacks call {@link Deployment}, which writes `rootDir` into the props. */
|
|
639
|
+
const DeploymentResource = Resource("Convex.Deployment", { defaultRemovalPolicy: "retain" });
|
|
640
|
+
/** `rootDir` in POSIX form, without "./" and a trailing slash, such as `apps/web` or ".". */
|
|
641
|
+
const normalizeRootDir = (rootDir) => {
|
|
642
|
+
const normalized = posix.normalize(rootDir.replaceAll("\\", "/"));
|
|
643
|
+
return normalized.length > 1 && normalized.endsWith("/") ? normalized.slice(0, -1) : normalized;
|
|
644
|
+
};
|
|
645
|
+
/** `rootDir` is an absolute path. The declaration stops with it as a defect, before the plan. */
|
|
646
|
+
var AbsoluteRootDir = class extends Schema.TaggedError()("AbsoluteRootDir", { rootDir: Schema.String }) {
|
|
647
|
+
get message() {
|
|
648
|
+
return `Convex.Deployment rootDir ${this.rootDir} is an absolute path. State keeps rootDir for every machine that runs the stack, so set it relative to the directory where the deploy runs, such as "apps/web".`;
|
|
649
|
+
}
|
|
650
|
+
};
|
|
651
|
+
/**
|
|
652
|
+
* `Convex.Deployment("id", props)`. The props go to state with `rootDir` in
|
|
653
|
+
* POSIX form, and with "." when it is not set, so that every row names the
|
|
654
|
+
* app directory of its deployment. An absolute `rootDir` stops the
|
|
655
|
+
* declaration, so it never reaches the plan or state. The check dies,
|
|
656
|
+
* because the program of `Alchemy.Stack` can fail only with a ConfigError.
|
|
657
|
+
* `win32.isAbsolute` also answers true for a POSIX absolute path. The other
|
|
658
|
+
* fields keep it usable where Alchemy takes a resource class, such as
|
|
659
|
+
* `Provider.collection`.
|
|
660
|
+
*/
|
|
661
|
+
const Deployment = Object.assign((id, props) => {
|
|
662
|
+
const rootDir = props.rootDir ?? ".";
|
|
663
|
+
return win32.isAbsolute(rootDir) ? Effect.die(new AbsoluteRootDir({ rootDir })) : DeploymentResource(id, {
|
|
664
|
+
...props,
|
|
665
|
+
rootDir: normalizeRootDir(rootDir)
|
|
666
|
+
});
|
|
667
|
+
}, {
|
|
668
|
+
Type: DeploymentResource.Type,
|
|
669
|
+
Props: DeploymentResource.Props,
|
|
670
|
+
Self: DeploymentResource.Self,
|
|
671
|
+
Provider: DeploymentResource.Provider,
|
|
672
|
+
Aliases: DeploymentResource.Aliases,
|
|
673
|
+
ref: (id, options) => DeploymentResource.ref(id, options)
|
|
674
|
+
});
|
|
632
675
|
/** The props name another deployment than the one in state. */
|
|
633
676
|
var DeploymentIdentityChange = class extends Schema.TaggedError()("DeploymentIdentityChange", {
|
|
634
677
|
/** Name of the deployment in state, such as `happy-animal-123`. */
|
|
@@ -750,7 +793,7 @@ const ProjectSlugs = Schema.Struct({
|
|
|
750
793
|
});
|
|
751
794
|
/** True for an answer that says this credential cannot read the object. */
|
|
752
795
|
const isRefused = (error) => error.status === 400 || error.status === 401 || error.status === 403 || error.status === 404;
|
|
753
|
-
const DeploymentProvider = () => Provider.effect(
|
|
796
|
+
const DeploymentProvider = () => Provider.effect(DeploymentResource, Effect.gen(function* () {
|
|
754
797
|
const api = yield* ManagementApi;
|
|
755
798
|
const credentials = yield* Credentials;
|
|
756
799
|
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
|
|
@@ -843,7 +886,8 @@ const DeploymentProvider = () => Provider.effect(Deployment, Effect.gen(function
|
|
|
843
886
|
return row === void 0 ? void 0 : targetOf(row, output.type, output.previewName);
|
|
844
887
|
});
|
|
845
888
|
/** The content identity of `source` and `env` on a deployment, or undefined when there is nothing to push. */
|
|
846
|
-
const wantedHash = (news, deployment) => news.source === void 0 && Object.keys(news.env ?? {}).length === 0 ? Effect.succeed(void 0) : pushHash({
|
|
889
|
+
const wantedHash = (news, rootDir, deployment) => news.source === void 0 && Object.keys(news.env ?? {}).length === 0 ? Effect.succeed(void 0) : pushHash({
|
|
890
|
+
rootDir,
|
|
847
891
|
source: news.source,
|
|
848
892
|
deployment,
|
|
849
893
|
env: news.env ?? {}
|
|
@@ -854,12 +898,15 @@ const DeploymentProvider = () => Provider.effect(Deployment, Effect.gen(function
|
|
|
854
898
|
"type",
|
|
855
899
|
"previewName"
|
|
856
900
|
],
|
|
857
|
-
diff: Effect.fn(function* ({ news, output }) {
|
|
901
|
+
diff: Effect.fn(function* ({ news, olds, output }) {
|
|
858
902
|
if (!isResolved(news) || output === void 0) return void 0;
|
|
859
903
|
yield* checkIdentity(output, news);
|
|
904
|
+
const rootDir = news.rootDir ?? ".";
|
|
905
|
+
if (news.source !== void 0) yield* checkSource(rootDir, news.source);
|
|
906
|
+
if (olds.rootDir !== rootDir) return { action: "update" };
|
|
860
907
|
const access = yield* accessFor(addressOf(news), changesEnv(news, output));
|
|
861
908
|
if ((yield* live(access, output))?.name !== output.name) return { action: "update" };
|
|
862
|
-
return (yield* wantedHash(news, output.name)) === output.hash ? { action: "noop" } : { action: "update" };
|
|
909
|
+
return (yield* wantedHash(news, rootDir, output.name)) === output.hash ? { action: "noop" } : { action: "update" };
|
|
863
910
|
}),
|
|
864
911
|
read: Effect.fn(function* ({ olds, output }) {
|
|
865
912
|
if (output !== void 0) {
|
|
@@ -897,7 +944,8 @@ const DeploymentProvider = () => Provider.effect(Deployment, Effect.gen(function
|
|
|
897
944
|
}),
|
|
898
945
|
reconcile: Effect.fn(function* ({ fqn, news, output }) {
|
|
899
946
|
if (output !== void 0) yield* checkIdentity(output, news);
|
|
900
|
-
|
|
947
|
+
const rootDir = news.rootDir ?? ".";
|
|
948
|
+
if (news.source !== void 0) yield* checkSource(rootDir, news.source);
|
|
901
949
|
const address = addressOf(news);
|
|
902
950
|
const access = yield* accessFor(address, changesEnv(news, output));
|
|
903
951
|
const env = news.env ?? {};
|
|
@@ -905,7 +953,7 @@ const DeploymentProvider = () => Provider.effect(Deployment, Effect.gen(function
|
|
|
905
953
|
const adopt = yield* shouldAdopt(fqn);
|
|
906
954
|
const refuse = (name) => new OwnedBySomeoneElse({
|
|
907
955
|
message: `Project ${address.projectId} already has ${news.type} deployment ${name}${news.type === "prod" ? " with code" : ` named "${news.name}"`}. Re-run with --adopt to take it over${news.type === "prod" ? "" : ", or use another name"}.`,
|
|
908
|
-
resourceType:
|
|
956
|
+
resourceType: DeploymentResource.Type,
|
|
909
957
|
physicalName: name
|
|
910
958
|
});
|
|
911
959
|
const { target, created } = yield* Effect.gen(function* () {
|
|
@@ -963,7 +1011,7 @@ const DeploymentProvider = () => Provider.effect(Deployment, Effect.gen(function
|
|
|
963
1011
|
};
|
|
964
1012
|
});
|
|
965
1013
|
const previousEnvNames = output?.name === target.name ? envNamesOf(output) : [];
|
|
966
|
-
const before = yield* wantedHash(news, target.name);
|
|
1014
|
+
const before = yield* wantedHash(news, rootDir, target.name);
|
|
967
1015
|
if (before === void 0 && previousEnvNames.length === 0) return {
|
|
968
1016
|
...target,
|
|
969
1017
|
hash: void 0,
|
|
@@ -977,6 +1025,7 @@ const DeploymentProvider = () => Provider.effect(Deployment, Effect.gen(function
|
|
|
977
1025
|
const options = {
|
|
978
1026
|
deployment: target.name,
|
|
979
1027
|
url: target.url,
|
|
1028
|
+
rootDir,
|
|
980
1029
|
source: news.source,
|
|
981
1030
|
env,
|
|
982
1031
|
previousEnvNames,
|
|
@@ -994,7 +1043,7 @@ const DeploymentProvider = () => Provider.effect(Deployment, Effect.gen(function
|
|
|
994
1043
|
}))).pipe(Effect.onError(() => created && access.kind !== "deployKey" ? absentAsUndefined(retryIdempotentWrite(access.api.requestVoid("delete deployment", (client) => client.POST("/deployments/{deployment_name}/delete", { params: { path: { deployment_name: target.name } } })))).pipe(Effect.catch((error) => Effect.logWarning(`Convex.Deployment could not delete ${target.name} after the failed push (${error.message}). The next run takes it over only with --adopt.`))) : Effect.void));
|
|
995
1044
|
return {
|
|
996
1045
|
...target,
|
|
997
|
-
hash: yield* wantedHash(news, target.name),
|
|
1046
|
+
hash: yield* wantedHash(news, rootDir, target.name),
|
|
998
1047
|
envNames: Object.keys(env).sort()
|
|
999
1048
|
};
|
|
1000
1049
|
}),
|
|
@@ -1328,7 +1377,7 @@ var Providers = class extends Provider.ProviderCollection()("Convex") {};
|
|
|
1328
1377
|
* default lookup (`CONVEX_ACCESS_TOKEN`, then the Convex CLI login, and
|
|
1329
1378
|
* `CONVEX_DEPLOY_KEY`).
|
|
1330
1379
|
*/
|
|
1331
|
-
const providers = (credentials = fromConfig()) => Layer.effect(Providers, Provider.collection([Project,
|
|
1380
|
+
const providers = (credentials = fromConfig()) => Layer.effect(Providers, Provider.collection([Project, DeploymentResource])).pipe(Layer.provide(Layer.mergeAll(ProjectProvider(), DeploymentProvider())), Layer.provide(ManagementApiLive()), Layer.provide(credentials), Layer.orDie);
|
|
1332
1381
|
//#endregion
|
|
1333
1382
|
//#region src/RunRecord.ts
|
|
1334
1383
|
/** The key of the record in the stage output document. */
|
|
@@ -1506,8 +1555,18 @@ const makeFunctionApi = (url, key) => ({ call: (path, args) => post(`${url}/api/
|
|
|
1506
1555
|
/** The value of a reply, or the Convex message, which names the function and the cause, such as a missing key action. */
|
|
1507
1556
|
const valueOf = (reply) => reply.status === "success" ? Effect.succeed(reply.value) : Effect.fail(failure(reply.errorMessage.trim()));
|
|
1508
1557
|
/** The functions of the store with Alchemy's encoding: the JSON text of encodeState. */
|
|
1509
|
-
const remoteOf = (api) => {
|
|
1558
|
+
const remoteOf = (api, record) => {
|
|
1510
1559
|
const run = (name, args) => api.call(`state:${name}`, args).pipe(Effect.flatMap(valueOf));
|
|
1560
|
+
const write = (name, args) => Effect.gen(function* () {
|
|
1561
|
+
const currentRun = record === void 0 ? void 0 : {
|
|
1562
|
+
...record,
|
|
1563
|
+
recordedAt: new Date(yield* Clock.currentTimeMillis).toISOString()
|
|
1564
|
+
};
|
|
1565
|
+
return yield* run(name, {
|
|
1566
|
+
...args,
|
|
1567
|
+
run: currentRun
|
|
1568
|
+
});
|
|
1569
|
+
});
|
|
1511
1570
|
const strings = (name, args) => run(name, args).pipe(Effect.flatMap(decode(Schema.Array(Schema.String), name)));
|
|
1512
1571
|
const optional = (name, args) => run(name, args).pipe(Effect.flatMap(decode(Schema.NullOr(Schema.String), name)));
|
|
1513
1572
|
const encode = (value) => JSON.stringify(encodeState(value));
|
|
@@ -1531,13 +1590,13 @@ const remoteOf = (api) => {
|
|
|
1531
1590
|
stack: r.stack,
|
|
1532
1591
|
stage: r.stage
|
|
1533
1592
|
}).pipe(Effect.map((text) => text === null ? void 0 : JSON.parse(text, reviveState))),
|
|
1534
|
-
set: (r) =>
|
|
1593
|
+
set: (r) => write("set", {
|
|
1535
1594
|
stack: r.stack,
|
|
1536
1595
|
stage: r.stage,
|
|
1537
1596
|
fqn: r.fqn,
|
|
1538
1597
|
value: encode(r.value)
|
|
1539
1598
|
}),
|
|
1540
|
-
delete: (r) =>
|
|
1599
|
+
delete: (r) => write("remove", {
|
|
1541
1600
|
stack: r.stack,
|
|
1542
1601
|
stage: r.stage,
|
|
1543
1602
|
fqn: r.fqn
|
|
@@ -1546,7 +1605,7 @@ const remoteOf = (api) => {
|
|
|
1546
1605
|
stack: r.stack,
|
|
1547
1606
|
stage: r.stage
|
|
1548
1607
|
}),
|
|
1549
|
-
setOutput: (r) =>
|
|
1608
|
+
setOutput: (r) => write("setOutput", {
|
|
1550
1609
|
stack: r.stack,
|
|
1551
1610
|
stage: r.stage,
|
|
1552
1611
|
value: encode(r.value)
|
|
@@ -1569,10 +1628,11 @@ const storeDirectory = () => join(dirname(fileURLToPath(import.meta.url)), "..",
|
|
|
1569
1628
|
*/
|
|
1570
1629
|
const pushStore = (options, deployment) => Effect.gen(function* () {
|
|
1571
1630
|
const cli = yield* installedCli(join(options.store, ".."));
|
|
1572
|
-
yield* Effect.logInfo(`Convex state: pushing the store version
|
|
1631
|
+
yield* Effect.logInfo(`Convex state: pushing the store version 3 to ${deployment.name}`);
|
|
1573
1632
|
yield* withPushKey(options.api, deployment.name, PUSH_KEY_ACTIONS, (key) => push(options.spawner, key, {
|
|
1574
1633
|
deployment: deployment.name,
|
|
1575
1634
|
url: deployment.deploymentUrl,
|
|
1635
|
+
rootDir: join(options.store, ".."),
|
|
1576
1636
|
source: {
|
|
1577
1637
|
path: options.store,
|
|
1578
1638
|
command: [
|
|
@@ -1631,17 +1691,17 @@ const makeConvexState = (options) => Effect.gen(function* () {
|
|
|
1631
1691
|
current = next;
|
|
1632
1692
|
return next.call(path, args);
|
|
1633
1693
|
})))) };
|
|
1634
|
-
|
|
1635
|
-
if (version === void 0 || version <
|
|
1694
|
+
let version = yield* storeVersion(functions);
|
|
1695
|
+
if (version === void 0 || version < 3) {
|
|
1636
1696
|
if (version === void 0 && deployment.lastDeployTime) return yield* failure(`project ${STORE_PROJECT_NAME} (${project.id}) of team ${team} has code that is not the state store, and Convex.state does not push over it. Rename that project in the Convex dashboard.`);
|
|
1637
|
-
|
|
1638
|
-
if (
|
|
1697
|
+
version = yield* storeVersion(functions);
|
|
1698
|
+
if (version === void 0 || version < 3) {
|
|
1639
1699
|
yield* pushStore(options, deployment);
|
|
1640
|
-
|
|
1641
|
-
if (pushed === void 0 || pushed < 2) return yield* failure(`${deployment.name} answers store version ${pushed ?? "none"} after the push of version 2.`);
|
|
1700
|
+
version = yield* storeVersion(functions);
|
|
1642
1701
|
}
|
|
1643
|
-
}
|
|
1644
|
-
|
|
1702
|
+
}
|
|
1703
|
+
if (version !== 3) return yield* failure(`${deployment.name} answers store version ${version ?? "none"}, and this package needs store version 3.`);
|
|
1704
|
+
const remote = remoteOf(functions, options.run);
|
|
1645
1705
|
/** The stack's output plus the record, when the run has one and the output has a place for it. */
|
|
1646
1706
|
const documentOf = (request) => Effect.gen(function* () {
|
|
1647
1707
|
const { run } = options;
|
|
@@ -1709,6 +1769,6 @@ const state = (options = {}) => Layer.effect(State, Effect.gen(function* () {
|
|
|
1709
1769
|
}).pipe(Effect.provideContext(context), Effect.orDie));
|
|
1710
1770
|
}));
|
|
1711
1771
|
//#endregion
|
|
1712
|
-
export { ACCESS_TOKEN_ENV, AmbiguousDeployment, AmbiguousProject, CodePushFailed, ConvexApiError, ConvexAppNotFound, ConvexCliNotFound, CreatedProjectNotFound, Credentials, CredentialsError, DEPLOY_KEY_ENV, Deployment, DeploymentIdentityChange, EnvironmentNeedsDeployKey, ManagementApi, ProductionDeploymentNotFound, Project, ProjectDeploymentChange, ProjectNotFound, ProjectTeamChange, Providers, PushTargetMismatch, RUN_RECORD_KEY, RunRecordError, STORE_PROJECT_NAME, VariablesOwnedBySomeoneElse, fromConfig, fromValues, parseDeployOutput, providers, runRecord, state, withRunRecord };
|
|
1772
|
+
export { ACCESS_TOKEN_ENV, AbsoluteRootDir, AmbiguousDeployment, AmbiguousProject, CodePushFailed, ConvexApiError, ConvexAppNotFound, ConvexCliNotFound, CreatedProjectNotFound, Credentials, CredentialsError, DEPLOY_KEY_ENV, Deployment, DeploymentIdentityChange, EnvironmentNeedsDeployKey, ManagementApi, ProductionDeploymentNotFound, Project, ProjectDeploymentChange, ProjectNotFound, ProjectTeamChange, Providers, PushTargetMismatch, RUN_RECORD_KEY, RunRecordError, STORE_PROJECT_NAME, VariablesOwnedBySomeoneElse, fromConfig, fromValues, parseDeployOutput, providers, runRecord, state, withRunRecord };
|
|
1713
1773
|
|
|
1714
1774
|
//# sourceMappingURL=index.js.map
|