convex 1.45.0 → 1.46.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +48 -6
- package/dist/browser.bundle.js +1 -1
- package/dist/browser.bundle.js.map +2 -2
- package/dist/cjs/browser/http_client.js.map +2 -2
- package/dist/cjs/browser/query_options.js.map +2 -2
- package/dist/cjs/browser/simple_client.js.map +2 -2
- package/dist/cjs/browser/sync/optimistic_updates.js.map +1 -1
- package/dist/cjs/browser/sync/optimistic_updates_impl.js.map +2 -2
- package/dist/cjs/cli/codegen.js +2 -0
- package/dist/cjs/cli/codegen.js.map +2 -2
- package/dist/cjs/cli/deploy.js +1 -0
- package/dist/cjs/cli/deploy.js.map +2 -2
- package/dist/cjs/cli/docs.js +3 -36
- package/dist/cjs/cli/docs.js.map +2 -2
- package/dist/cjs/cli/lib/checkForLargeIndexDeletion.js +101 -60
- package/dist/cjs/cli/lib/checkForLargeIndexDeletion.js.map +2 -2
- package/dist/cjs/cli/lib/checkForSlowSchemaValidation.js +107 -0
- package/dist/cjs/cli/lib/checkForSlowSchemaValidation.js.map +7 -0
- package/dist/cjs/cli/lib/codegen.js.map +2 -2
- package/dist/cjs/cli/lib/components.js +12 -0
- package/dist/cjs/cli/lib/components.js.map +2 -2
- package/dist/cjs/cli/lib/deploy2.js +29 -2
- package/dist/cjs/cli/lib/deploy2.js.map +2 -2
- package/dist/cjs/cli/lib/deployApi/evaluateSchema.js +73 -0
- package/dist/cjs/cli/lib/deployApi/evaluateSchema.js.map +7 -0
- package/dist/cjs/cli/lib/deployApi/finishPush.js +1 -0
- package/dist/cjs/cli/lib/deployApi/finishPush.js.map +2 -2
- package/dist/cjs/cli/lib/deployApi/startPush.js +1 -1
- package/dist/cjs/cli/lib/deployApi/startPush.js.map +2 -2
- package/dist/cjs/cli/lib/dev.js +1 -0
- package/dist/cjs/cli/lib/dev.js.map +2 -2
- package/dist/cjs/cli/lib/generatedFunctionLogsApi.js.map +1 -1
- package/dist/cjs/cli/lib/localDeployment/run.js +30 -1
- package/dist/cjs/cli/lib/localDeployment/run.js.map +2 -2
- package/dist/cjs/cli/lib/localDeployment/upgrade.js +6 -5
- package/dist/cjs/cli/lib/localDeployment/upgrade.js.map +2 -2
- package/dist/cjs/cli/lib/localDeployment/utils.js +5 -1
- package/dist/cjs/cli/lib/localDeployment/utils.js.map +2 -2
- package/dist/cjs/cli/lib/run.js +1 -0
- package/dist/cjs/cli/lib/run.js.map +2 -2
- package/dist/cjs/cli/lib/utils/utils.js +36 -29
- package/dist/cjs/cli/lib/utils/utils.js.map +2 -2
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/nextjs/index.js.map +2 -2
- package/dist/cjs/react/client.js.map +2 -2
- package/dist/cjs/react/hydration.js.map +2 -2
- package/dist/cjs/react/queries_observer.js.map +2 -2
- package/dist/cjs/react/use_paginated_query2.js.map +2 -2
- package/dist/cjs/react/use_queries.js.map +2 -2
- package/dist/cjs/server/api.js.map +2 -2
- package/dist/cjs/server/components/index.js.map +2 -2
- package/dist/cjs/server/cron.js +10 -10
- package/dist/cjs/server/cron.js.map +2 -2
- package/dist/cjs/server/impl/actions_impl.js.map +2 -2
- package/dist/cjs/server/impl/meta_impl.js +8 -2
- package/dist/cjs/server/impl/meta_impl.js.map +2 -2
- package/dist/cjs/server/impl/scheduler_impl.js.map +2 -2
- package/dist/cjs/server/index.js.map +2 -2
- package/dist/cjs/server/meta.js.map +1 -1
- package/dist/cjs/server/registration.js.map +1 -1
- package/dist/cjs/server/scheduler.js.map +1 -1
- package/dist/cjs/server/schema.js +50 -3
- package/dist/cjs/server/schema.js.map +2 -2
- package/dist/cjs/values/validator.js +1 -1
- package/dist/cjs/values/validator.js.map +2 -2
- package/dist/cjs/values/validators.js +81 -25
- package/dist/cjs/values/validators.js.map +2 -2
- package/dist/cjs-types/browser/http_client.d.ts +5 -5
- package/dist/cjs-types/browser/http_client.d.ts.map +1 -1
- package/dist/cjs-types/browser/query_options.d.ts +2 -2
- package/dist/cjs-types/browser/query_options.d.ts.map +1 -1
- package/dist/cjs-types/browser/simple_client.d.ts +6 -6
- package/dist/cjs-types/browser/simple_client.d.ts.map +1 -1
- package/dist/cjs-types/browser/sync/optimistic_updates.d.ts +4 -4
- package/dist/cjs-types/browser/sync/optimistic_updates.d.ts.map +1 -1
- package/dist/cjs-types/browser/sync/optimistic_updates_impl.d.ts.map +1 -1
- package/dist/cjs-types/cli/codegen.d.ts.map +1 -1
- package/dist/cjs-types/cli/docs.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/checkForLargeIndexDeletion.d.ts +26 -5
- package/dist/cjs-types/cli/lib/checkForLargeIndexDeletion.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/checkForSlowSchemaValidation.d.ts +14 -0
- package/dist/cjs-types/cli/lib/checkForSlowSchemaValidation.d.ts.map +1 -0
- package/dist/cjs-types/cli/lib/codegen.d.ts +1 -0
- package/dist/cjs-types/cli/lib/codegen.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/components.d.ts +1 -0
- package/dist/cjs-types/cli/lib/components.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/deploy2.d.ts +6 -0
- package/dist/cjs-types/cli/lib/deploy2.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/deployApi/evaluateSchema.d.ts +453 -0
- package/dist/cjs-types/cli/lib/deployApi/evaluateSchema.d.ts.map +1 -0
- package/dist/cjs-types/cli/lib/deployApi/finishPush.d.ts +1 -2
- package/dist/cjs-types/cli/lib/deployApi/finishPush.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/dev.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/generatedFunctionLogsApi.d.ts +2 -0
- package/dist/cjs-types/cli/lib/generatedFunctionLogsApi.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/localDeployment/run.d.ts +2 -0
- package/dist/cjs-types/cli/lib/localDeployment/run.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/localDeployment/upgrade.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/localDeployment/utils.d.ts +1 -0
- package/dist/cjs-types/cli/lib/localDeployment/utils.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/run.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/utils/utils.d.ts +5 -5
- package/dist/cjs-types/cli/lib/utils/utils.d.ts.map +1 -1
- package/dist/cjs-types/index.d.ts +1 -1
- package/dist/cjs-types/nextjs/index.d.ts +6 -6
- package/dist/cjs-types/nextjs/index.d.ts.map +1 -1
- package/dist/cjs-types/react/client.d.ts +15 -15
- package/dist/cjs-types/react/client.d.ts.map +1 -1
- package/dist/cjs-types/react/hydration.d.ts +3 -3
- package/dist/cjs-types/react/hydration.d.ts.map +1 -1
- package/dist/cjs-types/react/queries_observer.d.ts +9 -9
- package/dist/cjs-types/react/queries_observer.d.ts.map +1 -1
- package/dist/cjs-types/react/use_paginated_query2.d.ts.map +1 -1
- package/dist/cjs-types/react/use_queries.d.ts +14 -6
- package/dist/cjs-types/react/use_queries.d.ts.map +1 -1
- package/dist/cjs-types/server/api.d.ts +157 -7
- package/dist/cjs-types/server/api.d.ts.map +1 -1
- package/dist/cjs-types/server/components/index.d.ts +2 -2
- package/dist/cjs-types/server/components/index.d.ts.map +1 -1
- package/dist/cjs-types/server/cron.d.ts +21 -20
- package/dist/cjs-types/server/cron.d.ts.map +1 -1
- package/dist/cjs-types/server/impl/actions_impl.d.ts +4 -4
- package/dist/cjs-types/server/impl/actions_impl.d.ts.map +1 -1
- package/dist/cjs-types/server/impl/meta_impl.d.ts.map +1 -1
- package/dist/cjs-types/server/impl/scheduler_impl.d.ts.map +1 -1
- package/dist/cjs-types/server/index.d.ts +1 -1
- package/dist/cjs-types/server/index.d.ts.map +1 -1
- package/dist/cjs-types/server/meta.d.ts.map +1 -1
- package/dist/cjs-types/server/registration.d.ts +7 -7
- package/dist/cjs-types/server/registration.d.ts.map +1 -1
- package/dist/cjs-types/server/scheduler.d.ts +9 -7
- package/dist/cjs-types/server/scheduler.d.ts.map +1 -1
- package/dist/cjs-types/server/schema.d.ts +1 -0
- package/dist/cjs-types/server/schema.d.ts.map +1 -1
- package/dist/cjs-types/values/validator.d.ts.map +1 -1
- package/dist/cjs-types/values/validators.d.ts +30 -0
- package/dist/cjs-types/values/validators.d.ts.map +1 -1
- package/dist/cli.bundle.cjs +347 -133
- package/dist/cli.bundle.cjs.map +4 -4
- package/dist/esm/browser/http_client.js.map +2 -2
- package/dist/esm/browser/query_options.js.map +2 -2
- package/dist/esm/browser/simple_client.js.map +2 -2
- package/dist/esm/browser/sync/optimistic_updates_impl.js.map +2 -2
- package/dist/esm/cli/codegen.js +2 -0
- package/dist/esm/cli/codegen.js.map +2 -2
- package/dist/esm/cli/deploy.js +1 -0
- package/dist/esm/cli/deploy.js.map +2 -2
- package/dist/esm/cli/docs.js +3 -43
- package/dist/esm/cli/docs.js.map +2 -2
- package/dist/esm/cli/lib/checkForLargeIndexDeletion.js +100 -60
- package/dist/esm/cli/lib/checkForLargeIndexDeletion.js.map +2 -2
- package/dist/esm/cli/lib/checkForSlowSchemaValidation.js +85 -0
- package/dist/esm/cli/lib/checkForSlowSchemaValidation.js.map +7 -0
- package/dist/esm/cli/lib/codegen.js.map +2 -2
- package/dist/esm/cli/lib/components.js +12 -0
- package/dist/esm/cli/lib/components.js.map +2 -2
- package/dist/esm/cli/lib/deploy2.js +30 -2
- package/dist/esm/cli/lib/deploy2.js.map +2 -2
- package/dist/esm/cli/lib/deployApi/evaluateSchema.js +46 -0
- package/dist/esm/cli/lib/deployApi/evaluateSchema.js.map +7 -0
- package/dist/esm/cli/lib/deployApi/finishPush.js +1 -1
- package/dist/esm/cli/lib/deployApi/finishPush.js.map +2 -2
- package/dist/esm/cli/lib/deployApi/startPush.js +1 -1
- package/dist/esm/cli/lib/deployApi/startPush.js.map +2 -2
- package/dist/esm/cli/lib/dev.js +1 -0
- package/dist/esm/cli/lib/dev.js.map +2 -2
- package/dist/esm/cli/lib/localDeployment/run.js +30 -2
- package/dist/esm/cli/lib/localDeployment/run.js.map +2 -2
- package/dist/esm/cli/lib/localDeployment/upgrade.js +4 -3
- package/dist/esm/cli/lib/localDeployment/upgrade.js.map +2 -2
- package/dist/esm/cli/lib/localDeployment/utils.js +3 -0
- package/dist/esm/cli/lib/localDeployment/utils.js.map +2 -2
- package/dist/esm/cli/lib/run.js +1 -0
- package/dist/esm/cli/lib/run.js.map +2 -2
- package/dist/esm/cli/lib/utils/utils.js +36 -30
- package/dist/esm/cli/lib/utils/utils.js.map +2 -2
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/nextjs/index.js.map +2 -2
- package/dist/esm/react/client.js.map +2 -2
- package/dist/esm/react/hydration.js +3 -1
- package/dist/esm/react/hydration.js.map +2 -2
- package/dist/esm/react/queries_observer.js +3 -1
- package/dist/esm/react/queries_observer.js.map +2 -2
- package/dist/esm/react/use_paginated_query2.js +3 -1
- package/dist/esm/react/use_paginated_query2.js.map +2 -2
- package/dist/esm/react/use_queries.js.map +2 -2
- package/dist/esm/server/api.js.map +2 -2
- package/dist/esm/server/components/index.js.map +2 -2
- package/dist/esm/server/cron.js +13 -11
- package/dist/esm/server/cron.js.map +2 -2
- package/dist/esm/server/impl/actions_impl.js.map +2 -2
- package/dist/esm/server/impl/meta_impl.js +9 -3
- package/dist/esm/server/impl/meta_impl.js.map +2 -2
- package/dist/esm/server/impl/scheduler_impl.js.map +2 -2
- package/dist/esm/server/index.js.map +2 -2
- package/dist/esm/server/schema.js +50 -3
- package/dist/esm/server/schema.js.map +2 -2
- package/dist/esm/values/validator.js +1 -1
- package/dist/esm/values/validator.js.map +2 -2
- package/dist/esm/values/validators.js +81 -25
- package/dist/esm/values/validators.js.map +2 -2
- package/dist/esm-types/browser/http_client.d.ts +5 -5
- package/dist/esm-types/browser/http_client.d.ts.map +1 -1
- package/dist/esm-types/browser/query_options.d.ts +2 -2
- package/dist/esm-types/browser/query_options.d.ts.map +1 -1
- package/dist/esm-types/browser/simple_client.d.ts +6 -6
- package/dist/esm-types/browser/simple_client.d.ts.map +1 -1
- package/dist/esm-types/browser/sync/optimistic_updates.d.ts +4 -4
- package/dist/esm-types/browser/sync/optimistic_updates.d.ts.map +1 -1
- package/dist/esm-types/browser/sync/optimistic_updates_impl.d.ts.map +1 -1
- package/dist/esm-types/cli/codegen.d.ts.map +1 -1
- package/dist/esm-types/cli/docs.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/checkForLargeIndexDeletion.d.ts +26 -5
- package/dist/esm-types/cli/lib/checkForLargeIndexDeletion.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/checkForSlowSchemaValidation.d.ts +14 -0
- package/dist/esm-types/cli/lib/checkForSlowSchemaValidation.d.ts.map +1 -0
- package/dist/esm-types/cli/lib/codegen.d.ts +1 -0
- package/dist/esm-types/cli/lib/codegen.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/components.d.ts +1 -0
- package/dist/esm-types/cli/lib/components.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/deploy2.d.ts +6 -0
- package/dist/esm-types/cli/lib/deploy2.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/deployApi/evaluateSchema.d.ts +453 -0
- package/dist/esm-types/cli/lib/deployApi/evaluateSchema.d.ts.map +1 -0
- package/dist/esm-types/cli/lib/deployApi/finishPush.d.ts +1 -2
- package/dist/esm-types/cli/lib/deployApi/finishPush.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/dev.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/generatedFunctionLogsApi.d.ts +2 -0
- package/dist/esm-types/cli/lib/generatedFunctionLogsApi.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/localDeployment/run.d.ts +2 -0
- package/dist/esm-types/cli/lib/localDeployment/run.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/localDeployment/upgrade.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/localDeployment/utils.d.ts +1 -0
- package/dist/esm-types/cli/lib/localDeployment/utils.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/run.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/utils/utils.d.ts +5 -5
- package/dist/esm-types/cli/lib/utils/utils.d.ts.map +1 -1
- package/dist/esm-types/index.d.ts +1 -1
- package/dist/esm-types/nextjs/index.d.ts +6 -6
- package/dist/esm-types/nextjs/index.d.ts.map +1 -1
- package/dist/esm-types/react/client.d.ts +15 -15
- package/dist/esm-types/react/client.d.ts.map +1 -1
- package/dist/esm-types/react/hydration.d.ts +3 -3
- package/dist/esm-types/react/hydration.d.ts.map +1 -1
- package/dist/esm-types/react/queries_observer.d.ts +9 -9
- package/dist/esm-types/react/queries_observer.d.ts.map +1 -1
- package/dist/esm-types/react/use_paginated_query2.d.ts.map +1 -1
- package/dist/esm-types/react/use_queries.d.ts +14 -6
- package/dist/esm-types/react/use_queries.d.ts.map +1 -1
- package/dist/esm-types/server/api.d.ts +157 -7
- package/dist/esm-types/server/api.d.ts.map +1 -1
- package/dist/esm-types/server/components/index.d.ts +2 -2
- package/dist/esm-types/server/components/index.d.ts.map +1 -1
- package/dist/esm-types/server/cron.d.ts +21 -20
- package/dist/esm-types/server/cron.d.ts.map +1 -1
- package/dist/esm-types/server/impl/actions_impl.d.ts +4 -4
- package/dist/esm-types/server/impl/actions_impl.d.ts.map +1 -1
- package/dist/esm-types/server/impl/meta_impl.d.ts.map +1 -1
- package/dist/esm-types/server/impl/scheduler_impl.d.ts.map +1 -1
- package/dist/esm-types/server/index.d.ts +1 -1
- package/dist/esm-types/server/index.d.ts.map +1 -1
- package/dist/esm-types/server/meta.d.ts.map +1 -1
- package/dist/esm-types/server/registration.d.ts +7 -7
- package/dist/esm-types/server/registration.d.ts.map +1 -1
- package/dist/esm-types/server/scheduler.d.ts +9 -7
- package/dist/esm-types/server/scheduler.d.ts.map +1 -1
- package/dist/esm-types/server/schema.d.ts +1 -0
- package/dist/esm-types/server/schema.d.ts.map +1 -1
- package/dist/esm-types/values/validator.d.ts.map +1 -1
- package/dist/esm-types/values/validators.d.ts +30 -0
- package/dist/esm-types/values/validators.d.ts.map +1 -1
- package/dist/react.bundle.js +1 -1
- package/dist/react.bundle.js.map +2 -2
- package/package.json +5 -5
- package/src/browser/http_client.ts +43 -10
- package/src/browser/query_options.ts +11 -5
- package/src/browser/simple_client.ts +35 -14
- package/src/browser/sync/optimistic_updates.ts +17 -4
- package/src/browser/sync/optimistic_updates_impl.ts +17 -4
- package/src/cli/codegen.ts +1 -0
- package/src/cli/deploy.ts +1 -0
- package/src/cli/docs.ts +3 -44
- package/src/cli/lib/checkForLargeIndexDeletion.ts +154 -82
- package/src/cli/lib/checkForSlowSchemaValidation.ts +130 -0
- package/src/cli/lib/codegen.ts +1 -0
- package/src/cli/lib/components.ts +17 -0
- package/src/cli/lib/deploy2.ts +56 -1
- package/src/cli/lib/deployApi/evaluateSchema.ts +62 -0
- package/src/cli/lib/deployApi/finishPush.ts +1 -1
- package/src/cli/lib/deployApi/startPush.ts +1 -1
- package/src/cli/lib/dev.ts +1 -0
- package/src/cli/lib/generatedFunctionLogsApi.ts +2 -0
- package/src/cli/lib/localDeployment/run.ts +44 -2
- package/src/cli/lib/localDeployment/upgrade.ts +4 -6
- package/src/cli/lib/localDeployment/utils.ts +6 -0
- package/src/cli/lib/run.ts +1 -0
- package/src/cli/lib/utils/utils.ts +63 -35
- package/src/index.ts +1 -1
- package/src/nextjs/index.ts +19 -8
- package/src/react/client.ts +73 -30
- package/src/react/hydration.tsx +14 -6
- package/src/react/queries_observer.ts +19 -16
- package/src/react/use_paginated_query2.ts +10 -6
- package/src/react/use_queries.ts +23 -7
- package/src/server/api.ts +220 -14
- package/src/server/components/index.ts +4 -6
- package/src/server/cron.ts +34 -24
- package/src/server/impl/actions_impl.ts +13 -4
- package/src/server/impl/meta_impl.ts +8 -1
- package/src/server/impl/scheduler_impl.ts +13 -6
- package/src/server/index.ts +1 -0
- package/src/server/meta.ts +25 -0
- package/src/server/registration.ts +28 -7
- package/src/server/scheduler.ts +22 -7
- package/src/server/schema.ts +55 -0
- package/src/values/validator.ts +3 -1
- package/src/values/validators.ts +84 -26
|
@@ -4,18 +4,34 @@ import {
|
|
|
4
4
|
changeSpinner,
|
|
5
5
|
logFinishedStep,
|
|
6
6
|
logMessage,
|
|
7
|
+
logVerbose,
|
|
7
8
|
stopSpinner,
|
|
8
9
|
} from "../../bundler/log.js";
|
|
9
10
|
import { formatIndex } from "./indexes.js";
|
|
10
11
|
import { promptYesNo } from "./utils/prompts.js";
|
|
11
12
|
import { Span } from "./tracing.js";
|
|
12
13
|
import { StartPushRequest } from "./deployApi/startPush.js";
|
|
13
|
-
import { evaluatePush } from "./deploy2.js";
|
|
14
|
-
import { DeveloperIndexConfig
|
|
14
|
+
import { evaluatePush, evaluateSchema } from "./deploy2.js";
|
|
15
|
+
import { DeveloperIndexConfig } from "./deployApi/finishPush.js";
|
|
15
16
|
import { runSystemQuery } from "./run.js";
|
|
16
17
|
|
|
17
18
|
const MIN_DOCUMENTS_FOR_INDEX_DELETE_WARNING = 100_000;
|
|
18
19
|
|
|
20
|
+
type CheckOptions = {
|
|
21
|
+
url: string;
|
|
22
|
+
deploymentName: string | null;
|
|
23
|
+
adminKey: string;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
type DeletedIndex = {
|
|
27
|
+
// The component instance path ("" for the root component), matching the
|
|
28
|
+
// keys of both `componentSchemaEvaluations` and `indexDiffs`.
|
|
29
|
+
componentPath: string;
|
|
30
|
+
index: DeveloperIndexConfig;
|
|
31
|
+
documentsCount: number;
|
|
32
|
+
replacedBy: DeveloperIndexConfig | null;
|
|
33
|
+
};
|
|
34
|
+
|
|
19
35
|
export async function checkForLargeIndexDeletion({
|
|
20
36
|
ctx,
|
|
21
37
|
span,
|
|
@@ -26,92 +42,41 @@ export async function checkForLargeIndexDeletion({
|
|
|
26
42
|
ctx: Context;
|
|
27
43
|
span: Span;
|
|
28
44
|
request: StartPushRequest;
|
|
29
|
-
options:
|
|
30
|
-
url: string;
|
|
31
|
-
deploymentName: string | null;
|
|
32
|
-
adminKey: string;
|
|
33
|
-
};
|
|
45
|
+
options: CheckOptions;
|
|
34
46
|
askForConfirmation: boolean;
|
|
35
47
|
}): Promise<void> {
|
|
36
48
|
changeSpinner("Verifying that the push isn’t deleting large indexes...");
|
|
37
49
|
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
})),
|
|
47
|
-
);
|
|
50
|
+
const deletedIndexes =
|
|
51
|
+
(await deletedIndexesFromSchemaEvaluation({
|
|
52
|
+
ctx,
|
|
53
|
+
span,
|
|
54
|
+
request,
|
|
55
|
+
options,
|
|
56
|
+
})) ??
|
|
57
|
+
(await deletedIndexesFromTableSizes({ ctx, span, request, options }));
|
|
48
58
|
|
|
49
59
|
if (deletedIndexes.length === 0) {
|
|
50
60
|
logFinishedStep("No indexes are deleted by this push");
|
|
51
61
|
return;
|
|
52
62
|
}
|
|
53
63
|
|
|
54
|
-
const tablesWithDeletedIndexes = [
|
|
55
|
-
...new Set(
|
|
56
|
-
deletedIndexes.map(
|
|
57
|
-
({ componentDefinitionPath, index }) =>
|
|
58
|
-
`${componentDefinitionPath}:${getTableName(index)}`,
|
|
59
|
-
),
|
|
60
|
-
),
|
|
61
|
-
].map((str) => {
|
|
62
|
-
const [componentDefinitionPath, table] = str.split(":");
|
|
63
|
-
return { componentDefinitionPath, table };
|
|
64
|
-
});
|
|
65
|
-
changeSpinner("Checking whether the deleted indexes are on large tables...");
|
|
66
|
-
const documentCounts = await Promise.all(
|
|
67
|
-
tablesWithDeletedIndexes.map(
|
|
68
|
-
async ({ componentDefinitionPath, table }) => ({
|
|
69
|
-
componentDefinitionPath,
|
|
70
|
-
table,
|
|
71
|
-
count: (await runSystemQuery(ctx, {
|
|
72
|
-
deploymentUrl: options.url,
|
|
73
|
-
adminKey: options.adminKey,
|
|
74
|
-
functionName: "_system/cli/tableSize:default",
|
|
75
|
-
componentPath: componentDefinitionPath,
|
|
76
|
-
args: { tableName: table },
|
|
77
|
-
})) as number,
|
|
78
|
-
}),
|
|
79
|
-
),
|
|
80
|
-
);
|
|
81
|
-
const deletedIndexesWithDocumentsCount = deletedIndexes.map(
|
|
82
|
-
({ componentDefinitionPath, index }) => ({
|
|
83
|
-
componentDefinitionPath,
|
|
84
|
-
index,
|
|
85
|
-
count: documentCounts.find(
|
|
86
|
-
(count) =>
|
|
87
|
-
count.table === getTableName(index) &&
|
|
88
|
-
count.componentDefinitionPath === componentDefinitionPath,
|
|
89
|
-
)!.count,
|
|
90
|
-
}),
|
|
91
|
-
);
|
|
92
|
-
|
|
93
64
|
const minDocumentsForWarning = minDocumentsForIndexDeleteWarning();
|
|
94
65
|
if (
|
|
95
|
-
!
|
|
96
|
-
({
|
|
66
|
+
!deletedIndexes.some(
|
|
67
|
+
({ documentsCount }) => documentsCount >= minDocumentsForWarning,
|
|
97
68
|
)
|
|
98
69
|
) {
|
|
99
70
|
logFinishedStep("No large indexes are deleted by this push");
|
|
100
71
|
return;
|
|
101
72
|
}
|
|
102
73
|
|
|
103
|
-
logMessage(`⚠️ This code push will ${chalkStderr.bold("delete")} the following ${
|
|
74
|
+
logMessage(`⚠️ This code push will ${chalkStderr.bold("delete")} the following ${deletedIndexes.length === 1 ? "index" : "indexes"}
|
|
104
75
|
from your production deployment (${options.url}):
|
|
105
76
|
|
|
106
|
-
${
|
|
107
|
-
.map((
|
|
108
|
-
formatDeletedIndex({
|
|
109
|
-
componentDefinitionPath,
|
|
110
|
-
index,
|
|
111
|
-
indexDiff: indexDiffs[componentDefinitionPath],
|
|
112
|
-
documentsCount: count,
|
|
113
|
-
minDocumentsForWarning,
|
|
114
|
-
}),
|
|
77
|
+
${deletedIndexes
|
|
78
|
+
.map((deletedIndex) =>
|
|
79
|
+
formatDeletedIndex({ ...deletedIndex, minDocumentsForWarning }),
|
|
115
80
|
)
|
|
116
81
|
.join("\n")}
|
|
117
82
|
|
|
@@ -139,7 +104,7 @@ to be backfilled again if you want to restore it later.
|
|
|
139
104
|
stopSpinner();
|
|
140
105
|
if (
|
|
141
106
|
!(await promptYesNo(ctx, {
|
|
142
|
-
message: `Delete ${
|
|
107
|
+
message: `Delete ${deletedIndexes.length === 1 ? "this index" : "these indexes"}?`,
|
|
143
108
|
default: false,
|
|
144
109
|
}))
|
|
145
110
|
) {
|
|
@@ -153,30 +118,137 @@ to be backfilled again if you want to restore it later.
|
|
|
153
118
|
logFinishedStep("Proceeding with push.");
|
|
154
119
|
}
|
|
155
120
|
|
|
121
|
+
// Preferred source: one schema evaluation reports every dropped index
|
|
122
|
+
// together with its table's document count, requiring only the
|
|
123
|
+
// `deployment:deploy` permission the push itself needs. Returns null when the
|
|
124
|
+
// deployment doesn't support the endpoint, in which case the caller falls
|
|
125
|
+
// back to sizing tables one system query at a time.
|
|
126
|
+
export async function deletedIndexesFromSchemaEvaluation({
|
|
127
|
+
ctx,
|
|
128
|
+
span,
|
|
129
|
+
request,
|
|
130
|
+
options,
|
|
131
|
+
}: {
|
|
132
|
+
ctx: Context;
|
|
133
|
+
span: Span;
|
|
134
|
+
request: StartPushRequest;
|
|
135
|
+
options: CheckOptions;
|
|
136
|
+
}): Promise<DeletedIndex[] | null> {
|
|
137
|
+
try {
|
|
138
|
+
const response = await evaluateSchema(
|
|
139
|
+
ctx,
|
|
140
|
+
span,
|
|
141
|
+
request,
|
|
142
|
+
options,
|
|
143
|
+
/* bestEffort */ true,
|
|
144
|
+
);
|
|
145
|
+
return Object.entries(response.componentSchemaEvaluations).flatMap(
|
|
146
|
+
([componentPath, prediction]) =>
|
|
147
|
+
prediction.indexes
|
|
148
|
+
.filter((index) => index.change === "dropped")
|
|
149
|
+
.map((index) => ({
|
|
150
|
+
componentPath,
|
|
151
|
+
index,
|
|
152
|
+
documentsCount: index.numDocs,
|
|
153
|
+
replacedBy:
|
|
154
|
+
prediction.indexes.find(
|
|
155
|
+
(other) =>
|
|
156
|
+
other.change === "added" && other.name === index.name,
|
|
157
|
+
) ?? null,
|
|
158
|
+
})),
|
|
159
|
+
);
|
|
160
|
+
} catch (error: unknown) {
|
|
161
|
+
logVerbose(
|
|
162
|
+
`Schema evaluation unavailable, sizing deleted indexes per table: ${error instanceof Error ? error.message : String(error)}`,
|
|
163
|
+
);
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Fallback for deployments without `evaluate_schema`: diff indexes with
|
|
169
|
+
// `evaluate_push`, then size each affected table with a system query. The
|
|
170
|
+
// system query needs the `deployment:data:view` permission, which a
|
|
171
|
+
// deploy-scoped key may lack.
|
|
172
|
+
export async function deletedIndexesFromTableSizes({
|
|
173
|
+
ctx,
|
|
174
|
+
span,
|
|
175
|
+
request,
|
|
176
|
+
options,
|
|
177
|
+
}: {
|
|
178
|
+
ctx: Context;
|
|
179
|
+
span: Span;
|
|
180
|
+
request: StartPushRequest;
|
|
181
|
+
options: CheckOptions;
|
|
182
|
+
}): Promise<DeletedIndex[]> {
|
|
183
|
+
const { schemaChange } = await evaluatePush(ctx, span, request, options);
|
|
184
|
+
|
|
185
|
+
const indexDiffs = schemaChange.indexDiffs ?? {};
|
|
186
|
+
const deletedIndexes = Object.entries(indexDiffs).flatMap(
|
|
187
|
+
([componentPath, indexDiff]) =>
|
|
188
|
+
indexDiff.removed_indexes.map((index) => ({
|
|
189
|
+
componentPath,
|
|
190
|
+
index,
|
|
191
|
+
replacedBy:
|
|
192
|
+
indexDiff.added_indexes.find((other) => other.name === index.name) ??
|
|
193
|
+
null,
|
|
194
|
+
})),
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
if (deletedIndexes.length === 0) {
|
|
198
|
+
return [];
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const tablesWithDeletedIndexes = [
|
|
202
|
+
...new Set(
|
|
203
|
+
deletedIndexes.map(
|
|
204
|
+
({ componentPath, index }) => `${componentPath}:${getTableName(index)}`,
|
|
205
|
+
),
|
|
206
|
+
),
|
|
207
|
+
].map((str) => {
|
|
208
|
+
const [componentPath, table] = str.split(":");
|
|
209
|
+
return { componentPath, table };
|
|
210
|
+
});
|
|
211
|
+
changeSpinner("Checking whether the deleted indexes are on large tables...");
|
|
212
|
+
const documentCounts = await Promise.all(
|
|
213
|
+
tablesWithDeletedIndexes.map(async ({ componentPath, table }) => ({
|
|
214
|
+
componentPath,
|
|
215
|
+
table,
|
|
216
|
+
count: (await runSystemQuery(ctx, {
|
|
217
|
+
deploymentUrl: options.url,
|
|
218
|
+
adminKey: options.adminKey,
|
|
219
|
+
functionName: "_system/cli/tableSize:default",
|
|
220
|
+
componentPath,
|
|
221
|
+
args: { tableName: table },
|
|
222
|
+
})) as number,
|
|
223
|
+
})),
|
|
224
|
+
);
|
|
225
|
+
return deletedIndexes.map(({ componentPath, index, replacedBy }) => ({
|
|
226
|
+
componentPath,
|
|
227
|
+
index,
|
|
228
|
+
replacedBy,
|
|
229
|
+
documentsCount: documentCounts.find(
|
|
230
|
+
(count) =>
|
|
231
|
+
count.table === getTableName(index) &&
|
|
232
|
+
count.componentPath === componentPath,
|
|
233
|
+
)!.count,
|
|
234
|
+
}));
|
|
235
|
+
}
|
|
236
|
+
|
|
156
237
|
function formatDeletedIndex({
|
|
157
|
-
|
|
238
|
+
componentPath,
|
|
158
239
|
index,
|
|
159
|
-
indexDiff,
|
|
160
240
|
documentsCount,
|
|
241
|
+
replacedBy,
|
|
161
242
|
minDocumentsForWarning,
|
|
162
|
-
}: {
|
|
163
|
-
componentDefinitionPath: string;
|
|
164
|
-
index: DeveloperIndexConfig;
|
|
165
|
-
indexDiff: IndexDiff;
|
|
166
|
-
documentsCount: number;
|
|
167
|
-
minDocumentsForWarning: number;
|
|
168
|
-
}) {
|
|
243
|
+
}: DeletedIndex & { minDocumentsForWarning: number }) {
|
|
169
244
|
const componentNameFormatted =
|
|
170
|
-
|
|
171
|
-
? `${chalkStderr.gray(componentDefinitionPath)}:`
|
|
172
|
-
: "";
|
|
245
|
+
componentPath !== "" ? `${chalkStderr.gray(componentPath)}:` : "";
|
|
173
246
|
|
|
174
247
|
const documentsCountFormatted =
|
|
175
248
|
documentsCount >= minDocumentsForWarning
|
|
176
249
|
? ` ${chalkStderr.yellowBright(`⚠️ ${documentsCount.toLocaleString()} documents`)}`
|
|
177
250
|
: ` ${documentsCount.toLocaleString()} ${documentsCount === 1 ? "document" : "documents"}`;
|
|
178
251
|
|
|
179
|
-
const replacedBy = indexDiff.added_indexes.find((i) => i.name === index.name);
|
|
180
252
|
const replacedByFormatted = replacedBy
|
|
181
253
|
? `\n ${chalkStderr.green("→ replaced by:")} ${formatIndex(replacedBy)}`
|
|
182
254
|
: "";
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { chalkStderr } from "chalk";
|
|
2
|
+
import { Context } from "../../bundler/context.js";
|
|
3
|
+
import { logMessage, logVerbose } from "../../bundler/log.js";
|
|
4
|
+
import { Span } from "./tracing.js";
|
|
5
|
+
import { StartPushRequest } from "./deployApi/startPush.js";
|
|
6
|
+
import {
|
|
7
|
+
EvaluateSchemaResponse,
|
|
8
|
+
TablePrediction,
|
|
9
|
+
} from "./deployApi/evaluateSchema.js";
|
|
10
|
+
import { evaluateSchema } from "./deploy2.js";
|
|
11
|
+
import { formatSize } from "./utils/utils.js";
|
|
12
|
+
|
|
13
|
+
const MIN_BYTES_FOR_SCHEMA_WALK_WARNING = 1 << 27; // 128 MiB
|
|
14
|
+
|
|
15
|
+
export async function checkForSlowSchemaValidation({
|
|
16
|
+
ctx,
|
|
17
|
+
span,
|
|
18
|
+
request,
|
|
19
|
+
options,
|
|
20
|
+
}: {
|
|
21
|
+
ctx: Context;
|
|
22
|
+
span: Span;
|
|
23
|
+
request: StartPushRequest;
|
|
24
|
+
options: {
|
|
25
|
+
url: string;
|
|
26
|
+
deploymentName: string | null;
|
|
27
|
+
adminKey: string;
|
|
28
|
+
};
|
|
29
|
+
}): Promise<void> {
|
|
30
|
+
const response = await evaluateSchemaBestEffort({
|
|
31
|
+
ctx,
|
|
32
|
+
span,
|
|
33
|
+
request,
|
|
34
|
+
options,
|
|
35
|
+
});
|
|
36
|
+
if (response === null) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const walkedTables = Object.entries(
|
|
41
|
+
response.componentSchemaEvaluations,
|
|
42
|
+
).flatMap(([componentPath, prediction]) =>
|
|
43
|
+
prediction.tables
|
|
44
|
+
.filter((table) => table.outcome === "mustWalk")
|
|
45
|
+
.map((table) => ({ componentPath, table })),
|
|
46
|
+
);
|
|
47
|
+
if (walkedTables.length === 0) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const totalBytes = walkedTables.reduce(
|
|
52
|
+
(sum, { table }) => sum + table.sizeBytes,
|
|
53
|
+
0,
|
|
54
|
+
);
|
|
55
|
+
if (totalBytes < minBytesForSchemaWalkWarning()) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
logMessage(`⚠️ This schema change requires checking every document in the following ${walkedTables.length === 1 ? "table" : "tables"} against your new schema, totaling ${chalkStderr.yellowBright(formatSize(totalBytes))}. This deploy may take a while:
|
|
60
|
+
|
|
61
|
+
${walkedTables
|
|
62
|
+
.map(({ componentPath, table }) =>
|
|
63
|
+
formatWalkedTable({ componentPath, table }),
|
|
64
|
+
)
|
|
65
|
+
.join("\n")}
|
|
66
|
+
`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// This warning is advisory: if evaluation fails, fall back to skipping it
|
|
70
|
+
// rather than aborting the push over a check that isn't required for
|
|
71
|
+
// correctness. Plausibly transient failures — network errors and 5xx
|
|
72
|
+
// responses (e.g. table summaries still bootstrapping) — are retried with
|
|
73
|
+
// backoff by the shared fetch wrapper (see `pushCode`); anything else is
|
|
74
|
+
// deterministic, including a 2xx whose shape the CLI doesn't recognize, so
|
|
75
|
+
// it skips the check immediately.
|
|
76
|
+
async function evaluateSchemaBestEffort({
|
|
77
|
+
ctx,
|
|
78
|
+
span,
|
|
79
|
+
request,
|
|
80
|
+
options,
|
|
81
|
+
}: {
|
|
82
|
+
ctx: Context;
|
|
83
|
+
span: Span;
|
|
84
|
+
request: StartPushRequest;
|
|
85
|
+
options: {
|
|
86
|
+
url: string;
|
|
87
|
+
deploymentName: string | null;
|
|
88
|
+
adminKey: string;
|
|
89
|
+
};
|
|
90
|
+
}): Promise<EvaluateSchemaResponse | null> {
|
|
91
|
+
try {
|
|
92
|
+
return await evaluateSchema(
|
|
93
|
+
ctx,
|
|
94
|
+
span,
|
|
95
|
+
request,
|
|
96
|
+
options,
|
|
97
|
+
/* bestEffort */ true,
|
|
98
|
+
);
|
|
99
|
+
} catch (error: unknown) {
|
|
100
|
+
logVerbose(
|
|
101
|
+
`Skipping slow schema validation check: ${error instanceof Error ? error.message : String(error)}`,
|
|
102
|
+
);
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function formatWalkedTable({
|
|
108
|
+
componentPath,
|
|
109
|
+
table,
|
|
110
|
+
}: {
|
|
111
|
+
componentPath: string;
|
|
112
|
+
table: TablePrediction;
|
|
113
|
+
}) {
|
|
114
|
+
const componentPrefix =
|
|
115
|
+
componentPath !== "" ? `${chalkStderr.gray(componentPath)}: ` : "";
|
|
116
|
+
const docsFormatted = `${table.numDocs.toLocaleString()} documents, `;
|
|
117
|
+
const sizeFormatted = formatSize(table.sizeBytes);
|
|
118
|
+
return ` ${componentPrefix}${table.name} (${docsFormatted}${sizeFormatted})`;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function minBytesForSchemaWalkWarning(): number {
|
|
122
|
+
const envValue = process.env.CONVEX_MIN_BYTES_FOR_SCHEMA_WALK_WARNING;
|
|
123
|
+
if (envValue !== undefined) {
|
|
124
|
+
const parsed = parseInt(envValue, 10);
|
|
125
|
+
if (!isNaN(parsed)) {
|
|
126
|
+
return parsed;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return MIN_BYTES_FOR_SCHEMA_WALK_WARNING;
|
|
130
|
+
}
|
package/src/cli/lib/codegen.ts
CHANGED
|
@@ -52,6 +52,7 @@ import { DeploymentType } from "./api.js";
|
|
|
52
52
|
import { deploymentDashboardUrlPage } from "./dashboard.js";
|
|
53
53
|
import { formatIndex, LargeIndexDeletionCheck } from "./indexes.js";
|
|
54
54
|
import { checkForLargeIndexDeletion } from "./checkForLargeIndexDeletion.js";
|
|
55
|
+
import { checkForSlowSchemaValidation } from "./checkForSlowSchemaValidation.js";
|
|
55
56
|
import { LogManager } from "./logs.js";
|
|
56
57
|
import { createHash } from "crypto";
|
|
57
58
|
import { Bundle, BundleHash } from "../../bundler/index.js";
|
|
@@ -75,6 +76,10 @@ export type PushOptions = {
|
|
|
75
76
|
pushAllModules: boolean;
|
|
76
77
|
logManager?: LogManager | undefined;
|
|
77
78
|
largeIndexDeletionCheck: LargeIndexDeletionCheck;
|
|
79
|
+
// Whether a dry run should warn when the schema change would block the
|
|
80
|
+
// deploy on a slow table walk. On for deploys; off for commands whose dry
|
|
81
|
+
// runs never deploy (e.g. codegen).
|
|
82
|
+
warnOnSlowSchemaValidation: boolean;
|
|
78
83
|
message: string | null;
|
|
79
84
|
};
|
|
80
85
|
|
|
@@ -229,6 +234,7 @@ async function startComponentsPushAndCodegen(
|
|
|
229
234
|
pushAllModules?: boolean;
|
|
230
235
|
debugNodeApis: boolean;
|
|
231
236
|
largeIndexDeletionCheck: LargeIndexDeletionCheck;
|
|
237
|
+
warnOnSlowSchemaValidation: boolean;
|
|
232
238
|
codegenOnlyThisComponent?: string | undefined;
|
|
233
239
|
},
|
|
234
240
|
): Promise<StartPushResponse | null> {
|
|
@@ -458,6 +464,17 @@ async function startComponentsPushAndCodegen(
|
|
|
458
464
|
);
|
|
459
465
|
}
|
|
460
466
|
|
|
467
|
+
if (options.dryRun && options.warnOnSlowSchemaValidation) {
|
|
468
|
+
await parentSpan.enterAsync("checkForSlowSchemaValidation", (span) =>
|
|
469
|
+
checkForSlowSchemaValidation({
|
|
470
|
+
ctx,
|
|
471
|
+
span,
|
|
472
|
+
request: startPushRequest,
|
|
473
|
+
options,
|
|
474
|
+
}),
|
|
475
|
+
);
|
|
476
|
+
}
|
|
477
|
+
|
|
461
478
|
changeSpinner("Uploading functions to Convex...");
|
|
462
479
|
const startPushResponse = await parentSpan.enterAsync("startPush", (span) =>
|
|
463
480
|
startPush(ctx, span, startPushRequest, options),
|
package/src/cli/lib/deploy2.ts
CHANGED
|
@@ -22,6 +22,10 @@ import {
|
|
|
22
22
|
startPushResponse,
|
|
23
23
|
StartPushResponse,
|
|
24
24
|
} from "./deployApi/startPush.js";
|
|
25
|
+
import {
|
|
26
|
+
EvaluateSchemaResponse,
|
|
27
|
+
evaluateSchemaResponse,
|
|
28
|
+
} from "./deployApi/evaluateSchema.js";
|
|
25
29
|
import {
|
|
26
30
|
AppDefinitionConfig,
|
|
27
31
|
ComponentDefinitionConfig,
|
|
@@ -103,6 +107,35 @@ export async function evaluatePush(
|
|
|
103
107
|
return evaluatePushResponse.parse(response);
|
|
104
108
|
}
|
|
105
109
|
|
|
110
|
+
export async function evaluateSchema(
|
|
111
|
+
ctx: Context,
|
|
112
|
+
span: Span,
|
|
113
|
+
request: StartPushRequest,
|
|
114
|
+
options: {
|
|
115
|
+
url: string;
|
|
116
|
+
deploymentName: string | null;
|
|
117
|
+
deploymentType?: DeploymentType;
|
|
118
|
+
},
|
|
119
|
+
// When set, a failed evaluation throws the raw error instead of crashing
|
|
120
|
+
// the process, so best-effort callers (e.g. advisory checks) can recover.
|
|
121
|
+
bestEffort?: boolean,
|
|
122
|
+
): Promise<EvaluateSchemaResponse> {
|
|
123
|
+
const response = await pushCode(
|
|
124
|
+
ctx,
|
|
125
|
+
span,
|
|
126
|
+
request,
|
|
127
|
+
options,
|
|
128
|
+
"/api/deploy2/evaluate_schema",
|
|
129
|
+
bestEffort,
|
|
130
|
+
);
|
|
131
|
+
return evaluateSchemaResponse.parse(response);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Retries for best-effort requests, where a transient failure should be
|
|
135
|
+
// ridden out if possible but the command proceeds without the result
|
|
136
|
+
// otherwise.
|
|
137
|
+
const BEST_EFFORT_RETRIES = 5;
|
|
138
|
+
|
|
106
139
|
async function pushCode(
|
|
107
140
|
ctx: Context,
|
|
108
141
|
span: Span,
|
|
@@ -112,7 +145,11 @@ async function pushCode(
|
|
|
112
145
|
deploymentName: string | null;
|
|
113
146
|
deploymentType?: DeploymentType;
|
|
114
147
|
},
|
|
115
|
-
endpoint:
|
|
148
|
+
endpoint:
|
|
149
|
+
| "/api/deploy2/start_push"
|
|
150
|
+
| "/api/deploy2/evaluate_push"
|
|
151
|
+
| "/api/deploy2/evaluate_schema",
|
|
152
|
+
bestEffort?: boolean,
|
|
116
153
|
): Promise<unknown> {
|
|
117
154
|
// Log a summary of the push request instead of the full object
|
|
118
155
|
const unchangedModuleCount =
|
|
@@ -136,6 +173,18 @@ async function pushCode(
|
|
|
136
173
|
deploymentUrl: options.url,
|
|
137
174
|
adminKey: request.adminKey,
|
|
138
175
|
onError,
|
|
176
|
+
// Best-effort callers tolerate failure, so retry only plausibly
|
|
177
|
+
// transient conditions — network errors and 5xx responses (e.g. table
|
|
178
|
+
// summaries still bootstrapping) — and fail fast on everything else,
|
|
179
|
+
// like a 404 from a deployment whose backend doesn't yet expose the
|
|
180
|
+
// endpoint.
|
|
181
|
+
...(bestEffort
|
|
182
|
+
? {
|
|
183
|
+
maxRetries: BEST_EFFORT_RETRIES,
|
|
184
|
+
shouldRetry: (error: Error | null, response: Response | null) =>
|
|
185
|
+
error !== null || (response !== null && response.status >= 500),
|
|
186
|
+
}
|
|
187
|
+
: {}),
|
|
139
188
|
});
|
|
140
189
|
try {
|
|
141
190
|
const response = await fetch(endpoint, {
|
|
@@ -149,6 +198,11 @@ async function pushCode(
|
|
|
149
198
|
});
|
|
150
199
|
return await response.json();
|
|
151
200
|
} catch (error: unknown) {
|
|
201
|
+
if (bestEffort) {
|
|
202
|
+
// The caller handles this itself instead of crashing the process.
|
|
203
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
204
|
+
throw error;
|
|
205
|
+
}
|
|
152
206
|
return await handlePushConfigError(
|
|
153
207
|
ctx,
|
|
154
208
|
error,
|
|
@@ -453,6 +507,7 @@ export async function deployToDeployment(
|
|
|
453
507
|
largeIndexDeletionCheck: options.allowDeletingLargeIndexes
|
|
454
508
|
? "has confirmation"
|
|
455
509
|
: "ask for confirmation",
|
|
510
|
+
warnOnSlowSchemaValidation: true,
|
|
456
511
|
message: options.message,
|
|
457
512
|
};
|
|
458
513
|
showSpinner(`Deploying to ${url}...${options.dryRun ? " [dry run]" : ""}`);
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { componentDefinitionPath, componentPath } from "./paths.js";
|
|
3
|
+
import { developerIndexConfig } from "./finishPush.js";
|
|
4
|
+
import { looseObject } from "./utils.js";
|
|
5
|
+
|
|
6
|
+
// Hand-mirrors `TableValidationOutcome` in
|
|
7
|
+
// `crates/common/src/schemas/mod.rs` (`#[serde(rename_all = "camelCase")]`),
|
|
8
|
+
// like the rest of this deployApi directory: there's no codegen sharing
|
|
9
|
+
// types between the Rust backend and this package.
|
|
10
|
+
export const tableValidationOutcome = z.enum([
|
|
11
|
+
"notValidated",
|
|
12
|
+
"supersetOfEnforced",
|
|
13
|
+
"supersetOfShape",
|
|
14
|
+
"mustWalk",
|
|
15
|
+
]);
|
|
16
|
+
export type TableValidationOutcome = z.infer<typeof tableValidationOutcome>;
|
|
17
|
+
|
|
18
|
+
export const indexChangePrediction = z.enum([
|
|
19
|
+
"added",
|
|
20
|
+
"identical",
|
|
21
|
+
"enabled",
|
|
22
|
+
"disabled",
|
|
23
|
+
"dropped",
|
|
24
|
+
]);
|
|
25
|
+
export type IndexChangePrediction = z.infer<typeof indexChangePrediction>;
|
|
26
|
+
|
|
27
|
+
export const tablePrediction = looseObject({
|
|
28
|
+
name: z.string(),
|
|
29
|
+
outcome: tableValidationOutcome,
|
|
30
|
+
numDocs: z.number(),
|
|
31
|
+
sizeBytes: z.number(),
|
|
32
|
+
});
|
|
33
|
+
export type TablePrediction = z.infer<typeof tablePrediction>;
|
|
34
|
+
|
|
35
|
+
export const indexPrediction = z.intersection(
|
|
36
|
+
developerIndexConfig,
|
|
37
|
+
looseObject({
|
|
38
|
+
change: indexChangePrediction,
|
|
39
|
+
needsBackfill: z.boolean(),
|
|
40
|
+
numDocs: z.number(),
|
|
41
|
+
}),
|
|
42
|
+
);
|
|
43
|
+
export type IndexPrediction = z.infer<typeof indexPrediction>;
|
|
44
|
+
|
|
45
|
+
export const componentSchemaPrediction = looseObject({
|
|
46
|
+
definitionPath: z.string(),
|
|
47
|
+
schemaValidation: z.boolean(),
|
|
48
|
+
tables: z.array(tablePrediction),
|
|
49
|
+
indexes: z.array(indexPrediction),
|
|
50
|
+
});
|
|
51
|
+
export type ComponentSchemaPrediction = z.infer<
|
|
52
|
+
typeof componentSchemaPrediction
|
|
53
|
+
>;
|
|
54
|
+
|
|
55
|
+
export const evaluateSchemaResponse = looseObject({
|
|
56
|
+
componentSchemaEvaluations: z.record(
|
|
57
|
+
componentPath,
|
|
58
|
+
componentSchemaPrediction,
|
|
59
|
+
),
|
|
60
|
+
newComponentDefinitions: z.array(componentDefinitionPath),
|
|
61
|
+
});
|
|
62
|
+
export type EvaluateSchemaResponse = z.infer<typeof evaluateSchemaResponse>;
|
|
@@ -45,7 +45,7 @@ export const cronDiff = looseObject({
|
|
|
45
45
|
});
|
|
46
46
|
export type CronDiff = z.infer<typeof cronDiff>;
|
|
47
47
|
|
|
48
|
-
const developerIndexConfig = z.intersection(
|
|
48
|
+
export const developerIndexConfig = z.intersection(
|
|
49
49
|
z.discriminatedUnion("type", [
|
|
50
50
|
looseObject({
|
|
51
51
|
name: z.string(),
|
|
@@ -29,7 +29,7 @@ export type StartPushRequest = z.infer<typeof startPushRequest>;
|
|
|
29
29
|
export const schemaChange = looseObject({
|
|
30
30
|
allocatedComponentIds: z.any(),
|
|
31
31
|
schemaIds: z.any(),
|
|
32
|
-
indexDiffs: z.record(
|
|
32
|
+
indexDiffs: z.record(componentPath, indexDiff).optional(),
|
|
33
33
|
});
|
|
34
34
|
export type SchemaChange = z.infer<typeof schemaChange>;
|
|
35
35
|
|
package/src/cli/lib/dev.ts
CHANGED
|
@@ -148,6 +148,7 @@ export async function devAgainstDeployment(
|
|
|
148
148
|
pushAllModules: devOptions.pushAllModules,
|
|
149
149
|
logManager, // Pass logManager to control logs during deploy
|
|
150
150
|
largeIndexDeletionCheck: "no verification", // `convex dev` can’t push to prod
|
|
151
|
+
warnOnSlowSchemaValidation: true,
|
|
151
152
|
message: null,
|
|
152
153
|
},
|
|
153
154
|
devOptions,
|
|
@@ -103,6 +103,8 @@ export interface components {
|
|
|
103
103
|
/** Format: int64 */
|
|
104
104
|
databaseWriteDocuments: number;
|
|
105
105
|
/** Format: int64 */
|
|
106
|
+
databaseWriteIndexRows: number;
|
|
107
|
+
/** Format: int64 */
|
|
106
108
|
storageReadBytes: number;
|
|
107
109
|
/** Format: int64 */
|
|
108
110
|
storageWriteBytes: number;
|