affect-cli 0.0.4 → 0.0.5

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.
Files changed (3) hide show
  1. package/README.md +10 -12
  2. package/dist/index.js +548 -119
  3. package/package.json +4 -4
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # affect-cli
2
2
 
3
- Shared environment and deployment commands for [Affect](https://github.com/ludicroushq/affect). Requires Bun 1.4.2 or later and a project-local Convex CLI.
3
+ Shared environment and deployment commands for Affect projects. Requires Bun 1.4.2 or later and a project-local Convex CLI.
4
4
 
5
5
  ```sh
6
6
  bun add --dev --exact affect-cli
@@ -10,11 +10,11 @@ bunx --no-install affect --help
10
10
  Run commands from the application repository root:
11
11
 
12
12
  - `affect env` prints shell exports from `env/{development,preview,production,ci}/.env`. It requires the matching `DOTENV_PRIVATE_KEY` when that file exists. Treat its output as secrets.
13
- - `affect env sync-dev [--force]` reads only `env/development/.env` with its matching `DOTENV_PRIVATE_KEY` and synchronizes declared server settings to its verified hosted development backend. It never deploys code or builds the frontend. It ignores inherited CI, production, account-token and provider-host selection. Missing required settings fail; absent optional settings preserve remote values; explicit empty strings remain values. Existing differing values refuse the entire batch unless `--force` is supplied. Omission never deletes a remote setting. Output contains only the verified target and setting counts.
13
+ - `affect env sync-dev [--force]` reads only `env/development/.env` with its matching `DOTENV_PRIVATE_KEY` and synchronizes declared server settings to its verified hosted development backend. The profile must provide the canonical `VITE_CONVEX_URL` and `VITE_CONVEX_SITE_URL` pair and a development-scoped deploy key. It never deploys code or builds the frontend. It ignores inherited CI, production, account-token and provider-host selection. Missing required settings fail; absent optional settings preserve remote values; explicit empty strings remain values. Existing differing values refuse the entire batch unless `--force` is supplied. Omission never deletes a remote setting. Output contains only the verified target and setting counts.
14
14
  - `affect run -- <command> [args...]` loads that environment and runs a command. Existing environment values take precedence; arguments, standard I/O, and exit codes are preserved.
15
15
  - `affect dotenvx -- …` forwards arguments to the bundled native dotenvx CLI, for example `affect dotenvx -- encrypt -f env/development/.env --no-armor --no-native`.
16
16
  - `affect setup` initializes an anonymous local Convex backend only for a fresh project, or retries its environment import. It preserves existing linked deployments and credentials.
17
- - `affect deploy` uses Convex's native deploy/build sequence, imports the selected backend environment, and builds the frontend. Vercel supplies `VERCEL_ENV=preview|production` and the preview branch name automatically; put the matching deploy key in the encrypted file. `--build` is its internal Convex callback.
17
+ - `affect deploy` invokes Convex's native deploy sequence for the selected Vercel-scoped profile. Native `convex deploy` pushes Convex backend code and runs the root build callback; Vercel supplies `VERCEL_ENV=preview|production` and the preview branch name automatically, and the matching deploy key remains encrypted in the profile. The callback requires the verified `VITE_CONVEX_URL` and `VITE_CONVEX_SITE_URL` pair and runs the root TanStack build. Frontend build output is not published by `affect deploy`; publication belongs to the configured frontend host. `--build` is its internal Convex callback.
18
18
 
19
19
  Except for the explicitly development-only `env sync-dev`, selection uses `VERCEL_ENV`, then `ci` for GitHub Actions/CI, otherwise `development`. Files stay in the application; cryptography stays in dotenvx. Deployment follows Affect's `apps/web` layout.
20
20
 
@@ -30,18 +30,16 @@ export default {
30
30
  } satisfies EnvDefinition;
31
31
  ```
32
32
 
33
- Use the profile's development-scoped deploy key and canonical public Convex cloud/site origins. Before any update the command verifies the provider's cloud/development identity, owning team/project and both canonical URLs. Reserved credential/control/client-public names are rejected even if declared. Only present declared server settings are sent, using the native Convex JSON environment API without temporary plaintext files; native Convex remains responsible for provider limits and application value validation. The command needs metadata and environment read/write permissions; it does not create credentials or fall back to a broader login. Profile values use the same dotenvx decryption and interpolation as `affect env`.
33
+ Use the profile's development-scoped deploy key and canonical public Convex cloud/site origins (`VITE_CONVEX_URL` and `VITE_CONVEX_SITE_URL`). Before any update the command verifies the provider's cloud/development identity, owning team/project and both canonical URLs. Reserved credential/control/client-public names are rejected even if declared. Only present declared server settings are sent, using the native Convex JSON environment API without temporary plaintext files; native Convex remains responsible for provider limits and application value validation. The command needs metadata and environment read/write permissions; it does not create credentials or fall back to a broader login. Profile values use the same dotenvx decryption and interpolation as `affect env`. The profile remains encrypted with dotenvx; only settings declared by `convex/env.config.ts` cross into the backend.
34
34
 
35
- For example, an application's package scripts can load their environment automatically:
35
+ From the application root, run the TanStack development script with the selected profile:
36
36
 
37
- ```json
38
- {
39
- "scripts": {
40
- "dev": "affect run -- convex dev --start \"bun run dev:web\""
41
- }
42
- }
37
+ ```sh
38
+ bunx --no-install affect run -- bun run dev
43
39
  ```
44
40
 
41
+ `affect run` supplies the selected profile to the application process; it does not start a Convex watcher. The canonical Convex URLs are Vite build-time values. A host may separately provide runtime-only listener settings for its server, but `affect deploy` does not create a runtime env file or copy the deploy key into the frontend. Vercel supplies `VERCEL_ENV` and, for previews, `VERCEL_GIT_COMMIT_REF`; the CLI uses those host values to select the target and branch, then reads the matching deploy key from the encrypted profile.
42
+
45
43
  ## Development and releases
46
44
 
47
45
  ```sh
@@ -52,4 +50,4 @@ bun run changeset version
52
50
  bun run release
53
51
  ```
54
52
 
55
- For automated releases, commit a changeset with each releasable change. The release workflow opens a version PR; merging it publishes to npm. Configure npm's GitHub trusted publisher for `ludicroushq/affect-cli`, workflow `release.yml`, with direct publishing enabled. No npm token is needed. `bun run release` remains available for an intentional manual release.
53
+ For automated releases, commit a changeset with each releasable change. The release workflow opens a version PR; merging it publishes to npm. Configure npm's GitHub trusted publisher for `nahtnam/affect-cli`, workflow `release.yml`, with direct publishing enabled. No npm token is needed. `bun run release` remains available for an intentional manual release.
package/dist/index.js CHANGED
@@ -7572,6 +7572,28 @@ function String3() {
7572
7572
  function Number4() {
7573
7573
  return transform(globalThis.Number);
7574
7574
  }
7575
+ function parseJson(options) {
7576
+ return transformEffect((input, parseOptions) => try_3({
7577
+ try: () => JSON.parse(input, options?.reviver),
7578
+ catch: () => new InvalidValue({
7579
+ expected: "a valid JSON string"
7580
+ }, input, parseOptions)
7581
+ }));
7582
+ }
7583
+ function stringifyJson(options) {
7584
+ return transformEffect((input, parseOptions) => try_3({
7585
+ try: () => {
7586
+ const output = JSON.stringify(input, options?.replacer, options?.space);
7587
+ if (output === undefined) {
7588
+ throw new TypeError("Value cannot be represented as JSON");
7589
+ }
7590
+ return output;
7591
+ },
7592
+ catch: () => new InvalidValue({
7593
+ expected: "a JSON-serializable value"
7594
+ }, input, parseOptions)
7595
+ }));
7596
+ }
7575
7597
  function encodeBase64() {
7576
7598
  return transform(encode);
7577
7599
  }
@@ -7581,6 +7603,15 @@ function decodeBase64() {
7581
7603
  }, input, options)));
7582
7604
  }
7583
7605
 
7606
+ // node_modules/effect/dist/internal/schema/content.js
7607
+ var ContentTypeId = /* @__PURE__ */ Symbol.for("~effect/Schema/content");
7608
+ function setContent(operation, content) {
7609
+ Object.defineProperty(operation, ContentTypeId, {
7610
+ value: content
7611
+ });
7612
+ return operation;
7613
+ }
7614
+
7584
7615
  // node_modules/effect/dist/SchemaTransformation.js
7585
7616
  var TypeId18 = "~effect/SchemaTransformation/Transformation";
7586
7617
  var Transformation = class extends Class {
@@ -7678,6 +7709,12 @@ var urlFromString = /* @__PURE__ */ transformEffect2({
7678
7709
  encode: (url) => succeed6(url.href)
7679
7710
  });
7680
7711
  var uint8ArrayFromBase64String = /* @__PURE__ */ new Transformation(/* @__PURE__ */ decodeBase64(), /* @__PURE__ */ encodeBase64());
7712
+ function fromJsonString(options) {
7713
+ return new Transformation(parseJson(options ?? {}), setContent(stringifyJson(options), {
7714
+ mediaType: "application/json",
7715
+ preserveSchema: options?.reviver === undefined && options?.replacer === undefined
7716
+ }));
7717
+ }
7681
7718
 
7682
7719
  // node_modules/effect/dist/SchemaAST.js
7683
7720
  function makeGuard(tag) {
@@ -12369,6 +12406,7 @@ function Literal2(literal) {
12369
12406
  return out;
12370
12407
  }
12371
12408
  var Unknown2 = /* @__PURE__ */ make25(unknown);
12409
+ var Null2 = /* @__PURE__ */ make25(null_);
12372
12410
  var Undefined2 = /* @__PURE__ */ make25(undefined_2);
12373
12411
  var String5 = /* @__PURE__ */ make25(string2);
12374
12412
  var Number6 = /* @__PURE__ */ make25(number2);
@@ -12422,6 +12460,7 @@ function Literals(literals) {
12422
12460
  }
12423
12461
  });
12424
12462
  }
12463
+ var NullOr = /* @__PURE__ */ lambda((self) => Union2([self, Null2]));
12425
12464
  var UndefinedOr = /* @__PURE__ */ lambda((self) => Union2([self, Undefined2]));
12426
12465
  function decodeTo2(to, transformation) {
12427
12466
  return (from) => {
@@ -12668,6 +12707,12 @@ var URL2 = /* @__PURE__ */ instanceOf(globalThis.URL, {
12668
12707
  toCodecJson: () => link3()(URLString, urlFromString)
12669
12708
  });
12670
12709
  var URLFromString = /* @__PURE__ */ URLString.pipe(/* @__PURE__ */ decodeTo2(URL2, urlFromString));
12710
+ var JsonString = /* @__PURE__ */ String5.annotate({
12711
+ expected: "a string that will be decoded as JSON"
12712
+ });
12713
+ function fromJsonString2(schema, options) {
12714
+ return JsonString.pipe(decodeTo2(schema, fromJsonString(options)));
12715
+ }
12671
12716
  var File = /* @__PURE__ */ instanceOf(globalThis.File, {
12672
12717
  representation: {
12673
12718
  id: "effect/schema/File",
@@ -18573,7 +18618,7 @@ var runWith2 = (command, config) => {
18573
18618
  }) => andThen2(showUserError(error, userMessage), fail7(error))), catchFilter2((e) => isQuitError(e) ? succeed2(e) : fail2(e), (_) => interrupt2));
18574
18619
  };
18575
18620
  // package.json
18576
- var version = "0.0.4";
18621
+ var version = "0.0.5";
18577
18622
  // node_modules/effect/dist/http/HttpBody.js
18578
18623
  var TypeId35 = "~effect/http/HttpBody";
18579
18624
  var HttpBodyErrorTypeId = "~effect/http/HttpBody/HttpBodyError";
@@ -18935,14 +18980,6 @@ var getWebSource = (self) => self[WebSourceSymbol]?.();
18935
18980
  // node_modules/effect/dist/http/HttpClientResponse.js
18936
18981
  var TypeId39 = "~effect/http/HttpClientResponse";
18937
18982
  var fromWeb = (request, source) => new WebHttpClientResponse(request, source);
18938
- var filterStatusOk = (self) => self.status >= 200 && self.status < 300 ? succeed6(self) : fail7(new HttpClientError({
18939
- reason: new StatusCodeError({
18940
- response: self,
18941
- request: self.request,
18942
- description: "non 2xx status code"
18943
- })
18944
- }));
18945
-
18946
18983
  class WebHttpClientResponse extends Class2 {
18947
18984
  [TypeId38];
18948
18985
  [TypeId39];
@@ -19128,7 +19165,6 @@ var addHeaderAttributes = (span, phase, headers, filter, redactedNames) => {
19128
19165
  var TypeId40 = "~effect/http/HttpClient";
19129
19166
  var HttpClient = /* @__PURE__ */ Service("effect/HttpClient");
19130
19167
  var transformResponse = /* @__PURE__ */ dual(2, (self, f) => makeWith2((request) => f(self.postprocess(request)), self.preprocess));
19131
- var filterStatusOk2 = /* @__PURE__ */ transformResponse(/* @__PURE__ */ flatMap3(filterStatusOk));
19132
19168
  var makeWith2 = (postprocess, preprocess) => {
19133
19169
  const self = Object.create(Proto14);
19134
19170
  self.preprocess = preprocess;
@@ -19533,6 +19569,469 @@ var exports = fn2("Environment.exports")(function* exports() {
19533
19569
  `);
19534
19570
  });
19535
19571
 
19572
+ // src/deploy.ts
19573
+ var controlPlane = "https://api.convex.dev";
19574
+ var callbackMarker = "AFFECT_CONVEX_DEPLOY_CALLBACK";
19575
+ var callbackCommand = "bunx --no-install affect deploy --build";
19576
+ var deploymentNames = [
19577
+ "CONVEX_DEPLOY_KEY",
19578
+ "CONVEX_DEPLOYMENT_TOKEN",
19579
+ "CONVEX_DEPLOYMENT",
19580
+ "CONVEX_OVERRIDE_ACCESS_TOKEN",
19581
+ "CONVEX_SELF_HOSTED_URL",
19582
+ "CONVEX_SELF_HOSTED_ADMIN_KEY",
19583
+ "CONVEX_AGENT_MODE",
19584
+ "CONVEX_PROVISION_HOST"
19585
+ ];
19586
+ var canonicalNames = ["VITE_CONVEX_URL", "VITE_CONVEX_SITE_URL"];
19587
+ var publicBuildNames = ["VITE_SITE_URL", "VITE_POSTHOG_HOST", "VITE_POSTHOG_KEY"];
19588
+ var hostNames = [
19589
+ "CI",
19590
+ "GITHUB_ACTIONS",
19591
+ "VERCEL",
19592
+ "VERCEL_TARGET_ENV",
19593
+ "NOW_BUILDER",
19594
+ "VERCEL_GIT_COMMIT_SHA",
19595
+ "VERCEL_URL",
19596
+ "VERCEL_BRANCH_URL",
19597
+ "VERCEL_PROJECT_PRODUCTION_URL"
19598
+ ];
19599
+ var optionalSystemNames = ["TMPDIR", "TMP", "TEMP", "LANG", "LC_ALL"];
19600
+ var proxyNames = [
19601
+ "NODE_USE_ENV_PROXY",
19602
+ "HTTP_PROXY",
19603
+ "HTTPS_PROXY",
19604
+ "ALL_PROXY",
19605
+ "NO_PROXY",
19606
+ "http_proxy",
19607
+ "https_proxy",
19608
+ "all_proxy",
19609
+ "no_proxy"
19610
+ ];
19611
+ var reservedSetting = /^(?:CONVEX_|DOTENV_|(?:[A-Z0-9]+_)*PUBLIC_|VITE_|REACT_APP_|EXPO_PUBLIC_|VERCEL_|GITHUB_|NODE_|BUN_|AFFECT_|CI$|PATH$|HOME$|USERPROFILE$|PWD$|SHELL$|ENV$|TMPDIR$|(?:HTTPS?|ALL|NO)_PROXY$)/u;
19612
+ var failure = (cause) => new UserError({ cause });
19613
+ var empty9 = "";
19614
+ var Origin = URLFromString.check(makeFilter2((url) => url.protocol === "https:" && url.username === "" && url.password === "" && url.pathname === "/" && url.search === "" && url.hash === ""));
19615
+ var Id = Int.check(isGreaterThan2(0));
19616
+ var Slug = String5.check(isPattern2(/^[a-z0-9][a-z0-9_-]*$/u));
19617
+ var Identity = Struct({
19618
+ project: Slug,
19619
+ projectId: Id,
19620
+ team: Slug,
19621
+ teamId: Id
19622
+ });
19623
+ var Deployment = Struct({
19624
+ deploymentType: Literals(["dev", "preview", "prod"]),
19625
+ id: Id,
19626
+ kind: Literal2("cloud"),
19627
+ projectId: Id,
19628
+ teamId: Id
19629
+ });
19630
+ var CanonicalUrls = Struct({
19631
+ convexCloudUrl: Origin,
19632
+ convexSiteUrl: Origin
19633
+ });
19634
+ var PreviewAuthorization = Struct({
19635
+ adminKey: NonEmptyString,
19636
+ deploymentName: NonEmptyString,
19637
+ deploymentType: Literal2("preview"),
19638
+ isDefault: Boolean3,
19639
+ reference: NullOr(String5),
19640
+ url: Origin
19641
+ });
19642
+ var Declaration2 = Record(String5, Struct({
19643
+ isConvexValidator: Literal2(true),
19644
+ isOptional: Literals(["required", "optional"])
19645
+ }));
19646
+ var RootManifest = Struct({
19647
+ dependencies: optional2(Record(String5, String5)),
19648
+ devDependencies: optional2(Record(String5, String5)),
19649
+ scripts: Record(String5, String5),
19650
+ workspaces: ArraySchema(String5)
19651
+ });
19652
+ var WebManifest = Struct({
19653
+ dependencies: optional2(Record(String5, String5)),
19654
+ devDependencies: optional2(Record(String5, String5)),
19655
+ name: Literal2("@affect/web"),
19656
+ scripts: Record(String5, String5)
19657
+ });
19658
+ var inheritedNames = [
19659
+ "PATH",
19660
+ "CI",
19661
+ "GITHUB_ACTIONS",
19662
+ "VERCEL_ENV",
19663
+ "VERCEL_GIT_COMMIT_REF",
19664
+ "NODE_OPTIONS",
19665
+ "BUN_OPTIONS",
19666
+ ...deploymentNames,
19667
+ ...canonicalNames,
19668
+ ...publicBuildNames,
19669
+ ...hostNames,
19670
+ ...optionalSystemNames,
19671
+ ...proxyNames
19672
+ ];
19673
+ var readInheritedEnvironment = fnUntraced2(function* readInheritedEnvironment() {
19674
+ const inherited = {};
19675
+ for (const name of inheritedNames) {
19676
+ inherited[name] = yield* String6(name).pipe(withDefault3(empty9));
19677
+ }
19678
+ return inherited;
19679
+ });
19680
+ var httpRequest = fnUntraced2(function* httpRequest(url, authorization, body) {
19681
+ const client = yield* HttpClient;
19682
+ const request = setHeader(body === undefined ? get4(url) : post(url), "Authorization", authorization);
19683
+ const outgoing = body === undefined ? request : yield* bodyJson(request, body);
19684
+ const response = yield* client.execute(outgoing);
19685
+ if (response.status !== 200) {
19686
+ return yield* failure("Convex deployment verification failed.");
19687
+ }
19688
+ return response;
19689
+ }, mapError2(() => failure("Convex deployment verification failed.")));
19690
+ var json2 = (schema, response) => response.json.pipe(flatMap3(decodeEffect2(schema)), mapError2(() => failure("Convex deployment returned invalid metadata.")));
19691
+ var validateDeploymentControls = fnUntraced2(function* validateDeploymentControls(values, inherited) {
19692
+ for (const name of deploymentNames) {
19693
+ const configured = values[name] ?? empty9;
19694
+ const ambient = inherited[name] ?? empty9;
19695
+ if (name === "CONVEX_DEPLOY_KEY") {
19696
+ continue;
19697
+ }
19698
+ if (name === "CONVEX_PROVISION_HOST") {
19699
+ if (configured !== empty9 && configured !== controlPlane || ambient !== empty9 && ambient !== controlPlane) {
19700
+ return yield* failure("Convex provider host must be the standard Convex control plane.");
19701
+ }
19702
+ continue;
19703
+ }
19704
+ if (configured !== empty9 || ambient !== empty9) {
19705
+ return yield* failure("Conflicting Convex deployment authentication or target settings are not allowed.");
19706
+ }
19707
+ }
19708
+ return yield* void_3;
19709
+ });
19710
+ var validateProfileKey = fnUntraced2(function* validateProfileKey(target, branch, deployKey, values, inherited) {
19711
+ const matchingPrefix = target === "preview" ? "preview:" : "prod:";
19712
+ if (!deployKey.startsWith(matchingPrefix)) {
19713
+ return yield* failure("Encrypted project file must contain a Convex deploy key matching VERCEL_ENV.");
19714
+ }
19715
+ if (target === "preview") {
19716
+ if (!/^[A-Za-z0-9][A-Za-z0-9_./-]*$/u.test(branch)) {
19717
+ return yield* failure("Preview deployment requires a valid branch name.");
19718
+ }
19719
+ const parts = /^preview:(?<team>[a-z0-9][a-z0-9_-]*):(?<project>[a-z0-9][a-z0-9_-]*)\|(?<secret>.+)$/u.exec(deployKey);
19720
+ const groups = parts?.groups;
19721
+ if (groups?.["team"] === undefined || groups["project"] === undefined || groups["secret"] === undefined) {
19722
+ return yield* failure("Encrypted project file must contain a valid preview-scoped Convex deploy key.");
19723
+ }
19724
+ return {
19725
+ branch,
19726
+ deployKey,
19727
+ inherited,
19728
+ projectSlug: groups["project"],
19729
+ target,
19730
+ teamSlug: groups["team"],
19731
+ values
19732
+ };
19733
+ }
19734
+ if (!/^prod:[a-z0-9][a-z0-9-]*\|.+$/u.test(deployKey)) {
19735
+ return yield* failure("Encrypted project file must contain a valid production-scoped Convex deploy key.");
19736
+ }
19737
+ return { branch, deployKey, inherited, target, values };
19738
+ });
19739
+ var profile = fn2("Deploy.profile")(function* profile() {
19740
+ const { target, values } = yield* load();
19741
+ if (target !== "preview" && target !== "production") {
19742
+ return yield* failure("Deploy requires VERCEL_ENV=preview or production.");
19743
+ }
19744
+ const inherited = yield* readInheritedEnvironment();
19745
+ const inheritedKey = inherited["CONVEX_DEPLOY_KEY"] ?? empty9;
19746
+ const deployKey = values["CONVEX_DEPLOY_KEY"] ?? empty9;
19747
+ if (inheritedKey !== empty9 && inheritedKey !== deployKey) {
19748
+ return yield* failure("CONVEX_DEPLOY_KEY conflicts with the selected encrypted project file.");
19749
+ }
19750
+ yield* validateDeploymentControls(values, inherited);
19751
+ return yield* validateProfileKey(target, inherited["VERCEL_GIT_COMMIT_REF"] ?? empty9, deployKey, values, inherited);
19752
+ });
19753
+ var readDeclaration = fn2("Deploy.readDeclaration")(function* readDeclaration(root) {
19754
+ const path = yield* Path;
19755
+ const declarationPath = path.join(root, "convex", "env.config.ts");
19756
+ const imported = yield* try_3({
19757
+ catch: () => failure("Cannot load the declaration-only convex/env.config.ts."),
19758
+ try: () => {
19759
+ const module = import.meta.require(declarationPath);
19760
+ return module;
19761
+ }
19762
+ });
19763
+ const decoded = yield* decodeUnknownEffect2(Struct({ default: Declaration2 }))(imported).pipe(mapError2(() => failure("Cannot load a valid declaration-only Convex environment definition.")));
19764
+ const keys2 = keys(decoded.default);
19765
+ yield* decodeEffect2(ArraySchema(String5.check(makeFilter2((name) => !reservedSetting.test(name)))))(keys2).pipe(mapError2(() => failure("Server declaration contains a credential, control or client-public name.")));
19766
+ return decoded.default;
19767
+ });
19768
+ var readManifest = fn2("Deploy.readManifest")(function* readManifest(root, relativePath, schema) {
19769
+ const fs = yield* FileSystem;
19770
+ const path = yield* Path;
19771
+ const filePath = path.join(root, relativePath);
19772
+ const content = yield* fs.readFileString(filePath).pipe(mapError2(() => failure("The Affect TanStack workspace build contract is unavailable.")));
19773
+ const value = yield* decodeEffect2(fromJsonString2(schema))(content).pipe(mapError2(() => failure("The Affect TanStack workspace build contract is invalid.")));
19774
+ return value;
19775
+ });
19776
+ var preflight = fn2("Deploy.preflight")(function* preflight() {
19777
+ const path = yield* Path;
19778
+ const root = path.resolve(".");
19779
+ const [rootManifest, webManifest] = yield* all2([
19780
+ readManifest(root, "package.json", RootManifest),
19781
+ readManifest(root, "apps/web/package.json", WebManifest)
19782
+ ]);
19783
+ const dependencies = { ...rootManifest.dependencies, ...rootManifest.devDependencies };
19784
+ const webDependencies = { ...webManifest.dependencies, ...webManifest.devDependencies };
19785
+ if (!contains("apps/*")(rootManifest.workspaces) || rootManifest.scripts["build"] !== "bun run --filter @affect/web build" || dependencies["vite"] === undefined || dependencies["convex"] === undefined || webManifest.scripts["build"] !== "vite build" || webDependencies["@tanstack/react-start"] === undefined || webDependencies["vite"] === undefined) {
19786
+ return yield* failure("This CLI requires the Affect TanStack workspace build contract.");
19787
+ }
19788
+ const declaration = yield* readDeclaration(root);
19789
+ return { declaration, root };
19790
+ });
19791
+ var selectedBackendSettings = (values, declaration) => map3(filter(toEntries(declaration), ([name]) => has(values, name)), ([name]) => ({ name, value: values[name] ?? empty9 }));
19792
+ var validateRequiredSettings = (values, declaration) => {
19793
+ const required = filter(toEntries(declaration), ([name, validator]) => validator.isOptional === "required" && !has(values, name));
19794
+ if (required.length === 0) {
19795
+ return void_3;
19796
+ }
19797
+ const missing = [];
19798
+ for (const [name] of required) {
19799
+ missing.push(name);
19800
+ }
19801
+ return failure(`Missing required server settings: ${join(missing, ", ")}.`);
19802
+ };
19803
+ var childProfileCollision = (values, required) => {
19804
+ for (const name of required) {
19805
+ if (has(values, name)) {
19806
+ return true;
19807
+ }
19808
+ }
19809
+ return false;
19810
+ };
19811
+ var copyDefined = (source, names, values, into) => {
19812
+ for (const name of names) {
19813
+ if (!has(values, name) && source[name] !== empty9) {
19814
+ into[name] = source[name] ?? empty9;
19815
+ }
19816
+ }
19817
+ };
19818
+ var temporaryHome = fnUntraced2(function* temporaryHome(prepareMessage, cleanupMessage) {
19819
+ const fileSystem = yield* FileSystem;
19820
+ return yield* acquireRelease2(fileSystem.makeTempDirectory({ prefix: "affect-cli-home-" }).pipe(mapError2(() => failure(prepareMessage))), (directory) => fileSystem.remove(directory, { force: true, recursive: true }).pipe(mapError2(() => failure(cleanupMessage)), ignore2));
19821
+ });
19822
+ var verifiedDeployment = fn2("Deploy.verifyDeployment")(function* verifiedDeployment(selected, callbackCloud, callbackSite) {
19823
+ const key = selected.deployKey;
19824
+ if (selected.target === "production") {
19825
+ const endpoint = yield* json2(Origin, yield* httpRequest(`${controlPlane}/api/deployment/url_for_key`, `Bearer ${key}`, {
19826
+ deployKey: key
19827
+ }));
19828
+ const deploymentAuthorization = `Convex ${key}`;
19829
+ const deploymentName = key.slice("prod:".length).split("|", 1)[0] ?? empty9;
19830
+ const identity = yield* json2(Identity, yield* httpRequest(`${controlPlane}/api/deployment/team_and_project_for_key`, `Bearer ${key}`, { deployKey: key }));
19831
+ const info = yield* json2(Deployment, yield* httpRequest(`${endpoint.origin}/api/v1/deployment_info`, deploymentAuthorization));
19832
+ if (info.deploymentType !== "prod" || info.teamId !== identity.teamId || info.projectId !== identity.projectId) {
19833
+ return yield* failure("Production deploy key and Convex deployment metadata do not match.");
19834
+ }
19835
+ const canonical = yield* json2(CanonicalUrls, yield* httpRequest(`${endpoint.origin}/api/v1/get_canonical_urls`, deploymentAuthorization));
19836
+ if (canonical.convexCloudUrl.origin !== endpoint.origin || canonical.convexCloudUrl.origin !== callbackCloud.origin || canonical.convexSiteUrl.origin !== callbackSite.origin) {
19837
+ return yield* failure("Native Convex URLs do not match the selected production deployment.");
19838
+ }
19839
+ return {
19840
+ adminKey: key,
19841
+ cloud: canonical.convexCloudUrl.origin,
19842
+ deploymentName,
19843
+ deploymentType: "prod",
19844
+ identity,
19845
+ site: canonical.convexSiteUrl.origin,
19846
+ url: endpoint.origin
19847
+ };
19848
+ }
19849
+ const teamSlugFromKey = selected.teamSlug ?? empty9;
19850
+ const projectSlugFromKey = selected.projectSlug ?? empty9;
19851
+ const authorization = yield* json2(PreviewAuthorization, yield* httpRequest(`${controlPlane}/api/deployment/authorize_preview`, `Bearer ${key}`, {
19852
+ previewName: selected.branch,
19853
+ projectSelection: {
19854
+ kind: "teamAndProjectSlugs",
19855
+ projectSlug: projectSlugFromKey,
19856
+ teamSlug: teamSlugFromKey
19857
+ }
19858
+ }));
19859
+ const endpoint = authorization.url;
19860
+ const deploymentAuthorization = `Convex ${authorization.adminKey}`;
19861
+ const { deploymentName } = authorization;
19862
+ const info = yield* json2(Deployment, yield* httpRequest(`${endpoint.origin}/api/v1/deployment_info`, deploymentAuthorization));
19863
+ if (authorization.deploymentType !== "preview" || info.deploymentType !== "preview") {
19864
+ return yield* failure("Preview authorization and Convex deployment metadata do not match.");
19865
+ }
19866
+ const canonical = yield* json2(CanonicalUrls, yield* httpRequest(`${endpoint.origin}/api/v1/get_canonical_urls`, deploymentAuthorization));
19867
+ if (canonical.convexCloudUrl.origin !== endpoint.origin || canonical.convexCloudUrl.origin !== callbackCloud.origin || canonical.convexSiteUrl.origin !== callbackSite.origin) {
19868
+ return yield* failure("Native Convex URLs do not match the selected preview deployment.");
19869
+ }
19870
+ return {
19871
+ adminKey: authorization.adminKey,
19872
+ cloud: canonical.convexCloudUrl.origin,
19873
+ deploymentName,
19874
+ deploymentType: "preview",
19875
+ identity: {
19876
+ project: projectSlugFromKey,
19877
+ projectId: info.projectId,
19878
+ team: teamSlugFromKey,
19879
+ teamId: info.teamId
19880
+ },
19881
+ site: canonical.convexSiteUrl.origin,
19882
+ url: endpoint.origin
19883
+ };
19884
+ });
19885
+ var buildEnvironment = (selected, values, verified, scratchHome) => {
19886
+ const child = {};
19887
+ copyDefined(selected.inherited, ["PATH", ...optionalSystemNames], values, child);
19888
+ child[process.platform === "win32" ? "USERPROFILE" : "HOME"] = scratchHome;
19889
+ child["VERCEL_ENV"] = selected.target;
19890
+ if (selected.target === "preview") {
19891
+ child["VERCEL_GIT_COMMIT_REF"] = selected.branch;
19892
+ }
19893
+ copyDefined(selected.inherited, hostNames, values, child);
19894
+ for (const name of canonicalNames) {
19895
+ child[name] = name === "VITE_CONVEX_URL" ? verified.cloud : verified.site;
19896
+ }
19897
+ for (const name of publicBuildNames) {
19898
+ const profileValue = values[name];
19899
+ const inheritedValue = selected.inherited[name] ?? empty9;
19900
+ if (profileValue !== undefined) {
19901
+ child[name] = profileValue;
19902
+ } else if (inheritedValue !== empty9) {
19903
+ child[name] = inheritedValue;
19904
+ }
19905
+ }
19906
+ return child;
19907
+ };
19908
+ var syncSettings = fn2("Deploy.syncSettings")(function* syncSettings(verified, settings) {
19909
+ if (settings.length === 0) {
19910
+ return yield* void_3;
19911
+ }
19912
+ const client = yield* HttpClient;
19913
+ const request = yield* bodyJson(setHeader(post(`${verified.url}/api/v1/update_environment_variables`), "Authorization", `Convex ${verified.adminKey}`), { changes: settings });
19914
+ const response = yield* client.execute(request);
19915
+ if (response.status !== 200) {
19916
+ return yield* failure("Could not synchronize Convex environment variables.");
19917
+ }
19918
+ return yield* void_3;
19919
+ }, mapError2(() => failure("Could not synchronize Convex environment variables.")));
19920
+ var runBuildCallback = fn2("Deploy.runBuildCallback")(function* runBuildCallback() {
19921
+ const callbackMode = yield* String6(callbackMarker).pipe(withDefault3(empty9));
19922
+ if (callbackMode !== "1") {
19923
+ return yield* failure("The Convex build callback can only run through affect deploy.");
19924
+ }
19925
+ const selected = yield* profile();
19926
+ const { declaration, root } = yield* preflight();
19927
+ yield* validateRequiredSettings(selected.values, declaration);
19928
+ const cloudText = yield* NonEmptyString2("VITE_CONVEX_URL").pipe(mapError2(() => failure("Native Convex did not inject the canonical cloud URL.")));
19929
+ const siteText = yield* NonEmptyString2("VITE_CONVEX_SITE_URL").pipe(mapError2(() => failure("Native Convex did not inject the canonical site URL.")));
19930
+ const cloud = yield* decodeEffect2(Origin)(cloudText).pipe(mapError2(() => failure("Native Convex injected an invalid cloud URL.")));
19931
+ const site = yield* decodeEffect2(Origin)(siteText).pipe(mapError2(() => failure("Native Convex injected an invalid site URL.")));
19932
+ const verified = yield* verifiedDeployment(selected, cloud, site).pipe(provide3(layer11), provideService2(RequestInit, { redirect: "error" }));
19933
+ const settings = selectedBackendSettings(selected.values, declaration);
19934
+ yield* syncSettings(verified, settings).pipe(provide3(layer11), provideService2(RequestInit, { redirect: "error" }));
19935
+ yield* error(`Convex target: ${verified.identity.team}/${verified.identity.project}; ${verified.deploymentType} ${verified.deploymentName}.`);
19936
+ const home = yield* temporaryHome("Could not prepare an isolated build environment.", "Could not clean the isolated build environment.");
19937
+ const env = buildEnvironment(selected, selected.values, verified, home);
19938
+ const child = yield* make18("bun", ["run", "build"], {
19939
+ cwd: root,
19940
+ env,
19941
+ extendEnv: false,
19942
+ stderr: "inherit",
19943
+ stdin: "inherit",
19944
+ stdout: "inherit"
19945
+ });
19946
+ const status = yield* child.exitCode;
19947
+ if (status !== 0) {
19948
+ return yield* failure(`bun run build exited with status ${status}.`);
19949
+ }
19950
+ return yield* void_3;
19951
+ });
19952
+ var nativeEnvironment = (selected, values, privateKey, home) => {
19953
+ const env = {};
19954
+ for (const name of [
19955
+ ...hostNames,
19956
+ ...optionalSystemNames,
19957
+ ...proxyNames,
19958
+ "NODE_OPTIONS",
19959
+ "BUN_OPTIONS"
19960
+ ]) {
19961
+ env[name] = empty9;
19962
+ }
19963
+ copyDefined(selected.inherited, ["PATH", ...optionalSystemNames, ...hostNames, ...proxyNames], values, env);
19964
+ env["VERCEL_ENV"] = selected.target;
19965
+ if (selected.target === "preview") {
19966
+ env["VERCEL_GIT_COMMIT_REF"] = selected.branch;
19967
+ }
19968
+ env[process.platform === "win32" ? "USERPROFILE" : "HOME"] = home;
19969
+ env["CONVEX_PROVISION_HOST"] = controlPlane;
19970
+ env["CONVEX_DEPLOY_KEY"] = selected.deployKey;
19971
+ env["DOTENV_PRIVATE_KEY"] = privateKey;
19972
+ env[callbackMarker] = "1";
19973
+ for (const name of deploymentNames) {
19974
+ if (name !== "CONVEX_DEPLOY_KEY" && name !== "CONVEX_PROVISION_HOST") {
19975
+ env[name] = empty9;
19976
+ }
19977
+ }
19978
+ for (const name of canonicalNames) {
19979
+ env[name] = empty9;
19980
+ }
19981
+ for (const name of publicBuildNames) {
19982
+ env[name] = values[name] ?? selected.inherited[name] ?? empty9;
19983
+ }
19984
+ return env;
19985
+ };
19986
+ var deployNative = fn2("Deploy.native")(function* deployNative(selected, values, root) {
19987
+ const privateKey = yield* NonEmptyString2("DOTENV_PRIVATE_KEY").pipe(mapError2(() => failure("Set the matching DOTENV_PRIVATE_KEY for the selected profile.")));
19988
+ const home = yield* temporaryHome("Could not prepare an isolated Convex configuration home.", "Could not clean the isolated Convex configuration home.");
19989
+ const env = nativeEnvironment(selected, values, privateKey, home);
19990
+ const args = [
19991
+ "--no-install",
19992
+ "convex",
19993
+ "deploy",
19994
+ "--cmd-url-env-var-name",
19995
+ "VITE_CONVEX_URL",
19996
+ ...selected.target === "preview" ? ["--preview-name", selected.branch] : [],
19997
+ "--cmd",
19998
+ callbackCommand
19999
+ ];
20000
+ const child = yield* make18("bunx", args, {
20001
+ cwd: root,
20002
+ env,
20003
+ extendEnv: false,
20004
+ stderr: "inherit",
20005
+ stdin: "inherit",
20006
+ stdout: "inherit"
20007
+ });
20008
+ const status = yield* child.exitCode;
20009
+ if (status !== 0) {
20010
+ return yield* failure(`Convex deploy exited with status ${status}.`);
20011
+ }
20012
+ return yield* void_3;
20013
+ });
20014
+ var deploy = fn2("Deploy.run")(function* deploy(build) {
20015
+ if (build) {
20016
+ return yield* runBuildCallback();
20017
+ }
20018
+ const selected = yield* profile();
20019
+ const { declaration } = yield* preflight();
20020
+ yield* validateRequiredSettings(selected.values, declaration);
20021
+ const requiredCollisions = [
20022
+ "PATH",
20023
+ "VERCEL_ENV",
20024
+ ...selected.target === "preview" ? ["VERCEL_GIT_COMMIT_REF"] : []
20025
+ ];
20026
+ if (childProfileCollision(selected.values, requiredCollisions)) {
20027
+ return yield* failure("Encrypted profile conflicts with required deployment environment settings.");
20028
+ }
20029
+ const path = yield* Path;
20030
+ const root = path.resolve(".");
20031
+ yield* error(`Convex target: ${selected.target}${selected.target === "preview" ? ` (${selected.branch})` : ""}; selected by env/${selected.target}/.env.`);
20032
+ return yield* deployNative(selected, selected.values, root);
20033
+ }, scoped2);
20034
+
19536
20035
  // src/process.ts
19537
20036
  var run6 = fn2("Process.run")(function* run(command) {
19538
20037
  const child = yield* command;
@@ -19553,76 +20052,6 @@ var convex = (args, env, input) => run6(make18("bunx", ["--no-install", "convex"
19553
20052
  stdout: "inherit"
19554
20053
  }));
19555
20054
 
19556
- // src/deploy.ts
19557
- var convexManagedEnvironmentNames = [
19558
- "CONVEX_DEPLOY_KEY",
19559
- "CONVEX_DEPLOYMENT_TOKEN",
19560
- "CONVEX_DEPLOYMENT",
19561
- "CONVEX_SELF_HOSTED_URL",
19562
- "CONVEX_SELF_HOSTED_ADMIN_KEY",
19563
- "CONVEX_URL",
19564
- "PUBLIC_CONVEX_URL",
19565
- "NEXT_PUBLIC_CONVEX_URL",
19566
- "VITE_CONVEX_URL",
19567
- "REACT_APP_CONVEX_URL",
19568
- "EXPO_PUBLIC_CONVEX_URL",
19569
- "CONVEX_SITE_URL",
19570
- "PUBLIC_CONVEX_SITE_URL",
19571
- "NEXT_PUBLIC_CONVEX_SITE_URL",
19572
- "VITE_CONVEX_SITE_URL",
19573
- "REACT_APP_CONVEX_SITE_URL",
19574
- "EXPO_PUBLIC_CONVEX_SITE_URL"
19575
- ];
19576
- var deploy = fn2("Deploy.run")(function* deploy(build) {
19577
- const environment = yield* load();
19578
- const { target, values, file } = environment;
19579
- if (target !== "preview" && target !== "production") {
19580
- return yield* new UserError({
19581
- cause: "Deploy requires VERCEL_ENV=preview or production."
19582
- });
19583
- }
19584
- const branch = yield* String6("VERCEL_GIT_COMMIT_REF").pipe(withDefault3(""));
19585
- if (target === "preview" && !branch) {
19586
- return yield* new UserError({ cause: "Preview deployment requires a branch name." });
19587
- }
19588
- const prefix = target === "preview" ? "preview:" : "prod:";
19589
- const deployKey = values["CONVEX_DEPLOY_KEY"] ?? "";
19590
- if (!deployKey.startsWith(prefix)) {
19591
- return yield* new UserError({
19592
- cause: "Encrypted project file must contain a Convex deploy key matching VERCEL_ENV."
19593
- });
19594
- }
19595
- yield* error(`Convex target: ${target}${target === "preview" ? ` (${branch})` : ""}; selected by env/${target}/.env.`);
19596
- if (build) {
19597
- const cloud = yield* NonEmptyString2("NEXT_PUBLIC_CONVEX_URL");
19598
- const site = yield* NonEmptyString2("NEXT_PUBLIC_CONVEX_SITE_URL");
19599
- const changes = map3(filter(toEntries(values), ([name]) => !contains(name)(convexManagedEnvironmentNames)), ([name, value]) => ({ name, value }));
19600
- if (changes.length > 0) {
19601
- yield* gen2(function* syncEnvironmentVariables() {
19602
- const client = yield* HttpClient;
19603
- const request = yield* bodyJson(setHeader(post(`${cloud}/api/v1/update_environment_variables`), "Authorization", `Convex ${deployKey}`), { changes });
19604
- yield* filterStatusOk2(client).execute(request).pipe(asVoid2);
19605
- }).pipe(provide3(layer11), mapError2(() => new UserError({
19606
- cause: "Could not synchronize Convex environment variables."
19607
- })));
19608
- }
19609
- return yield* run6(make18("bun", ["run", "build"], {
19610
- env: { ...values, NEXT_PUBLIC_CONVEX_SITE_URL: site, NEXT_PUBLIC_CONVEX_URL: cloud },
19611
- extendEnv: true,
19612
- stderr: "inherit",
19613
- stdout: "inherit"
19614
- })).pipe(asVoid2);
19615
- }
19616
- const fs = yield* FileSystem;
19617
- yield* fs.copyFile(file, "apps/web/.env.production");
19618
- return yield* convex([
19619
- "deploy",
19620
- ...target === "preview" ? ["--preview-name", branch] : [],
19621
- "--cmd",
19622
- "bunx --no-install affect deploy --build"
19623
- ], values).pipe(asVoid2);
19624
- });
19625
-
19626
20055
  // src/dotenv.ts
19627
20056
  var dotenvx = fn2("Dotenvx.run")(function* dotenvx(args, capture) {
19628
20057
  const path = yield* Path;
@@ -19701,30 +20130,30 @@ var setup = fn2("Setup.run")(function* setup() {
19701
20130
  });
19702
20131
 
19703
20132
  // src/sync-dev.ts
19704
- var failure = (cause) => new UserError({ cause });
19705
- var reserved = /^(?:CONVEX_|DOTENV_|NEXT_PUBLIC_|PUBLIC_|VITE_|REACT_APP_|EXPO_PUBLIC_|VERCEL_|GITHUB_|NODE_|BUN_|AFFECT_|CI$|PATH$|HOME$|PWD$|SHELL$|ENV$|TMPDIR$|(?:HTTPS?|ALL|NO)_PROXY$)/u;
20133
+ var failure2 = (cause) => new UserError({ cause });
20134
+ var reserved = /^(?:CONVEX_|DOTENV_|(?:[A-Z0-9]+_)*PUBLIC_|VITE_|REACT_APP_|EXPO_PUBLIC_|VERCEL_|GITHUB_|NODE_|BUN_|AFFECT_|CI$|PATH$|HOME$|PWD$|SHELL$|ENV$|TMPDIR$|(?:HTTPS?|ALL|NO)_PROXY$)/u;
19706
20135
  var SettingName = String5.check(makeFilter2((name) => !reserved.test(name)));
19707
- var Declaration2 = Record(String5, Struct({
20136
+ var Declaration3 = Record(String5, Struct({
19708
20137
  isConvexValidator: Literal2(true),
19709
20138
  isOptional: Literals(["required", "optional"])
19710
20139
  }));
19711
- var Origin = URLFromString.check(makeFilter2((url) => url.protocol === "https:" && url.username === "" && url.password === "" && url.pathname === "/" && url.search === "" && url.hash === ""));
20140
+ var Origin2 = URLFromString.check(makeFilter2((url) => url.protocol === "https:" && url.username === "" && url.password === "" && url.pathname === "/" && url.search === "" && url.hash === ""));
19712
20141
  var Profile = Struct({
19713
20142
  CONVEX_DEPLOY_KEY: String5.check(isPattern2(/^dev:[a-z0-9-]+\|.+$/u)),
19714
- NEXT_PUBLIC_CONVEX_SITE_URL: Origin,
19715
- NEXT_PUBLIC_CONVEX_URL: Origin
20143
+ VITE_CONVEX_SITE_URL: Origin2,
20144
+ VITE_CONVEX_URL: Origin2
19716
20145
  });
19717
- var Slug = String5.check(isPattern2(/^[a-z0-9][a-z0-9_-]*$/u));
19718
- var Id = Int.check(isGreaterThan2(0));
19719
- var Identity = Struct({ project: Slug, projectId: Id, team: Slug, teamId: Id });
19720
- var Deployment = Struct({
20146
+ var Slug2 = String5.check(isPattern2(/^[a-z0-9][a-z0-9_-]*$/u));
20147
+ var Id2 = Int.check(isGreaterThan2(0));
20148
+ var Identity2 = Struct({ project: Slug2, projectId: Id2, team: Slug2, teamId: Id2 });
20149
+ var Deployment2 = Struct({
19721
20150
  deploymentType: Literal2("dev"),
19722
- id: Id,
20151
+ id: Id2,
19723
20152
  kind: Literal2("cloud"),
19724
- projectId: Id,
19725
- teamId: Id
20153
+ projectId: Id2,
20154
+ teamId: Id2
19726
20155
  });
19727
- var CanonicalUrls = Struct({ convexCloudUrl: Origin, convexSiteUrl: Origin });
20156
+ var CanonicalUrls2 = Struct({ convexCloudUrl: Origin2, convexSiteUrl: Origin2 });
19728
20157
  var Existing = Struct({
19729
20158
  environmentVariables: Record(String5, String5)
19730
20159
  });
@@ -19734,35 +20163,35 @@ var request = fn2("DevelopmentEnv.request")(function* request(url, authorization
19734
20163
  const outgoing = body === undefined ? base : yield* bodyJson(base, body);
19735
20164
  const response = yield* client.execute(outgoing);
19736
20165
  if (response.status !== 200) {
19737
- return yield* failure("Development environment request failed.");
20166
+ return yield* failure2("Development environment request failed.");
19738
20167
  }
19739
20168
  return response;
19740
- }, mapError2(() => failure("Development environment request failed.")));
19741
- var json2 = (schema, response) => response.json.pipe(flatMap3(decodeUnknownEffect2(schema)), mapError2(() => failure("Invalid development deployment metadata.")));
20169
+ }, mapError2(() => failure2("Development environment request failed.")));
20170
+ var json3 = (schema, response) => response.json.pipe(flatMap3(decodeUnknownEffect2(schema)), mapError2(() => failure2("Invalid development deployment metadata.")));
19742
20171
  var syncDev = fn2("DevelopmentEnv.sync")(function* syncDev(force) {
19743
20172
  const path = yield* Path;
19744
20173
  const fs = yield* FileSystem;
19745
20174
  const file = path.resolve("env", "development", ".env");
19746
20175
  if (!(yield* fs.exists(file))) {
19747
- return yield* failure("Missing env/development/.env.");
20176
+ return yield* failure2("Missing env/development/.env.");
19748
20177
  }
19749
- yield* NonEmptyString2("DOTENV_PRIVATE_KEY").pipe(mapError2(() => failure("Set the matching development DOTENV_PRIVATE_KEY.")));
20178
+ yield* NonEmptyString2("DOTENV_PRIVATE_KEY").pipe(mapError2(() => failure2("Set the matching development DOTENV_PRIVATE_KEY.")));
19750
20179
  const values = yield* read2(file);
19751
- const profile = yield* decodeUnknownEffect2(Profile)(values).pipe(mapError2(() => failure("Development profile requires a dev-scoped key and HTTPS Convex origins.")));
20180
+ const profile = yield* decodeUnknownEffect2(Profile)(values).pipe(mapError2(() => failure2("Development profile requires a dev-scoped key and HTTPS Convex origins.")));
19752
20181
  const name = profile.CONVEX_DEPLOY_KEY.split("|")[0]?.slice(4);
19753
20182
  if ((values["CONVEX_DEPLOYMENT"] ?? "") !== "" && values["CONVEX_DEPLOYMENT"] !== `dev:${name}`) {
19754
- return yield* failure("CONVEX_DEPLOYMENT does not match the development key.");
20183
+ return yield* failure2("CONVEX_DEPLOYMENT does not match the development key.");
19755
20184
  }
19756
20185
  const declarationModule = yield* try_3({
19757
- catch: () => failure("Cannot load the declaration-only convex/env.config.ts."),
19758
- try: () => decodeUnknownEffect2(Struct({ default: Declaration2 }))(import.meta.require(path.resolve("convex", "env.config.ts")))
19759
- }).pipe(flatten3, mapError2(() => failure("Cannot load a valid declaration-only convex/env.config.ts with Convex validators.")));
20186
+ catch: () => failure2("Cannot load the declaration-only convex/env.config.ts."),
20187
+ try: () => decodeUnknownEffect2(Struct({ default: Declaration3 }))(import.meta.require(path.resolve("convex", "env.config.ts")))
20188
+ }).pipe(flatten3, mapError2(() => failure2("Cannot load a valid declaration-only convex/env.config.ts with Convex validators.")));
19760
20189
  const declaration = declarationModule.default;
19761
- yield* decodeEffect2(ArraySchema(SettingName))(keys(declaration)).pipe(mapError2(() => failure("Server declaration contains a credential, control or client-public name.")));
20190
+ yield* decodeEffect2(ArraySchema(SettingName))(keys(declaration)).pipe(mapError2(() => failure2("Server declaration contains a credential, control or client-public name.")));
19762
20191
  const entries = toEntries(declaration);
19763
20192
  const missing = filter(entries, ([key, validator]) => validator.isOptional === "required" && !has(values, key));
19764
20193
  if (missing.length > 0) {
19765
- return yield* failure(`Missing required server settings: ${join(map3(missing, ([key]) => key), ", ")}.`);
20194
+ return yield* failure2(`Missing required server settings: ${join(map3(missing, ([key]) => key), ", ")}.`);
19766
20195
  }
19767
20196
  const selected = filterMap(entries, ([key]) => {
19768
20197
  const value = has(values, key) ? values[key] : undefined;
@@ -19771,26 +20200,26 @@ var syncDev = fn2("DevelopmentEnv.sync")(function* syncDev(force) {
19771
20200
  const key = profile.CONVEX_DEPLOY_KEY;
19772
20201
  const bearer = `Bearer ${key}`;
19773
20202
  const lookup = { deployKey: key };
19774
- const cloud = yield* json2(Origin, yield* request("https://api.convex.dev/api/deployment/url_for_key", bearer, lookup));
19775
- if (cloud.origin !== profile.NEXT_PUBLIC_CONVEX_URL.origin) {
19776
- return yield* failure("Development key and public Convex URL do not match.");
20203
+ const cloud = yield* json3(Origin2, yield* request("https://api.convex.dev/api/deployment/url_for_key", bearer, lookup));
20204
+ if (cloud.origin !== profile.VITE_CONVEX_URL.origin) {
20205
+ return yield* failure2("Development key and public Convex URL do not match.");
19777
20206
  }
19778
- const identity = yield* json2(Identity, yield* request("https://api.convex.dev/api/deployment/team_and_project_for_key", bearer, lookup));
20207
+ const identity = yield* json3(Identity2, yield* request("https://api.convex.dev/api/deployment/team_and_project_for_key", bearer, lookup));
19779
20208
  const authorization = `Convex ${key}`;
19780
- const deployment = yield* json2(Deployment, yield* request(`${cloud.origin}/api/v1/deployment_info`, authorization));
20209
+ const deployment = yield* json3(Deployment2, yield* request(`${cloud.origin}/api/v1/deployment_info`, authorization));
19781
20210
  if (deployment.teamId !== identity.teamId || deployment.projectId !== identity.projectId) {
19782
- return yield* failure("Development deployment identity does not match the key.");
20211
+ return yield* failure2("Development deployment identity does not match the key.");
19783
20212
  }
19784
- const urls = yield* json2(CanonicalUrls, yield* request(`${cloud.origin}/api/v1/get_canonical_urls`, authorization));
19785
- if (urls.convexCloudUrl.origin !== cloud.origin || urls.convexSiteUrl.origin !== profile.NEXT_PUBLIC_CONVEX_SITE_URL.origin) {
19786
- return yield* failure("Development canonical Convex URLs do not match the profile.");
20213
+ const urls = yield* json3(CanonicalUrls2, yield* request(`${cloud.origin}/api/v1/get_canonical_urls`, authorization));
20214
+ if (urls.convexCloudUrl.origin !== cloud.origin || urls.convexSiteUrl.origin !== profile.VITE_CONVEX_SITE_URL.origin) {
20215
+ return yield* failure2("Development canonical Convex URLs do not match the profile.");
19787
20216
  }
19788
20217
  yield* error(`Convex target: ${identity.team}/${identity.project}; development ${name} (ID ${deployment.id}).`);
19789
- const existing = yield* json2(Existing, yield* request(`${cloud.origin}/api/v1/list_environment_variables`, authorization));
20218
+ const existing = yield* json3(Existing, yield* request(`${cloud.origin}/api/v1/list_environment_variables`, authorization));
19790
20219
  const changed = filter(selected, (entry) => !has(existing.environmentVariables, entry.name) || existing.environmentVariables[entry.name] !== entry.value);
19791
20220
  const conflicts = filter(changed, (entry) => has(existing.environmentVariables, entry.name));
19792
20221
  if (!force && conflicts.length > 0) {
19793
- return yield* failure(`Existing settings differ: ${join(map3(conflicts, (entry) => entry.name), ", ")}. Use --force to overwrite them.`);
20222
+ return yield* failure2(`Existing settings differ: ${join(map3(conflicts, (entry) => entry.name), ", ")}. Use --force to overwrite them.`);
19794
20223
  }
19795
20224
  if (changed.length > 0) {
19796
20225
  yield* request(`${cloud.origin}/api/v1/update_environment_variables`, authorization, {
@@ -19801,7 +20230,7 @@ var syncDev = fn2("DevelopmentEnv.sync")(function* syncDev(force) {
19801
20230
  }, provide3(layer11), provideService2(RequestInit, { redirect: "error" }));
19802
20231
 
19803
20232
  // src/index.ts
19804
- var program = make30("affect").pipe(withDescription3("Environment and deployment commands for Affect applications."), withSubcommands([
20233
+ var program = make30("affect").pipe(withDescription3("Environment and native deployment commands for Affect applications."), withSubcommands([
19805
20234
  make30("env", {}, () => exports().pipe(flatMap3(log))).pipe(withDescription3("Print shell exports for the selected encrypted environment."), withSubcommands([
19806
20235
  make30("sync-dev", { force: Boolean6("force").pipe(withDefault5(false)) }, ({ force }) => syncDev(force)).pipe(withDescription3("Sync declared server settings to the verified hosted development backend; --force overwrites conflicts. No deployment."))
19807
20236
  ])),
@@ -19811,6 +20240,6 @@ var program = make30("affect").pipe(withDescription3("Environment and deployment
19811
20240
  }, ({ command, params }) => run7(command, params)).pipe(withDescription3("Run a command with the selected encrypted environment.")),
19812
20241
  make30("dotenvx", { args: String10("args").pipe(variadic2()) }, ({ args }) => dotenvx(args, false)).pipe(withDescription3("Run the bundled dotenvx CLI; pass its flags after --.")),
19813
20242
  make30("setup", {}, setup).pipe(withDescription3("Initialize or retry an anonymous local Convex backend.")),
19814
- make30("deploy", { build: Boolean6("build").pipe(withDefault5(false)) }, ({ build }) => deploy(build)).pipe(withDescription3("Deploy the selected Vercel preview or production environment."))
20243
+ make30("deploy", { build: Boolean6("build").pipe(withDefault5(false)) }, ({ build }) => deploy(build)).pipe(withDescription3("Run native Convex deploy and the TanStack build for the selected Vercel target; does not publish frontend output. --build is the internal callback."))
19815
20244
  ]), run5({ version }), provide3(layer10), provideService2(LogToStderr2, true));
19816
20245
  runMain2(program);
package/package.json CHANGED
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "affect-cli",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "description": "Affect command-line interface",
5
- "homepage": "https://github.com/ludicroushq/affect-cli#readme",
5
+ "homepage": "https://github.com/nahtnam/affect-cli#readme",
6
6
  "bugs": {
7
- "url": "https://github.com/ludicroushq/affect-cli/issues"
7
+ "url": "https://github.com/nahtnam/affect-cli/issues"
8
8
  },
9
9
  "license": "MIT",
10
10
  "repository": {
11
11
  "type": "git",
12
- "url": "git+https://github.com/ludicroushq/affect-cli.git"
12
+ "url": "git+https://github.com/nahtnam/affect-cli.git"
13
13
  },
14
14
  "bin": {
15
15
  "affect": "dist/index.js"