convex 1.48.0 → 1.49.0-alpha.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.
Files changed (248) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/browser.bundle.js +1 -1
  3. package/dist/browser.bundle.js.map +1 -1
  4. package/dist/cjs/bundler/context.js +7 -5
  5. package/dist/cjs/bundler/context.js.map +2 -2
  6. package/dist/cjs/bundler/fs.js +47 -6
  7. package/dist/cjs/bundler/fs.js.map +2 -2
  8. package/dist/cjs/cli/account.js +237 -0
  9. package/dist/cjs/cli/account.js.map +7 -0
  10. package/dist/cjs/cli/configure.js +15 -2
  11. package/dist/cjs/cli/configure.js.map +2 -2
  12. package/dist/cjs/cli/lib/accountManagement.js +196 -0
  13. package/dist/cjs/cli/lib/accountManagement.js.map +7 -0
  14. package/dist/cjs/cli/lib/accounts.js +334 -0
  15. package/dist/cjs/cli/lib/accounts.js.map +7 -0
  16. package/dist/cjs/cli/lib/deployKeyWarning.js +43 -0
  17. package/dist/cjs/cli/lib/deployKeyWarning.js.map +7 -0
  18. package/dist/cjs/cli/lib/deployment.js +2 -0
  19. package/dist/cjs/cli/lib/deployment.js.map +2 -2
  20. package/dist/cjs/cli/lib/deploymentSelection.js +27 -18
  21. package/dist/cjs/cli/lib/deploymentSelection.js.map +2 -2
  22. package/dist/cjs/cli/lib/envvars.js +32 -0
  23. package/dist/cjs/cli/lib/envvars.js.map +2 -2
  24. package/dist/cjs/cli/lib/fsUtils.js +1 -1
  25. package/dist/cjs/cli/lib/fsUtils.js.map +2 -2
  26. package/dist/cjs/cli/lib/generateDocs.js +1 -1
  27. package/dist/cjs/cli/lib/generateDocs.js.map +1 -1
  28. package/dist/cjs/cli/lib/login.js +42 -4
  29. package/dist/cjs/cli/lib/login.js.map +3 -3
  30. package/dist/cjs/cli/lib/mcp/requestContext.js +5 -1
  31. package/dist/cjs/cli/lib/mcp/requestContext.js.map +2 -2
  32. package/dist/cjs/cli/lib/plugins/claudeCode.js +188 -0
  33. package/dist/cjs/cli/lib/plugins/claudeCode.js.map +7 -0
  34. package/dist/cjs/cli/lib/plugins/codex.js +167 -0
  35. package/dist/cjs/cli/lib/plugins/codex.js.map +7 -0
  36. package/dist/cjs/cli/lib/plugins/harness.js +50 -0
  37. package/dist/cjs/cli/lib/plugins/harness.js.map +7 -0
  38. package/dist/cjs/cli/lib/plugins/marketplaces.js +76 -0
  39. package/dist/cjs/cli/lib/plugins/marketplaces.js.map +7 -0
  40. package/dist/cjs/cli/lib/plugins/skills.js +98 -0
  41. package/dist/cjs/cli/lib/plugins/skills.js.map +7 -0
  42. package/dist/cjs/cli/lib/plugins/utils.js +125 -0
  43. package/dist/cjs/cli/lib/plugins/utils.js.map +7 -0
  44. package/dist/cjs/cli/lib/utils/utils.js +18 -9
  45. package/dist/cjs/cli/lib/utils/utils.js.map +2 -2
  46. package/dist/cjs/cli/login.js +213 -114
  47. package/dist/cjs/cli/login.js.map +3 -3
  48. package/dist/cjs/cli/logout.js +113 -12
  49. package/dist/cjs/cli/logout.js.map +3 -3
  50. package/dist/cjs/cli/mcp.js +43 -10
  51. package/dist/cjs/cli/mcp.js.map +3 -3
  52. package/dist/cjs/cli/plugins.js +114 -0
  53. package/dist/cjs/cli/plugins.js.map +7 -0
  54. package/dist/cjs/cli/program.js +3 -1
  55. package/dist/cjs/cli/program.js.map +2 -2
  56. package/dist/cjs/index.js +1 -1
  57. package/dist/cjs/index.js.map +1 -1
  58. package/dist/cjs/server/impl/actions_impl.js.map +2 -2
  59. package/dist/cjs-types/bundler/context.d.ts +5 -0
  60. package/dist/cjs-types/bundler/context.d.ts.map +1 -1
  61. package/dist/cjs-types/bundler/fs.d.ts +7 -2
  62. package/dist/cjs-types/bundler/fs.d.ts.map +1 -1
  63. package/dist/cjs-types/cli/account.d.ts +6 -0
  64. package/dist/cjs-types/cli/account.d.ts.map +1 -0
  65. package/dist/cjs-types/cli/configure.d.ts.map +1 -1
  66. package/dist/cjs-types/cli/lib/accountManagement.d.ts +10 -0
  67. package/dist/cjs-types/cli/lib/accountManagement.d.ts.map +1 -0
  68. package/dist/cjs-types/cli/lib/accounts.d.ts +59 -0
  69. package/dist/cjs-types/cli/lib/accounts.d.ts.map +1 -0
  70. package/dist/cjs-types/cli/lib/deployKeyWarning.d.ts +3 -0
  71. package/dist/cjs-types/cli/lib/deployKeyWarning.d.ts.map +1 -0
  72. package/dist/cjs-types/cli/lib/deployment.d.ts +2 -0
  73. package/dist/cjs-types/cli/lib/deployment.d.ts.map +1 -1
  74. package/dist/cjs-types/cli/lib/deploymentSelection.d.ts +2 -1
  75. package/dist/cjs-types/cli/lib/deploymentSelection.d.ts.map +1 -1
  76. package/dist/cjs-types/cli/lib/envvars.d.ts +6 -0
  77. package/dist/cjs-types/cli/lib/envvars.d.ts.map +1 -1
  78. package/dist/cjs-types/cli/lib/fsUtils.d.ts +1 -0
  79. package/dist/cjs-types/cli/lib/fsUtils.d.ts.map +1 -1
  80. package/dist/cjs-types/cli/lib/login.d.ts +3 -1
  81. package/dist/cjs-types/cli/lib/login.d.ts.map +1 -1
  82. package/dist/cjs-types/cli/lib/mcp/requestContext.d.ts.map +1 -1
  83. package/dist/cjs-types/cli/lib/mcp/tools/insights.d.ts +2 -2
  84. package/dist/cjs-types/cli/lib/plugins/claudeCode.d.ts +25 -0
  85. package/dist/cjs-types/cli/lib/plugins/claudeCode.d.ts.map +1 -0
  86. package/dist/cjs-types/cli/lib/plugins/codex.d.ts +25 -0
  87. package/dist/cjs-types/cli/lib/plugins/codex.d.ts.map +1 -0
  88. package/dist/cjs-types/cli/lib/plugins/harness.d.ts +33 -0
  89. package/dist/cjs-types/cli/lib/plugins/harness.d.ts.map +1 -0
  90. package/dist/cjs-types/cli/lib/plugins/marketplaces.d.ts +40 -0
  91. package/dist/cjs-types/cli/lib/plugins/marketplaces.d.ts.map +1 -0
  92. package/dist/cjs-types/cli/lib/plugins/skills.d.ts +18 -0
  93. package/dist/cjs-types/cli/lib/plugins/skills.d.ts.map +1 -0
  94. package/dist/cjs-types/cli/lib/plugins/utils.d.ts +21 -0
  95. package/dist/cjs-types/cli/lib/plugins/utils.d.ts.map +1 -0
  96. package/dist/cjs-types/cli/lib/utils/utils.d.ts +5 -0
  97. package/dist/cjs-types/cli/lib/utils/utils.d.ts.map +1 -1
  98. package/dist/cjs-types/cli/login.d.ts +21 -0
  99. package/dist/cjs-types/cli/login.d.ts.map +1 -1
  100. package/dist/cjs-types/cli/logout.d.ts +8 -1
  101. package/dist/cjs-types/cli/logout.d.ts.map +1 -1
  102. package/dist/cjs-types/cli/mcp.d.ts.map +1 -1
  103. package/dist/cjs-types/cli/plugins.d.ts +3 -0
  104. package/dist/cjs-types/cli/plugins.d.ts.map +1 -0
  105. package/dist/cjs-types/cli/program.d.ts.map +1 -1
  106. package/dist/cjs-types/index.d.ts +1 -1
  107. package/dist/cjs-types/index.d.ts.map +1 -1
  108. package/dist/cjs-types/server/impl/actions_impl.d.ts +3 -2
  109. package/dist/cjs-types/server/impl/actions_impl.d.ts.map +1 -1
  110. package/dist/cli.bundle.cjs +10059 -7094
  111. package/dist/cli.bundle.cjs.map +4 -4
  112. package/dist/esm/bundler/context.js +7 -5
  113. package/dist/esm/bundler/context.js.map +2 -2
  114. package/dist/esm/bundler/fs.js +47 -6
  115. package/dist/esm/bundler/fs.js.map +2 -2
  116. package/dist/esm/cli/account.js +221 -0
  117. package/dist/esm/cli/account.js.map +7 -0
  118. package/dist/esm/cli/configure.js +15 -2
  119. package/dist/esm/cli/configure.js.map +2 -2
  120. package/dist/esm/cli/lib/accountManagement.js +179 -0
  121. package/dist/esm/cli/lib/accountManagement.js.map +7 -0
  122. package/dist/esm/cli/lib/accounts.js +289 -0
  123. package/dist/esm/cli/lib/accounts.js.map +7 -0
  124. package/dist/esm/cli/lib/deployKeyWarning.js +27 -0
  125. package/dist/esm/cli/lib/deployKeyWarning.js.map +7 -0
  126. package/dist/esm/cli/lib/deployment.js +2 -2
  127. package/dist/esm/cli/lib/deployment.js.map +2 -2
  128. package/dist/esm/cli/lib/deploymentSelection.js +35 -20
  129. package/dist/esm/cli/lib/deploymentSelection.js.map +2 -2
  130. package/dist/esm/cli/lib/envvars.js +35 -1
  131. package/dist/esm/cli/lib/envvars.js.map +2 -2
  132. package/dist/esm/cli/lib/fsUtils.js +1 -1
  133. package/dist/esm/cli/lib/fsUtils.js.map +2 -2
  134. package/dist/esm/cli/lib/generateDocs.js +1 -1
  135. package/dist/esm/cli/lib/generateDocs.js.map +1 -1
  136. package/dist/esm/cli/lib/login.js +52 -4
  137. package/dist/esm/cli/lib/login.js.map +3 -3
  138. package/dist/esm/cli/lib/mcp/requestContext.js +5 -1
  139. package/dist/esm/cli/lib/mcp/requestContext.js.map +2 -2
  140. package/dist/esm/cli/lib/plugins/claudeCode.js +160 -0
  141. package/dist/esm/cli/lib/plugins/claudeCode.js.map +7 -0
  142. package/dist/esm/cli/lib/plugins/codex.js +140 -0
  143. package/dist/esm/cli/lib/plugins/codex.js.map +7 -0
  144. package/dist/esm/cli/lib/plugins/harness.js +17 -0
  145. package/dist/esm/cli/lib/plugins/harness.js.map +7 -0
  146. package/dist/esm/cli/lib/plugins/marketplaces.js +53 -0
  147. package/dist/esm/cli/lib/plugins/marketplaces.js.map +7 -0
  148. package/dist/esm/cli/lib/plugins/skills.js +65 -0
  149. package/dist/esm/cli/lib/plugins/skills.js.map +7 -0
  150. package/dist/esm/cli/lib/plugins/utils.js +86 -0
  151. package/dist/esm/cli/lib/plugins/utils.js.map +7 -0
  152. package/dist/esm/cli/lib/utils/utils.js +16 -9
  153. package/dist/esm/cli/lib/utils/utils.js.map +2 -2
  154. package/dist/esm/cli/login.js +225 -112
  155. package/dist/esm/cli/login.js.map +3 -3
  156. package/dist/esm/cli/logout.js +110 -13
  157. package/dist/esm/cli/logout.js.map +2 -2
  158. package/dist/esm/cli/mcp.js +34 -10
  159. package/dist/esm/cli/mcp.js.map +2 -2
  160. package/dist/esm/cli/plugins.js +99 -0
  161. package/dist/esm/cli/plugins.js.map +7 -0
  162. package/dist/esm/cli/program.js +3 -1
  163. package/dist/esm/cli/program.js.map +2 -2
  164. package/dist/esm/index.js +1 -1
  165. package/dist/esm/index.js.map +1 -1
  166. package/dist/esm/server/impl/actions_impl.js.map +2 -2
  167. package/dist/esm-types/bundler/context.d.ts +5 -0
  168. package/dist/esm-types/bundler/context.d.ts.map +1 -1
  169. package/dist/esm-types/bundler/fs.d.ts +7 -2
  170. package/dist/esm-types/bundler/fs.d.ts.map +1 -1
  171. package/dist/esm-types/cli/account.d.ts +6 -0
  172. package/dist/esm-types/cli/account.d.ts.map +1 -0
  173. package/dist/esm-types/cli/configure.d.ts.map +1 -1
  174. package/dist/esm-types/cli/lib/accountManagement.d.ts +10 -0
  175. package/dist/esm-types/cli/lib/accountManagement.d.ts.map +1 -0
  176. package/dist/esm-types/cli/lib/accounts.d.ts +59 -0
  177. package/dist/esm-types/cli/lib/accounts.d.ts.map +1 -0
  178. package/dist/esm-types/cli/lib/deployKeyWarning.d.ts +3 -0
  179. package/dist/esm-types/cli/lib/deployKeyWarning.d.ts.map +1 -0
  180. package/dist/esm-types/cli/lib/deployment.d.ts +2 -0
  181. package/dist/esm-types/cli/lib/deployment.d.ts.map +1 -1
  182. package/dist/esm-types/cli/lib/deploymentSelection.d.ts +2 -1
  183. package/dist/esm-types/cli/lib/deploymentSelection.d.ts.map +1 -1
  184. package/dist/esm-types/cli/lib/envvars.d.ts +6 -0
  185. package/dist/esm-types/cli/lib/envvars.d.ts.map +1 -1
  186. package/dist/esm-types/cli/lib/fsUtils.d.ts +1 -0
  187. package/dist/esm-types/cli/lib/fsUtils.d.ts.map +1 -1
  188. package/dist/esm-types/cli/lib/login.d.ts +3 -1
  189. package/dist/esm-types/cli/lib/login.d.ts.map +1 -1
  190. package/dist/esm-types/cli/lib/mcp/requestContext.d.ts.map +1 -1
  191. package/dist/esm-types/cli/lib/mcp/tools/insights.d.ts +2 -2
  192. package/dist/esm-types/cli/lib/plugins/claudeCode.d.ts +25 -0
  193. package/dist/esm-types/cli/lib/plugins/claudeCode.d.ts.map +1 -0
  194. package/dist/esm-types/cli/lib/plugins/codex.d.ts +25 -0
  195. package/dist/esm-types/cli/lib/plugins/codex.d.ts.map +1 -0
  196. package/dist/esm-types/cli/lib/plugins/harness.d.ts +33 -0
  197. package/dist/esm-types/cli/lib/plugins/harness.d.ts.map +1 -0
  198. package/dist/esm-types/cli/lib/plugins/marketplaces.d.ts +40 -0
  199. package/dist/esm-types/cli/lib/plugins/marketplaces.d.ts.map +1 -0
  200. package/dist/esm-types/cli/lib/plugins/skills.d.ts +18 -0
  201. package/dist/esm-types/cli/lib/plugins/skills.d.ts.map +1 -0
  202. package/dist/esm-types/cli/lib/plugins/utils.d.ts +21 -0
  203. package/dist/esm-types/cli/lib/plugins/utils.d.ts.map +1 -0
  204. package/dist/esm-types/cli/lib/utils/utils.d.ts +5 -0
  205. package/dist/esm-types/cli/lib/utils/utils.d.ts.map +1 -1
  206. package/dist/esm-types/cli/login.d.ts +21 -0
  207. package/dist/esm-types/cli/login.d.ts.map +1 -1
  208. package/dist/esm-types/cli/logout.d.ts +8 -1
  209. package/dist/esm-types/cli/logout.d.ts.map +1 -1
  210. package/dist/esm-types/cli/mcp.d.ts.map +1 -1
  211. package/dist/esm-types/cli/plugins.d.ts +3 -0
  212. package/dist/esm-types/cli/plugins.d.ts.map +1 -0
  213. package/dist/esm-types/cli/program.d.ts.map +1 -1
  214. package/dist/esm-types/index.d.ts +1 -1
  215. package/dist/esm-types/index.d.ts.map +1 -1
  216. package/dist/esm-types/server/impl/actions_impl.d.ts +3 -2
  217. package/dist/esm-types/server/impl/actions_impl.d.ts.map +1 -1
  218. package/dist/react.bundle.js +1 -1
  219. package/dist/react.bundle.js.map +1 -1
  220. package/package.json +2 -2
  221. package/src/bundler/context.ts +9 -5
  222. package/src/bundler/fs.ts +54 -5
  223. package/src/cli/account.ts +320 -0
  224. package/src/cli/configure.ts +18 -2
  225. package/src/cli/lib/accountManagement.ts +262 -0
  226. package/src/cli/lib/accounts.ts +400 -0
  227. package/src/cli/lib/deployKeyWarning.ts +43 -0
  228. package/src/cli/lib/deployment.ts +2 -2
  229. package/src/cli/lib/deploymentSelection.ts +37 -18
  230. package/src/cli/lib/envvars.ts +43 -1
  231. package/src/cli/lib/fsUtils.ts +5 -2
  232. package/src/cli/lib/generateDocs.ts +1 -1
  233. package/src/cli/lib/login.ts +64 -3
  234. package/src/cli/lib/mcp/requestContext.ts +7 -1
  235. package/src/cli/lib/plugins/claudeCode.ts +201 -0
  236. package/src/cli/lib/plugins/codex.ts +177 -0
  237. package/src/cli/lib/plugins/harness.ts +49 -0
  238. package/src/cli/lib/plugins/marketplaces.ts +94 -0
  239. package/src/cli/lib/plugins/skills.ts +101 -0
  240. package/src/cli/lib/plugins/utils.ts +121 -0
  241. package/src/cli/lib/utils/utils.ts +19 -15
  242. package/src/cli/login.ts +293 -168
  243. package/src/cli/logout.ts +142 -17
  244. package/src/cli/mcp.ts +48 -11
  245. package/src/cli/plugins.ts +154 -0
  246. package/src/cli/program.ts +4 -0
  247. package/src/index.ts +1 -1
  248. package/src/server/impl/actions_impl.ts +3 -2
@@ -0,0 +1,289 @@
1
+ "use strict";
2
+ import path from "path";
3
+ import { isDeepStrictEqual } from "util";
4
+ import { randomUUID } from "crypto";
5
+ import * as dotenv from "dotenv";
6
+ import { z } from "zod";
7
+ import { logFinishedStep, logWarning } from "../../bundler/log.js";
8
+ import { globalConfigPath, readGlobalConfig } from "./utils/globalConfig.js";
9
+ import { ENV_VAR_FILE_PATH, rootDirectory } from "./utils/utils.js";
10
+ import { CONVEX_ACCOUNT_ENV_VAR } from "./envvars.js";
11
+ const settingsSchema = z.object({
12
+ defaultAccount: z.string().optional(),
13
+ directories: z.record(z.string()).optional(),
14
+ revokeReplacedTokens: z.boolean().optional()
15
+ }).passthrough();
16
+ const credentialsSchema = z.object({
17
+ accessToken: z.string().min(1),
18
+ memberId: z.string().optional(),
19
+ email: z.string().optional()
20
+ }).passthrough();
21
+ export async function readAccountSettings(ctx) {
22
+ if (!ctx.fs.exists(globalConfigPath())) return {};
23
+ try {
24
+ return settingsSchema.parse(
25
+ JSON.parse(ctx.fs.readUtf8File(globalConfigPath()))
26
+ );
27
+ } catch {
28
+ return await ctx.crash({
29
+ exitCode: 1,
30
+ errorType: "invalid filesystem data",
31
+ printedMessage: `Unable to read account settings from ${globalConfigPath()}. Check defaultAccount, directories, and revokeReplacedTokens.`
32
+ });
33
+ }
34
+ }
35
+ function writeAccountSettings(ctx, settings) {
36
+ if (Object.keys(settings).length === 0) {
37
+ if (ctx.fs.exists(globalConfigPath())) ctx.fs.unlink(globalConfigPath());
38
+ return;
39
+ }
40
+ const temporary = `${globalConfigPath()}.${randomUUID()}.tmp`;
41
+ try {
42
+ ctx.fs.writeUtf8File(temporary, JSON.stringify(settings, null, 2), 384);
43
+ ctx.fs.swapTmpFile(temporary, globalConfigPath());
44
+ } finally {
45
+ if (ctx.fs.exists(temporary)) ctx.fs.unlink(temporary);
46
+ }
47
+ }
48
+ export async function updateAccountSettings(ctx, update, afterWrite) {
49
+ const lockPath = `${globalConfigPath()}.lock`;
50
+ ctx.fs.mkdir(rootDirectory(), { allowExisting: true });
51
+ const deadline = Date.now() + 5e3;
52
+ for (; ; ) {
53
+ try {
54
+ ctx.fs.mkdir(lockPath);
55
+ break;
56
+ } catch (err) {
57
+ if (err.code !== "EEXIST") throw err;
58
+ if (Date.now() >= deadline) {
59
+ return await ctx.crash({
60
+ exitCode: 1,
61
+ errorType: "fatal",
62
+ printedMessage: `Another command is updating Convex accounts. Retry after it finishes. If it was interrupted, remove ${lockPath}.`
63
+ });
64
+ }
65
+ await new Promise((resolve) => setTimeout(resolve, 25));
66
+ }
67
+ }
68
+ let released = false;
69
+ const release = () => {
70
+ if (released) return;
71
+ ctx.fs.rmdir(lockPath);
72
+ released = true;
73
+ };
74
+ const cleanup = ctx.registerCleanup(async () => release());
75
+ try {
76
+ const settings = await readAccountSettings(ctx);
77
+ const result = await update(settings);
78
+ writeAccountSettings(ctx, settings);
79
+ afterWrite?.();
80
+ return result;
81
+ } finally {
82
+ ctx.removeCleanup(cleanup);
83
+ release();
84
+ }
85
+ }
86
+ export function accountConfigPath(name) {
87
+ return path.join(
88
+ rootDirectory(),
89
+ "accounts",
90
+ `${encodeURIComponent(name)}.json`
91
+ );
92
+ }
93
+ export async function validateAccountName(ctx, name) {
94
+ if (!/^[a-z0-9][a-z0-9_-]*$/.test(name)) {
95
+ await ctx.crash({
96
+ exitCode: 1,
97
+ errorType: "invalid filesystem or env vars",
98
+ printedMessage: "Account names must start with a lowercase letter or number and contain only lowercase letters, numbers, hyphens, and underscores."
99
+ });
100
+ }
101
+ }
102
+ export async function getAccountSelection(ctx, options = {}) {
103
+ let name = options.name;
104
+ let source = "--account";
105
+ if (name === void 0 && process.env[CONVEX_ACCOUNT_ENV_VAR] !== void 0) {
106
+ name = process.env[CONVEX_ACCOUNT_ENV_VAR];
107
+ source = `${CONVEX_ACCOUNT_ENV_VAR} environment variable`;
108
+ }
109
+ if (name === void 0) {
110
+ const files = options.envFile ? [options.envFile] : [ENV_VAR_FILE_PATH, ".env"];
111
+ for (const file of files) {
112
+ if (!ctx.fs.exists(file)) continue;
113
+ name = dotenv.parse(ctx.fs.readUtf8File(file))[CONVEX_ACCOUNT_ENV_VAR];
114
+ if (name !== void 0) {
115
+ source = `${CONVEX_ACCOUNT_ENV_VAR} in ${file}`;
116
+ break;
117
+ }
118
+ }
119
+ }
120
+ if (name === void 0) {
121
+ const config = await readAccountSettings(ctx);
122
+ const binding = findAccountDirectory(
123
+ config.directories ?? {},
124
+ process.cwd()
125
+ );
126
+ name = binding?.name ?? config.defaultAccount;
127
+ source = binding ? `directory selection for ${binding.directory}` : `default account in ${globalConfigPath()}`;
128
+ }
129
+ if (name === void 0) return null;
130
+ await validateAccountName(ctx, name);
131
+ return { name, source };
132
+ }
133
+ export async function readAccountAuth(ctx, account, allowMissing = false) {
134
+ const credentials = await readAccountCredentials(ctx, account, allowMissing);
135
+ return credentials === null ? null : {
136
+ kind: "accessToken",
137
+ accessToken: credentials.accessToken,
138
+ header: `Bearer ${credentials.accessToken}`,
139
+ account
140
+ };
141
+ }
142
+ export async function readAccountCredentials(ctx, account, allowMissing = false) {
143
+ await validateAccountName(ctx, account.name);
144
+ const configPath = accountConfigPath(account.name);
145
+ if (!ctx.fs.exists(configPath)) {
146
+ if (allowMissing) return null;
147
+ return await ctx.crash({
148
+ exitCode: 1,
149
+ errorType: "invalid filesystem data",
150
+ printedMessage: `Account "${account.name}" selected by ${account.source} is not logged in. Run \`npx convex login --account ${account.name}\`.`
151
+ });
152
+ }
153
+ try {
154
+ return credentialsSchema.parse(JSON.parse(ctx.fs.readUtf8File(configPath)));
155
+ } catch {
156
+ return await ctx.crash({
157
+ exitCode: 1,
158
+ errorType: "invalid filesystem data",
159
+ printedMessage: `Unable to read credentials for account "${account.name}" from ${configPath}.`
160
+ });
161
+ }
162
+ }
163
+ export function readAccountToken(ctx, name) {
164
+ try {
165
+ const token = JSON.parse(
166
+ ctx.fs.readUtf8File(accountConfigPath(name))
167
+ ).accessToken;
168
+ return typeof token === "string" && token.length > 0 ? token : null;
169
+ } catch {
170
+ return null;
171
+ }
172
+ }
173
+ async function writeCredentialsFile(ctx, name, credentials) {
174
+ const configPath = accountConfigPath(name);
175
+ const directory = path.dirname(configPath);
176
+ ctx.fs.mkdir(directory, { allowExisting: true });
177
+ for (const dir of [rootDirectory(), directory]) {
178
+ if (!ctx.fs.lstat(dir).isDirectory()) {
179
+ return await ctx.crash({
180
+ exitCode: 1,
181
+ errorType: "invalid filesystem data",
182
+ printedMessage: `Cannot save account credentials through a symlink or non-directory: ${dir}.`
183
+ });
184
+ }
185
+ }
186
+ const temporary = `${configPath}.${randomUUID()}.tmp`;
187
+ try {
188
+ ctx.fs.writeUtf8File(
189
+ temporary,
190
+ JSON.stringify(credentials, null, 2),
191
+ 384
192
+ );
193
+ ctx.fs.swapTmpFile(temporary, configPath);
194
+ } finally {
195
+ if (ctx.fs.exists(temporary)) ctx.fs.unlink(temporary);
196
+ }
197
+ }
198
+ export async function writeAccountCredentials(ctx, name, accessToken, metadata = {}, expected, onConflict) {
199
+ await validateAccountName(ctx, name);
200
+ await updateAccountSettings(ctx, async (settings) => {
201
+ if (expected !== void 0) {
202
+ const current = await readAccountCredentials(
203
+ ctx,
204
+ { name, source: "login" },
205
+ true
206
+ );
207
+ if (!isDeepStrictEqual(current, expected)) {
208
+ await onConflict?.();
209
+ return await ctx.crash({
210
+ exitCode: 1,
211
+ errorType: "fatal",
212
+ printedMessage: `Account "${name}" changed during login. Retry the login.`
213
+ });
214
+ }
215
+ }
216
+ await writeCredentialsFile(ctx, name, { ...metadata, accessToken });
217
+ if (settings.defaultAccount === name) settings.accessToken = accessToken;
218
+ });
219
+ }
220
+ export async function legacyAuthForFirstAccount(ctx, account) {
221
+ const settings = await readAccountSettings(ctx);
222
+ const accountsDir = path.dirname(accountConfigPath(account.name));
223
+ if (settings.defaultAccount !== void 0 || ctx.fs.exists(accountsDir) && ctx.fs.listDir(accountsDir).some((entry) => entry.name.endsWith(".json"))) {
224
+ return null;
225
+ }
226
+ const config = readGlobalConfig(ctx);
227
+ return config === null ? null : {
228
+ kind: "accessToken",
229
+ accessToken: config.accessToken,
230
+ header: `Bearer ${config.accessToken}`,
231
+ account
232
+ };
233
+ }
234
+ export async function initializeDefaultAccount(ctx, account, namingLegacyAccount, select = true) {
235
+ const defaultAccount = await updateAccountSettings(ctx, async (settings) => {
236
+ if (settings.defaultAccount !== void 0) return void 0;
237
+ const credentials = await readAccountCredentials(ctx, account);
238
+ const accessToken = credentials.accessToken;
239
+ const legacyToken = settings.accessToken;
240
+ if (!select && (savedAccountNames(ctx).some((name) => name !== account.name) || !namingLegacyAccount && typeof legacyToken === "string" && legacyToken.length > 0 && legacyToken !== accessToken))
241
+ return void 0;
242
+ if (!namingLegacyAccount && typeof legacyToken === "string" && legacyToken.length > 0 && legacyToken !== accessToken) {
243
+ let legacyName = "default";
244
+ for (let suffix = 2; ctx.fs.exists(accountConfigPath(legacyName)); suffix++) {
245
+ legacyName = `default-${suffix}`;
246
+ }
247
+ await writeCredentialsFile(ctx, legacyName, { accessToken: legacyToken });
248
+ settings.defaultAccount = legacyName;
249
+ } else {
250
+ settings.defaultAccount = account.name;
251
+ settings.accessToken = accessToken;
252
+ }
253
+ return settings.defaultAccount;
254
+ });
255
+ if (defaultAccount !== void 0)
256
+ logFinishedStep(`Default account: ${defaultAccount}`);
257
+ }
258
+ export function findAccountDirectory(directories, cwd) {
259
+ let directory = path.resolve(cwd);
260
+ for (; ; ) {
261
+ if (Object.hasOwn(directories, directory)) {
262
+ return { directory, name: directories[directory] };
263
+ }
264
+ const parent = path.dirname(directory);
265
+ if (parent === directory) return null;
266
+ directory = parent;
267
+ }
268
+ }
269
+ export function savedAccountNames(ctx) {
270
+ const directory = path.join(rootDirectory(), "accounts");
271
+ if (!ctx.fs.exists(directory)) return [];
272
+ return ctx.fs.listDir(directory).filter((entry) => entry.name.endsWith(".json")).map((entry) => entry.name.slice(0, -5)).sort();
273
+ }
274
+ export async function writeAccountDirectory(ctx, name) {
275
+ await validateAccountName(ctx, name);
276
+ await updateAccountSettings(ctx, (settings) => {
277
+ settings.directories = { ...settings.directories, [process.cwd()]: name };
278
+ });
279
+ logFinishedStep(
280
+ `Saved directory selection: ${name} (applies to this directory and its subdirectories).`
281
+ );
282
+ const selected = await getAccountSelection(ctx);
283
+ if (selected !== null && selected.name !== name) {
284
+ logWarning(
285
+ `Account "${selected.name}" selected by ${selected.source} overrides this directory selection. Remove that override to use account "${name}".`
286
+ );
287
+ }
288
+ }
289
+ //# sourceMappingURL=accounts.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/cli/lib/accounts.ts"],
4
+ "sourcesContent": ["import path from \"path\";\nimport { isDeepStrictEqual } from \"util\";\nimport { randomUUID } from \"crypto\";\nimport { TempPath } from \"../../bundler/fs.js\";\nimport * as dotenv from \"dotenv\";\nimport { z } from \"zod\";\nimport { BigBrainAuth, Context } from \"../../bundler/context.js\";\nimport { logFinishedStep, logWarning } from \"../../bundler/log.js\";\nimport { globalConfigPath, readGlobalConfig } from \"./utils/globalConfig.js\";\nimport { ENV_VAR_FILE_PATH, rootDirectory } from \"./utils/utils.js\";\n\nimport { CONVEX_ACCOUNT_ENV_VAR } from \"./envvars.js\";\n\nexport type AccountSelection = {\n name: string;\n source: string;\n};\n\nconst settingsSchema = z\n .object({\n defaultAccount: z.string().optional(),\n directories: z.record(z.string()).optional(),\n revokeReplacedTokens: z.boolean().optional(),\n })\n .passthrough();\n\nconst credentialsSchema = z\n .object({\n accessToken: z.string().min(1),\n memberId: z.string().optional(),\n email: z.string().optional(),\n })\n .passthrough();\n\nexport type AccountCredentials = z.infer<typeof credentialsSchema>;\n\nexport async function readAccountSettings(\n ctx: Context,\n): Promise<z.infer<typeof settingsSchema>> {\n if (!ctx.fs.exists(globalConfigPath())) return {};\n try {\n return settingsSchema.parse(\n JSON.parse(ctx.fs.readUtf8File(globalConfigPath())),\n );\n } catch {\n return await ctx.crash({\n exitCode: 1,\n errorType: \"invalid filesystem data\",\n printedMessage: `Unable to read account settings from ${globalConfigPath()}. Check defaultAccount, directories, and revokeReplacedTokens.`,\n });\n }\n}\n\nfunction writeAccountSettings(ctx: Context, settings: Record<string, unknown>) {\n if (Object.keys(settings).length === 0) {\n if (ctx.fs.exists(globalConfigPath())) ctx.fs.unlink(globalConfigPath());\n return;\n }\n const temporary = `${globalConfigPath()}.${randomUUID()}.tmp` as TempPath;\n try {\n ctx.fs.writeUtf8File(temporary, JSON.stringify(settings, null, 2), 0o600);\n ctx.fs.swapTmpFile(temporary, globalConfigPath());\n } finally {\n if (ctx.fs.exists(temporary)) ctx.fs.unlink(temporary);\n }\n}\n\nexport async function updateAccountSettings<T>(\n ctx: Context,\n update: (settings: z.infer<typeof settingsSchema>) => T | Promise<T>,\n afterWrite?: () => void,\n): Promise<T> {\n const lockPath = `${globalConfigPath()}.lock`;\n ctx.fs.mkdir(rootDirectory(), { allowExisting: true });\n const deadline = Date.now() + 5000;\n for (;;) {\n try {\n ctx.fs.mkdir(lockPath);\n break;\n } catch (err: any) {\n // Only the process that creates the directory owns the update lock.\n // eslint-disable-next-line no-restricted-syntax\n if (err.code !== \"EEXIST\") throw err;\n if (Date.now() >= deadline) {\n return await ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: `Another command is updating Convex accounts. Retry after it finishes. If it was interrupted, remove ${lockPath}.`,\n });\n }\n await new Promise((resolve) => setTimeout(resolve, 25));\n }\n }\n let released = false;\n const release = () => {\n if (released) return;\n ctx.fs.rmdir(lockPath);\n released = true;\n };\n const cleanup = ctx.registerCleanup(async () => release());\n try {\n const settings = await readAccountSettings(ctx);\n const result = await update(settings);\n writeAccountSettings(ctx, settings);\n // Credential deletion follows persistence while sharing the lock with renewals.\n afterWrite?.();\n return result;\n } finally {\n ctx.removeCleanup(cleanup);\n release();\n }\n}\n\nexport function accountConfigPath(name: string): string {\n return path.join(\n rootDirectory(),\n \"accounts\",\n `${encodeURIComponent(name)}.json`,\n );\n}\n\nexport async function validateAccountName(\n ctx: Context,\n name: string,\n): Promise<void> {\n if (!/^[a-z0-9][a-z0-9_-]*$/.test(name)) {\n await ctx.crash({\n exitCode: 1,\n errorType: \"invalid filesystem or env vars\",\n printedMessage:\n \"Account names must start with a lowercase letter or number and contain only lowercase letters, numbers, hyphens, and underscores.\",\n });\n }\n}\n\nexport async function getAccountSelection(\n ctx: Context,\n options: { name?: string | undefined; envFile?: string | undefined } = {},\n): Promise<AccountSelection | null> {\n let name = options.name;\n let source = \"--account\";\n if (name === undefined && process.env[CONVEX_ACCOUNT_ENV_VAR] !== undefined) {\n name = process.env[CONVEX_ACCOUNT_ENV_VAR];\n source = `${CONVEX_ACCOUNT_ENV_VAR} environment variable`;\n }\n if (name === undefined) {\n const files = options.envFile\n ? [options.envFile]\n : [ENV_VAR_FILE_PATH, \".env\"];\n for (const file of files) {\n if (!ctx.fs.exists(file)) continue;\n name = dotenv.parse(ctx.fs.readUtf8File(file))[CONVEX_ACCOUNT_ENV_VAR];\n if (name !== undefined) {\n source = `${CONVEX_ACCOUNT_ENV_VAR} in ${file}`;\n break;\n }\n }\n }\n if (name === undefined) {\n const config = await readAccountSettings(ctx);\n const binding = findAccountDirectory(\n config.directories ?? {},\n process.cwd(),\n );\n name = binding?.name ?? config.defaultAccount;\n source = binding\n ? `directory selection for ${binding.directory}`\n : `default account in ${globalConfigPath()}`;\n }\n if (name === undefined) return null;\n await validateAccountName(ctx, name);\n return { name, source };\n}\n\nexport async function readAccountAuth(\n ctx: Context,\n account: AccountSelection,\n allowMissing = false,\n): Promise<Extract<BigBrainAuth, { kind: \"accessToken\" }> | null> {\n const credentials = await readAccountCredentials(ctx, account, allowMissing);\n return credentials === null\n ? null\n : {\n kind: \"accessToken\",\n accessToken: credentials.accessToken,\n header: `Bearer ${credentials.accessToken}`,\n account,\n };\n}\n\nexport async function readAccountCredentials(\n ctx: Context,\n account: AccountSelection,\n allowMissing = false,\n): Promise<AccountCredentials | null> {\n await validateAccountName(ctx, account.name);\n const configPath = accountConfigPath(account.name);\n if (!ctx.fs.exists(configPath)) {\n if (allowMissing) return null;\n return await ctx.crash({\n exitCode: 1,\n errorType: \"invalid filesystem data\",\n printedMessage: `Account \"${account.name}\" selected by ${account.source} is not logged in. Run \\`npx convex login --account ${account.name}\\`.`,\n });\n }\n try {\n return credentialsSchema.parse(JSON.parse(ctx.fs.readUtf8File(configPath)));\n } catch {\n return await ctx.crash({\n exitCode: 1,\n errorType: \"invalid filesystem data\",\n printedMessage: `Unable to read credentials for account \"${account.name}\" from ${configPath}.`,\n });\n }\n}\n\nexport function readAccountToken(ctx: Context, name: string): string | null {\n try {\n const token = JSON.parse(\n ctx.fs.readUtf8File(accountConfigPath(name)),\n ).accessToken;\n return typeof token === \"string\" && token.length > 0 ? token : null;\n } catch {\n return null;\n }\n}\n\nasync function writeCredentialsFile(\n ctx: Context,\n name: string,\n credentials: AccountCredentials,\n) {\n const configPath = accountConfigPath(name);\n const directory = path.dirname(configPath);\n ctx.fs.mkdir(directory, { allowExisting: true });\n for (const dir of [rootDirectory(), directory]) {\n if (!ctx.fs.lstat(dir).isDirectory()) {\n return await ctx.crash({\n exitCode: 1,\n errorType: \"invalid filesystem data\",\n printedMessage: `Cannot save account credentials through a symlink or non-directory: ${dir}.`,\n });\n }\n }\n const temporary = `${configPath}.${randomUUID()}.tmp` as TempPath;\n try {\n ctx.fs.writeUtf8File(\n temporary,\n JSON.stringify(credentials, null, 2),\n 0o600,\n );\n ctx.fs.swapTmpFile(temporary, configPath);\n } finally {\n if (ctx.fs.exists(temporary)) ctx.fs.unlink(temporary);\n }\n}\n\nexport async function writeAccountCredentials(\n ctx: Context,\n name: string,\n accessToken: string,\n metadata: Omit<AccountCredentials, \"accessToken\"> = {},\n expected?: AccountCredentials | null,\n onConflict?: () => Promise<void>,\n): Promise<void> {\n await validateAccountName(ctx, name);\n await updateAccountSettings(ctx, async (settings) => {\n if (expected !== undefined) {\n const current = await readAccountCredentials(\n ctx,\n { name, source: \"login\" },\n true,\n );\n if (!isDeepStrictEqual(current, expected)) {\n await onConflict?.();\n return await ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: `Account \"${name}\" changed during login. Retry the login.`,\n });\n }\n }\n await writeCredentialsFile(ctx, name, { ...metadata, accessToken });\n if (settings.defaultAccount === name) settings.accessToken = accessToken;\n });\n}\n\nexport async function legacyAuthForFirstAccount(\n ctx: Context,\n account: AccountSelection,\n): Promise<Extract<BigBrainAuth, { kind: \"accessToken\" }> | null> {\n const settings = await readAccountSettings(ctx);\n const accountsDir = path.dirname(accountConfigPath(account.name));\n if (\n settings.defaultAccount !== undefined ||\n (ctx.fs.exists(accountsDir) &&\n ctx.fs.listDir(accountsDir).some((entry) => entry.name.endsWith(\".json\")))\n ) {\n return null;\n }\n const config = readGlobalConfig(ctx);\n return config === null\n ? null\n : {\n kind: \"accessToken\",\n accessToken: config.accessToken,\n header: `Bearer ${config.accessToken}`,\n account,\n };\n}\n\nexport async function initializeDefaultAccount(\n ctx: Context,\n account: AccountSelection,\n namingLegacyAccount: boolean,\n select = true,\n) {\n const defaultAccount = await updateAccountSettings(ctx, async (settings) => {\n if (settings.defaultAccount !== undefined) return undefined;\n const credentials = await readAccountCredentials(ctx, account);\n const accessToken = credentials!.accessToken;\n const legacyToken = settings.accessToken;\n if (\n !select &&\n (savedAccountNames(ctx).some((name) => name !== account.name) ||\n (!namingLegacyAccount &&\n typeof legacyToken === \"string\" &&\n legacyToken.length > 0 &&\n legacyToken !== accessToken))\n )\n return undefined;\n if (\n !namingLegacyAccount &&\n typeof legacyToken === \"string\" &&\n legacyToken.length > 0 &&\n legacyToken !== accessToken\n ) {\n // An explicitly new login keeps the previous account as the default for\n // directories that haven't selected an account.\n let legacyName = \"default\";\n for (\n let suffix = 2;\n ctx.fs.exists(accountConfigPath(legacyName));\n suffix++\n ) {\n legacyName = `default-${suffix}`;\n }\n await writeCredentialsFile(ctx, legacyName, { accessToken: legacyToken });\n settings.defaultAccount = legacyName;\n } else {\n settings.defaultAccount = account.name;\n settings.accessToken = accessToken;\n }\n\n return settings.defaultAccount;\n });\n if (defaultAccount !== undefined)\n logFinishedStep(`Default account: ${defaultAccount}`);\n}\n\nexport function findAccountDirectory(\n directories: Record<string, string>,\n cwd: string,\n): { directory: string; name: string } | null {\n let directory = path.resolve(cwd);\n for (;;) {\n if (Object.hasOwn(directories, directory)) {\n return { directory, name: directories[directory] };\n }\n const parent = path.dirname(directory);\n if (parent === directory) return null;\n directory = parent;\n }\n}\n\nexport function savedAccountNames(ctx: Context): string[] {\n const directory = path.join(rootDirectory(), \"accounts\");\n if (!ctx.fs.exists(directory)) return [];\n return ctx.fs\n .listDir(directory)\n .filter((entry) => entry.name.endsWith(\".json\"))\n .map((entry) => entry.name.slice(0, -5))\n .sort();\n}\n\nexport async function writeAccountDirectory(ctx: Context, name: string) {\n await validateAccountName(ctx, name);\n await updateAccountSettings(ctx, (settings) => {\n settings.directories = { ...settings.directories, [process.cwd()]: name };\n });\n logFinishedStep(\n `Saved directory selection: ${name} (applies to this directory and its subdirectories).`,\n );\n const selected = await getAccountSelection(ctx);\n if (selected !== null && selected.name !== name) {\n logWarning(\n `Account \"${selected.name}\" selected by ${selected.source} overrides this directory selection. Remove that override to use account \"${name}\".`,\n );\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ import { logWarning } from "../../bundler/log.js";
3
+ import {
4
+ deploymentNameFromAdminKey,
5
+ deploymentTypeFromAdminKey,
6
+ isDeploymentKey,
7
+ isPreviewDeployKey,
8
+ isProjectKey
9
+ } from "./deployment.js";
10
+ import { getDeployKeySource } from "./envvars.js";
11
+ import { IGNORED_DEPLOY_KEY, readDeployKeyFromEnv } from "./utils/utils.js";
12
+ const warnedContexts = /* @__PURE__ */ new WeakSet();
13
+ export function warnIfDeployKeyOverridesLogin(ctx, hasAccount) {
14
+ if (!hasAccount || warnedContexts.has(ctx) || process.env.CONVEX_OVERRIDE_ACCESS_TOKEN)
15
+ return;
16
+ const key = readDeployKeyFromEnv((name) => process.env[name]);
17
+ if (key === void 0 || key === IGNORED_DEPLOY_KEY || isPreviewDeployKey(key))
18
+ return;
19
+ const { envVarName, source } = getDeployKeySource(key);
20
+ const type = deploymentTypeFromAdminKey(key);
21
+ const target = isDeploymentKey(key) ? `${type === "prod" ? "production" : type} deployment "${deploymentNameFromAdminKey(key)}"` : isProjectKey(key) ? "the project selected by the key" : "the deployment selected by the key";
22
+ logWarning(
23
+ `WARNING: ${envVarName} in ${source} overrides your Convex account for deployment commands. They target ${target}. Remove ${envVarName} to use the selected account.`
24
+ );
25
+ warnedContexts.add(ctx);
26
+ }
27
+ //# sourceMappingURL=deployKeyWarning.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/cli/lib/deployKeyWarning.ts"],
4
+ "sourcesContent": ["import { Context } from \"../../bundler/context.js\";\nimport { logWarning } from \"../../bundler/log.js\";\nimport {\n deploymentNameFromAdminKey,\n deploymentTypeFromAdminKey,\n isDeploymentKey,\n isPreviewDeployKey,\n isProjectKey,\n} from \"./deployment.js\";\nimport { getDeployKeySource } from \"./envvars.js\";\nimport { IGNORED_DEPLOY_KEY, readDeployKeyFromEnv } from \"./utils/utils.js\";\n\nconst warnedContexts = new WeakSet<Context>();\n\nexport function warnIfDeployKeyOverridesLogin(\n ctx: Context,\n hasAccount: boolean,\n) {\n if (\n !hasAccount ||\n warnedContexts.has(ctx) ||\n process.env.CONVEX_OVERRIDE_ACCESS_TOKEN\n )\n return;\n const key = readDeployKeyFromEnv((name) => process.env[name]);\n if (\n key === undefined ||\n key === IGNORED_DEPLOY_KEY ||\n isPreviewDeployKey(key)\n )\n return;\n const { envVarName, source } = getDeployKeySource(key);\n const type = deploymentTypeFromAdminKey(key);\n const target = isDeploymentKey(key)\n ? `${type === \"prod\" ? \"production\" : type} deployment \"${deploymentNameFromAdminKey(key)}\"`\n : isProjectKey(key)\n ? \"the project selected by the key\"\n : \"the deployment selected by the key\";\n logWarning(\n `WARNING: ${envVarName} in ${source} overrides your Convex account for deployment commands. They target ${target}. Remove ${envVarName} to use the selected account.`,\n );\n warnedContexts.add(ctx);\n}\n"],
5
+ "mappings": ";AACA,SAAS,kBAAkB;AAC3B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,0BAA0B;AACnC,SAAS,oBAAoB,4BAA4B;AAEzD,MAAM,iBAAiB,oBAAI,QAAiB;AAErC,gBAAS,8BACd,KACA,YACA;AACA,MACE,CAAC,cACD,eAAe,IAAI,GAAG,KACtB,QAAQ,IAAI;AAEZ;AACF,QAAM,MAAM,qBAAqB,CAAC,SAAS,QAAQ,IAAI,IAAI,CAAC;AAC5D,MACE,QAAQ,UACR,QAAQ,sBACR,mBAAmB,GAAG;AAEtB;AACF,QAAM,EAAE,YAAY,OAAO,IAAI,mBAAmB,GAAG;AACrD,QAAM,OAAO,2BAA2B,GAAG;AAC3C,QAAM,SAAS,gBAAgB,GAAG,IAC9B,GAAG,SAAS,SAAS,eAAe,IAAI,gBAAgB,2BAA2B,GAAG,CAAC,MACvF,aAAa,GAAG,IACd,oCACA;AACN;AAAA,IACE,YAAY,UAAU,OAAO,MAAM,uEAAuE,MAAM,YAAY,UAAU;AAAA,EACxI;AACA,iBAAe,IAAI,GAAG;AACxB;",
6
+ "names": []
7
+ }
@@ -61,7 +61,7 @@ export async function eraseDeploymentEnvVar(ctx) {
61
61
  ctx.fs.writeUtf8File(ENV_VAR_FILE_PATH, changedFile);
62
62
  return true;
63
63
  }
64
- async function gitIgnoreEnvVarFile(ctx) {
64
+ export async function gitIgnoreEnvVarFile(ctx) {
65
65
  const gitIgnorePath = ".gitignore";
66
66
  const gitIgnoreContents = ctx.fs.exists(gitIgnorePath) ? ctx.fs.readUtf8File(gitIgnorePath) : "";
67
67
  const changedGitIgnore = changesToGitIgnore(gitIgnoreContents);
@@ -125,7 +125,7 @@ export async function deploymentNameFromAdminKeyOrCrash(ctx, adminKey) {
125
125
  }
126
126
  return deploymentName;
127
127
  }
128
- function deploymentNameFromAdminKey(adminKey) {
128
+ export function deploymentNameFromAdminKey(adminKey) {
129
129
  const parts = adminKey.split("|");
130
130
  if (parts.length === 1) {
131
131
  return null;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/cli/lib/deployment.ts"],
4
- "sourcesContent": ["import * as dotenv from \"dotenv\";\nimport { Context } from \"../../bundler/context.js\";\nimport { changedEnvVarFile, getEnvVarRegex } from \"./envvars.js\";\nimport {\n CONVEX_DEPLOY_KEY_ENV_VAR_NAME,\n CONVEX_DEPLOYMENT_ENV_VAR_NAME,\n ENV_VAR_FILE_PATH,\n} from \"./utils/utils.js\";\nimport { DeploymentType } from \"./api.js\";\n\n// Given a deployment string like \"dev:tall-forest-1234\"\n// returns only the slug \"tall-forest-1234\".\n// If there's no prefix returns the original string.\nexport function stripDeploymentTypePrefix(deployment: string) {\n return deployment.split(\":\").at(-1)!;\n}\n\n// Handling legacy CONVEX_DEPLOYMENT without type prefix as well\nexport function getDeploymentTypeFromConfiguredDeployment(raw: string) {\n const typeRaw = raw.split(\":\")[0];\n const type =\n typeRaw === \"prod\" ||\n typeRaw === \"dev\" ||\n typeRaw === \"preview\" ||\n typeRaw === \"local\"\n ? typeRaw\n : null;\n return type;\n}\n\nexport function isAnonymousDeployment(deploymentName: string) {\n return deploymentName.startsWith(\"anonymous-\");\n}\n\nexport function removeAnonymousPrefix(deploymentName: string) {\n if (isAnonymousDeployment(deploymentName)) {\n return deploymentName.slice(\"anonymous-\".length);\n }\n return deploymentName;\n}\n\nexport async function writeDeploymentEnvVar(\n ctx: Context,\n deploymentType: DeploymentType,\n deployment: {\n team: string | null;\n project: string | null;\n deploymentName: string;\n },\n existingValue: string | null,\n): Promise<{ wroteToGitIgnore: boolean; changedDeploymentEnvVar: boolean }> {\n const existingFile = ctx.fs.exists(ENV_VAR_FILE_PATH)\n ? ctx.fs.readUtf8File(ENV_VAR_FILE_PATH)\n : null;\n const changedFile = changesToEnvVarFile(\n existingFile,\n deploymentType,\n deployment,\n );\n const deploymentEnvVarValue =\n deploymentType + \":\" + deployment.deploymentName;\n // The `existingValue` that reaches this function is at least sometimes is missing its prefix.\n // Until this is cleaned up consider either of these values not a change.\n // Otherwise we spam the init instructions (Welcome to Convex etc.) on every run of `npx convex dev`.\n const changedDeploymentEnvVar =\n !!changedFile &&\n existingValue !== deployment.deploymentName &&\n existingValue !== deploymentEnvVarValue;\n\n if (changedFile !== null) {\n ctx.fs.writeUtf8File(ENV_VAR_FILE_PATH, changedFile);\n // Only do this if we're not reinitializing an existing setup\n return {\n wroteToGitIgnore: await gitIgnoreEnvVarFile(ctx),\n changedDeploymentEnvVar,\n };\n }\n return {\n wroteToGitIgnore: false,\n changedDeploymentEnvVar,\n };\n}\n\n// Only used in the internal --url flow\nexport async function eraseDeploymentEnvVar(ctx: Context): Promise<boolean> {\n const existingFile = ctx.fs.exists(ENV_VAR_FILE_PATH)\n ? ctx.fs.readUtf8File(ENV_VAR_FILE_PATH)\n : null;\n if (existingFile === null) {\n return false;\n }\n const config = dotenv.parse(existingFile);\n const existing = config[CONVEX_DEPLOYMENT_ENV_VAR_NAME];\n if (existing === undefined) {\n return false;\n }\n const changedFile = existingFile.replace(\n getEnvVarRegex(CONVEX_DEPLOYMENT_ENV_VAR_NAME),\n \"\",\n );\n ctx.fs.writeUtf8File(ENV_VAR_FILE_PATH, changedFile);\n return true;\n}\n\nasync function gitIgnoreEnvVarFile(ctx: Context): Promise<boolean> {\n const gitIgnorePath = \".gitignore\";\n const gitIgnoreContents = ctx.fs.exists(gitIgnorePath)\n ? ctx.fs.readUtf8File(gitIgnorePath)\n : \"\";\n const changedGitIgnore = changesToGitIgnore(gitIgnoreContents);\n if (changedGitIgnore !== null) {\n ctx.fs.writeUtf8File(gitIgnorePath, changedGitIgnore);\n return true;\n }\n return false;\n}\n\n// exported for tests\nexport function changesToEnvVarFile(\n existingFile: string | null,\n deploymentType: DeploymentType,\n {\n team,\n project,\n deploymentName,\n }: { team: string | null; project: string | null; deploymentName: string },\n): string | null {\n const deploymentValue = deploymentType + \":\" + deploymentName;\n const commentOnPreviousLine = \"# Deployment used by `npx convex dev`\";\n const commentAfterValue =\n team !== null && project !== null\n ? `team: ${team}, project: ${project}`\n : null;\n return changedEnvVarFile({\n existingFileContent: existingFile,\n envVarName: CONVEX_DEPLOYMENT_ENV_VAR_NAME,\n envVarValue: deploymentValue,\n commentAfterValue,\n commentOnPreviousLine,\n });\n}\n\n// exported for tests\nexport function changesToGitIgnore(existingFile: string | null): string | null {\n if (existingFile === null) {\n return `${ENV_VAR_FILE_PATH}\\n`;\n }\n const gitIgnoreLines = existingFile.split(\"\\n\");\n const envVarFileIgnored = gitIgnoreLines.some((line) => {\n if (line.startsWith(\"#\")) return false;\n if (line.startsWith(\"!\")) return false;\n\n // .gitignore ignores trailing whitespace, and also we need to remove\n // the trailing `\\r` from Windows-style newline since we split on `\\n`.\n const trimmedLine = line.trimEnd();\n\n const envIgnorePatterns = [\n /^\\.env\\.local$/,\n /^\\.env\\.\\*$/,\n /^\\.env\\*$/,\n /^.*\\.local$/,\n /^\\.env\\*\\.local$/,\n ];\n\n return envIgnorePatterns.some((pattern) => pattern.test(trimmedLine));\n });\n if (!envVarFileIgnored) {\n return `${existingFile}\\n${ENV_VAR_FILE_PATH}\\n`;\n } else {\n return null;\n }\n}\n\nexport async function deploymentNameFromAdminKeyOrCrash(\n ctx: Context,\n adminKey: string,\n) {\n const deploymentName = deploymentNameFromAdminKey(adminKey);\n if (deploymentName === null) {\n return await ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: `Please set ${CONVEX_DEPLOY_KEY_ENV_VAR_NAME} to a new key which you can find on your Convex dashboard.`,\n });\n }\n return deploymentName;\n}\n\nfunction deploymentNameFromAdminKey(adminKey: string) {\n const parts = adminKey.split(\"|\");\n if (parts.length === 1) {\n return null;\n }\n if (isPreviewDeployKey(adminKey)) {\n // Preview deploy keys do not contain a deployment name.\n return null;\n }\n return stripDeploymentTypePrefix(parts[0]);\n}\n\n// Needed to differentiate a preview deploy key\n// from a concrete preview deployment's deploy key.\n// preview deploy key: `preview:team:project|key`\n// preview deployment's deploy key: `preview:deploymentName|key`\nexport function isPreviewDeployKey(adminKey: string) {\n const parts = adminKey.split(\"|\");\n if (parts.length === 1) {\n return false;\n }\n const [prefix] = parts;\n const prefixParts = prefix.split(\":\");\n return prefixParts[0] === \"preview\" && prefixParts.length === 3;\n}\n\nexport function isProjectKey(adminKey: string) {\n return /^project:.*\\|/.test(adminKey);\n}\n\n// \"dev deploy keys\" and \"prod deploy keys\" are deployment keys.\n// On the client these are also known as admin keys.\nexport function isDeploymentKey(adminKey: string) {\n return /^(dev|prod):.*\\|/.test(adminKey);\n}\n\n// For current keys returns prod|dev|preview,\n// for legacy keys returns \"prod\".\n// Examples:\n// \"prod:deploymentName|key\" -> \"prod\"\n// \"preview:deploymentName|key\" -> \"preview\"\n// \"dev:deploymentName|key\" -> \"dev\"\n// \"custom:deploymentName|key\" -> \"custom\"\n// \"key\" -> \"prod\"\nexport function deploymentTypeFromAdminKey(adminKey: string) {\n const parts = adminKey.split(\":\");\n if (parts.length === 1) {\n return \"prod\";\n }\n return parts.at(0)! as DeploymentType;\n}\n\nexport async function getTeamAndProjectFromPreviewAdminKey(\n ctx: Context,\n adminKey: string,\n) {\n const parts = adminKey.split(\"|\")[0].split(\":\");\n if (parts.length !== 3) {\n return await ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage:\n \"Malformed preview CONVEX_DEPLOY_KEY, get a new key from Project Settings.\",\n });\n }\n const [_preview, teamSlug, projectSlug] = parts;\n return { teamSlug, projectSlug };\n}\n\nexport type CleanupDeploymentFunc = () => Promise<void>;\nexport type DeploymentDetails = {\n deploymentName: string;\n deploymentUrl: string;\n adminKey: string;\n reference: string | null;\n isDefault: boolean;\n};\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import * as dotenv from \"dotenv\";\nimport { Context } from \"../../bundler/context.js\";\nimport { changedEnvVarFile, getEnvVarRegex } from \"./envvars.js\";\nimport {\n CONVEX_DEPLOY_KEY_ENV_VAR_NAME,\n CONVEX_DEPLOYMENT_ENV_VAR_NAME,\n ENV_VAR_FILE_PATH,\n} from \"./utils/utils.js\";\nimport { DeploymentType } from \"./api.js\";\n\n// Given a deployment string like \"dev:tall-forest-1234\"\n// returns only the slug \"tall-forest-1234\".\n// If there's no prefix returns the original string.\nexport function stripDeploymentTypePrefix(deployment: string) {\n return deployment.split(\":\").at(-1)!;\n}\n\n// Handling legacy CONVEX_DEPLOYMENT without type prefix as well\nexport function getDeploymentTypeFromConfiguredDeployment(raw: string) {\n const typeRaw = raw.split(\":\")[0];\n const type =\n typeRaw === \"prod\" ||\n typeRaw === \"dev\" ||\n typeRaw === \"preview\" ||\n typeRaw === \"local\"\n ? typeRaw\n : null;\n return type;\n}\n\nexport function isAnonymousDeployment(deploymentName: string) {\n return deploymentName.startsWith(\"anonymous-\");\n}\n\nexport function removeAnonymousPrefix(deploymentName: string) {\n if (isAnonymousDeployment(deploymentName)) {\n return deploymentName.slice(\"anonymous-\".length);\n }\n return deploymentName;\n}\n\nexport async function writeDeploymentEnvVar(\n ctx: Context,\n deploymentType: DeploymentType,\n deployment: {\n team: string | null;\n project: string | null;\n deploymentName: string;\n },\n existingValue: string | null,\n): Promise<{ wroteToGitIgnore: boolean; changedDeploymentEnvVar: boolean }> {\n const existingFile = ctx.fs.exists(ENV_VAR_FILE_PATH)\n ? ctx.fs.readUtf8File(ENV_VAR_FILE_PATH)\n : null;\n const changedFile = changesToEnvVarFile(\n existingFile,\n deploymentType,\n deployment,\n );\n const deploymentEnvVarValue =\n deploymentType + \":\" + deployment.deploymentName;\n // The `existingValue` that reaches this function is at least sometimes is missing its prefix.\n // Until this is cleaned up consider either of these values not a change.\n // Otherwise we spam the init instructions (Welcome to Convex etc.) on every run of `npx convex dev`.\n const changedDeploymentEnvVar =\n !!changedFile &&\n existingValue !== deployment.deploymentName &&\n existingValue !== deploymentEnvVarValue;\n\n if (changedFile !== null) {\n ctx.fs.writeUtf8File(ENV_VAR_FILE_PATH, changedFile);\n // Only do this if we're not reinitializing an existing setup\n return {\n wroteToGitIgnore: await gitIgnoreEnvVarFile(ctx),\n changedDeploymentEnvVar,\n };\n }\n return {\n wroteToGitIgnore: false,\n changedDeploymentEnvVar,\n };\n}\n\n// Only used in the internal --url flow\nexport async function eraseDeploymentEnvVar(ctx: Context): Promise<boolean> {\n const existingFile = ctx.fs.exists(ENV_VAR_FILE_PATH)\n ? ctx.fs.readUtf8File(ENV_VAR_FILE_PATH)\n : null;\n if (existingFile === null) {\n return false;\n }\n const config = dotenv.parse(existingFile);\n const existing = config[CONVEX_DEPLOYMENT_ENV_VAR_NAME];\n if (existing === undefined) {\n return false;\n }\n const changedFile = existingFile.replace(\n getEnvVarRegex(CONVEX_DEPLOYMENT_ENV_VAR_NAME),\n \"\",\n );\n ctx.fs.writeUtf8File(ENV_VAR_FILE_PATH, changedFile);\n return true;\n}\n\nexport async function gitIgnoreEnvVarFile(ctx: Context): Promise<boolean> {\n const gitIgnorePath = \".gitignore\";\n const gitIgnoreContents = ctx.fs.exists(gitIgnorePath)\n ? ctx.fs.readUtf8File(gitIgnorePath)\n : \"\";\n const changedGitIgnore = changesToGitIgnore(gitIgnoreContents);\n if (changedGitIgnore !== null) {\n ctx.fs.writeUtf8File(gitIgnorePath, changedGitIgnore);\n return true;\n }\n return false;\n}\n\n// exported for tests\nexport function changesToEnvVarFile(\n existingFile: string | null,\n deploymentType: DeploymentType,\n {\n team,\n project,\n deploymentName,\n }: { team: string | null; project: string | null; deploymentName: string },\n): string | null {\n const deploymentValue = deploymentType + \":\" + deploymentName;\n const commentOnPreviousLine = \"# Deployment used by `npx convex dev`\";\n const commentAfterValue =\n team !== null && project !== null\n ? `team: ${team}, project: ${project}`\n : null;\n return changedEnvVarFile({\n existingFileContent: existingFile,\n envVarName: CONVEX_DEPLOYMENT_ENV_VAR_NAME,\n envVarValue: deploymentValue,\n commentAfterValue,\n commentOnPreviousLine,\n });\n}\n\n// exported for tests\nexport function changesToGitIgnore(existingFile: string | null): string | null {\n if (existingFile === null) {\n return `${ENV_VAR_FILE_PATH}\\n`;\n }\n const gitIgnoreLines = existingFile.split(\"\\n\");\n const envVarFileIgnored = gitIgnoreLines.some((line) => {\n if (line.startsWith(\"#\")) return false;\n if (line.startsWith(\"!\")) return false;\n\n // .gitignore ignores trailing whitespace, and also we need to remove\n // the trailing `\\r` from Windows-style newline since we split on `\\n`.\n const trimmedLine = line.trimEnd();\n\n const envIgnorePatterns = [\n /^\\.env\\.local$/,\n /^\\.env\\.\\*$/,\n /^\\.env\\*$/,\n /^.*\\.local$/,\n /^\\.env\\*\\.local$/,\n ];\n\n return envIgnorePatterns.some((pattern) => pattern.test(trimmedLine));\n });\n if (!envVarFileIgnored) {\n return `${existingFile}\\n${ENV_VAR_FILE_PATH}\\n`;\n } else {\n return null;\n }\n}\n\nexport async function deploymentNameFromAdminKeyOrCrash(\n ctx: Context,\n adminKey: string,\n) {\n const deploymentName = deploymentNameFromAdminKey(adminKey);\n if (deploymentName === null) {\n return await ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage: `Please set ${CONVEX_DEPLOY_KEY_ENV_VAR_NAME} to a new key which you can find on your Convex dashboard.`,\n });\n }\n return deploymentName;\n}\n\nexport function deploymentNameFromAdminKey(adminKey: string) {\n const parts = adminKey.split(\"|\");\n if (parts.length === 1) {\n return null;\n }\n if (isPreviewDeployKey(adminKey)) {\n // Preview deploy keys do not contain a deployment name.\n return null;\n }\n return stripDeploymentTypePrefix(parts[0]);\n}\n\n// Needed to differentiate a preview deploy key\n// from a concrete preview deployment's deploy key.\n// preview deploy key: `preview:team:project|key`\n// preview deployment's deploy key: `preview:deploymentName|key`\nexport function isPreviewDeployKey(adminKey: string) {\n const parts = adminKey.split(\"|\");\n if (parts.length === 1) {\n return false;\n }\n const [prefix] = parts;\n const prefixParts = prefix.split(\":\");\n return prefixParts[0] === \"preview\" && prefixParts.length === 3;\n}\n\nexport function isProjectKey(adminKey: string) {\n return /^project:.*\\|/.test(adminKey);\n}\n\n// \"dev deploy keys\" and \"prod deploy keys\" are deployment keys.\n// On the client these are also known as admin keys.\nexport function isDeploymentKey(adminKey: string) {\n return /^(dev|prod):.*\\|/.test(adminKey);\n}\n\n// For current keys returns prod|dev|preview,\n// for legacy keys returns \"prod\".\n// Examples:\n// \"prod:deploymentName|key\" -> \"prod\"\n// \"preview:deploymentName|key\" -> \"preview\"\n// \"dev:deploymentName|key\" -> \"dev\"\n// \"custom:deploymentName|key\" -> \"custom\"\n// \"key\" -> \"prod\"\nexport function deploymentTypeFromAdminKey(adminKey: string) {\n const parts = adminKey.split(\":\");\n if (parts.length === 1) {\n return \"prod\";\n }\n return parts.at(0)! as DeploymentType;\n}\n\nexport async function getTeamAndProjectFromPreviewAdminKey(\n ctx: Context,\n adminKey: string,\n) {\n const parts = adminKey.split(\"|\")[0].split(\":\");\n if (parts.length !== 3) {\n return await ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n printedMessage:\n \"Malformed preview CONVEX_DEPLOY_KEY, get a new key from Project Settings.\",\n });\n }\n const [_preview, teamSlug, projectSlug] = parts;\n return { teamSlug, projectSlug };\n}\n\nexport type CleanupDeploymentFunc = () => Promise<void>;\nexport type DeploymentDetails = {\n deploymentName: string;\n deploymentUrl: string;\n adminKey: string;\n reference: string | null;\n isDefault: boolean;\n};\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -25,28 +25,36 @@ import {
25
25
  targetProjectForLocalSelector
26
26
  } from "./localDeployment/projectMismatch.js";
27
27
  import { chalkStderr } from "chalk";
28
- import { getBuildEnvironment } from "./envvars.js";
28
+ import {
29
+ getBuildEnvironment,
30
+ loadProjectEnvironmentVariables
31
+ } from "./envvars.js";
29
32
  import { readGlobalConfig } from "./utils/globalConfig.js";
33
+ import {
34
+ getAccountSelection,
35
+ readAccountAuth
36
+ } from "./accounts.js";
30
37
  import {
31
38
  CONVEX_DEPLOYMENT_ENV_VAR_NAME,
32
39
  CONVEX_DEPLOYMENT_TOKEN_ENV_VAR_NAME,
33
40
  CONVEX_DEPLOY_KEY_ENV_VAR_NAME,
34
41
  CONVEX_SELF_HOSTED_ADMIN_KEY_VAR_NAME,
35
42
  CONVEX_SELF_HOSTED_URL_VAR_NAME,
36
- ENV_VAR_FILE_PATH,
37
43
  bigBrainAPI,
38
44
  processDeployKeyValue,
39
45
  readDeployKeyFromEnv,
46
+ readDeployKeyEnvVar,
40
47
  typedPlatformClient
41
48
  } from "./utils/utils.js";
42
49
  import * as dotenv from "dotenv";
43
50
  export async function initializeBigBrainAuth(ctx, initialArgs) {
44
51
  if (initialArgs.url !== void 0 && initialArgs.adminKey !== void 0) {
45
52
  ctx._updateBigBrainAuth(
46
- getBigBrainAuth(ctx, {
53
+ await getBigBrainAuth(ctx, {
47
54
  previewDeployKey: null,
48
55
  projectKey: null,
49
- deploymentKey: null
56
+ deploymentKey: null,
57
+ skipAccount: true
50
58
  })
51
59
  );
52
60
  return;
@@ -64,29 +72,30 @@ export async function initializeBigBrainAuth(ctx, initialArgs) {
64
72
  const rawDeployKey2 = readDeployKeyFromEnv((name) => config[name]);
65
73
  const deployKey2 = await processDeployKeyValue(ctx, rawDeployKey2);
66
74
  if (deployKey2 !== void 0) {
67
- const bigBrainAuth = getBigBrainAuth(ctx, {
75
+ const bigBrainAuth = await getBigBrainAuth(ctx, {
68
76
  previewDeployKey: isPreviewDeployKey(deployKey2) ? deployKey2 : null,
69
77
  projectKey: isProjectKey(deployKey2) ? deployKey2 : null,
70
- deploymentKey: isDeploymentKey(deployKey2) ? deployKey2 : null
78
+ deploymentKey: isDeploymentKey(deployKey2) ? deployKey2 : null,
79
+ envFile: initialArgs.envFile
71
80
  });
72
81
  ctx._updateBigBrainAuth(bigBrainAuth);
73
82
  return;
74
83
  }
75
84
  ctx._updateBigBrainAuth(
76
- getBigBrainAuth(ctx, {
85
+ await getBigBrainAuth(ctx, {
77
86
  previewDeployKey: null,
78
87
  projectKey: null,
79
- deploymentKey: null
88
+ deploymentKey: null,
89
+ envFile: initialArgs.envFile
80
90
  })
81
91
  );
82
92
  return;
83
93
  }
84
- dotenv.config({ path: ENV_VAR_FILE_PATH });
85
- dotenv.config();
94
+ loadProjectEnvironmentVariables();
86
95
  const rawDeployKey = readDeployKeyFromEnv((name) => process.env[name]);
87
96
  const deployKey = await processDeployKeyValue(ctx, rawDeployKey);
88
97
  if (deployKey !== void 0) {
89
- const bigBrainAuth = getBigBrainAuth(ctx, {
98
+ const bigBrainAuth = await getBigBrainAuth(ctx, {
90
99
  previewDeployKey: isPreviewDeployKey(deployKey) ? deployKey : null,
91
100
  projectKey: isProjectKey(deployKey) ? deployKey : null,
92
101
  deploymentKey: isDeploymentKey(deployKey) ? deployKey : null
@@ -95,7 +104,7 @@ export async function initializeBigBrainAuth(ctx, initialArgs) {
95
104
  return;
96
105
  }
97
106
  ctx._updateBigBrainAuth(
98
- getBigBrainAuth(ctx, {
107
+ await getBigBrainAuth(ctx, {
99
108
  previewDeployKey: null,
100
109
  projectKey: null,
101
110
  deploymentKey: null
@@ -103,7 +112,7 @@ export async function initializeBigBrainAuth(ctx, initialArgs) {
103
112
  );
104
113
  return;
105
114
  }
106
- export async function updateBigBrainAuthAfterLogin(ctx, accessToken) {
115
+ export async function updateBigBrainAuthAfterLogin(ctx, accessToken, account) {
107
116
  const existingAuth = ctx.bigBrainAuth();
108
117
  if (existingAuth !== null && existingAuth.kind === "projectKey") {
109
118
  logVerbose(
@@ -114,18 +123,20 @@ export async function updateBigBrainAuthAfterLogin(ctx, accessToken) {
114
123
  ctx._updateBigBrainAuth({
115
124
  accessToken,
116
125
  kind: "accessToken",
117
- header: `Bearer ${accessToken}`
126
+ header: `Bearer ${accessToken}`,
127
+ ...account ? { account } : {}
118
128
  });
119
129
  }
120
130
  export async function clearBigBrainAuth(ctx) {
121
131
  ctx._updateBigBrainAuth(null);
122
132
  }
123
- function getBigBrainAuth(ctx, opts) {
133
+ async function getBigBrainAuth(ctx, opts) {
124
134
  if (process.env.CONVEX_OVERRIDE_ACCESS_TOKEN) {
125
135
  return {
126
136
  accessToken: process.env.CONVEX_OVERRIDE_ACCESS_TOKEN,
127
137
  kind: "accessToken",
128
- header: `Bearer ${process.env.CONVEX_OVERRIDE_ACCESS_TOKEN}`
138
+ header: `Bearer ${process.env.CONVEX_OVERRIDE_ACCESS_TOKEN}`,
139
+ account: null
129
140
  };
130
141
  }
131
142
  if (opts.projectKey !== null) {
@@ -142,12 +153,17 @@ function getBigBrainAuth(ctx, opts) {
142
153
  deploymentKey: opts.deploymentKey
143
154
  };
144
155
  }
156
+ const account = opts.skipAccount ? null : await getAccountSelection(ctx, { envFile: opts.envFile });
157
+ if (account !== null) {
158
+ return await readAccountAuth(ctx, account);
159
+ }
145
160
  const globalConfig = readGlobalConfig(ctx);
146
161
  if (globalConfig) {
147
162
  return {
148
163
  kind: "accessToken",
149
164
  header: `Bearer ${globalConfig.accessToken}`,
150
- accessToken: globalConfig.accessToken
165
+ accessToken: globalConfig.accessToken,
166
+ account: null
151
167
  };
152
168
  }
153
169
  if (opts.previewDeployKey !== null) {
@@ -187,7 +203,7 @@ export async function ensureAuthCanCreateDeployment(ctx) {
187
203
  )} and try again.`
188
204
  });
189
205
  }
190
- const envVar = process.env[CONVEX_DEPLOY_KEY_ENV_VAR_NAME] ? CONVEX_DEPLOY_KEY_ENV_VAR_NAME : CONVEX_DEPLOYMENT_TOKEN_ENV_VAR_NAME;
206
+ const envVar = readDeployKeyEnvVar((name) => process.env[name])?.name ?? CONVEX_DEPLOY_KEY_ENV_VAR_NAME;
191
207
  return await ctx.crash({
192
208
  exitCode: 1,
193
209
  errorType: "fatal",
@@ -357,8 +373,7 @@ async function resolveBaseDeploymentSelection(ctx, cliArgs, selectionWithinProje
357
373
  }
358
374
  return result2.metadata;
359
375
  }
360
- dotenv.config({ path: ENV_VAR_FILE_PATH });
361
- dotenv.config();
376
+ loadProjectEnvironmentVariables();
362
377
  const result = await getDeploymentSelectionFromEnv(
363
378
  ctx,
364
379
  selectionWithinProject,