convex 1.42.2 → 1.43.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 (276) hide show
  1. package/CHANGELOG.md +8 -1
  2. package/bin/main-dev +6 -1
  3. package/dist/browser.bundle.js +49 -10
  4. package/dist/browser.bundle.js.map +2 -2
  5. package/dist/cjs/browser/index.js.map +2 -2
  6. package/dist/cjs/browser/simple_client-node.js +35 -35
  7. package/dist/cjs/browser/simple_client-node.js.map +2 -2
  8. package/dist/cjs/browser/sync/client.js.map +1 -1
  9. package/dist/cjs/browser/sync/paginated_query_client.js +20 -9
  10. package/dist/cjs/browser/sync/paginated_query_client.js.map +2 -2
  11. package/dist/cjs/cli/codegen_templates/component_api.js +2 -2
  12. package/dist/cjs/cli/codegen_templates/component_api.js.map +2 -2
  13. package/dist/cjs/cli/codegen_templates/validator_helpers.js +2 -0
  14. package/dist/cjs/cli/codegen_templates/validator_helpers.js.map +2 -2
  15. package/dist/cjs/cli/deployment.js +2 -1
  16. package/dist/cjs/cli/deployment.js.map +2 -2
  17. package/dist/cjs/cli/deploymentCreate.js.map +2 -2
  18. package/dist/cjs/cli/generatedApi.js.map +1 -1
  19. package/dist/cjs/cli/lib/deployApi/validator.js +1 -0
  20. package/dist/cjs/cli/lib/deployApi/validator.js.map +2 -2
  21. package/dist/cjs/cli/lib/deploymentSelection.js.map +2 -2
  22. package/dist/cjs/cli/lib/generateDocs.js +1 -1
  23. package/dist/cjs/cli/lib/generateDocs.js.map +2 -2
  24. package/dist/cjs/cli/lib/generatedFunctionLogsApi.js.map +1 -1
  25. package/dist/cjs/cli/lib/localDeployment/projectMismatch.js.map +2 -2
  26. package/dist/cjs/cli/lib/login.js +23 -23
  27. package/dist/cjs/cli/lib/login.js.map +2 -2
  28. package/dist/cjs/cli/lib/typecheck.js +28 -25
  29. package/dist/cjs/cli/lib/typecheck.js.map +2 -2
  30. package/dist/cjs/cli/lib/usageLimits.js +164 -0
  31. package/dist/cjs/cli/lib/usageLimits.js.map +7 -0
  32. package/dist/cjs/cli/usageLimits.js +326 -0
  33. package/dist/cjs/cli/usageLimits.js.map +7 -0
  34. package/dist/cjs/index.js +1 -1
  35. package/dist/cjs/index.js.map +1 -1
  36. package/dist/cjs/react/client.js.map +2 -2
  37. package/dist/cjs/server/components/index.js.map +2 -2
  38. package/dist/cjs/server/cron.js +33 -29
  39. package/dist/cjs/server/cron.js.map +2 -2
  40. package/dist/cjs/server/database.js.map +1 -1
  41. package/dist/cjs/server/impl/database_impl.js +3 -0
  42. package/dist/cjs/server/impl/database_impl.js.map +2 -2
  43. package/dist/cjs/server/log.js +2 -1
  44. package/dist/cjs/server/log.js.map +2 -2
  45. package/dist/cjs/server/logVars.js +12 -1
  46. package/dist/cjs/server/logVars.js.map +2 -2
  47. package/dist/cjs/server/meta.js.map +1 -1
  48. package/dist/cjs/values/compare.js +5 -1
  49. package/dist/cjs/values/compare.js.map +2 -2
  50. package/dist/cjs/values/index.js +1 -0
  51. package/dist/cjs/values/index.js.map +2 -2
  52. package/dist/cjs/values/size.js +4 -0
  53. package/dist/cjs/values/size.js.map +2 -2
  54. package/dist/cjs/values/validator.js +11 -0
  55. package/dist/cjs/values/validator.js.map +2 -2
  56. package/dist/cjs/values/validators.js +20 -0
  57. package/dist/cjs/values/validators.js.map +2 -2
  58. package/dist/cjs/values/value.js +31 -0
  59. package/dist/cjs/values/value.js.map +2 -2
  60. package/dist/cjs-types/browser/index.d.ts.map +1 -1
  61. package/dist/cjs-types/browser/sync/paginated_query_client.d.ts +1 -38
  62. package/dist/cjs-types/browser/sync/paginated_query_client.d.ts.map +1 -1
  63. package/dist/cjs-types/cli/codegen_templates/component_api.d.ts.map +1 -1
  64. package/dist/cjs-types/cli/codegen_templates/validator_helpers.d.ts.map +1 -1
  65. package/dist/cjs-types/cli/codegen_templates/validator_helpers.test.d.ts +2 -0
  66. package/dist/cjs-types/cli/codegen_templates/validator_helpers.test.d.ts.map +1 -0
  67. package/dist/cjs-types/cli/deployment.d.ts.map +1 -1
  68. package/dist/cjs-types/cli/deploymentCreate.d.ts +2 -2
  69. package/dist/cjs-types/cli/generatedApi.d.ts +43 -43
  70. package/dist/cjs-types/cli/generatedApi.d.ts.map +1 -1
  71. package/dist/cjs-types/cli/lib/deployApi/validator.d.ts +6 -0
  72. package/dist/cjs-types/cli/lib/deployApi/validator.d.ts.map +1 -1
  73. package/dist/cjs-types/cli/lib/deploymentSelection.d.ts +2 -2
  74. package/dist/cjs-types/cli/lib/deploymentSelection.d.ts.map +1 -1
  75. package/dist/cjs-types/cli/lib/generatedFunctionLogsApi.d.ts +45 -45
  76. package/dist/cjs-types/cli/lib/generatedFunctionLogsApi.d.ts.map +1 -1
  77. package/dist/cjs-types/cli/lib/localDeployment/projectMismatch.d.ts +2 -2
  78. package/dist/cjs-types/cli/lib/localDeployment/projectMismatch.d.ts.map +1 -1
  79. package/dist/cjs-types/cli/lib/login.d.ts.map +1 -1
  80. package/dist/cjs-types/cli/lib/mcp/tools/insights.d.ts +24 -24
  81. package/dist/cjs-types/cli/lib/typecheck.d.ts +2 -0
  82. package/dist/cjs-types/cli/lib/typecheck.d.ts.map +1 -1
  83. package/dist/cjs-types/cli/lib/typecheck.test.d.ts +2 -0
  84. package/dist/cjs-types/cli/lib/typecheck.test.d.ts.map +1 -0
  85. package/dist/cjs-types/cli/lib/usageLimits.d.ts +46 -0
  86. package/dist/cjs-types/cli/lib/usageLimits.d.ts.map +1 -0
  87. package/dist/cjs-types/cli/usageLimits.d.ts +22 -0
  88. package/dist/cjs-types/cli/usageLimits.d.ts.map +1 -0
  89. package/dist/cjs-types/index.d.ts +1 -1
  90. package/dist/cjs-types/index.d.ts.map +1 -1
  91. package/dist/cjs-types/react/client.d.ts.map +1 -1
  92. package/dist/cjs-types/server/components/index.d.ts +26 -8
  93. package/dist/cjs-types/server/components/index.d.ts.map +1 -1
  94. package/dist/cjs-types/server/cron.d.ts +20 -11
  95. package/dist/cjs-types/server/cron.d.ts.map +1 -1
  96. package/dist/cjs-types/server/cron.test.d.ts +2 -0
  97. package/dist/cjs-types/server/cron.test.d.ts.map +1 -0
  98. package/dist/cjs-types/server/database.d.ts.map +1 -1
  99. package/dist/cjs-types/server/impl/database_impl.d.ts.map +1 -1
  100. package/dist/cjs-types/server/log.d.ts.map +1 -1
  101. package/dist/cjs-types/server/logVars.d.ts +14 -1
  102. package/dist/cjs-types/server/logVars.d.ts.map +1 -1
  103. package/dist/cjs-types/server/meta.d.ts +2 -2
  104. package/dist/cjs-types/server/meta.d.ts.map +1 -1
  105. package/dist/cjs-types/values/compare.d.ts.map +1 -1
  106. package/dist/cjs-types/values/index.d.ts +2 -2
  107. package/dist/cjs-types/values/index.d.ts.map +1 -1
  108. package/dist/cjs-types/values/size.d.ts +1 -1
  109. package/dist/cjs-types/values/size.d.ts.map +1 -1
  110. package/dist/cjs-types/values/validator.d.ts +10 -1
  111. package/dist/cjs-types/values/validator.d.ts.map +1 -1
  112. package/dist/cjs-types/values/validators.d.ts +14 -3
  113. package/dist/cjs-types/values/validators.d.ts.map +1 -1
  114. package/dist/cjs-types/values/value.d.ts +18 -1
  115. package/dist/cjs-types/values/value.d.ts.map +1 -1
  116. package/dist/cli.bundle.cjs +2327 -1866
  117. package/dist/cli.bundle.cjs.map +4 -4
  118. package/dist/esm/browser/index.js.map +2 -2
  119. package/dist/esm/browser/simple_client-node.js +35 -35
  120. package/dist/esm/browser/simple_client-node.js.map +1 -1
  121. package/dist/esm/browser/sync/client.js.map +1 -1
  122. package/dist/esm/browser/sync/paginated_query_client.js +20 -9
  123. package/dist/esm/browser/sync/paginated_query_client.js.map +2 -2
  124. package/dist/esm/cli/codegen_templates/component_api.js +8 -3
  125. package/dist/esm/cli/codegen_templates/component_api.js.map +2 -2
  126. package/dist/esm/cli/codegen_templates/validator_helpers.js +2 -0
  127. package/dist/esm/cli/codegen_templates/validator_helpers.js.map +2 -2
  128. package/dist/esm/cli/deployment.js +2 -1
  129. package/dist/esm/cli/deployment.js.map +2 -2
  130. package/dist/esm/cli/deploymentCreate.js.map +2 -2
  131. package/dist/esm/cli/lib/deployApi/validator.js +1 -0
  132. package/dist/esm/cli/lib/deployApi/validator.js.map +2 -2
  133. package/dist/esm/cli/lib/deploymentSelection.js.map +2 -2
  134. package/dist/esm/cli/lib/generateDocs.js +1 -1
  135. package/dist/esm/cli/lib/generateDocs.js.map +2 -2
  136. package/dist/esm/cli/lib/localDeployment/projectMismatch.js.map +2 -2
  137. package/dist/esm/cli/lib/login.js +23 -23
  138. package/dist/esm/cli/lib/login.js.map +2 -2
  139. package/dist/esm/cli/lib/typecheck.js +27 -25
  140. package/dist/esm/cli/lib/typecheck.js.map +2 -2
  141. package/dist/esm/cli/lib/usageLimits.js +129 -0
  142. package/dist/esm/cli/lib/usageLimits.js.map +7 -0
  143. package/dist/esm/cli/usageLimits.js +316 -0
  144. package/dist/esm/cli/usageLimits.js.map +7 -0
  145. package/dist/esm/index.js +1 -1
  146. package/dist/esm/index.js.map +1 -1
  147. package/dist/esm/react/client.js.map +2 -2
  148. package/dist/esm/server/components/index.js.map +2 -2
  149. package/dist/esm/server/cron.js +33 -29
  150. package/dist/esm/server/cron.js.map +2 -2
  151. package/dist/esm/server/impl/database_impl.js +4 -1
  152. package/dist/esm/server/impl/database_impl.js.map +2 -2
  153. package/dist/esm/server/log.js +3 -2
  154. package/dist/esm/server/log.js.map +2 -2
  155. package/dist/esm/server/logVars.js +11 -1
  156. package/dist/esm/server/logVars.js.map +2 -2
  157. package/dist/esm/values/compare.js +5 -1
  158. package/dist/esm/values/compare.js.map +2 -2
  159. package/dist/esm/values/index.js +1 -1
  160. package/dist/esm/values/index.js.map +2 -2
  161. package/dist/esm/values/size.js +4 -0
  162. package/dist/esm/values/size.js.map +2 -2
  163. package/dist/esm/values/validator.js +12 -0
  164. package/dist/esm/values/validator.js.map +2 -2
  165. package/dist/esm/values/validators.js +19 -0
  166. package/dist/esm/values/validators.js.map +2 -2
  167. package/dist/esm/values/value.js +29 -1
  168. package/dist/esm/values/value.js.map +2 -2
  169. package/dist/esm-types/browser/index.d.ts.map +1 -1
  170. package/dist/esm-types/browser/sync/paginated_query_client.d.ts +1 -38
  171. package/dist/esm-types/browser/sync/paginated_query_client.d.ts.map +1 -1
  172. package/dist/esm-types/cli/codegen_templates/component_api.d.ts.map +1 -1
  173. package/dist/esm-types/cli/codegen_templates/validator_helpers.d.ts.map +1 -1
  174. package/dist/esm-types/cli/codegen_templates/validator_helpers.test.d.ts +2 -0
  175. package/dist/esm-types/cli/codegen_templates/validator_helpers.test.d.ts.map +1 -0
  176. package/dist/esm-types/cli/deployment.d.ts.map +1 -1
  177. package/dist/esm-types/cli/deploymentCreate.d.ts +2 -2
  178. package/dist/esm-types/cli/generatedApi.d.ts +43 -43
  179. package/dist/esm-types/cli/generatedApi.d.ts.map +1 -1
  180. package/dist/esm-types/cli/lib/deployApi/validator.d.ts +6 -0
  181. package/dist/esm-types/cli/lib/deployApi/validator.d.ts.map +1 -1
  182. package/dist/esm-types/cli/lib/deploymentSelection.d.ts +2 -2
  183. package/dist/esm-types/cli/lib/deploymentSelection.d.ts.map +1 -1
  184. package/dist/esm-types/cli/lib/generatedFunctionLogsApi.d.ts +45 -45
  185. package/dist/esm-types/cli/lib/generatedFunctionLogsApi.d.ts.map +1 -1
  186. package/dist/esm-types/cli/lib/localDeployment/projectMismatch.d.ts +2 -2
  187. package/dist/esm-types/cli/lib/localDeployment/projectMismatch.d.ts.map +1 -1
  188. package/dist/esm-types/cli/lib/login.d.ts.map +1 -1
  189. package/dist/esm-types/cli/lib/mcp/tools/insights.d.ts +24 -24
  190. package/dist/esm-types/cli/lib/typecheck.d.ts +2 -0
  191. package/dist/esm-types/cli/lib/typecheck.d.ts.map +1 -1
  192. package/dist/esm-types/cli/lib/typecheck.test.d.ts +2 -0
  193. package/dist/esm-types/cli/lib/typecheck.test.d.ts.map +1 -0
  194. package/dist/esm-types/cli/lib/usageLimits.d.ts +46 -0
  195. package/dist/esm-types/cli/lib/usageLimits.d.ts.map +1 -0
  196. package/dist/esm-types/cli/usageLimits.d.ts +22 -0
  197. package/dist/esm-types/cli/usageLimits.d.ts.map +1 -0
  198. package/dist/esm-types/index.d.ts +1 -1
  199. package/dist/esm-types/index.d.ts.map +1 -1
  200. package/dist/esm-types/react/client.d.ts.map +1 -1
  201. package/dist/esm-types/server/components/index.d.ts +26 -8
  202. package/dist/esm-types/server/components/index.d.ts.map +1 -1
  203. package/dist/esm-types/server/cron.d.ts +20 -11
  204. package/dist/esm-types/server/cron.d.ts.map +1 -1
  205. package/dist/esm-types/server/cron.test.d.ts +2 -0
  206. package/dist/esm-types/server/cron.test.d.ts.map +1 -0
  207. package/dist/esm-types/server/database.d.ts.map +1 -1
  208. package/dist/esm-types/server/impl/database_impl.d.ts.map +1 -1
  209. package/dist/esm-types/server/log.d.ts.map +1 -1
  210. package/dist/esm-types/server/logVars.d.ts +14 -1
  211. package/dist/esm-types/server/logVars.d.ts.map +1 -1
  212. package/dist/esm-types/server/meta.d.ts +2 -2
  213. package/dist/esm-types/server/meta.d.ts.map +1 -1
  214. package/dist/esm-types/values/compare.d.ts.map +1 -1
  215. package/dist/esm-types/values/index.d.ts +2 -2
  216. package/dist/esm-types/values/index.d.ts.map +1 -1
  217. package/dist/esm-types/values/size.d.ts +1 -1
  218. package/dist/esm-types/values/size.d.ts.map +1 -1
  219. package/dist/esm-types/values/validator.d.ts +10 -1
  220. package/dist/esm-types/values/validator.d.ts.map +1 -1
  221. package/dist/esm-types/values/validators.d.ts +14 -3
  222. package/dist/esm-types/values/validators.d.ts.map +1 -1
  223. package/dist/esm-types/values/value.d.ts +18 -1
  224. package/dist/esm-types/values/value.d.ts.map +1 -1
  225. package/dist/react.bundle.js +53 -11
  226. package/dist/react.bundle.js.map +2 -2
  227. package/package.json +8 -8
  228. package/schemas/convex.schema.json +2 -1
  229. package/src/browser/index.ts +2 -0
  230. package/src/browser/sync/client.test.ts +8 -1
  231. package/src/browser/sync/client.ts +63 -0
  232. package/src/browser/sync/paginated_query_client.test.ts +209 -1
  233. package/src/browser/sync/paginated_query_client.ts +29 -11
  234. package/src/cli/codegen_templates/component_api.ts +8 -3
  235. package/src/cli/codegen_templates/validator_helpers.test.ts +31 -0
  236. package/src/cli/codegen_templates/validator_helpers.ts +6 -0
  237. package/src/cli/deployment.ts +4 -1
  238. package/src/cli/deploymentCreate.test.ts +2 -2
  239. package/src/cli/deploymentCreate.ts +2 -2
  240. package/src/cli/generatedApi.ts +43 -43
  241. package/src/cli/lib/deployApi/validator.ts +1 -0
  242. package/src/cli/lib/deploymentSelection.ts +2 -2
  243. package/src/cli/lib/generateDocs.test.ts +1 -1
  244. package/src/cli/lib/generateDocs.ts +3 -3
  245. package/src/cli/lib/generatedFunctionLogsApi.ts +45 -45
  246. package/src/cli/lib/localDeployment/projectMismatch.ts +2 -2
  247. package/src/cli/lib/login.ts +33 -30
  248. package/src/cli/lib/typecheck.test.ts +71 -0
  249. package/src/cli/lib/typecheck.ts +33 -27
  250. package/src/cli/lib/usageLimits.ts +242 -0
  251. package/src/cli/usageLimits.ts +420 -0
  252. package/src/index.ts +1 -1
  253. package/src/react/ConvexAuthState.test.tsx +24 -8
  254. package/src/react/auth_websocket.test.tsx +39 -29
  255. package/src/react/client.ts +3 -2
  256. package/src/react/client_provided_base_client.test.tsx +154 -36
  257. package/src/server/audit_logging.test.ts +2 -0
  258. package/src/server/components/index.test.ts +33 -1
  259. package/src/server/components/index.ts +41 -14
  260. package/src/server/cron.test.ts +58 -0
  261. package/src/server/cron.ts +82 -21
  262. package/src/server/database.ts +17 -0
  263. package/src/server/impl/database_impl.ts +4 -1
  264. package/src/server/log.ts +4 -1
  265. package/src/server/logVars.ts +17 -1
  266. package/src/server/meta.ts +2 -2
  267. package/src/server/schema.test.ts +6 -1
  268. package/src/values/compare.ts +5 -2
  269. package/src/values/index.ts +2 -1
  270. package/src/values/size.test.ts +5 -0
  271. package/src/values/size.ts +5 -1
  272. package/src/values/validator.test.ts +16 -1
  273. package/src/values/validator.ts +13 -0
  274. package/src/values/validators.ts +29 -1
  275. package/src/values/value.test.ts +35 -0
  276. package/src/values/value.ts +56 -1
@@ -14,6 +14,7 @@ import * as semver from "semver";
14
14
  import { formatDuration, spawnAsync } from "./utils/utils.js";
15
15
  import { readProjectConfig } from "./config.js";
16
16
  import { WatchContext } from "./watch.js";
17
+ import { Filesystem } from "../../bundler/fs.js";
17
18
 
18
19
  export type TypecheckResult = "cantTypeCheck" | "success" | "typecheckFailed";
19
20
 
@@ -139,33 +140,7 @@ async function runTsc(
139
140
  tscArgs: string[],
140
141
  handleResult: TypecheckResultHandler,
141
142
  ): Promise<void> {
142
- // Check if the TypeScript compiler is even installed
143
- let compilerPath: string | undefined;
144
- switch (typescriptCompiler) {
145
- case "tsgo": {
146
- // @typescript/native-preview@7.0.0-dev.20260626.1 switched to using `bin/tsgo` instead of `bin/tsgo.js`.
147
- const tsgoPaths = ["tsgo", "tsgo.js"].map((filename) =>
148
- path.join(
149
- "node_modules",
150
- "@typescript",
151
- "native-preview",
152
- "bin",
153
- filename,
154
- ),
155
- );
156
- compilerPath = tsgoPaths.find((path) => ctx.fs.exists(path));
157
- break;
158
- }
159
- case "tsc": {
160
- const tscPath = path.join("node_modules", "typescript", "bin", "tsc");
161
- if (ctx.fs.exists(tscPath)) {
162
- compilerPath = tscPath;
163
- }
164
- break;
165
- }
166
- default:
167
- typescriptCompiler satisfies never;
168
- }
143
+ const compilerPath = findTypeScriptCompilerPath(ctx.fs, typescriptCompiler);
169
144
  if (!compilerPath) {
170
145
  return handleResult("cantTypeCheck", () => {
171
146
  logError(
@@ -197,6 +172,37 @@ async function runTsc(
197
172
  }
198
173
  }
199
174
 
175
+ export function findTypeScriptCompilerPath(
176
+ fs: Pick<Filesystem, "exists">,
177
+ typescriptCompiler: TypescriptCompiler,
178
+ ): string | undefined {
179
+ switch (typescriptCompiler) {
180
+ case "tsgo": {
181
+ // @typescript/native-preview@7.0.0-dev.20260626.1 switched to using `bin/tsgo` instead of `bin/tsgo.js`.
182
+ const tsgoPaths = ["tsgo", "tsgo.js"].map((filename) =>
183
+ path.join(
184
+ "node_modules",
185
+ "@typescript",
186
+ "native-preview",
187
+ "bin",
188
+ filename,
189
+ ),
190
+ );
191
+ return tsgoPaths.find((path) => fs.exists(path));
192
+ }
193
+ case "tsc": {
194
+ const tscPaths = [
195
+ // TypeScript 7's recommended alias when the TypeScript 6 API is also installed.
196
+ path.join("node_modules", "@typescript", "native", "bin", "tsc"),
197
+ path.join("node_modules", "typescript", "bin", "tsc"),
198
+ ];
199
+ return tscPaths.find((path) => fs.exists(path));
200
+ }
201
+ default:
202
+ typescriptCompiler satisfies never;
203
+ }
204
+ }
205
+
200
206
  async function runTscInner(
201
207
  ctx: Context,
202
208
  tscPath: string,
@@ -0,0 +1,242 @@
1
+ import type {
2
+ GetCurrentUsageResponse,
3
+ UsageLimitConfigRequest,
4
+ UsageLimitConfigResponse,
5
+ UsageLimitMetric,
6
+ } from "@convex-dev/platform/deploymentApi";
7
+ import { Context } from "../../bundler/context.js";
8
+ import { deploymentFetch, logAndHandleFetchError } from "./utils/utils.js";
9
+
10
+ export type UsageLimitDeployment = {
11
+ deploymentUrl: string;
12
+ adminKey: string;
13
+ };
14
+
15
+ export const USAGE_LIMIT_METRICS = [
16
+ "functionCalls",
17
+ "queryMutationComputeGbHours",
18
+ "actionComputeConvexGbHours",
19
+ "actionComputeNodeJsGbHours",
20
+ "actionComputeCpuGbHours",
21
+ "databaseIoGb",
22
+ "searchQueryGb",
23
+ "dataEgressGb",
24
+ ] as const satisfies readonly UsageLimitMetric[];
25
+
26
+ // Fails to compile if the backend's `UsageLimitMetric` gains a metric not listed
27
+ // above, so the CLI's `--metric` choices and ordering stay complete.
28
+ type MissingMetric = Exclude<
29
+ UsageLimitMetric,
30
+ (typeof USAGE_LIMIT_METRICS)[number]
31
+ >;
32
+ const _metricsExhaustive: [MissingMetric] extends [never] ? true : never = true;
33
+ void _metricsExhaustive;
34
+
35
+ export const USAGE_LIMIT_WINDOWS = ["day", "month"] as const;
36
+ export type UsageLimitWindow = (typeof USAGE_LIMIT_WINDOWS)[number];
37
+
38
+ export const USAGE_LIMIT_TYPES = ["warning", "disable"] as const;
39
+ export type UsageLimitType = (typeof USAGE_LIMIT_TYPES)[number];
40
+
41
+ export const METRIC_LABELS: Record<UsageLimitMetric, string> = {
42
+ functionCalls: "Function calls",
43
+ queryMutationComputeGbHours: "Query/Mutation compute",
44
+ actionComputeConvexGbHours: "Action compute",
45
+ actionComputeNodeJsGbHours: "Action compute (Node.js)",
46
+ actionComputeCpuGbHours: "Action compute (CPU)",
47
+ databaseIoGb: "Database I/O",
48
+ searchQueryGb: "Search queries",
49
+ dataEgressGb: "Data egress",
50
+ };
51
+
52
+ export function metricLabel(metric: string): string {
53
+ // Look up permissively: a newer backend may report a metric this CLI's label
54
+ // map doesn't know, in which case fall back to the raw id.
55
+ return (METRIC_LABELS as Record<string, string>)[metric] ?? metric;
56
+ }
57
+
58
+ async function usageLimitFetch(
59
+ ctx: Context,
60
+ deployment: UsageLimitDeployment,
61
+ path: string,
62
+ init?: { method?: string; body?: unknown },
63
+ ): Promise<unknown> {
64
+ const fetch = deploymentFetch(ctx, deployment);
65
+ try {
66
+ const response = await fetch(`/api/v1${path}`, {
67
+ method: init?.method ?? "GET",
68
+ ...(init?.body !== undefined ? { body: JSON.stringify(init.body) } : {}),
69
+ });
70
+ const text = await response.text();
71
+ return text.length > 0 ? JSON.parse(text) : undefined;
72
+ } catch (e) {
73
+ return await logAndHandleFetchError(ctx, e);
74
+ }
75
+ }
76
+
77
+ export async function listUsageLimits(
78
+ ctx: Context,
79
+ deployment: UsageLimitDeployment,
80
+ ): Promise<UsageLimitConfigResponse[]> {
81
+ const result = (await usageLimitFetch(
82
+ ctx,
83
+ deployment,
84
+ "/list_usage_limits",
85
+ )) as {
86
+ usageLimits: UsageLimitConfigResponse[];
87
+ };
88
+ return result.usageLimits;
89
+ }
90
+
91
+ export async function createUsageLimit(
92
+ ctx: Context,
93
+ deployment: UsageLimitDeployment,
94
+ config: UsageLimitConfigRequest,
95
+ ): Promise<UsageLimitConfigResponse> {
96
+ const result = (await usageLimitFetch(
97
+ ctx,
98
+ deployment,
99
+ "/create_usage_limit",
100
+ {
101
+ method: "POST",
102
+ body: config,
103
+ },
104
+ )) as { usageLimit: UsageLimitConfigResponse };
105
+ return result.usageLimit;
106
+ }
107
+
108
+ export async function updateUsageLimit(
109
+ ctx: Context,
110
+ deployment: UsageLimitDeployment,
111
+ id: string,
112
+ config: UsageLimitConfigRequest,
113
+ ): Promise<UsageLimitConfigResponse> {
114
+ const result = (await usageLimitFetch(
115
+ ctx,
116
+ deployment,
117
+ `/update_usage_limit/${id}`,
118
+ { method: "POST", body: config },
119
+ )) as { usageLimit: UsageLimitConfigResponse };
120
+ return result.usageLimit;
121
+ }
122
+
123
+ export async function deleteUsageLimit(
124
+ ctx: Context,
125
+ deployment: UsageLimitDeployment,
126
+ id: string,
127
+ ): Promise<void> {
128
+ await usageLimitFetch(ctx, deployment, `/delete_usage_limit/${id}`, {
129
+ method: "POST",
130
+ });
131
+ }
132
+
133
+ export async function getCurrentUsage(
134
+ ctx: Context,
135
+ deployment: UsageLimitDeployment,
136
+ ): Promise<GetCurrentUsageResponse> {
137
+ return (await usageLimitFetch(
138
+ ctx,
139
+ deployment,
140
+ "/get_current_usage",
141
+ )) as GetCurrentUsageResponse;
142
+ }
143
+
144
+ function metricRank(metric: string): number {
145
+ const i = (USAGE_LIMIT_METRICS as readonly string[]).indexOf(metric);
146
+ // Unknown metrics (e.g. a newer backend adds one) sort last, stably.
147
+ return i === -1 ? USAGE_LIMIT_METRICS.length : i;
148
+ }
149
+
150
+ // Windows coarsest-first and warning-before-disable,.
151
+ const windowRank = (w: string) => (w === "month" ? 0 : 1);
152
+ const typeRank = (t: string) => (t === "warning" ? 0 : 1);
153
+
154
+ export function compareUsageLimits(
155
+ a: { metric: string; window: string; limitType: string },
156
+ b: { metric: string; window: string; limitType: string },
157
+ ): number {
158
+ return (
159
+ metricRank(a.metric) - metricRank(b.metric) ||
160
+ windowRank(a.window) - windowRank(b.window) ||
161
+ typeRank(a.limitType) - typeRank(b.limitType)
162
+ );
163
+ }
164
+
165
+ export function compareMetricNames(a: string, b: string): number {
166
+ return metricRank(a) - metricRank(b);
167
+ }
168
+
169
+ // A limit annotated with the current usage in its window and whether it's
170
+ // currently triggered.
171
+ export type UsageLimitStatus = UsageLimitConfigResponse & {
172
+ currentUsage: number | null;
173
+ unit: string | null;
174
+ triggered: boolean;
175
+ };
176
+
177
+ function usageInWindow(
178
+ usage: GetCurrentUsageResponse,
179
+ metric: string,
180
+ window: string,
181
+ ): number | null {
182
+ const m = usage.metrics[metric];
183
+ if (m === undefined) {
184
+ return null;
185
+ }
186
+ return window === "day" ? m.usage.current_day : m.usage.current_month;
187
+ }
188
+
189
+ // List usage limits annotated with current usage and triggered state, sorted in
190
+ // dashboard order. Fetches the limits and current usage together.
191
+ export async function listUsageLimitsWithStatus(
192
+ ctx: Context,
193
+ deployment: UsageLimitDeployment,
194
+ ): Promise<{
195
+ limits: UsageLimitStatus[];
196
+ seedStatus: GetCurrentUsageResponse["seedStatus"];
197
+ }> {
198
+ const [limits, usage] = await Promise.all([
199
+ listUsageLimits(ctx, deployment),
200
+ getCurrentUsage(ctx, deployment),
201
+ ]);
202
+ const withStatus = limits
203
+ .map((limit): UsageLimitStatus => {
204
+ const currentUsage = usageInWindow(usage, limit.metric, limit.window);
205
+ const unit = usage.metrics[limit.metric]?.unit ?? null;
206
+ const triggered =
207
+ limit.enabled && currentUsage !== null && currentUsage >= limit.limit;
208
+ return { ...limit, currentUsage, unit, triggered };
209
+ })
210
+ .sort(compareUsageLimits);
211
+ return { limits: withStatus, seedStatus: usage.seedStatus };
212
+ }
213
+
214
+ // A usage limit is uniquely identified by (metric, window, limitType) — the
215
+ // same key the backend enforces uniqueness on. The HTTP API addresses limits by
216
+ // document id, so callers who know the natural key list and resolve it here.
217
+ export type UsageLimitKey = {
218
+ metric: UsageLimitMetric;
219
+ window: string;
220
+ limitType: string;
221
+ };
222
+
223
+ export async function findUsageLimitByKey(
224
+ ctx: Context,
225
+ deployment: UsageLimitDeployment & { deploymentNotice: string },
226
+ key: UsageLimitKey,
227
+ ): Promise<UsageLimitConfigResponse> {
228
+ const match = (await listUsageLimits(ctx, deployment)).find(
229
+ (limit) =>
230
+ limit.metric === key.metric &&
231
+ limit.window === key.window &&
232
+ limit.limitType === key.limitType,
233
+ );
234
+ if (match === undefined) {
235
+ return ctx.crash({
236
+ exitCode: 1,
237
+ errorType: "fatal",
238
+ printedMessage: `error: No ${key.limitType} usage limit on ${key.metric} per ${key.window}${deployment.deploymentNotice}.`,
239
+ });
240
+ }
241
+ return match;
242
+ }