@samebase/alchemy-convex 0.28.0 → 0.29.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 CHANGED
@@ -44,8 +44,8 @@ export default Alchemy.Stack(
44
44
  const backend =
45
45
  stage === "prod"
46
46
  ? yield* Convex.Deployment("Backend", {
47
- // An existing project. A new one: { team: "my-team", name: "my-app" }.
48
- project: yield* Convex.Project("Project", { team: "my-team", slug: "my-app" }),
47
+ // An existing project of the team of the token. A new one: { name: "my-app" }.
48
+ project: yield* Convex.Project("Project", { slug: "my-app" }),
49
49
  type: "prod",
50
50
  source: "./convex",
51
51
  env: { AUTH_SECRET: Config.Redacted("AUTH_SECRET") },
@@ -81,7 +81,7 @@ relative to it:
81
81
 
82
82
  ```ts
83
83
  Effect.gen(function* () {
84
- const project = yield* Convex.Project("Project", { team: "my-team", slug: "my-app" });
84
+ const project = yield* Convex.Project("Project", { slug: "my-app" });
85
85
  const backend = yield* Convex.Deployment("Backend", {
86
86
  project,
87
87
  type: "prod",
@@ -166,34 +166,36 @@ values explicitly: `Convex.providers(Convex.fromValues({ accessToken, deployKey
166
166
 
167
167
  ## State in Convex
168
168
 
169
- `state: Convex.state({ team })` keeps the Alchemy state of every stack and stage of a Convex team in
170
- one project of that team, `alchemy-state-store`, the same name as the Cloudflare state store of
171
- Alchemy, so a repository holds one secret and a stack can create and destroy its own project.
169
+ `state: Convex.state()` keeps the Alchemy state of every stack and stage of a Convex team in one
170
+ project of that team, `alchemy-state-store`, the same name as the Cloudflare state store of Alchemy,
171
+ so a repository holds one secret and a stack can create and destroy its own project.
172
172
  [docs/design/convex-state.md](docs/design/convex-state.md) records the decisions and the
173
173
  measurements.
174
174
 
175
175
  ```ts
176
176
  export default Alchemy.Stack(
177
177
  process.env["GITHUB_REPOSITORY"] ?? "my-org/my-app", // the stack name: the repository
178
- { providers: Convex.providers(), state: Convex.state({ team: "my-team" }) },
178
+ { providers: Convex.providers(), state: Convex.state() },
179
179
  Effect.gen(function* () {
180
180
  /* ... */
181
181
  }),
182
182
  );
183
183
  ```
184
184
 
185
- Every run needs the team token in `CONVEX_ACCESS_TOKEN`, or the Convex CLI login on a laptop. A team
186
- access token names its team, so `Convex.state()` needs no `team` with one; a `team` slug that is set
187
- must be the slug of that team, checked against its projects, and a token of another team fails the
188
- run. The Convex CLI login needs the slug or the id. The first run of a team creates the project
189
- `alchemy-state-store` and pushes the store functions to its production deployment with the Convex
190
- CLI of the app; a later version of this package pushes a newer store when it finds an older one. A
191
- store that is newer than the package fails the run with both versions, so the repositories of a team
192
- upgrade the package together. Each run makes a deploy key of that deployment that can only run the
193
- store's internal functions, and deletes it at the end. Rows are in the tables `resources` and
194
- `outputs` of the component `alchemyState` in the dashboard, under the stack name. The store has no
195
- lock: run one deploy of a stage at a time, such as with a CI concurrency group. The store and its
196
- readers (Samebase) are released and upgraded together.
185
+ Every run needs the team token in `CONVEX_ACCESS_TOKEN`, or the Convex CLI login on a laptop. The
186
+ state and the projects are in the team of that credential. A team access token and an OAuth token of
187
+ a team name their team. The Convex CLI login names no team, so the run uses the team of the
188
+ deployment that the Convex CLI selected: `CONVEX_DEPLOYMENT` in the environment or in `.env.local`,
189
+ which `npx convex dev` writes. A local or anonymous deployment is in no team, so the run stops and
190
+ asks for a cloud deployment. The first run of a team creates the project `alchemy-state-store` and
191
+ pushes the store functions to its production deployment with the Convex CLI of the app; a later
192
+ version of this package pushes a newer store when it finds an older one. A store that is newer than
193
+ the package fails the run with both versions, so the repositories of a team upgrade the package
194
+ together. Each run makes a deploy key of that deployment that can only run the store's internal
195
+ functions, and deletes it at the end. Rows are in the tables `resources` and `outputs` of the
196
+ component `alchemyState` in the dashboard, under the stack name. The store has no lock: run one
197
+ deploy of a stage at a time, such as with a CI concurrency group. The store and its readers
198
+ (Samebase) are released and upgraded together.
197
199
 
198
200
  Store version 3 supports native subscriptions. A trusted server checks repository access, then calls
199
201
  internal `reader:authorize({ repository, subject })` with a deployment credential. It gives the
@@ -264,11 +266,11 @@ call.
264
266
 
265
267
  ## Resources
266
268
 
267
- - `Convex.Project`: `{ team, name, deploymentRegion?, deploymentType? }` creates a project with its
268
- default deployment, or takes over one with that exact name with `--adopt`. A changed `name`
269
- renames the project in place. `{ team, slug }` is an existing project, found by its slug and taken
270
- over with `--adopt`; it never creates or renames a project. Outputs `projectId`, `slug`, `name`,
271
- `teamId`, `prodDeploymentName`, `prodDeploymentUrl`.
269
+ - `Convex.Project`: `{ name, deploymentRegion?, deploymentType? }` creates a project with its
270
+ default deployment in the team of the credential, or takes over one with that exact name with
271
+ `--adopt`. A changed `name` renames the project in place. `{ slug }` is an existing project of
272
+ that team, found by its slug and taken over with `--adopt`; it never creates or renames a project.
273
+ Outputs `projectId`, `slug`, `name`, `teamId`, `prodDeploymentName`, `prodDeploymentUrl`.
272
274
  - `Convex.Deployment`: `{ project, type: "prod" }` or `{ project, type: "dev" | "preview", name }`,
273
275
  each with optional `rootDir`, `source`, and `env`. Outputs `name` (such as `happy-animal-123`),
274
276
  `url`, `siteUrl`, `type`, `projectId`, `reference`, `previewName`, `hash`, and `envNames`.
@@ -461,8 +463,8 @@ repository `owner/name`. A stack without the stage of the pull request has no ca
461
463
 
462
464
  - `Convex.Project` and `Convex.Deployment` have the removal policy `retain`. `alchemy destroy`
463
465
  forgets them and Convex keeps them. Add `RemovalPolicy.destroy()` to delete with the resource.
464
- - A project is never replaced. A change of `team`, `slug`, `deploymentType`, or `deploymentRegion`
465
- stops the deploy with a typed error that names the fix.
466
+ - A project is never replaced. A change of `slug`, `deploymentType`, or `deploymentRegion`, or a
467
+ credential of another team, stops the deploy with a typed error that names the fix.
466
468
  - A deployment keeps its `project`, `type`, and `name`; a change stops the deploy with
467
469
  `DeploymentIdentityChange`. A production deployment is never deleted, also not with
468
470
  `RemovalPolicy.destroy()`, and also not a dev deployment that became one.
@@ -494,8 +496,6 @@ repository `owner/name`. A stack without the stage of the pull request has no ca
494
496
  deployment must answer there.
495
497
  - A run that stops between a deployment create and the state write leaves a deployment that state
496
498
  does not know. The next run stops with `OwnedBySomeoneElse`; run it with `--adopt`.
497
- - Team slugs for `{ team, name }` resolve through an unofficial dashboard endpoint. Pass the numeric
498
- team id to avoid it. `{ team, slug }` uses the official endpoint.
499
499
  - Not covered: deployment regions and classes, custom domains, log streams, teams and members,
500
500
  components, snapshots.
501
501
 
@@ -512,11 +512,11 @@ pnpm run test:live # real API calls, see below
512
512
 
513
513
  Unit tests run against recorded Management API payloads in `test/fixtures/management/` and a fake
514
514
  Convex CLI. Live tests run only with `ALCHEMY_CONVEX_LIVE=1`, which `pnpm run test:live` sets. They
515
- need a Convex login or `CONVEX_ACCESS_TOKEN` that can create projects in `ALCHEMY_CONVEX_LIVE_TEAM`.
516
- Each test creates a project whose name starts with `ALCHEMY_CONVEX_LIVE_PREFIX` (default
517
- `tmp-alchemy-convex-`), deletes it at the end, also after a failure, and refuses to delete a
518
- project, or a deployment of a project, without that prefix. A file argument runs one live file only,
519
- for example `pnpm run test:live test/live/plane.live.test.ts`.
515
+ need a team access token of `ALCHEMY_CONVEX_LIVE_TEAM` in `CONVEX_ACCESS_TOKEN`: the projects are in
516
+ the team of the token. Each test creates a project whose name starts with
517
+ `ALCHEMY_CONVEX_LIVE_PREFIX` (default `tmp-alchemy-convex-`), deletes it at the end, also after a
518
+ failure, and refuses to delete a project, or a deployment of a project, without that prefix. A file
519
+ argument runs one live file only, for example `pnpm run test:live test/live/plane.live.test.ts`.
520
520
 
521
521
  Releases: change `version` in `package.json` in a pull request. After the merge,
522
522
  `.github/workflows/release.yml` publishes that version from `main` with npm trusted publishing.
@@ -18,10 +18,11 @@ import { diffBindings, isResolved } from "alchemy/Diff";
18
18
  import * as Provider from "alchemy/Provider";
19
19
  import * as ChildProcessSpawner from "effect/process/ChildProcessSpawner";
20
20
  import { AlchemyContext } from "alchemy/AlchemyContext";
21
+ import { readFileSync } from "node:fs";
22
+ import { parseEnv, promisify, stripVTControlCharacters } from "node:util";
21
23
  import { createDeploymentClient, createManagementClient } from "@convex-dev/platform";
22
24
  import * as Schedule from "effect/Schedule";
23
25
  import { createHash } from "node:crypto";
24
- import { promisify, stripVTControlCharacters } from "node:util";
25
26
  import { hashDirectory } from "alchemy/Command/Memo";
26
27
  import * as Clock from "effect/Clock";
27
28
  import * as ChildProcess from "effect/process/ChildProcess";
@@ -173,6 +174,28 @@ const TeamRow = Schema.Struct({
173
174
  const TeamRows = Schema.Array(TeamRow);
174
175
  /** The first page of GET /teams/{team_id}/projects: every row carries the slug of the team. */
175
176
  const ProjectSlugRows = Schema.Struct({ items: Schema.Array(Schema.Struct({ teamSlug: Schema.String })) });
177
+ /** GET /deployments/{name}: the project of the deployment. */
178
+ const DeploymentProject = Schema.Struct({ projectId: Schema.Number });
179
+ /** GET /projects/{id}: the team of the project. */
180
+ const ProjectTeam = Schema.Struct({ teamId: Schema.Number });
181
+ /**
182
+ * The cloud deployment that the Convex CLI selected: CONVEX_DEPLOYMENT in the environment or in
183
+ * `.env.local` of the working directory, as `npx convex dev` writes it (`dev:happy-animal-123`),
184
+ * without the type prefix. Undefined when neither has it, and for a local or anonymous deployment
185
+ * (`local:local-team-app`, `anonymous:anonymous-app`), which runs on this machine and is in no team.
186
+ */
187
+ const selectedDeployment = () => {
188
+ const fromEnv = process.env["CONVEX_DEPLOYMENT"];
189
+ const value = fromEnv !== void 0 && fromEnv !== "" ? fromEnv : (() => {
190
+ try {
191
+ return parseEnv(readFileSync(".env.local", "utf8"))["CONVEX_DEPLOYMENT"];
192
+ } catch {
193
+ return;
194
+ }
195
+ })();
196
+ const name = /^(?:(?:dev|prod|preview):)?([^:]+)$/.exec(value ?? "")?.[1];
197
+ return name === void 0 || name.startsWith("anonymous-") ? void 0 : name;
198
+ };
176
199
  /** GET /token_details: the team of a team token, or the project of a project token. */
177
200
  const TokenDetails = Schema.Union([Schema.Struct({
178
201
  type: Schema.Literal("teamToken"),
@@ -194,17 +217,36 @@ const makeService = (source) => {
194
217
  const tokenDetails = Effect.runSync(Effect.cached(request("get token details", (c) => c.GET("/token_details")).pipe(Effect.map((body) => Schema.decodeUnknownSync(TokenDetails)(body)), Effect.catchIf((error) => error.status === 403, () => Effect.succeed(void 0)))));
195
218
  /** The slug of the team, from the first project of its listing, or undefined for a team without one. Read once. */
196
219
  const teamSlug = (teamId) => request("list projects", (c) => c.GET("/teams/{team_id}/projects", { params: { path: { team_id: teamId } } })).pipe(Effect.map((body) => Schema.decodeUnknownSync(ProjectSlugRows)(body).items[0]?.teamSlug));
220
+ const projectTokenError = (projectId) => new ConvexApiError({
221
+ operation: "resolve team",
222
+ status: 403,
223
+ message: `the access token belongs to project ${projectId}, and a project token cannot create projects. Use a team access token.`
224
+ });
225
+ const teamId = Effect.runSync(Effect.cached(Effect.gen(function* () {
226
+ const details = yield* tokenDetails;
227
+ if (details?.type === "teamToken") return details.teamId;
228
+ if (details?.type === "projectToken") return yield* projectTokenError(details.projectId);
229
+ const selected = selectedDeployment();
230
+ if (selected === void 0) return yield* new ConvexApiError({
231
+ operation: "resolve team",
232
+ status: 0,
233
+ message: "the Convex CLI login names no team, and no cloud deployment is selected. Run `npx convex dev` once with a cloud deployment."
234
+ });
235
+ const deployment = yield* request("get deployment", (c) => c.GET("/deployments/{deployment_name}", { params: { path: { deployment_name: selected } } }));
236
+ const { projectId } = Schema.decodeUnknownSync(DeploymentProject)(deployment);
237
+ const project = yield* request("get project", (c) => c.GET("/projects/{project_id}", { params: { path: { project_id: projectId } } }));
238
+ return Schema.decodeUnknownSync(ProjectTeam)(project).teamId;
239
+ })));
197
240
  const resolveTeamId = (team) => Effect.gen(function* () {
198
241
  if (typeof team === "number") return team;
199
- if (team !== void 0 && /^\d+$/.test(team)) return Number(team);
242
+ if (/^\d+$/.test(team)) return Number(team);
200
243
  const details = yield* tokenDetails;
201
244
  if (details?.type === "teamToken") {
202
- if (team === void 0) return details.teamId;
203
245
  const slug = yield* teamSlug(details.teamId);
204
246
  if (slug === void 0) return yield* new ConvexApiError({
205
247
  operation: "resolve team",
206
248
  status: 0,
207
- message: `team "${team}" cannot be checked against the access token: team ${details.teamId} has no project yet. Set team to ${details.teamId}, or leave it out.`
249
+ message: `team "${team}" cannot be checked against the access token: team ${details.teamId} has no project yet. Set team to ${details.teamId}.`
208
250
  });
209
251
  if (slug !== team) return yield* new ConvexApiError({
210
252
  operation: "resolve team",
@@ -213,16 +255,7 @@ const makeService = (source) => {
213
255
  });
214
256
  return details.teamId;
215
257
  }
216
- if (details?.type === "projectToken") return yield* new ConvexApiError({
217
- operation: "resolve team",
218
- status: 403,
219
- message: `the access token belongs to project ${details.projectId}, and a project token cannot create projects. Use a team access token.`
220
- });
221
- if (team === void 0) return yield* new ConvexApiError({
222
- operation: "resolve team",
223
- status: 0,
224
- message: "set team to the slug or the id of the Convex team: this access token does not name a team."
225
- });
258
+ if (details?.type === "projectToken") return yield* projectTokenError(details.projectId);
226
259
  const resolved = yield* credentials;
227
260
  const match = (yield* Effect.tryPromise({
228
261
  try: async () => {
@@ -253,6 +286,7 @@ const makeService = (source) => {
253
286
  request,
254
287
  requestVoid,
255
288
  deploymentRequest,
289
+ teamId,
256
290
  resolveTeamId,
257
291
  isCredentialToken,
258
292
  isOAuthCredential,
@@ -1097,14 +1131,14 @@ const DeploymentProvider = () => Provider.effect(DeploymentResource, Effect.gen(
1097
1131
  //#endregion
1098
1132
  //#region src/Project.ts
1099
1133
  const Project = Resource("Convex.Project", { defaultRemovalPolicy: "retain" });
1100
- /** The props change the team of an existing project. Convex cannot move a project. */
1134
+ /** The credential is of another team than the project. Convex cannot move a project. */
1101
1135
  var ProjectTeamChange = class extends Schema.TaggedError()("ProjectTeamChange", {
1102
1136
  projectId: Schema.Number,
1103
1137
  teamId: Schema.Number,
1104
1138
  requestedTeamId: Schema.Number
1105
1139
  }) {
1106
1140
  get message() {
1107
- return `Convex.Project cannot move project ${this.projectId} from team ${this.teamId} to team ${this.requestedTeamId}. Set team back to ${this.teamId}. To use the other team, create a new resource with a new logical id and move the data yourself.`;
1141
+ return `Convex.Project cannot move project ${this.projectId} from team ${this.teamId} to team ${this.requestedTeamId}, the team of the credential. Use a token of team ${this.teamId}, or with the Convex CLI login, select a deployment of team ${this.teamId}. To use the other team, create a new resource with a new logical id and move the data yourself.`;
1108
1142
  }
1109
1143
  };
1110
1144
  /**
@@ -1140,11 +1174,11 @@ var CreatedProjectNotFound = class extends Schema.TaggedError()("CreatedProjectN
1140
1174
  };
1141
1175
  /** No project in the team has the slug. A `slug` resource never creates one. */
1142
1176
  var ProjectNotFound = class extends Schema.TaggedError()("ProjectNotFound", {
1143
- team: Schema.String,
1177
+ teamId: Schema.Number,
1144
1178
  slug: Schema.String
1145
1179
  }) {
1146
1180
  get message() {
1147
- return `Team ${this.team} has no project with the slug "${this.slug}", and a Convex.Project with a slug never creates one. Check the slug in the project URL of the Convex dashboard, or use name to create a project.`;
1181
+ return `Team ${this.teamId} has no project with the slug "${this.slug}", and a Convex.Project with a slug never creates one. Check the slug in the project URL of the Convex dashboard, or use name to create a project.`;
1148
1182
  }
1149
1183
  };
1150
1184
  /** The props change the slug of a `slug` resource: that is another project. */
@@ -1206,8 +1240,6 @@ const checkCreateTimeProps = (projectId, olds, news) => {
1206
1240
  }));
1207
1241
  return Effect.void;
1208
1242
  };
1209
- /** True when `team`, a slug or a numeric id, names the team of the project. */
1210
- const isTeamOf = (details, team) => typeof team === "number" || /^\d+$/.test(team) ? details.teamId === Number(team) : details.teamSlug === team;
1211
1243
  /** The row of the project's default production deployment, or undefined. */
1212
1244
  const prodDeploymentOf = (api, projectId) => api.request("list deployments", (client) => client.GET("/projects/{project_id}/list_deployments", { params: { path: { project_id: projectId } } })).pipe(Effect.map((rows) => Schema.decodeUnknownSync(DeploymentRows)(rows).find((row) => row.deploymentType === "prod" && row.isDefault)));
1213
1245
  /** GET /projects/{id}, or undefined after a 404. */
@@ -1281,9 +1313,9 @@ const ProjectProvider = () => Provider.effect(Project, Effect.gen(function* () {
1281
1313
  prodDeploymentUrl: prod?.deploymentUrl
1282
1314
  })));
1283
1315
  const getById = (projectId) => getProjectById(api, projectId);
1284
- /** The project with this slug in the team, or undefined. Official endpoint; the team can be a slug. */
1285
- const getBySlug = (team, slug) => absentAsUndefined(api.request("get project by slug", (client) => client.GET("/teams/{team_id_or_slug}/projects/{project_slug}", { params: { path: {
1286
- team_id_or_slug: String(team),
1316
+ /** The project with this slug in the team, or undefined. */
1317
+ const getBySlug = (teamId, slug) => absentAsUndefined(api.request("get project by slug", (client) => client.GET("/teams/{team_id_or_slug}/projects/{project_slug}", { params: { path: {
1318
+ team_id_or_slug: String(teamId),
1287
1319
  project_slug: slug
1288
1320
  } } }))).pipe(Effect.map((body) => body === void 0 ? void 0 : Schema.decodeUnknownSync(ProjectDetails)(body)));
1289
1321
  const findByName = (teamId, name) => findProjectByName(api, teamId, name);
@@ -1313,45 +1345,37 @@ const ProjectProvider = () => Provider.effect(Project, Effect.gen(function* () {
1313
1345
  diff: Effect.fn(function* ({ olds, news, output }) {
1314
1346
  if (!isResolved(news)) return void 0;
1315
1347
  if (output === void 0) return void 0;
1316
- if ("slug" in news) {
1348
+ const teamId = yield* api.teamId;
1349
+ if (teamId !== output.teamId) return yield* new ProjectTeamChange({
1350
+ projectId: output.projectId,
1351
+ teamId: output.teamId,
1352
+ requestedTeamId: teamId
1353
+ });
1354
+ if (news.slug !== void 0) {
1317
1355
  if (news.slug !== output.slug) return yield* new ProjectSlugChange({
1318
1356
  projectId: output.projectId,
1319
1357
  slug: output.slug,
1320
1358
  requestedSlug: news.slug
1321
1359
  });
1322
- if (olds.team !== news.team) {
1323
- const details = yield* getById(output.projectId);
1324
- if (details !== void 0 && !isTeamOf(details, news.team)) return yield* new ProjectTeamChange({
1325
- projectId: output.projectId,
1326
- teamId: output.teamId,
1327
- requestedTeamId: yield* api.resolveTeamId(news.team)
1328
- });
1329
- }
1330
1360
  return { action: "noop" };
1331
1361
  }
1332
- if (olds.team !== news.team) {
1333
- const requestedTeamId = yield* api.resolveTeamId(news.team);
1334
- if (requestedTeamId !== output.teamId) return yield* new ProjectTeamChange({
1335
- projectId: output.projectId,
1336
- teamId: output.teamId,
1337
- requestedTeamId
1338
- });
1339
- }
1340
- return "name" in olds && olds.name === news.name ? void 0 : { action: "update" };
1362
+ return olds.name === news.name ? void 0 : { action: "update" };
1341
1363
  }),
1342
1364
  read: Effect.fn(function* ({ olds, output }) {
1343
1365
  if (output !== void 0) {
1344
1366
  const details = yield* getById(output.projectId);
1345
1367
  return details === void 0 ? void 0 : yield* attributesOf(details);
1346
1368
  }
1347
- const existing = "slug" in olds ? yield* getBySlug(olds.team, olds.slug) : yield* findByName(yield* api.resolveTeamId(olds.team), olds.name);
1369
+ const teamId = yield* api.teamId;
1370
+ const existing = olds.slug !== void 0 ? yield* getBySlug(teamId, olds.slug) : yield* findByName(teamId, olds.name);
1348
1371
  return existing === void 0 ? void 0 : Unowned(yield* attributesOf(existing));
1349
1372
  }),
1350
1373
  reconcile: Effect.fn(function* ({ fqn, olds, news, output }) {
1351
- if ("slug" in news) {
1352
- const details = output === void 0 ? yield* getBySlug(news.team, news.slug) : yield* getById(output.projectId);
1374
+ const teamId = yield* api.teamId;
1375
+ if (news.slug !== void 0) {
1376
+ const details = output === void 0 ? yield* getBySlug(teamId, news.slug) : yield* getById(output.projectId);
1353
1377
  if (details === void 0) return yield* new ProjectNotFound({
1354
- team: String(news.team),
1378
+ teamId,
1355
1379
  slug: news.slug
1356
1380
  });
1357
1381
  if (details.slug !== news.slug) return yield* new ProjectSlugChange({
@@ -1359,10 +1383,10 @@ const ProjectProvider = () => Provider.effect(Project, Effect.gen(function* () {
1359
1383
  slug: details.slug,
1360
1384
  requestedSlug: news.slug
1361
1385
  });
1362
- if (!isTeamOf(details, news.team)) return yield* new ProjectTeamChange({
1386
+ if (details.teamId !== teamId) return yield* new ProjectTeamChange({
1363
1387
  projectId: details.id,
1364
1388
  teamId: details.teamId,
1365
- requestedTeamId: yield* api.resolveTeamId(news.team)
1389
+ requestedTeamId: teamId
1366
1390
  });
1367
1391
  if (output === void 0 && !(yield* shouldAdopt(fqn))) return yield* new OwnedBySomeoneElse({
1368
1392
  message: `Convex project ${details.id} ("${news.slug}") exists and is not in this stack's state. Re-run with --adopt to take it over.`,
@@ -1371,9 +1395,8 @@ const ProjectProvider = () => Provider.effect(Project, Effect.gen(function* () {
1371
1395
  });
1372
1396
  return yield* attributesOf(details);
1373
1397
  }
1374
- const teamId = yield* api.resolveTeamId(news.team);
1375
1398
  if (output !== void 0) {
1376
- if (olds !== void 0 && "name" in olds) yield* checkCreateTimeProps(output.projectId, olds, news);
1399
+ if (olds !== void 0 && olds.name !== void 0) yield* checkCreateTimeProps(output.projectId, olds, news);
1377
1400
  if (output.teamId !== teamId) return yield* new ProjectTeamChange({
1378
1401
  projectId: output.projectId,
1379
1402
  teamId: output.teamId,
@@ -1715,8 +1738,8 @@ const ensureSealed = (options, deployment, functions) => Effect.gen(function* ()
1715
1738
  * the run whose project is not the oldest deletes its own, which holds
1716
1739
  * nothing yet, and uses the oldest, so that every run ends on one store.
1717
1740
  */
1718
- const createStoreProject = (api, teamId, team) => Effect.gen(function* () {
1719
- yield* Effect.logInfo(`Convex state: creating the project ${STORE_PROJECT_NAME} in team ${team}`);
1741
+ const createStoreProject = (api, teamId) => Effect.gen(function* () {
1742
+ yield* Effect.logInfo(`Convex state: creating the project ${STORE_PROJECT_NAME} in team ${teamId}`);
1720
1743
  const created = yield* createProject(api, teamId, {
1721
1744
  name: STORE_PROJECT_NAME,
1722
1745
  deploymentType: "prod",
@@ -1735,9 +1758,8 @@ const createStoreProject = (api, teamId, team) => Effect.gen(function* () {
1735
1758
  */
1736
1759
  const makeConvexState = (options) => Effect.gen(function* () {
1737
1760
  const { api } = options;
1738
- const teamId = yield* api.resolveTeamId(options.team);
1739
- const team = options.team ?? teamId;
1740
- const project = (yield* findProjectByName(api, teamId, "alchemy-state-store")) ?? (yield* createStoreProject(api, teamId, team));
1761
+ const teamId = yield* api.teamId;
1762
+ const project = (yield* findProjectByName(api, teamId, "alchemy-state-store")) ?? (yield* createStoreProject(api, teamId));
1741
1763
  const deployment = yield* prodDeploymentOf(api, project.id);
1742
1764
  if (deployment === void 0) return yield* new ProductionDeploymentNotFound({ projectId: project.id });
1743
1765
  const keys = [];
@@ -1753,7 +1775,7 @@ const makeConvexState = (options) => Effect.gen(function* () {
1753
1775
  })))) };
1754
1776
  let version = yield* storeVersion(functions);
1755
1777
  if (version === void 0 || version < 5) {
1756
- 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.`);
1778
+ if (version === void 0 && deployment.lastDeployTime) return yield* failure(`project ${STORE_PROJECT_NAME} (${project.id}) of team ${teamId} has code that is not the state store, and Convex.state does not push over it. Rename that project in the Convex dashboard.`);
1757
1779
  version = yield* storeVersion(functions);
1758
1780
  if (version === void 0 || version < 5) {
1759
1781
  yield* pushStore(options, deployment);
@@ -1802,14 +1824,13 @@ const makeConvexState = (options) => Effect.gen(function* () {
1802
1824
  };
1803
1825
  });
1804
1826
  /**
1805
- * Alchemy state in the `alchemy-state-store` project of `team`, with the team token
1806
- * in CONVEX_ACCESS_TOKEN or the Convex CLI login. A team access token names
1807
- * its team, so `team` is optional with one; the Convex CLI login needs the
1808
- * slug or the id. The first use of the run finds or creates the project and
1809
- * pushes the store when it is missing or older. `alchemy plan` on another
1810
- * stack never touches Convex.
1827
+ * Alchemy state in the `alchemy-state-store` project of the team of the credential: the team token
1828
+ * in CONVEX_ACCESS_TOKEN, which names its team, or the Convex CLI login, with the team of the
1829
+ * deployment that the CLI selected (CONVEX_DEPLOYMENT, see ManagementApi.teamId). The first use of
1830
+ * the run finds or creates the project and pushes the store when it is missing or older.
1831
+ * `alchemy plan` on another stack never touches Convex.
1811
1832
  */
1812
- const state = (options = {}) => Layer.effect(State, Effect.gen(function* () {
1833
+ const state = () => Layer.effect(State, Effect.gen(function* () {
1813
1834
  const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
1814
1835
  const scope = yield* Scope.Scope;
1815
1836
  const context = yield* Effect.context();
@@ -1820,7 +1841,6 @@ const state = (options = {}) => Layer.effect(State, Effect.gen(function* () {
1820
1841
  env: process.env
1821
1842
  }).pipe(Effect.catch((error) => Effect.logWarning(`Convex state: the stage outputs of this run carry no record. ${error.message}`).pipe(Effect.as(void 0))));
1822
1843
  return yield* makeConvexState({
1823
- team: options.team,
1824
1844
  api,
1825
1845
  spawner,
1826
1846
  scope,
@@ -1992,4 +2012,4 @@ const registerDevelopmentClient = (options) => Effect.gen(function* () {
1992
2012
  //#endregion
1993
2013
  export { PushTargetMismatch as A, DEPLOY_KEY_ENV as B, DeploymentProvider as C, ConvexAppNotFound as D, CodePushFailed as E, ManagementApi as F, fromValues as H, ManagementApiLive as I, ACCESS_TOKEN_ENV as L, installedCli as M, parseDeployOutput as N, ConvexCliNotFound as O, ConvexApiError as P, Credentials as R, DeploymentIdentityChange as S, ProductionDeploymentNotFound as T, fromConfig as V, ProjectProvider as _, registerDevelopmentClient as a, AmbiguousDeployment as b, RUN_RECORD_KEY as c, withRunRecord as d, AmbiguousProject as f, ProjectNotFound as g, ProjectDeploymentChange as h, HubClientProvider as i, VariablesOwnedBySomeoneElse as j, EnvironmentNeedsDeployKey as k, RunRecordError as l, Project as m, HubClient as n, STORE_PROJECT_NAME as o, CreatedProjectNotFound as p, HubClientFailed as r, state as s, HUB_PROJECT_NAME as t, runRecord as u, ProjectTeamChange as v, DeploymentResource as w, Deployment as x, AbsoluteRootDir as y, CredentialsError as z };
1994
2014
 
1995
- //# sourceMappingURL=HubClient-BcegkjaP.js.map
2015
+ //# sourceMappingURL=HubClient-HeGoVOLO.js.map