convex 1.44.0 → 1.45.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 +13 -0
- package/dist/browser.bundle.js +1 -1
- package/dist/browser.bundle.js.map +1 -1
- package/dist/cjs/cli/convexExport.js +1 -1
- package/dist/cjs/cli/convexExport.js.map +1 -1
- package/dist/cjs/cli/index.js +2 -32
- package/dist/cjs/cli/index.js.map +2 -2
- package/dist/cjs/cli/lib/api.js +11 -5
- package/dist/cjs/cli/lib/api.js.map +2 -2
- package/dist/cjs/cli/lib/convexExport.js +12 -1
- package/dist/cjs/cli/lib/convexExport.js.map +2 -2
- package/dist/cjs/cli/lib/dashboard.js.map +2 -2
- package/dist/cjs/cli/lib/generatedFunctionLogsApi.js.map +1 -1
- package/dist/cjs/cli/lib/indexes.js +1 -1
- package/dist/cjs/cli/lib/indexes.js.map +1 -1
- package/dist/cjs/cli/lib/localDeployment/upgrade.js +23 -188
- package/dist/cjs/cli/lib/localDeployment/upgrade.js.map +3 -3
- package/dist/cjs/cli/lib/mcp/tools/index.js.map +1 -1
- package/dist/cjs/cli/mcp.js +76 -69
- package/dist/cjs/cli/mcp.js.map +2 -2
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/server/impl/actions_impl.js.map +2 -2
- package/dist/cjs/server/index.js.map +2 -2
- package/dist/cjs-types/cli/lib/api.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/convexExport.d.ts +1 -0
- package/dist/cjs-types/cli/lib/convexExport.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/dashboard.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/upgrade.d.ts +2 -0
- package/dist/cjs-types/cli/lib/localDeployment/upgrade.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/mcp/tools/index.d.ts +1 -1
- package/dist/cjs-types/cli/lib/mcp/tools/index.d.ts.map +1 -1
- package/dist/cjs-types/cli/mcp.d.ts +3 -0
- package/dist/cjs-types/cli/mcp.d.ts.map +1 -1
- package/dist/cjs-types/index.d.ts +1 -1
- package/dist/cjs-types/server/impl/actions_impl.d.ts +14 -0
- package/dist/cjs-types/server/impl/actions_impl.d.ts.map +1 -1
- package/dist/cjs-types/server/index.d.ts +1 -0
- package/dist/cjs-types/server/index.d.ts.map +1 -1
- package/dist/cli.bundle.cjs +31210 -25495
- package/dist/cli.bundle.cjs.map +4 -4
- package/dist/esm/cli/convexExport.js +1 -1
- package/dist/esm/cli/convexExport.js.map +1 -1
- package/dist/esm/cli/index.js +2 -32
- package/dist/esm/cli/index.js.map +2 -2
- package/dist/esm/cli/lib/api.js +11 -5
- package/dist/esm/cli/lib/api.js.map +2 -2
- package/dist/esm/cli/lib/convexExport.js +16 -3
- package/dist/esm/cli/lib/convexExport.js.map +2 -2
- package/dist/esm/cli/lib/dashboard.js.map +2 -2
- package/dist/esm/cli/lib/indexes.js +1 -1
- package/dist/esm/cli/lib/indexes.js.map +1 -1
- package/dist/esm/cli/lib/localDeployment/upgrade.js +22 -190
- package/dist/esm/cli/lib/localDeployment/upgrade.js.map +2 -2
- package/dist/esm/cli/lib/mcp/tools/index.js.map +1 -1
- package/dist/esm/cli/mcp.js +75 -72
- package/dist/esm/cli/mcp.js.map +2 -2
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/server/impl/actions_impl.js.map +2 -2
- package/dist/esm/server/index.js.map +2 -2
- package/dist/esm-types/cli/lib/api.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/convexExport.d.ts +1 -0
- package/dist/esm-types/cli/lib/convexExport.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/dashboard.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/upgrade.d.ts +2 -0
- package/dist/esm-types/cli/lib/localDeployment/upgrade.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/mcp/tools/index.d.ts +1 -1
- package/dist/esm-types/cli/lib/mcp/tools/index.d.ts.map +1 -1
- package/dist/esm-types/cli/mcp.d.ts +3 -0
- package/dist/esm-types/cli/mcp.d.ts.map +1 -1
- package/dist/esm-types/index.d.ts +1 -1
- package/dist/esm-types/server/impl/actions_impl.d.ts +14 -0
- package/dist/esm-types/server/impl/actions_impl.d.ts.map +1 -1
- package/dist/esm-types/server/index.d.ts +1 -0
- package/dist/esm-types/server/index.d.ts.map +1 -1
- package/dist/react.bundle.js +1 -1
- package/dist/react.bundle.js.map +1 -1
- package/package.json +3 -3
- package/src/cli/convexExport.ts +1 -1
- package/src/cli/index.ts +2 -35
- package/src/cli/lib/api.ts +11 -5
- package/src/cli/lib/convexExport.ts +21 -0
- package/src/cli/lib/dashboard.ts +2 -0
- package/src/cli/lib/generatedFunctionLogsApi.ts +2 -0
- package/src/cli/lib/indexes.ts +1 -1
- package/src/cli/lib/localDeployment/upgrade.ts +34 -207
- package/src/cli/lib/mcp/tools/index.ts +1 -1
- package/src/cli/mcp.ts +91 -77
- package/src/index.ts +1 -1
- package/src/server/impl/actions_impl.ts +3 -1
- package/src/server/index.ts +0 -3
- package/dist/cjs-types/browser/http_client.test.d.ts +0 -2
- package/dist/cjs-types/browser/http_client.test.d.ts.map +0 -1
- package/dist/cjs-types/browser/query_options.test.d.ts +0 -2
- package/dist/cjs-types/browser/query_options.test.d.ts.map +0 -1
- package/dist/cjs-types/browser/simple_client.test.d.ts +0 -2
- package/dist/cjs-types/browser/simple_client.test.d.ts.map +0 -1
- package/dist/cjs-types/browser/sync/client.test.d.ts +0 -5
- package/dist/cjs-types/browser/sync/client.test.d.ts.map +0 -1
- package/dist/cjs-types/browser/sync/client_node.test.d.ts +0 -2
- package/dist/cjs-types/browser/sync/client_node.test.d.ts.map +0 -1
- package/dist/cjs-types/browser/sync/client_node_test_helpers.d.ts +0 -44
- package/dist/cjs-types/browser/sync/client_node_test_helpers.d.ts.map +0 -1
- package/dist/cjs-types/browser/sync/local_state.test.d.ts +0 -2
- package/dist/cjs-types/browser/sync/local_state.test.d.ts.map +0 -1
- package/dist/cjs-types/browser/sync/optimistic_query_set.test.d.ts +0 -2
- package/dist/cjs-types/browser/sync/optimistic_query_set.test.d.ts.map +0 -1
- package/dist/cjs-types/browser/sync/paginated_query_client.test.d.ts +0 -2
- package/dist/cjs-types/browser/sync/paginated_query_client.test.d.ts.map +0 -1
- package/dist/cjs-types/browser/sync/protocol.test.d.ts +0 -5
- package/dist/cjs-types/browser/sync/protocol.test.d.ts.map +0 -1
- package/dist/cjs-types/browser/sync/request_manager.test.d.ts +0 -2
- package/dist/cjs-types/browser/sync/request_manager.test.d.ts.map +0 -1
- package/dist/cjs-types/bundler/fs.test.d.ts +0 -2
- package/dist/cjs-types/bundler/fs.test.d.ts.map +0 -1
- package/dist/cjs-types/bundler/index.test.d.ts +0 -2
- package/dist/cjs-types/bundler/index.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/codegen_templates/api.test.d.ts +0 -2
- package/dist/cjs-types/cli/codegen_templates/api.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/codegen_templates/common.test.d.ts +0 -2
- package/dist/cjs-types/cli/codegen_templates/common.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/codegen_templates/templates.test.d.ts +0 -2
- package/dist/cjs-types/cli/codegen_templates/templates.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/codegen_templates/validator_helpers.test.d.ts +0 -2
- package/dist/cjs-types/cli/codegen_templates/validator_helpers.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/configure.test.d.ts +0 -2
- package/dist/cjs-types/cli/configure.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/deploymentCreate.test.d.ts +0 -2
- package/dist/cjs-types/cli/deploymentCreate.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/deploymentSelect.test.d.ts +0 -2
- package/dist/cjs-types/cli/deploymentSelect.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/deploymentSelection.test.d.ts +0 -2
- package/dist/cjs-types/cli/deploymentSelection.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/deploymentToken.test.d.ts +0 -2
- package/dist/cjs-types/cli/deploymentToken.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/dev.test.d.ts +0 -2
- package/dist/cjs-types/cli/dev.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/envDefault.test.d.ts +0 -2
- package/dist/cjs-types/cli/envDefault.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/lib/aiFiles/agentsmd.test.d.ts +0 -2
- package/dist/cjs-types/cli/lib/aiFiles/agentsmd.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/lib/aiFiles/claudemd.test.d.ts +0 -2
- package/dist/cjs-types/cli/lib/aiFiles/claudemd.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/lib/aiFiles/guidelinesmd.test.d.ts +0 -2
- package/dist/cjs-types/cli/lib/aiFiles/guidelinesmd.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/lib/aiFiles/index.test.d.ts +0 -2
- package/dist/cjs-types/cli/lib/aiFiles/index.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/lib/aiFiles/integration.test.d.ts +0 -2
- package/dist/cjs-types/cli/lib/aiFiles/integration.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/lib/aiFiles/prompt.test.d.ts +0 -2
- package/dist/cjs-types/cli/lib/aiFiles/prompt.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/lib/aiFiles/state.test.d.ts +0 -2
- package/dist/cjs-types/cli/lib/aiFiles/state.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/lib/aiFiles/utils.test.d.ts +0 -2
- package/dist/cjs-types/cli/lib/aiFiles/utils.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/lib/codegen.test.d.ts +0 -2
- package/dist/cjs-types/cli/lib/codegen.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/lib/components.test.d.ts +0 -2
- package/dist/cjs-types/cli/lib/components.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/lib/config.test.d.ts +0 -2
- package/dist/cjs-types/cli/lib/config.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/lib/deployment.test.d.ts +0 -2
- package/dist/cjs-types/cli/lib/deployment.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/lib/deploymentSelector.test.d.ts +0 -2
- package/dist/cjs-types/cli/lib/deploymentSelector.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/lib/env.test.d.ts +0 -2
- package/dist/cjs-types/cli/lib/env.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/lib/expiration.test.d.ts +0 -2
- package/dist/cjs-types/cli/lib/expiration.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/lib/extractDeploymentNameForWorkOS.test.d.ts +0 -2
- package/dist/cjs-types/cli/lib/extractDeploymentNameForWorkOS.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/lib/formatEnvValueForDotfile.test.d.ts +0 -2
- package/dist/cjs-types/cli/lib/formatEnvValueForDotfile.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/lib/formatTargetedDeployment.test.d.ts +0 -2
- package/dist/cjs-types/cli/lib/formatTargetedDeployment.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/lib/fsUtils.test.d.ts +0 -2
- package/dist/cjs-types/cli/lib/fsUtils.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/lib/generateDocs.test.d.ts +0 -2
- package/dist/cjs-types/cli/lib/generateDocs.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/lib/indexes.test.d.ts +0 -2
- package/dist/cjs-types/cli/lib/indexes.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/lib/localDeployment/run.test.d.ts +0 -2
- package/dist/cjs-types/cli/lib/localDeployment/run.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/lib/localDeployment/secrets.test.d.ts +0 -2
- package/dist/cjs-types/cli/lib/localDeployment/secrets.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/lib/run.test.d.ts +0 -2
- package/dist/cjs-types/cli/lib/run.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/lib/runTestFunction.test.d.ts +0 -2
- package/dist/cjs-types/cli/lib/runTestFunction.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/lib/typecheck.test.d.ts +0 -2
- package/dist/cjs-types/cli/lib/typecheck.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/lib/updates.test.d.ts +0 -2
- package/dist/cjs-types/cli/lib/updates.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/lib/utils/hash.test.d.ts +0 -2
- package/dist/cjs-types/cli/lib/utils/hash.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/lib/utils/utils.test.d.ts +0 -2
- package/dist/cjs-types/cli/lib/utils/utils.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/lib/versionApi.test.d.ts +0 -2
- package/dist/cjs-types/cli/lib/versionApi.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/lib/workos/environmentApi.test.d.ts +0 -2
- package/dist/cjs-types/cli/lib/workos/environmentApi.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/lib/workos/workos.test.d.ts +0 -2
- package/dist/cjs-types/cli/lib/workos/workos.test.d.ts.map +0 -1
- package/dist/cjs-types/cli/login.test.d.ts +0 -2
- package/dist/cjs-types/cli/login.test.d.ts.map +0 -1
- package/dist/cjs-types/common/index.test.d.ts +0 -2
- package/dist/cjs-types/common/index.test.d.ts.map +0 -1
- package/dist/cjs-types/nextjs/nextjs.test.d.ts +0 -2
- package/dist/cjs-types/nextjs/nextjs.test.d.ts.map +0 -1
- package/dist/cjs-types/react/ConvexAuthState.test.d.ts +0 -2
- package/dist/cjs-types/react/ConvexAuthState.test.d.ts.map +0 -1
- package/dist/cjs-types/react/auth_helpers.test.d.ts +0 -2
- package/dist/cjs-types/react/auth_helpers.test.d.ts.map +0 -1
- package/dist/cjs-types/react/auth_websocket.test.d.ts +0 -2
- package/dist/cjs-types/react/auth_websocket.test.d.ts.map +0 -1
- package/dist/cjs-types/react/client.test.d.ts +0 -2
- package/dist/cjs-types/react/client.test.d.ts.map +0 -1
- package/dist/cjs-types/react/client_provided_base_client.test.d.ts +0 -2
- package/dist/cjs-types/react/client_provided_base_client.test.d.ts.map +0 -1
- package/dist/cjs-types/react/queries_observer.test.d.ts +0 -2
- package/dist/cjs-types/react/queries_observer.test.d.ts.map +0 -1
- package/dist/cjs-types/react/react_node.test.d.ts +0 -2
- package/dist/cjs-types/react/react_node.test.d.ts.map +0 -1
- package/dist/cjs-types/react/use_paginated_query.test.d.ts +0 -2
- package/dist/cjs-types/react/use_paginated_query.test.d.ts.map +0 -1
- package/dist/cjs-types/react/use_queries.test.d.ts +0 -5
- package/dist/cjs-types/react/use_queries.test.d.ts.map +0 -1
- package/dist/cjs-types/react/use_query.test.d.ts +0 -5
- package/dist/cjs-types/react/use_query.test.d.ts.map +0 -1
- package/dist/cjs-types/react/use_query_object_options.test.d.ts +0 -5
- package/dist/cjs-types/react/use_query_object_options.test.d.ts.map +0 -1
- package/dist/cjs-types/react/use_query_result.test.d.ts +0 -5
- package/dist/cjs-types/react/use_query_result.test.d.ts.map +0 -1
- package/dist/cjs-types/react-auth0/ConvexProviderWithAuth0.test.d.ts +0 -2
- package/dist/cjs-types/react-auth0/ConvexProviderWithAuth0.test.d.ts.map +0 -1
- package/dist/cjs-types/react-clerk/ConvexProviderWithClerk.test.d.ts +0 -2
- package/dist/cjs-types/react-clerk/ConvexProviderWithClerk.test.d.ts.map +0 -1
- package/dist/cjs-types/server/api.intersect.test.d.ts +0 -2
- package/dist/cjs-types/server/api.intersect.test.d.ts.map +0 -1
- package/dist/cjs-types/server/api.test.d.ts +0 -2
- package/dist/cjs-types/server/api.test.d.ts.map +0 -1
- package/dist/cjs-types/server/audit_logging.test.d.ts +0 -2
- package/dist/cjs-types/server/audit_logging.test.d.ts.map +0 -1
- package/dist/cjs-types/server/components/index.test.d.ts +0 -2
- package/dist/cjs-types/server/components/index.test.d.ts.map +0 -1
- package/dist/cjs-types/server/cron.test.d.ts +0 -2
- package/dist/cjs-types/server/cron.test.d.ts.map +0 -1
- package/dist/cjs-types/server/data_model.test.d.ts +0 -2
- package/dist/cjs-types/server/data_model.test.d.ts.map +0 -1
- package/dist/cjs-types/server/database.test.d.ts +0 -2
- package/dist/cjs-types/server/database.test.d.ts.map +0 -1
- package/dist/cjs-types/server/database_api.test.d.ts +0 -2
- package/dist/cjs-types/server/database_api.test.d.ts.map +0 -1
- package/dist/cjs-types/server/filter_builder.test.d.ts +0 -2
- package/dist/cjs-types/server/filter_builder.test.d.ts.map +0 -1
- package/dist/cjs-types/server/impl/actions_impl.test.d.ts +0 -2
- package/dist/cjs-types/server/impl/actions_impl.test.d.ts.map +0 -1
- package/dist/cjs-types/server/impl/filter_builder_impl.test.d.ts +0 -2
- package/dist/cjs-types/server/impl/filter_builder_impl.test.d.ts.map +0 -1
- package/dist/cjs-types/server/impl/query_impl.test.d.ts +0 -2
- package/dist/cjs-types/server/impl/query_impl.test.d.ts.map +0 -1
- package/dist/cjs-types/server/pagination.test.d.ts +0 -2
- package/dist/cjs-types/server/pagination.test.d.ts.map +0 -1
- package/dist/cjs-types/server/query.test.d.ts +0 -2
- package/dist/cjs-types/server/query.test.d.ts.map +0 -1
- package/dist/cjs-types/server/registration.test.d.ts +0 -2
- package/dist/cjs-types/server/registration.test.d.ts.map +0 -1
- package/dist/cjs-types/server/router.test.d.ts +0 -2
- package/dist/cjs-types/server/router.test.d.ts.map +0 -1
- package/dist/cjs-types/server/scheduler.test.d.ts +0 -2
- package/dist/cjs-types/server/scheduler.test.d.ts.map +0 -1
- package/dist/cjs-types/server/schema.test.d.ts +0 -2
- package/dist/cjs-types/server/schema.test.d.ts.map +0 -1
- package/dist/cjs-types/test/fake_watch.d.ts +0 -16
- package/dist/cjs-types/test/fake_watch.d.ts.map +0 -1
- package/dist/cjs-types/test/type_testing.d.ts +0 -9
- package/dist/cjs-types/test/type_testing.d.ts.map +0 -1
- package/dist/cjs-types/type_utils.test.d.ts +0 -2
- package/dist/cjs-types/type_utils.test.d.ts.map +0 -1
- package/dist/cjs-types/values/size.test.d.ts +0 -2
- package/dist/cjs-types/values/size.test.d.ts.map +0 -1
- package/dist/cjs-types/values/validator.test.d.ts +0 -2
- package/dist/cjs-types/values/validator.test.d.ts.map +0 -1
- package/dist/cjs-types/values/value.test.d.ts +0 -2
- package/dist/cjs-types/values/value.test.d.ts.map +0 -1
- package/dist/esm-types/browser/http_client.test.d.ts +0 -2
- package/dist/esm-types/browser/http_client.test.d.ts.map +0 -1
- package/dist/esm-types/browser/query_options.test.d.ts +0 -2
- package/dist/esm-types/browser/query_options.test.d.ts.map +0 -1
- package/dist/esm-types/browser/simple_client.test.d.ts +0 -2
- package/dist/esm-types/browser/simple_client.test.d.ts.map +0 -1
- package/dist/esm-types/browser/sync/client.test.d.ts +0 -5
- package/dist/esm-types/browser/sync/client.test.d.ts.map +0 -1
- package/dist/esm-types/browser/sync/client_node.test.d.ts +0 -2
- package/dist/esm-types/browser/sync/client_node.test.d.ts.map +0 -1
- package/dist/esm-types/browser/sync/client_node_test_helpers.d.ts +0 -44
- package/dist/esm-types/browser/sync/client_node_test_helpers.d.ts.map +0 -1
- package/dist/esm-types/browser/sync/local_state.test.d.ts +0 -2
- package/dist/esm-types/browser/sync/local_state.test.d.ts.map +0 -1
- package/dist/esm-types/browser/sync/optimistic_query_set.test.d.ts +0 -2
- package/dist/esm-types/browser/sync/optimistic_query_set.test.d.ts.map +0 -1
- package/dist/esm-types/browser/sync/paginated_query_client.test.d.ts +0 -2
- package/dist/esm-types/browser/sync/paginated_query_client.test.d.ts.map +0 -1
- package/dist/esm-types/browser/sync/protocol.test.d.ts +0 -5
- package/dist/esm-types/browser/sync/protocol.test.d.ts.map +0 -1
- package/dist/esm-types/browser/sync/request_manager.test.d.ts +0 -2
- package/dist/esm-types/browser/sync/request_manager.test.d.ts.map +0 -1
- package/dist/esm-types/bundler/fs.test.d.ts +0 -2
- package/dist/esm-types/bundler/fs.test.d.ts.map +0 -1
- package/dist/esm-types/bundler/index.test.d.ts +0 -2
- package/dist/esm-types/bundler/index.test.d.ts.map +0 -1
- package/dist/esm-types/cli/codegen_templates/api.test.d.ts +0 -2
- package/dist/esm-types/cli/codegen_templates/api.test.d.ts.map +0 -1
- package/dist/esm-types/cli/codegen_templates/common.test.d.ts +0 -2
- package/dist/esm-types/cli/codegen_templates/common.test.d.ts.map +0 -1
- package/dist/esm-types/cli/codegen_templates/templates.test.d.ts +0 -2
- package/dist/esm-types/cli/codegen_templates/templates.test.d.ts.map +0 -1
- package/dist/esm-types/cli/codegen_templates/validator_helpers.test.d.ts +0 -2
- package/dist/esm-types/cli/codegen_templates/validator_helpers.test.d.ts.map +0 -1
- package/dist/esm-types/cli/configure.test.d.ts +0 -2
- package/dist/esm-types/cli/configure.test.d.ts.map +0 -1
- package/dist/esm-types/cli/deploymentCreate.test.d.ts +0 -2
- package/dist/esm-types/cli/deploymentCreate.test.d.ts.map +0 -1
- package/dist/esm-types/cli/deploymentSelect.test.d.ts +0 -2
- package/dist/esm-types/cli/deploymentSelect.test.d.ts.map +0 -1
- package/dist/esm-types/cli/deploymentSelection.test.d.ts +0 -2
- package/dist/esm-types/cli/deploymentSelection.test.d.ts.map +0 -1
- package/dist/esm-types/cli/deploymentToken.test.d.ts +0 -2
- package/dist/esm-types/cli/deploymentToken.test.d.ts.map +0 -1
- package/dist/esm-types/cli/dev.test.d.ts +0 -2
- package/dist/esm-types/cli/dev.test.d.ts.map +0 -1
- package/dist/esm-types/cli/envDefault.test.d.ts +0 -2
- package/dist/esm-types/cli/envDefault.test.d.ts.map +0 -1
- package/dist/esm-types/cli/lib/aiFiles/agentsmd.test.d.ts +0 -2
- package/dist/esm-types/cli/lib/aiFiles/agentsmd.test.d.ts.map +0 -1
- package/dist/esm-types/cli/lib/aiFiles/claudemd.test.d.ts +0 -2
- package/dist/esm-types/cli/lib/aiFiles/claudemd.test.d.ts.map +0 -1
- package/dist/esm-types/cli/lib/aiFiles/guidelinesmd.test.d.ts +0 -2
- package/dist/esm-types/cli/lib/aiFiles/guidelinesmd.test.d.ts.map +0 -1
- package/dist/esm-types/cli/lib/aiFiles/index.test.d.ts +0 -2
- package/dist/esm-types/cli/lib/aiFiles/index.test.d.ts.map +0 -1
- package/dist/esm-types/cli/lib/aiFiles/integration.test.d.ts +0 -2
- package/dist/esm-types/cli/lib/aiFiles/integration.test.d.ts.map +0 -1
- package/dist/esm-types/cli/lib/aiFiles/prompt.test.d.ts +0 -2
- package/dist/esm-types/cli/lib/aiFiles/prompt.test.d.ts.map +0 -1
- package/dist/esm-types/cli/lib/aiFiles/state.test.d.ts +0 -2
- package/dist/esm-types/cli/lib/aiFiles/state.test.d.ts.map +0 -1
- package/dist/esm-types/cli/lib/aiFiles/utils.test.d.ts +0 -2
- package/dist/esm-types/cli/lib/aiFiles/utils.test.d.ts.map +0 -1
- package/dist/esm-types/cli/lib/codegen.test.d.ts +0 -2
- package/dist/esm-types/cli/lib/codegen.test.d.ts.map +0 -1
- package/dist/esm-types/cli/lib/components.test.d.ts +0 -2
- package/dist/esm-types/cli/lib/components.test.d.ts.map +0 -1
- package/dist/esm-types/cli/lib/config.test.d.ts +0 -2
- package/dist/esm-types/cli/lib/config.test.d.ts.map +0 -1
- package/dist/esm-types/cli/lib/deployment.test.d.ts +0 -2
- package/dist/esm-types/cli/lib/deployment.test.d.ts.map +0 -1
- package/dist/esm-types/cli/lib/deploymentSelector.test.d.ts +0 -2
- package/dist/esm-types/cli/lib/deploymentSelector.test.d.ts.map +0 -1
- package/dist/esm-types/cli/lib/env.test.d.ts +0 -2
- package/dist/esm-types/cli/lib/env.test.d.ts.map +0 -1
- package/dist/esm-types/cli/lib/expiration.test.d.ts +0 -2
- package/dist/esm-types/cli/lib/expiration.test.d.ts.map +0 -1
- package/dist/esm-types/cli/lib/extractDeploymentNameForWorkOS.test.d.ts +0 -2
- package/dist/esm-types/cli/lib/extractDeploymentNameForWorkOS.test.d.ts.map +0 -1
- package/dist/esm-types/cli/lib/formatEnvValueForDotfile.test.d.ts +0 -2
- package/dist/esm-types/cli/lib/formatEnvValueForDotfile.test.d.ts.map +0 -1
- package/dist/esm-types/cli/lib/formatTargetedDeployment.test.d.ts +0 -2
- package/dist/esm-types/cli/lib/formatTargetedDeployment.test.d.ts.map +0 -1
- package/dist/esm-types/cli/lib/fsUtils.test.d.ts +0 -2
- package/dist/esm-types/cli/lib/fsUtils.test.d.ts.map +0 -1
- package/dist/esm-types/cli/lib/generateDocs.test.d.ts +0 -2
- package/dist/esm-types/cli/lib/generateDocs.test.d.ts.map +0 -1
- package/dist/esm-types/cli/lib/indexes.test.d.ts +0 -2
- package/dist/esm-types/cli/lib/indexes.test.d.ts.map +0 -1
- package/dist/esm-types/cli/lib/localDeployment/run.test.d.ts +0 -2
- package/dist/esm-types/cli/lib/localDeployment/run.test.d.ts.map +0 -1
- package/dist/esm-types/cli/lib/localDeployment/secrets.test.d.ts +0 -2
- package/dist/esm-types/cli/lib/localDeployment/secrets.test.d.ts.map +0 -1
- package/dist/esm-types/cli/lib/run.test.d.ts +0 -2
- package/dist/esm-types/cli/lib/run.test.d.ts.map +0 -1
- package/dist/esm-types/cli/lib/runTestFunction.test.d.ts +0 -2
- package/dist/esm-types/cli/lib/runTestFunction.test.d.ts.map +0 -1
- package/dist/esm-types/cli/lib/typecheck.test.d.ts +0 -2
- package/dist/esm-types/cli/lib/typecheck.test.d.ts.map +0 -1
- package/dist/esm-types/cli/lib/updates.test.d.ts +0 -2
- package/dist/esm-types/cli/lib/updates.test.d.ts.map +0 -1
- package/dist/esm-types/cli/lib/utils/hash.test.d.ts +0 -2
- package/dist/esm-types/cli/lib/utils/hash.test.d.ts.map +0 -1
- package/dist/esm-types/cli/lib/utils/utils.test.d.ts +0 -2
- package/dist/esm-types/cli/lib/utils/utils.test.d.ts.map +0 -1
- package/dist/esm-types/cli/lib/versionApi.test.d.ts +0 -2
- package/dist/esm-types/cli/lib/versionApi.test.d.ts.map +0 -1
- package/dist/esm-types/cli/lib/workos/environmentApi.test.d.ts +0 -2
- package/dist/esm-types/cli/lib/workos/environmentApi.test.d.ts.map +0 -1
- package/dist/esm-types/cli/lib/workos/workos.test.d.ts +0 -2
- package/dist/esm-types/cli/lib/workos/workos.test.d.ts.map +0 -1
- package/dist/esm-types/cli/login.test.d.ts +0 -2
- package/dist/esm-types/cli/login.test.d.ts.map +0 -1
- package/dist/esm-types/common/index.test.d.ts +0 -2
- package/dist/esm-types/common/index.test.d.ts.map +0 -1
- package/dist/esm-types/nextjs/nextjs.test.d.ts +0 -2
- package/dist/esm-types/nextjs/nextjs.test.d.ts.map +0 -1
- package/dist/esm-types/react/ConvexAuthState.test.d.ts +0 -2
- package/dist/esm-types/react/ConvexAuthState.test.d.ts.map +0 -1
- package/dist/esm-types/react/auth_helpers.test.d.ts +0 -2
- package/dist/esm-types/react/auth_helpers.test.d.ts.map +0 -1
- package/dist/esm-types/react/auth_websocket.test.d.ts +0 -2
- package/dist/esm-types/react/auth_websocket.test.d.ts.map +0 -1
- package/dist/esm-types/react/client.test.d.ts +0 -2
- package/dist/esm-types/react/client.test.d.ts.map +0 -1
- package/dist/esm-types/react/client_provided_base_client.test.d.ts +0 -2
- package/dist/esm-types/react/client_provided_base_client.test.d.ts.map +0 -1
- package/dist/esm-types/react/queries_observer.test.d.ts +0 -2
- package/dist/esm-types/react/queries_observer.test.d.ts.map +0 -1
- package/dist/esm-types/react/react_node.test.d.ts +0 -2
- package/dist/esm-types/react/react_node.test.d.ts.map +0 -1
- package/dist/esm-types/react/use_paginated_query.test.d.ts +0 -2
- package/dist/esm-types/react/use_paginated_query.test.d.ts.map +0 -1
- package/dist/esm-types/react/use_queries.test.d.ts +0 -5
- package/dist/esm-types/react/use_queries.test.d.ts.map +0 -1
- package/dist/esm-types/react/use_query.test.d.ts +0 -5
- package/dist/esm-types/react/use_query.test.d.ts.map +0 -1
- package/dist/esm-types/react/use_query_object_options.test.d.ts +0 -5
- package/dist/esm-types/react/use_query_object_options.test.d.ts.map +0 -1
- package/dist/esm-types/react/use_query_result.test.d.ts +0 -5
- package/dist/esm-types/react/use_query_result.test.d.ts.map +0 -1
- package/dist/esm-types/react-auth0/ConvexProviderWithAuth0.test.d.ts +0 -2
- package/dist/esm-types/react-auth0/ConvexProviderWithAuth0.test.d.ts.map +0 -1
- package/dist/esm-types/react-clerk/ConvexProviderWithClerk.test.d.ts +0 -2
- package/dist/esm-types/react-clerk/ConvexProviderWithClerk.test.d.ts.map +0 -1
- package/dist/esm-types/server/api.intersect.test.d.ts +0 -2
- package/dist/esm-types/server/api.intersect.test.d.ts.map +0 -1
- package/dist/esm-types/server/api.test.d.ts +0 -2
- package/dist/esm-types/server/api.test.d.ts.map +0 -1
- package/dist/esm-types/server/audit_logging.test.d.ts +0 -2
- package/dist/esm-types/server/audit_logging.test.d.ts.map +0 -1
- package/dist/esm-types/server/components/index.test.d.ts +0 -2
- package/dist/esm-types/server/components/index.test.d.ts.map +0 -1
- package/dist/esm-types/server/cron.test.d.ts +0 -2
- package/dist/esm-types/server/cron.test.d.ts.map +0 -1
- package/dist/esm-types/server/data_model.test.d.ts +0 -2
- package/dist/esm-types/server/data_model.test.d.ts.map +0 -1
- package/dist/esm-types/server/database.test.d.ts +0 -2
- package/dist/esm-types/server/database.test.d.ts.map +0 -1
- package/dist/esm-types/server/database_api.test.d.ts +0 -2
- package/dist/esm-types/server/database_api.test.d.ts.map +0 -1
- package/dist/esm-types/server/filter_builder.test.d.ts +0 -2
- package/dist/esm-types/server/filter_builder.test.d.ts.map +0 -1
- package/dist/esm-types/server/impl/actions_impl.test.d.ts +0 -2
- package/dist/esm-types/server/impl/actions_impl.test.d.ts.map +0 -1
- package/dist/esm-types/server/impl/filter_builder_impl.test.d.ts +0 -2
- package/dist/esm-types/server/impl/filter_builder_impl.test.d.ts.map +0 -1
- package/dist/esm-types/server/impl/query_impl.test.d.ts +0 -2
- package/dist/esm-types/server/impl/query_impl.test.d.ts.map +0 -1
- package/dist/esm-types/server/pagination.test.d.ts +0 -2
- package/dist/esm-types/server/pagination.test.d.ts.map +0 -1
- package/dist/esm-types/server/query.test.d.ts +0 -2
- package/dist/esm-types/server/query.test.d.ts.map +0 -1
- package/dist/esm-types/server/registration.test.d.ts +0 -2
- package/dist/esm-types/server/registration.test.d.ts.map +0 -1
- package/dist/esm-types/server/router.test.d.ts +0 -2
- package/dist/esm-types/server/router.test.d.ts.map +0 -1
- package/dist/esm-types/server/scheduler.test.d.ts +0 -2
- package/dist/esm-types/server/scheduler.test.d.ts.map +0 -1
- package/dist/esm-types/server/schema.test.d.ts +0 -2
- package/dist/esm-types/server/schema.test.d.ts.map +0 -1
- package/dist/esm-types/test/fake_watch.d.ts +0 -16
- package/dist/esm-types/test/fake_watch.d.ts.map +0 -1
- package/dist/esm-types/test/type_testing.d.ts +0 -9
- package/dist/esm-types/test/type_testing.d.ts.map +0 -1
- package/dist/esm-types/type_utils.test.d.ts +0 -2
- package/dist/esm-types/type_utils.test.d.ts.map +0 -1
- package/dist/esm-types/values/size.test.d.ts +0 -2
- package/dist/esm-types/values/size.test.d.ts.map +0 -1
- package/dist/esm-types/values/validator.test.d.ts +0 -2
- package/dist/esm-types/values/validator.test.d.ts.map +0 -1
- package/dist/esm-types/values/value.test.d.ts +0 -2
- package/dist/esm-types/values/value.test.d.ts.map +0 -1
- package/src/browser/http_client.test.ts +0 -202
- package/src/browser/query_options.test.ts +0 -43
- package/src/browser/simple_client.test.ts +0 -104
- package/src/browser/sync/client.test.ts +0 -44
- package/src/browser/sync/client_node.test.ts +0 -1207
- package/src/browser/sync/client_node_test_helpers.ts +0 -200
- package/src/browser/sync/local_state.test.ts +0 -128
- package/src/browser/sync/optimistic_query_set.test.ts +0 -253
- package/src/browser/sync/paginated_query_client.test.ts +0 -597
- package/src/browser/sync/protocol.test.ts +0 -14
- package/src/browser/sync/request_manager.test.ts +0 -273
- package/src/bundler/fs.test.ts +0 -86
- package/src/bundler/index.test.ts +0 -210
- package/src/bundler/test_fixtures/js/project01/bar.js +0 -4
- package/src/bundler/test_fixtures/js/project01/file with spaces.js +0 -1
- package/src/bundler/test_fixtures/js/project01/foo.js +0 -9
- package/src/bundler/test_fixtures/js/project_with_https/https.js +0 -9
- package/src/bundler/test_fixtures/js/project_with_https_not_at_top_level/default.js +0 -3
- package/src/bundler/test_fixtures/js/project_with_https_not_at_top_level/more_code/https.js +0 -5
- package/src/bundler/test_fixtures/js/project_with_https_without_router/https.js +0 -1
- package/src/bundler/test_fixtures/js/project_with_node_shims/uses_node_shims.js +0 -4
- package/src/cli/codegen_templates/api.test.ts +0 -18
- package/src/cli/codegen_templates/common.test.ts +0 -52
- package/src/cli/codegen_templates/templates.test.ts +0 -16
- package/src/cli/codegen_templates/validator_helpers.test.ts +0 -31
- package/src/cli/configure.test.ts +0 -138
- package/src/cli/deploymentCreate.test.ts +0 -1376
- package/src/cli/deploymentSelect.test.ts +0 -1291
- package/src/cli/deploymentSelection.test.ts +0 -2546
- package/src/cli/deploymentToken.test.ts +0 -397
- package/src/cli/dev.test.ts +0 -157
- package/src/cli/envDefault.test.ts +0 -495
- package/src/cli/lib/__snapshots__/formatTargetedDeployment.test.ts.snap +0 -94
- package/src/cli/lib/aiFiles/agentsmd.test.ts +0 -133
- package/src/cli/lib/aiFiles/claudemd.test.ts +0 -92
- package/src/cli/lib/aiFiles/guidelinesmd.test.ts +0 -50
- package/src/cli/lib/aiFiles/index.test.ts +0 -986
- package/src/cli/lib/aiFiles/integration.test.ts +0 -692
- package/src/cli/lib/aiFiles/prompt.test.ts +0 -202
- package/src/cli/lib/aiFiles/state.test.ts +0 -305
- package/src/cli/lib/aiFiles/utils.test.ts +0 -50
- package/src/cli/lib/codegen.test.ts +0 -49
- package/src/cli/lib/components.test.ts +0 -227
- package/src/cli/lib/config.test.ts +0 -1026
- package/src/cli/lib/deployment.test.ts +0 -85
- package/src/cli/lib/deploymentSelector.test.ts +0 -107
- package/src/cli/lib/env.test.ts +0 -60
- package/src/cli/lib/expiration.test.ts +0 -159
- package/src/cli/lib/extractDeploymentNameForWorkOS.test.ts +0 -30
- package/src/cli/lib/formatEnvValueForDotfile.test.ts +0 -294
- package/src/cli/lib/formatTargetedDeployment.test.ts +0 -281
- package/src/cli/lib/fsUtils.test.ts +0 -67
- package/src/cli/lib/generateDocs.test.ts +0 -326
- package/src/cli/lib/indexes.test.ts +0 -77
- package/src/cli/lib/localDeployment/run.test.ts +0 -104
- package/src/cli/lib/localDeployment/secrets.test.ts +0 -53
- package/src/cli/lib/run.test.ts +0 -54
- package/src/cli/lib/runTestFunction.test.ts +0 -84
- package/src/cli/lib/typecheck.test.ts +0 -71
- package/src/cli/lib/updates.test.ts +0 -157
- package/src/cli/lib/utils/hash.test.ts +0 -25
- package/src/cli/lib/utils/utils.test.ts +0 -340
- package/src/cli/lib/versionApi.test.ts +0 -471
- package/src/cli/lib/workos/environmentApi.test.ts +0 -107
- package/src/cli/lib/workos/workos.test.ts +0 -242
- package/src/cli/login.test.ts +0 -261
- package/src/common/README.md +0 -2
- package/src/common/index.test.ts +0 -35
- package/src/nextjs/nextjs.test.tsx +0 -94
- package/src/react/ConvexAuthState.test.tsx +0 -702
- package/src/react/auth_helpers.test.tsx +0 -45
- package/src/react/auth_websocket.test.tsx +0 -1177
- package/src/react/client.test.tsx +0 -261
- package/src/react/client_provided_base_client.test.tsx +0 -174
- package/src/react/queries_observer.test.ts +0 -176
- package/src/react/react_node.test.ts +0 -78
- package/src/react/use_paginated_query.test.tsx +0 -1420
- package/src/react/use_queries.test.ts +0 -140
- package/src/react/use_query.test.ts +0 -71
- package/src/react/use_query_object_options.test.ts +0 -51
- package/src/react/use_query_result.test.ts +0 -75
- package/src/react-auth0/ConvexProviderWithAuth0.test.tsx +0 -17
- package/src/react-clerk/ConvexProviderWithClerk.test.tsx +0 -18
- package/src/server/README.md +0 -15
- package/src/server/api.intersect.test.ts +0 -109
- package/src/server/api.test.ts +0 -447
- package/src/server/audit_logging.test.ts +0 -131
- package/src/server/components/index.test.ts +0 -48
- package/src/server/cron.test.ts +0 -58
- package/src/server/data_model.test.ts +0 -221
- package/src/server/database.test.ts +0 -184
- package/src/server/database_api.test.ts +0 -439
- package/src/server/filter_builder.test.ts +0 -102
- package/src/server/impl/actions_impl.test.ts +0 -59
- package/src/server/impl/filter_builder_impl.test.ts +0 -13
- package/src/server/impl/query_impl.test.ts +0 -46
- package/src/server/pagination.test.ts +0 -49
- package/src/server/query.test.ts +0 -112
- package/src/server/registration.test.ts +0 -589
- package/src/server/router.test.ts +0 -148
- package/src/server/scheduler.test.ts +0 -31
- package/src/server/schema.test.ts +0 -1081
- package/src/test/fake_watch.ts +0 -54
- package/src/test/type_testing.ts +0 -21
- package/src/type_utils.test.ts +0 -62
- package/src/values/size.test.ts +0 -95
- package/src/values/validator.test.ts +0 -619
- package/src/values/value.test.ts +0 -232
- package/src/vendor/README.md +0 -18
- package/src/vendor/jwt-decode/README.md +0 -1
|
@@ -1,1207 +0,0 @@
|
|
|
1
|
-
import child_process from "child_process";
|
|
2
|
-
|
|
3
|
-
import { test, expect } from "vitest";
|
|
4
|
-
import { Long } from "../../vendor/long.js";
|
|
5
|
-
import { createHmac } from "crypto";
|
|
6
|
-
|
|
7
|
-
import { BaseConvexClient } from "./client.js";
|
|
8
|
-
import {
|
|
9
|
-
ActionRequest,
|
|
10
|
-
MutationRequest,
|
|
11
|
-
parseServerMessage,
|
|
12
|
-
RequestId,
|
|
13
|
-
WireServerMessage,
|
|
14
|
-
} from "./protocol.js";
|
|
15
|
-
import {
|
|
16
|
-
encodeServerMessage,
|
|
17
|
-
nodeWebSocket,
|
|
18
|
-
UpdateQueue,
|
|
19
|
-
withInMemoryWebSocket,
|
|
20
|
-
} from "./client_node_test_helpers.js";
|
|
21
|
-
import { FunctionArgs, makeFunctionReference } from "../../server/index.js";
|
|
22
|
-
|
|
23
|
-
test("BaseConvexClient protocol in node", async () => {
|
|
24
|
-
await withInMemoryWebSocket(async ({ address, receive }) => {
|
|
25
|
-
const client = new BaseConvexClient(
|
|
26
|
-
address,
|
|
27
|
-
() => {
|
|
28
|
-
// ignore updates.
|
|
29
|
-
},
|
|
30
|
-
{ webSocketConstructor: nodeWebSocket, unsavedChangesWarning: false },
|
|
31
|
-
);
|
|
32
|
-
|
|
33
|
-
expect((await receive()).type).toEqual("Connect");
|
|
34
|
-
expect((await receive()).type).toEqual("ModifyQuerySet");
|
|
35
|
-
|
|
36
|
-
await client.close();
|
|
37
|
-
});
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
// Run the test above in its own Node.js subprocess to ensure that it exists
|
|
41
|
-
// cleanly. This is the only point of this test.
|
|
42
|
-
test("BaseConvexClient closes cleanly", () => {
|
|
43
|
-
const p = child_process.spawnSync(
|
|
44
|
-
"node_modules/.bin/vitest",
|
|
45
|
-
[
|
|
46
|
-
"-t",
|
|
47
|
-
"BaseConvexClient protocol in node",
|
|
48
|
-
"src/browser/sync/client_node.test.ts",
|
|
49
|
-
],
|
|
50
|
-
{
|
|
51
|
-
encoding: "utf-8",
|
|
52
|
-
timeout: 35000,
|
|
53
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
54
|
-
env: {
|
|
55
|
-
...process.env,
|
|
56
|
-
FORCE_COLOR: "false",
|
|
57
|
-
},
|
|
58
|
-
},
|
|
59
|
-
);
|
|
60
|
-
|
|
61
|
-
// If this is a timeout, the test didn't exit cleanly! Check for timers.
|
|
62
|
-
expect(p.status).toBeFalsy();
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
test("Tests can encode longs in server messages", () => {
|
|
66
|
-
const orig: WireServerMessage = {
|
|
67
|
-
type: "Transition",
|
|
68
|
-
startVersion: { querySet: 0, identity: 0, ts: Long.fromNumber(0) },
|
|
69
|
-
endVersion: { querySet: 1, identity: 0, ts: Long.fromNumber(1) },
|
|
70
|
-
modifications: [
|
|
71
|
-
{
|
|
72
|
-
type: "QueryUpdated",
|
|
73
|
-
queryId: 0,
|
|
74
|
-
value: 0.0,
|
|
75
|
-
logLines: ["[LOG] 'Got stuff'"],
|
|
76
|
-
journal: null,
|
|
77
|
-
},
|
|
78
|
-
],
|
|
79
|
-
};
|
|
80
|
-
const encoded = encodeServerMessage(orig);
|
|
81
|
-
const decoded = parseServerMessage(JSON.parse(encoded));
|
|
82
|
-
expect(orig).toEqual(decoded);
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
// Detects an issue where actions sent before the WebSocket has connected
|
|
86
|
-
// are failed upon first connecting.
|
|
87
|
-
test("Actions can be called immediately", async () => {
|
|
88
|
-
await withInMemoryWebSocket(async ({ address, receive, send }) => {
|
|
89
|
-
const client = new BaseConvexClient(address, () => null, {
|
|
90
|
-
webSocketConstructor: nodeWebSocket,
|
|
91
|
-
unsavedChangesWarning: false,
|
|
92
|
-
});
|
|
93
|
-
const actionP = client.action("myAction", {});
|
|
94
|
-
|
|
95
|
-
expect((await receive()).type).toEqual("Connect");
|
|
96
|
-
expect((await receive()).type).toEqual("ModifyQuerySet");
|
|
97
|
-
const actionRequest = await receive();
|
|
98
|
-
expect(actionRequest.type).toEqual("Action");
|
|
99
|
-
const requestId = (actionRequest as ActionRequest).requestId;
|
|
100
|
-
|
|
101
|
-
send(actionSuccess(requestId));
|
|
102
|
-
expect(await actionP).toBe(42);
|
|
103
|
-
await client.close();
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
function actionSuccess(requestId: RequestId): WireServerMessage {
|
|
108
|
-
return {
|
|
109
|
-
type: "ActionResponse",
|
|
110
|
-
requestId: requestId,
|
|
111
|
-
success: true,
|
|
112
|
-
result: 42,
|
|
113
|
-
logLines: [],
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
test("maxObservedTimestamp is updated on mutation and transition", async () => {
|
|
118
|
-
await withInMemoryWebSocket(async ({ address, receive, send }) => {
|
|
119
|
-
const client = new BaseConvexClient(address, () => null, {
|
|
120
|
-
webSocketConstructor: nodeWebSocket,
|
|
121
|
-
unsavedChangesWarning: false,
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
expect(client.getMaxObservedTimestamp()).toBeUndefined();
|
|
125
|
-
|
|
126
|
-
const mutationP = client.mutation("myMutation", {});
|
|
127
|
-
|
|
128
|
-
expect((await receive()).type).toEqual("Connect");
|
|
129
|
-
expect((await receive()).type).toEqual("ModifyQuerySet");
|
|
130
|
-
const mutationRequest = await receive();
|
|
131
|
-
expect(mutationRequest.type).toEqual("Mutation");
|
|
132
|
-
const requestId = (mutationRequest as MutationRequest).requestId;
|
|
133
|
-
|
|
134
|
-
// Send a mutation, should update the max observed timestamp.
|
|
135
|
-
send({
|
|
136
|
-
type: "MutationResponse",
|
|
137
|
-
requestId: requestId,
|
|
138
|
-
success: true,
|
|
139
|
-
result: 42,
|
|
140
|
-
ts: Long.fromNumber(1000),
|
|
141
|
-
logLines: [],
|
|
142
|
-
});
|
|
143
|
-
// Wait until getMaxObservedTimestamp() gets updated
|
|
144
|
-
for (let i = 0; i < 10; i++) {
|
|
145
|
-
if (client.getMaxObservedTimestamp()) {
|
|
146
|
-
break;
|
|
147
|
-
}
|
|
148
|
-
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
149
|
-
}
|
|
150
|
-
expect(client.getMaxObservedTimestamp()).toEqual(Long.fromNumber(1000));
|
|
151
|
-
|
|
152
|
-
// Send a transition from before the mutation. Should not update the max
|
|
153
|
-
// observed timestamp nor resolve the mutation.
|
|
154
|
-
send({
|
|
155
|
-
type: "Transition",
|
|
156
|
-
startVersion: {
|
|
157
|
-
querySet: 0,
|
|
158
|
-
ts: Long.fromNumber(0),
|
|
159
|
-
identity: 0,
|
|
160
|
-
},
|
|
161
|
-
endVersion: {
|
|
162
|
-
querySet: 0,
|
|
163
|
-
ts: Long.fromNumber(500),
|
|
164
|
-
identity: 0,
|
|
165
|
-
},
|
|
166
|
-
modifications: [],
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
// Wait a bit and confirm the max timestamp has not been updated.
|
|
170
|
-
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
171
|
-
expect(client.getMaxObservedTimestamp()).toEqual(Long.fromNumber(1000));
|
|
172
|
-
|
|
173
|
-
// Send another transition with higher timestamp. This should resolve the
|
|
174
|
-
// transition and advanced the max observable timestamp.
|
|
175
|
-
send({
|
|
176
|
-
type: "Transition",
|
|
177
|
-
startVersion: {
|
|
178
|
-
querySet: 0,
|
|
179
|
-
ts: Long.fromNumber(500),
|
|
180
|
-
identity: 0,
|
|
181
|
-
},
|
|
182
|
-
endVersion: {
|
|
183
|
-
querySet: 0,
|
|
184
|
-
ts: Long.fromNumber(2000),
|
|
185
|
-
identity: 0,
|
|
186
|
-
},
|
|
187
|
-
modifications: [],
|
|
188
|
-
});
|
|
189
|
-
// Wait until the mutation is resolved.
|
|
190
|
-
expect(await mutationP).toBe(42);
|
|
191
|
-
expect(client.getMaxObservedTimestamp()).toEqual(Long.fromNumber(2000));
|
|
192
|
-
|
|
193
|
-
await client.close();
|
|
194
|
-
});
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
const apiQueriesA = makeFunctionReference<"query", {}, string>("queries:a");
|
|
198
|
-
const apiQueriesB = makeFunctionReference<"query", {}, string>("queries:b");
|
|
199
|
-
|
|
200
|
-
const _apiMutationsZ = makeFunctionReference<"mutation", {}>("mutations:z");
|
|
201
|
-
|
|
202
|
-
/**
|
|
203
|
-
* Regression test for
|
|
204
|
-
* - subscribing to query a
|
|
205
|
-
* - running a mutation that sets an optimistic update for queries a and b
|
|
206
|
-
* - receiving an update for a
|
|
207
|
-
*/
|
|
208
|
-
test("Setting optimistic updates for queries that have not yet been subscribed to", async () => {
|
|
209
|
-
await withInMemoryWebSocket(async ({ address, receive, send }) => {
|
|
210
|
-
const q = new UpdateQueue(10);
|
|
211
|
-
|
|
212
|
-
const client = new BaseConvexClient(
|
|
213
|
-
address,
|
|
214
|
-
(queryTokens) => {
|
|
215
|
-
q.onTransition(client)(queryTokens);
|
|
216
|
-
},
|
|
217
|
-
{
|
|
218
|
-
webSocketConstructor: nodeWebSocket,
|
|
219
|
-
unsavedChangesWarning: false,
|
|
220
|
-
verbose: true,
|
|
221
|
-
},
|
|
222
|
-
);
|
|
223
|
-
|
|
224
|
-
client.subscribe("queries:a", {});
|
|
225
|
-
|
|
226
|
-
expect((await receive()).type).toEqual("Connect");
|
|
227
|
-
const modify = await receive();
|
|
228
|
-
|
|
229
|
-
expect(modify.type).toEqual("ModifyQuerySet");
|
|
230
|
-
if (modify.type !== "ModifyQuerySet") {
|
|
231
|
-
return;
|
|
232
|
-
}
|
|
233
|
-
expect(modify.modifications.length).toBe(1);
|
|
234
|
-
expect(modify.modifications).toEqual([
|
|
235
|
-
{
|
|
236
|
-
type: "Add",
|
|
237
|
-
queryId: 0,
|
|
238
|
-
udfPath: "queries:a",
|
|
239
|
-
args: [{}],
|
|
240
|
-
},
|
|
241
|
-
]);
|
|
242
|
-
|
|
243
|
-
// Now that we're subscribed to queries:a,
|
|
244
|
-
// run a mutation that, optimistically and on the server,
|
|
245
|
-
// - modifies q1
|
|
246
|
-
// - modifies q2
|
|
247
|
-
|
|
248
|
-
const mutP = client.mutation(
|
|
249
|
-
"mutations:z",
|
|
250
|
-
{},
|
|
251
|
-
{
|
|
252
|
-
optimisticUpdate: (
|
|
253
|
-
localStore,
|
|
254
|
-
_args: FunctionArgs<typeof _apiMutationsZ>,
|
|
255
|
-
) => {
|
|
256
|
-
const curA = localStore.getQuery(apiQueriesA, {});
|
|
257
|
-
localStore.setQuery(
|
|
258
|
-
apiQueriesA,
|
|
259
|
-
{},
|
|
260
|
-
curA === undefined ? "a local" : `${curA} with a local applied`,
|
|
261
|
-
);
|
|
262
|
-
const curB = localStore.getQuery(apiQueriesB, {});
|
|
263
|
-
localStore.setQuery(
|
|
264
|
-
apiQueriesB,
|
|
265
|
-
{},
|
|
266
|
-
curB === undefined ? "b local" : `${curB} with b local applied`,
|
|
267
|
-
);
|
|
268
|
-
},
|
|
269
|
-
},
|
|
270
|
-
);
|
|
271
|
-
|
|
272
|
-
// Synchronously, the local store should update and the changes should be broadcast.
|
|
273
|
-
expect(client.localQueryResult("queries:a", {})).toEqual("a local");
|
|
274
|
-
// We haven't actually subscribed to this query but it had a value set in an optimistic update.
|
|
275
|
-
expect(client.localQueryResult("queries:b", {})).toEqual("b local");
|
|
276
|
-
const update1 = await q.updatePromises[0];
|
|
277
|
-
expect(q.updates).toHaveLength(1);
|
|
278
|
-
expect(update1).toEqual({
|
|
279
|
-
'{"udfPath":"queries:a","args":{}}': "a local",
|
|
280
|
-
'{"udfPath":"queries:b","args":{}}': "b local",
|
|
281
|
-
});
|
|
282
|
-
|
|
283
|
-
// Now a transition arrives containing only an update to query a.
|
|
284
|
-
// This previously crashed this execution context.
|
|
285
|
-
send({
|
|
286
|
-
type: "Transition",
|
|
287
|
-
startVersion: {
|
|
288
|
-
querySet: 0,
|
|
289
|
-
identity: 0,
|
|
290
|
-
ts: Long.fromNumber(0),
|
|
291
|
-
},
|
|
292
|
-
endVersion: {
|
|
293
|
-
querySet: 1,
|
|
294
|
-
identity: 0,
|
|
295
|
-
ts: Long.fromNumber(100),
|
|
296
|
-
},
|
|
297
|
-
modifications: [
|
|
298
|
-
{
|
|
299
|
-
type: "QueryUpdated",
|
|
300
|
-
queryId: 0,
|
|
301
|
-
value: "a server",
|
|
302
|
-
logLines: [],
|
|
303
|
-
journal: null,
|
|
304
|
-
},
|
|
305
|
-
],
|
|
306
|
-
});
|
|
307
|
-
|
|
308
|
-
const update2 = await q.updatePromises[1];
|
|
309
|
-
expect(update2).toEqual({
|
|
310
|
-
'{"udfPath":"queries:a","args":{}}': "a server with a local applied",
|
|
311
|
-
'{"udfPath":"queries:b","args":{}}': "b local",
|
|
312
|
-
});
|
|
313
|
-
expect(q.allResults).toEqual({
|
|
314
|
-
'{"udfPath":"queries:a","args":{}}': "a server with a local applied",
|
|
315
|
-
'{"udfPath":"queries:b","args":{}}': "b local",
|
|
316
|
-
});
|
|
317
|
-
expect(q.updates).toHaveLength(2);
|
|
318
|
-
|
|
319
|
-
const mutationRequest = await receive();
|
|
320
|
-
expect(mutationRequest.type).toEqual("Mutation");
|
|
321
|
-
expect(mutationRequest).toEqual({
|
|
322
|
-
type: "Mutation",
|
|
323
|
-
requestId: 0,
|
|
324
|
-
udfPath: "mutations:z",
|
|
325
|
-
args: [{}],
|
|
326
|
-
});
|
|
327
|
-
|
|
328
|
-
// Now the server sends:
|
|
329
|
-
|
|
330
|
-
// 1. MutationResponse saying the mutation has run
|
|
331
|
-
send({
|
|
332
|
-
type: "MutationResponse",
|
|
333
|
-
requestId: 0,
|
|
334
|
-
success: true,
|
|
335
|
-
result: null,
|
|
336
|
-
ts: Long.fromNumber(200), // "ZDhuVB3CRxg=", in example
|
|
337
|
-
logLines: [],
|
|
338
|
-
});
|
|
339
|
-
|
|
340
|
-
// 2. Transition bringing us up to date with the mutation
|
|
341
|
-
send({
|
|
342
|
-
type: "Transition",
|
|
343
|
-
startVersion: { querySet: 1, identity: 0, ts: Long.fromNumber(100) },
|
|
344
|
-
endVersion: { querySet: 1, identity: 0, ts: Long.fromNumber(200) },
|
|
345
|
-
modifications: [
|
|
346
|
-
{
|
|
347
|
-
type: "QueryUpdated",
|
|
348
|
-
queryId: 0,
|
|
349
|
-
value: "a server",
|
|
350
|
-
logLines: [],
|
|
351
|
-
journal: null,
|
|
352
|
-
},
|
|
353
|
-
],
|
|
354
|
-
});
|
|
355
|
-
|
|
356
|
-
expect(await q.updatePromises[2]).toEqual({
|
|
357
|
-
'{"udfPath":"queries:a","args":{}}': "a server",
|
|
358
|
-
// Now there's no more optimistic value for b!
|
|
359
|
-
'{"udfPath":"queries:b","args":{}}': undefined,
|
|
360
|
-
});
|
|
361
|
-
|
|
362
|
-
// After all that the mutation should resolve.
|
|
363
|
-
await mutP;
|
|
364
|
-
|
|
365
|
-
await client.close();
|
|
366
|
-
}, true);
|
|
367
|
-
});
|
|
368
|
-
|
|
369
|
-
/**
|
|
370
|
-
* Regression test for
|
|
371
|
-
* - subscribing to slow query a
|
|
372
|
-
* - subscribing to fast query b
|
|
373
|
-
* - receiving an update for b, without a
|
|
374
|
-
*/
|
|
375
|
-
test("Query results coming back out of order (fast query first, slower query later)", async () => {
|
|
376
|
-
await withInMemoryWebSocket(async ({ address, receive, send }) => {
|
|
377
|
-
const q = new UpdateQueue(10);
|
|
378
|
-
|
|
379
|
-
const client = new BaseConvexClient(
|
|
380
|
-
address,
|
|
381
|
-
(queryTokens) => {
|
|
382
|
-
q.onTransition(client)(queryTokens);
|
|
383
|
-
},
|
|
384
|
-
{
|
|
385
|
-
webSocketConstructor: nodeWebSocket,
|
|
386
|
-
unsavedChangesWarning: false,
|
|
387
|
-
verbose: true,
|
|
388
|
-
},
|
|
389
|
-
);
|
|
390
|
-
|
|
391
|
-
client.subscribe("queries:slow", {});
|
|
392
|
-
|
|
393
|
-
expect((await receive()).type).toEqual("Connect");
|
|
394
|
-
const modify = await receive();
|
|
395
|
-
|
|
396
|
-
expect(modify.type).toEqual("ModifyQuerySet");
|
|
397
|
-
if (modify.type !== "ModifyQuerySet") {
|
|
398
|
-
return;
|
|
399
|
-
}
|
|
400
|
-
expect(modify.modifications.length).toBe(1);
|
|
401
|
-
expect(modify.modifications).toEqual([
|
|
402
|
-
{
|
|
403
|
-
type: "Add",
|
|
404
|
-
queryId: 0,
|
|
405
|
-
udfPath: "queries:slow",
|
|
406
|
-
args: [{}],
|
|
407
|
-
},
|
|
408
|
-
]);
|
|
409
|
-
|
|
410
|
-
// Later we subscribe to a fast query
|
|
411
|
-
client.subscribe("queries:fast", {});
|
|
412
|
-
|
|
413
|
-
const modify2 = await receive();
|
|
414
|
-
|
|
415
|
-
expect(modify2.type).toEqual("ModifyQuerySet");
|
|
416
|
-
if (modify2.type !== "ModifyQuerySet") {
|
|
417
|
-
return;
|
|
418
|
-
}
|
|
419
|
-
expect(modify2.modifications.length).toBe(1);
|
|
420
|
-
expect(modify2.modifications).toEqual([
|
|
421
|
-
{
|
|
422
|
-
type: "Add",
|
|
423
|
-
queryId: 1,
|
|
424
|
-
udfPath: "queries:fast",
|
|
425
|
-
args: [{}],
|
|
426
|
-
},
|
|
427
|
-
]);
|
|
428
|
-
|
|
429
|
-
// Once the client has subscribed to queries:slow and queries:fast but has no results for either,
|
|
430
|
-
// the server is allowed to respond with a Transition that contains no mutations, "acknowledging"
|
|
431
|
-
// the slow query subscription but not responding with a value for it.
|
|
432
|
-
send({
|
|
433
|
-
type: "Transition",
|
|
434
|
-
startVersion: { querySet: 0, identity: 0, ts: Long.fromNumber(0) },
|
|
435
|
-
endVersion: { querySet: 1, identity: 0, ts: Long.fromNumber(100) },
|
|
436
|
-
modifications: [
|
|
437
|
-
// This is unusual, but allowed.
|
|
438
|
-
],
|
|
439
|
-
});
|
|
440
|
-
|
|
441
|
-
// TODO test what happens when this first Transition contains an update for a query that does not exist in this query set.
|
|
442
|
-
|
|
443
|
-
// apparently this triggers an update???
|
|
444
|
-
const update1 = await q.awaitPromiseAtIndexWithTimeout(0);
|
|
445
|
-
expect(update1).toEqual({});
|
|
446
|
-
|
|
447
|
-
// Later the server sends a fast result
|
|
448
|
-
send({
|
|
449
|
-
type: "Transition",
|
|
450
|
-
startVersion: { querySet: 1, identity: 0, ts: Long.fromNumber(100) },
|
|
451
|
-
endVersion: { querySet: 2, identity: 0, ts: Long.fromNumber(200) },
|
|
452
|
-
modifications: [
|
|
453
|
-
{
|
|
454
|
-
type: "QueryUpdated",
|
|
455
|
-
queryId: 1,
|
|
456
|
-
value: "fast result",
|
|
457
|
-
logLines: [],
|
|
458
|
-
journal: null,
|
|
459
|
-
},
|
|
460
|
-
],
|
|
461
|
-
});
|
|
462
|
-
const update2 = await q.awaitPromiseAtIndexWithTimeout(1);
|
|
463
|
-
|
|
464
|
-
expect(update2).toStrictEqual({
|
|
465
|
-
'{"udfPath":"queries:fast","args":{}}': "fast result",
|
|
466
|
-
});
|
|
467
|
-
expect(q.allResults).toStrictEqual({
|
|
468
|
-
'{"udfPath":"queries:fast","args":{}}': "fast result",
|
|
469
|
-
});
|
|
470
|
-
expect(q.updates).toHaveLength(2);
|
|
471
|
-
|
|
472
|
-
expect(client.localQueryResult("queries:fast", {})).toEqual("fast result");
|
|
473
|
-
expect(client.localQueryResult("queries:slow", {})).toEqual(undefined);
|
|
474
|
-
|
|
475
|
-
// Later the server sends a slow result
|
|
476
|
-
send({
|
|
477
|
-
type: "Transition",
|
|
478
|
-
startVersion: { querySet: 2, identity: 0, ts: Long.fromNumber(200) },
|
|
479
|
-
endVersion: { querySet: 2, identity: 0, ts: Long.fromNumber(300) },
|
|
480
|
-
modifications: [
|
|
481
|
-
{
|
|
482
|
-
type: "QueryUpdated",
|
|
483
|
-
queryId: 0,
|
|
484
|
-
value: "slow result",
|
|
485
|
-
logLines: [],
|
|
486
|
-
journal: null,
|
|
487
|
-
},
|
|
488
|
-
],
|
|
489
|
-
});
|
|
490
|
-
const update3 = await q.awaitPromiseAtIndexWithTimeout(2);
|
|
491
|
-
|
|
492
|
-
expect(update3).toStrictEqual({
|
|
493
|
-
'{"udfPath":"queries:slow","args":{}}': "slow result",
|
|
494
|
-
});
|
|
495
|
-
expect(q.allResults).toStrictEqual({
|
|
496
|
-
'{"udfPath":"queries:fast","args":{}}': "fast result",
|
|
497
|
-
'{"udfPath":"queries:slow","args":{}}': "slow result",
|
|
498
|
-
});
|
|
499
|
-
expect(q.updates).toHaveLength(3);
|
|
500
|
-
|
|
501
|
-
expect(client.localQueryResult("queries:fast", {})).toEqual("fast result");
|
|
502
|
-
expect(client.localQueryResult("queries:slow", {})).toEqual("slow result");
|
|
503
|
-
|
|
504
|
-
await client.close();
|
|
505
|
-
}, true);
|
|
506
|
-
});
|
|
507
|
-
|
|
508
|
-
/**
|
|
509
|
-
* Test to characterize behavior so we know if it changes. This behavior is not relied upon,
|
|
510
|
-
* we consider it a protocol error, but it does happen to work.
|
|
511
|
-
*
|
|
512
|
-
* - subscribe to slow query (query 0) (querySet 1)
|
|
513
|
-
* - subscribe to fast query (query 1) (querySet 2)
|
|
514
|
-
* - server sends message transitioning to querySet 1 that includes result for only the fast query (!)
|
|
515
|
-
* This works! The fast query result is not dropped on the floor.
|
|
516
|
-
* - server send message transitioning to querySet 2, plus it includes slow query.
|
|
517
|
-
*/
|
|
518
|
-
test("Transition contains result for query not in purported query set version", async () => {
|
|
519
|
-
await withInMemoryWebSocket(async ({ address, receive, send }) => {
|
|
520
|
-
const q = new UpdateQueue(10);
|
|
521
|
-
|
|
522
|
-
const client = new BaseConvexClient(
|
|
523
|
-
address,
|
|
524
|
-
(queryTokens) => {
|
|
525
|
-
q.onTransition(client)(queryTokens);
|
|
526
|
-
},
|
|
527
|
-
{
|
|
528
|
-
webSocketConstructor: nodeWebSocket,
|
|
529
|
-
unsavedChangesWarning: false,
|
|
530
|
-
verbose: true,
|
|
531
|
-
},
|
|
532
|
-
);
|
|
533
|
-
|
|
534
|
-
// Subscribe to slow query first
|
|
535
|
-
client.subscribe("queries:slow", {});
|
|
536
|
-
|
|
537
|
-
expect((await receive()).type).toEqual("Connect");
|
|
538
|
-
const modify1 = await receive();
|
|
539
|
-
|
|
540
|
-
expect(modify1.type).toEqual("ModifyQuerySet");
|
|
541
|
-
if (modify1.type !== "ModifyQuerySet") {
|
|
542
|
-
return;
|
|
543
|
-
}
|
|
544
|
-
expect(modify1.modifications).toEqual([
|
|
545
|
-
{
|
|
546
|
-
type: "Add",
|
|
547
|
-
queryId: 0,
|
|
548
|
-
udfPath: "queries:slow",
|
|
549
|
-
args: [{}],
|
|
550
|
-
},
|
|
551
|
-
]);
|
|
552
|
-
|
|
553
|
-
// Then subscribe to fast query
|
|
554
|
-
client.subscribe("queries:fast", {});
|
|
555
|
-
|
|
556
|
-
const modify2 = await receive();
|
|
557
|
-
expect(modify2.type).toEqual("ModifyQuerySet");
|
|
558
|
-
if (modify2.type !== "ModifyQuerySet") {
|
|
559
|
-
return;
|
|
560
|
-
}
|
|
561
|
-
expect(modify2.modifications).toEqual([
|
|
562
|
-
{
|
|
563
|
-
type: "Add",
|
|
564
|
-
queryId: 1,
|
|
565
|
-
udfPath: "queries:fast",
|
|
566
|
-
args: [{}],
|
|
567
|
-
},
|
|
568
|
-
]);
|
|
569
|
-
|
|
570
|
-
// Server sends malformed Transition: claims querySet version 1 (only slow query)
|
|
571
|
-
// but includes result for queryId 1 (fast query) which should be in querySet version 2
|
|
572
|
-
send({
|
|
573
|
-
type: "Transition",
|
|
574
|
-
startVersion: { querySet: 0, identity: 0, ts: Long.fromNumber(0) },
|
|
575
|
-
endVersion: { querySet: 1, identity: 0, ts: Long.fromNumber(100) },
|
|
576
|
-
modifications: [
|
|
577
|
-
{
|
|
578
|
-
type: "QueryUpdated",
|
|
579
|
-
queryId: 1, // But provides result for fast query!
|
|
580
|
-
value: "fast result from malformed transition",
|
|
581
|
-
logLines: [],
|
|
582
|
-
journal: null,
|
|
583
|
-
},
|
|
584
|
-
],
|
|
585
|
-
});
|
|
586
|
-
|
|
587
|
-
// Client should still process the result (the client is forgiving)
|
|
588
|
-
const update1 = await q.awaitPromiseAtIndexWithTimeout(0);
|
|
589
|
-
expect(update1).toEqual({
|
|
590
|
-
'{"udfPath":"queries:fast","args":{}}':
|
|
591
|
-
"fast result from malformed transition",
|
|
592
|
-
});
|
|
593
|
-
|
|
594
|
-
// The fast query result should be available
|
|
595
|
-
expect(client.localQueryResult("queries:fast", {})).toEqual(
|
|
596
|
-
"fast result from malformed transition",
|
|
597
|
-
);
|
|
598
|
-
expect(client.localQueryResult("queries:slow", {})).toEqual(undefined);
|
|
599
|
-
|
|
600
|
-
// Next transition should work normally
|
|
601
|
-
send({
|
|
602
|
-
type: "Transition",
|
|
603
|
-
startVersion: { querySet: 1, identity: 0, ts: Long.fromNumber(100) },
|
|
604
|
-
endVersion: { querySet: 2, identity: 0, ts: Long.fromNumber(200) },
|
|
605
|
-
modifications: [
|
|
606
|
-
{
|
|
607
|
-
type: "QueryUpdated",
|
|
608
|
-
queryId: 0,
|
|
609
|
-
value: "slow result",
|
|
610
|
-
logLines: [],
|
|
611
|
-
journal: null,
|
|
612
|
-
},
|
|
613
|
-
],
|
|
614
|
-
});
|
|
615
|
-
|
|
616
|
-
const update2 = await q.awaitPromiseAtIndexWithTimeout(1);
|
|
617
|
-
expect(update2).toEqual({
|
|
618
|
-
'{"udfPath":"queries:slow","args":{}}': "slow result",
|
|
619
|
-
});
|
|
620
|
-
|
|
621
|
-
// Both results should be available and the fast query result should persist
|
|
622
|
-
expect(client.localQueryResult("queries:fast", {})).toEqual(
|
|
623
|
-
"fast result from malformed transition",
|
|
624
|
-
);
|
|
625
|
-
expect(client.localQueryResult("queries:slow", {})).toEqual("slow result");
|
|
626
|
-
|
|
627
|
-
await client.close();
|
|
628
|
-
}, true);
|
|
629
|
-
});
|
|
630
|
-
|
|
631
|
-
/**
|
|
632
|
-
* Test to characterize existing behavior that we may want to change.
|
|
633
|
-
*
|
|
634
|
-
* - subscribe to a query
|
|
635
|
-
* - get a result
|
|
636
|
-
* - get a new "result" (Transition with QueryRemoved modification) that, if you didn't know better,
|
|
637
|
-
* you might send from the server to indicate this result is now loading
|
|
638
|
-
* - get a new real result (Transition with QueryUpdated modification)
|
|
639
|
-
*
|
|
640
|
-
* One might expect the client to publish updates "result, loading, result,"
|
|
641
|
-
* but the client only publishes "result."
|
|
642
|
-
*
|
|
643
|
-
* Currently the client stops tracking a query when it receives QueryRemoved
|
|
644
|
-
* from the server (it stops tracking it in the RemoteQuerySet).
|
|
645
|
-
*/
|
|
646
|
-
test("Query unsubscription triggers empty transition for listeners", async () => {
|
|
647
|
-
await withInMemoryWebSocket(async ({ address, receive, send }) => {
|
|
648
|
-
const q = new UpdateQueue(10);
|
|
649
|
-
|
|
650
|
-
const client = new BaseConvexClient(
|
|
651
|
-
address,
|
|
652
|
-
(queryTokens) => {
|
|
653
|
-
q.onTransition(client)(queryTokens);
|
|
654
|
-
},
|
|
655
|
-
{
|
|
656
|
-
webSocketConstructor: nodeWebSocket,
|
|
657
|
-
unsavedChangesWarning: false,
|
|
658
|
-
verbose: true,
|
|
659
|
-
},
|
|
660
|
-
);
|
|
661
|
-
|
|
662
|
-
client.subscribe("queries:test", {});
|
|
663
|
-
|
|
664
|
-
expect((await receive()).type).toEqual("Connect");
|
|
665
|
-
const modify1 = await receive();
|
|
666
|
-
|
|
667
|
-
expect(modify1.type).toEqual("ModifyQuerySet");
|
|
668
|
-
if (modify1.type !== "ModifyQuerySet") {
|
|
669
|
-
return;
|
|
670
|
-
}
|
|
671
|
-
expect(modify1.modifications).toEqual([
|
|
672
|
-
{
|
|
673
|
-
type: "Add",
|
|
674
|
-
queryId: 0,
|
|
675
|
-
udfPath: "queries:test",
|
|
676
|
-
args: [{}],
|
|
677
|
-
},
|
|
678
|
-
]);
|
|
679
|
-
|
|
680
|
-
// Server sends result for the query
|
|
681
|
-
send({
|
|
682
|
-
type: "Transition",
|
|
683
|
-
startVersion: { querySet: 0, identity: 0, ts: Long.fromNumber(0) },
|
|
684
|
-
endVersion: { querySet: 1, identity: 0, ts: Long.fromNumber(100) },
|
|
685
|
-
modifications: [
|
|
686
|
-
{
|
|
687
|
-
type: "QueryUpdated",
|
|
688
|
-
queryId: 0,
|
|
689
|
-
value: "test result",
|
|
690
|
-
logLines: [],
|
|
691
|
-
journal: null,
|
|
692
|
-
},
|
|
693
|
-
],
|
|
694
|
-
});
|
|
695
|
-
|
|
696
|
-
const update1 = await q.awaitPromiseAtIndexWithTimeout(0);
|
|
697
|
-
expect(update1).toEqual({
|
|
698
|
-
'{"udfPath":"queries:test","args":{}}': "test result",
|
|
699
|
-
});
|
|
700
|
-
expect(q.allResults).toStrictEqual({
|
|
701
|
-
'{"udfPath":"queries:test","args":{}}': "test result",
|
|
702
|
-
});
|
|
703
|
-
expect(client.localQueryResult("queries:test", {})).toEqual("test result");
|
|
704
|
-
|
|
705
|
-
// "QueryRemoved" from the server communicates that this query is now in an loading state.
|
|
706
|
-
send({
|
|
707
|
-
type: "Transition",
|
|
708
|
-
startVersion: { querySet: 1, identity: 0, ts: Long.fromNumber(100) },
|
|
709
|
-
endVersion: { querySet: 1, identity: 0, ts: Long.fromNumber(200) },
|
|
710
|
-
modifications: [
|
|
711
|
-
{
|
|
712
|
-
type: "QueryRemoved",
|
|
713
|
-
queryId: 0,
|
|
714
|
-
},
|
|
715
|
-
],
|
|
716
|
-
});
|
|
717
|
-
|
|
718
|
-
// The update received contains nothing so there's no notification
|
|
719
|
-
// that this has gone back to undefined!
|
|
720
|
-
const update2 = await q.awaitPromiseAtIndexWithTimeout(1);
|
|
721
|
-
|
|
722
|
-
// What we wish happened, if removing a query is supposed to be
|
|
723
|
-
// the same as setting it to undefined.
|
|
724
|
-
/*
|
|
725
|
-
expect(update2).toStrictEqual({
|
|
726
|
-
'{"udfPath":"queries:test","args":{}}': undefined,
|
|
727
|
-
});
|
|
728
|
-
*/
|
|
729
|
-
// what actually happens
|
|
730
|
-
expect(update2).toStrictEqual({});
|
|
731
|
-
|
|
732
|
-
expect(q.updates).toHaveLength(2);
|
|
733
|
-
|
|
734
|
-
// The query result is no longer available locally after removal...
|
|
735
|
-
expect(client.localQueryResult("queries:test", {})).toEqual(undefined);
|
|
736
|
-
|
|
737
|
-
// ...but anyone listening won't have been updated.
|
|
738
|
-
expect(q.allResults).toEqual({
|
|
739
|
-
'{"udfPath":"queries:test","args":{}}': "test result",
|
|
740
|
-
});
|
|
741
|
-
// So e.g. a useQuery() React hook would return the correct value (undefined),
|
|
742
|
-
// but that component would not be triggered to rerender. The displayed result
|
|
743
|
-
// will be stale until the component is rerendered for some other reason.
|
|
744
|
-
|
|
745
|
-
// What if we set a result again?
|
|
746
|
-
send({
|
|
747
|
-
type: "Transition",
|
|
748
|
-
startVersion: { querySet: 1, identity: 0, ts: Long.fromNumber(200) },
|
|
749
|
-
endVersion: { querySet: 1, identity: 0, ts: Long.fromNumber(300) },
|
|
750
|
-
modifications: [
|
|
751
|
-
{
|
|
752
|
-
type: "QueryUpdated",
|
|
753
|
-
queryId: 0,
|
|
754
|
-
value: "new test result",
|
|
755
|
-
logLines: [],
|
|
756
|
-
journal: null,
|
|
757
|
-
},
|
|
758
|
-
],
|
|
759
|
-
});
|
|
760
|
-
|
|
761
|
-
// What we might expect to happen if removing a query were equivalent to
|
|
762
|
-
// "updating the query to loading" and setting a value after worked:
|
|
763
|
-
/*
|
|
764
|
-
const update3 = await q.awaitPromiseAtIndexWithTimeout(2);
|
|
765
|
-
expect(update3).toEqual({
|
|
766
|
-
'{"udfPath":"queries:test","args":{}}': "new test result",
|
|
767
|
-
});
|
|
768
|
-
expect(q.allResults).toStrictEqual({
|
|
769
|
-
'{"udfPath":"queries:test","args":{}}': "new test result",
|
|
770
|
-
});
|
|
771
|
-
*/
|
|
772
|
-
// what actually happens
|
|
773
|
-
// wait a macrotask just in case
|
|
774
|
-
//await new Promise((r) => setTimeout(r, 0));
|
|
775
|
-
expect(q.updates).toHaveLength(2);
|
|
776
|
-
|
|
777
|
-
// This result is no longer tracked!
|
|
778
|
-
expect(client.localQueryResult("queries:test", {})).toEqual(undefined);
|
|
779
|
-
|
|
780
|
-
await client.close();
|
|
781
|
-
}, true);
|
|
782
|
-
});
|
|
783
|
-
|
|
784
|
-
test("TransitionChunk messages are assembled into a Transition", async () => {
|
|
785
|
-
await withInMemoryWebSocket(async ({ address, receive, send }) => {
|
|
786
|
-
const client = new BaseConvexClient(address, () => null, {
|
|
787
|
-
webSocketConstructor: nodeWebSocket,
|
|
788
|
-
unsavedChangesWarning: false,
|
|
789
|
-
});
|
|
790
|
-
expect((await receive()).type).toEqual("Connect");
|
|
791
|
-
expect((await receive()).type).toEqual("ModifyQuerySet");
|
|
792
|
-
|
|
793
|
-
const fullTransition: WireServerMessage = {
|
|
794
|
-
type: "Transition",
|
|
795
|
-
startVersion: {
|
|
796
|
-
querySet: 0,
|
|
797
|
-
ts: Long.fromNumber(0),
|
|
798
|
-
identity: 0,
|
|
799
|
-
},
|
|
800
|
-
endVersion: {
|
|
801
|
-
querySet: 1,
|
|
802
|
-
ts: Long.fromNumber(1000),
|
|
803
|
-
identity: 0,
|
|
804
|
-
},
|
|
805
|
-
modifications: [
|
|
806
|
-
{
|
|
807
|
-
type: "QueryUpdated",
|
|
808
|
-
queryId: 0,
|
|
809
|
-
value: { result: "chunk test data" },
|
|
810
|
-
logLines: [],
|
|
811
|
-
journal: null,
|
|
812
|
-
},
|
|
813
|
-
],
|
|
814
|
-
};
|
|
815
|
-
|
|
816
|
-
const fullJson = encodeServerMessage(fullTransition);
|
|
817
|
-
const midpoint = Math.floor(fullJson.length / 2);
|
|
818
|
-
const chunk1 = fullJson.substring(0, midpoint);
|
|
819
|
-
const chunk2 = fullJson.substring(midpoint);
|
|
820
|
-
|
|
821
|
-
const transitionId = "12345";
|
|
822
|
-
|
|
823
|
-
send({
|
|
824
|
-
type: "TransitionChunk",
|
|
825
|
-
chunk: chunk1,
|
|
826
|
-
partNumber: 0,
|
|
827
|
-
totalParts: 2,
|
|
828
|
-
transitionId,
|
|
829
|
-
});
|
|
830
|
-
|
|
831
|
-
expect(client.getMaxObservedTimestamp()).toBeUndefined();
|
|
832
|
-
|
|
833
|
-
send({
|
|
834
|
-
type: "TransitionChunk",
|
|
835
|
-
chunk: chunk2,
|
|
836
|
-
partNumber: 1,
|
|
837
|
-
totalParts: 2,
|
|
838
|
-
transitionId,
|
|
839
|
-
});
|
|
840
|
-
|
|
841
|
-
// synchronously, it's still undefined
|
|
842
|
-
expect(client.getMaxObservedTimestamp()).toEqual(undefined);
|
|
843
|
-
|
|
844
|
-
for (let i = 0; i < 10; i++) {
|
|
845
|
-
if (client.getMaxObservedTimestamp()) {
|
|
846
|
-
break;
|
|
847
|
-
}
|
|
848
|
-
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
849
|
-
}
|
|
850
|
-
|
|
851
|
-
expect(client.getMaxObservedTimestamp()).toEqual(Long.fromNumber(1000));
|
|
852
|
-
|
|
853
|
-
await client.close();
|
|
854
|
-
});
|
|
855
|
-
});
|
|
856
|
-
|
|
857
|
-
test("Backoff does not reset when queries synced but mutation is still inflight", async () => {
|
|
858
|
-
await withInMemoryWebSocket(async ({ address, receive, send, close }) => {
|
|
859
|
-
const client = new BaseConvexClient(address, () => null, {
|
|
860
|
-
webSocketConstructor: nodeWebSocket,
|
|
861
|
-
unsavedChangesWarning: false,
|
|
862
|
-
});
|
|
863
|
-
|
|
864
|
-
client.subscribe("queries:myQuery", {});
|
|
865
|
-
|
|
866
|
-
expect((await receive()).type).toEqual("Connect");
|
|
867
|
-
expect((await receive()).type).toEqual("ModifyQuerySet");
|
|
868
|
-
|
|
869
|
-
send({
|
|
870
|
-
type: "Transition",
|
|
871
|
-
startVersion: { querySet: 0, identity: 0, ts: Long.fromNumber(0) },
|
|
872
|
-
endVersion: { querySet: 1, identity: 0, ts: Long.fromNumber(100) },
|
|
873
|
-
modifications: [
|
|
874
|
-
{
|
|
875
|
-
type: "QueryUpdated",
|
|
876
|
-
queryId: 0,
|
|
877
|
-
value: "result",
|
|
878
|
-
logLines: [],
|
|
879
|
-
journal: null,
|
|
880
|
-
},
|
|
881
|
-
],
|
|
882
|
-
});
|
|
883
|
-
|
|
884
|
-
for (let i = 0; i < 20; i++) {
|
|
885
|
-
if (client.localQueryResult("queries:myQuery", {}) === "result") break;
|
|
886
|
-
await new Promise((r) => setTimeout(r, 50));
|
|
887
|
-
}
|
|
888
|
-
expect(client.connectionState().connectionRetries).toBe(0);
|
|
889
|
-
|
|
890
|
-
// Start a mutation, then server closes while it's inflight
|
|
891
|
-
const mutP = client.mutation("myMutation", {});
|
|
892
|
-
const mutReq = await receive();
|
|
893
|
-
expect(mutReq.type).toEqual("Mutation");
|
|
894
|
-
const requestId = (mutReq as MutationRequest).requestId;
|
|
895
|
-
|
|
896
|
-
close();
|
|
897
|
-
|
|
898
|
-
expect((await receive()).type).toEqual("Connect");
|
|
899
|
-
expect(client.connectionState().connectionRetries).toBeGreaterThan(0);
|
|
900
|
-
expect((await receive()).type).toEqual("ModifyQuerySet");
|
|
901
|
-
expect((await receive()).type).toEqual("Mutation");
|
|
902
|
-
|
|
903
|
-
// Server sends query results but NOT mutation response
|
|
904
|
-
send({
|
|
905
|
-
type: "Transition",
|
|
906
|
-
startVersion: { querySet: 0, identity: 0, ts: Long.fromNumber(0) },
|
|
907
|
-
endVersion: { querySet: 1, identity: 0, ts: Long.fromNumber(200) },
|
|
908
|
-
modifications: [
|
|
909
|
-
{
|
|
910
|
-
type: "QueryUpdated",
|
|
911
|
-
queryId: 0,
|
|
912
|
-
value: "result 2",
|
|
913
|
-
logLines: [],
|
|
914
|
-
journal: null,
|
|
915
|
-
},
|
|
916
|
-
],
|
|
917
|
-
});
|
|
918
|
-
|
|
919
|
-
for (let i = 0; i < 20; i++) {
|
|
920
|
-
if (client.localQueryResult("queries:myQuery", {}) === "result 2") break;
|
|
921
|
-
await new Promise((r) => setTimeout(r, 50));
|
|
922
|
-
}
|
|
923
|
-
|
|
924
|
-
// Retries should NOT reset — mutation is still inflight
|
|
925
|
-
expect(client.connectionState().connectionRetries).toBeGreaterThan(0);
|
|
926
|
-
|
|
927
|
-
// Now complete the mutation
|
|
928
|
-
send({
|
|
929
|
-
type: "MutationResponse",
|
|
930
|
-
requestId: requestId,
|
|
931
|
-
success: true,
|
|
932
|
-
result: null,
|
|
933
|
-
ts: Long.fromNumber(300),
|
|
934
|
-
logLines: [],
|
|
935
|
-
});
|
|
936
|
-
send({
|
|
937
|
-
type: "Transition",
|
|
938
|
-
startVersion: { querySet: 1, identity: 0, ts: Long.fromNumber(200) },
|
|
939
|
-
endVersion: { querySet: 1, identity: 0, ts: Long.fromNumber(400) },
|
|
940
|
-
modifications: [],
|
|
941
|
-
});
|
|
942
|
-
|
|
943
|
-
await mutP;
|
|
944
|
-
|
|
945
|
-
// Both queries and mutations synced — retries should reset
|
|
946
|
-
expect(client.connectionState().connectionRetries).toBe(0);
|
|
947
|
-
|
|
948
|
-
await client.close();
|
|
949
|
-
});
|
|
950
|
-
});
|
|
951
|
-
|
|
952
|
-
test("Backoff does not reset for idle client until server re-confirms queries", async () => {
|
|
953
|
-
await withInMemoryWebSocket(async ({ address, receive, send, close }) => {
|
|
954
|
-
const client = new BaseConvexClient(address, () => null, {
|
|
955
|
-
webSocketConstructor: nodeWebSocket,
|
|
956
|
-
unsavedChangesWarning: false,
|
|
957
|
-
});
|
|
958
|
-
|
|
959
|
-
client.subscribe("queries:myQuery", {});
|
|
960
|
-
|
|
961
|
-
expect((await receive()).type).toEqual("Connect");
|
|
962
|
-
expect((await receive()).type).toEqual("ModifyQuerySet");
|
|
963
|
-
|
|
964
|
-
send({
|
|
965
|
-
type: "Transition",
|
|
966
|
-
startVersion: { querySet: 0, identity: 0, ts: Long.fromNumber(0) },
|
|
967
|
-
endVersion: { querySet: 1, identity: 0, ts: Long.fromNumber(100) },
|
|
968
|
-
modifications: [
|
|
969
|
-
{
|
|
970
|
-
type: "QueryUpdated",
|
|
971
|
-
queryId: 0,
|
|
972
|
-
value: "result",
|
|
973
|
-
logLines: [],
|
|
974
|
-
journal: null,
|
|
975
|
-
},
|
|
976
|
-
],
|
|
977
|
-
});
|
|
978
|
-
|
|
979
|
-
for (let i = 0; i < 20; i++) {
|
|
980
|
-
if (client.localQueryResult("queries:myQuery", {}) === "result") break;
|
|
981
|
-
await new Promise((r) => setTimeout(r, 50));
|
|
982
|
-
}
|
|
983
|
-
expect(client.connectionState().connectionRetries).toBe(0);
|
|
984
|
-
|
|
985
|
-
// Server closes (idle client, no mutations in flight)
|
|
986
|
-
close();
|
|
987
|
-
|
|
988
|
-
expect((await receive()).type).toEqual("Connect");
|
|
989
|
-
expect(client.connectionState().connectionRetries).toBeGreaterThan(0);
|
|
990
|
-
expect((await receive()).type).toEqual("ModifyQuerySet");
|
|
991
|
-
|
|
992
|
-
// Empty transition — query not re-confirmed yet, retries should hold
|
|
993
|
-
send({
|
|
994
|
-
type: "Transition",
|
|
995
|
-
startVersion: { querySet: 0, identity: 0, ts: Long.fromNumber(0) },
|
|
996
|
-
endVersion: { querySet: 1, identity: 0, ts: Long.fromNumber(150) },
|
|
997
|
-
modifications: [],
|
|
998
|
-
});
|
|
999
|
-
await new Promise((r) => setTimeout(r, 100));
|
|
1000
|
-
expect(client.connectionState().connectionRetries).toBeGreaterThan(0);
|
|
1001
|
-
|
|
1002
|
-
// Server re-confirms the query
|
|
1003
|
-
send({
|
|
1004
|
-
type: "Transition",
|
|
1005
|
-
startVersion: { querySet: 1, identity: 0, ts: Long.fromNumber(150) },
|
|
1006
|
-
endVersion: { querySet: 1, identity: 0, ts: Long.fromNumber(200) },
|
|
1007
|
-
modifications: [
|
|
1008
|
-
{
|
|
1009
|
-
type: "QueryUpdated",
|
|
1010
|
-
queryId: 0,
|
|
1011
|
-
value: "result refreshed",
|
|
1012
|
-
logLines: [],
|
|
1013
|
-
journal: null,
|
|
1014
|
-
},
|
|
1015
|
-
],
|
|
1016
|
-
});
|
|
1017
|
-
|
|
1018
|
-
for (let i = 0; i < 20; i++) {
|
|
1019
|
-
if (client.localQueryResult("queries:myQuery", {}) === "result refreshed")
|
|
1020
|
-
break;
|
|
1021
|
-
await new Promise((r) => setTimeout(r, 50));
|
|
1022
|
-
}
|
|
1023
|
-
|
|
1024
|
-
// Query re-confirmed — retries should reset
|
|
1025
|
-
expect(client.connectionState().connectionRetries).toBe(0);
|
|
1026
|
-
|
|
1027
|
-
await client.close();
|
|
1028
|
-
});
|
|
1029
|
-
});
|
|
1030
|
-
|
|
1031
|
-
// We had an issue where fixing a bug related to having the client do proper exponential backoff
|
|
1032
|
-
// resulted in revealing that if a client was authenticated and had a WebSocket disconnect, the
|
|
1033
|
-
// count of retries would never get reset upon reconnect. This test covers that scenario.
|
|
1034
|
-
test("Retries do not increase across connections for auth'd clients", async () => {
|
|
1035
|
-
await withInMemoryWebSocket(async ({ address, receive, send, close }) => {
|
|
1036
|
-
const client = new BaseConvexClient(address, () => null, {
|
|
1037
|
-
webSocketConstructor: nodeWebSocket,
|
|
1038
|
-
unsavedChangesWarning: false,
|
|
1039
|
-
logger: true,
|
|
1040
|
-
verbose: true,
|
|
1041
|
-
});
|
|
1042
|
-
|
|
1043
|
-
// Setup auth
|
|
1044
|
-
const iat = Math.floor(Date.now() / 1000);
|
|
1045
|
-
const exp = iat + 3600;
|
|
1046
|
-
const token = encodeJwt({ sub: "user_123", exp, iat }, "test-secret");
|
|
1047
|
-
client.setAuth(
|
|
1048
|
-
async () => token,
|
|
1049
|
-
(_) => {},
|
|
1050
|
-
);
|
|
1051
|
-
|
|
1052
|
-
// Verify client handshake on "server" side.
|
|
1053
|
-
expect((await receive()).type).toEqual("Connect");
|
|
1054
|
-
expect((await receive()).type).toEqual("Authenticate");
|
|
1055
|
-
expect((await receive()).type).toEqual("ModifyQuerySet");
|
|
1056
|
-
|
|
1057
|
-
// Respond to the handshake noting that the identity was accepted (increased version).
|
|
1058
|
-
send({
|
|
1059
|
-
type: "Transition",
|
|
1060
|
-
startVersion: { querySet: 0, identity: 0, ts: Long.fromNumber(0) },
|
|
1061
|
-
endVersion: { querySet: 0, identity: 1, ts: Long.fromNumber(100) },
|
|
1062
|
-
modifications: [],
|
|
1063
|
-
});
|
|
1064
|
-
|
|
1065
|
-
// Subscribe to a query and verify the "server" receives it.
|
|
1066
|
-
client.subscribe("queries:myQuery", {});
|
|
1067
|
-
expect((await receive()).type).toEqual("ModifyQuerySet");
|
|
1068
|
-
|
|
1069
|
-
// Respond to the subscription with a result.
|
|
1070
|
-
send({
|
|
1071
|
-
type: "Transition",
|
|
1072
|
-
startVersion: { querySet: 0, identity: 1, ts: Long.fromNumber(100) },
|
|
1073
|
-
endVersion: { querySet: 1, identity: 1, ts: Long.fromNumber(200) },
|
|
1074
|
-
modifications: [
|
|
1075
|
-
{
|
|
1076
|
-
type: "QueryUpdated",
|
|
1077
|
-
queryId: 0,
|
|
1078
|
-
value: "result",
|
|
1079
|
-
logLines: [],
|
|
1080
|
-
journal: null,
|
|
1081
|
-
},
|
|
1082
|
-
],
|
|
1083
|
-
});
|
|
1084
|
-
|
|
1085
|
-
// Verify the client gets the subscription result.
|
|
1086
|
-
for (let i = 0; i < 20; i++) {
|
|
1087
|
-
if (client.localQueryResult("queries:myQuery", {}) === "result") break;
|
|
1088
|
-
await new Promise((r) => setTimeout(r, 50));
|
|
1089
|
-
}
|
|
1090
|
-
expect(client.localQueryResult("queries:myQuery", {})).toEqual("result");
|
|
1091
|
-
|
|
1092
|
-
// Unceremoniously drop the connection.
|
|
1093
|
-
close();
|
|
1094
|
-
|
|
1095
|
-
// The "server" should see the client handshake for a reconnect.
|
|
1096
|
-
expect((await receive()).type).toEqual("Connect");
|
|
1097
|
-
expect((await receive()).type).toEqual("Authenticate");
|
|
1098
|
-
expect((await receive()).type).toEqual("ModifyQuerySet");
|
|
1099
|
-
|
|
1100
|
-
// The client should record that it has begun a retry.
|
|
1101
|
-
expect(client.connectionState().connectionRetries).toBe(1);
|
|
1102
|
-
|
|
1103
|
-
// Respond to the handshake noting that the identity was accepted (increased version).
|
|
1104
|
-
send({
|
|
1105
|
-
type: "Transition",
|
|
1106
|
-
startVersion: { querySet: 0, identity: 0, ts: Long.fromNumber(0) },
|
|
1107
|
-
endVersion: { querySet: 0, identity: 1, ts: Long.fromNumber(100) },
|
|
1108
|
-
modifications: [],
|
|
1109
|
-
});
|
|
1110
|
-
// Let client handle the transition.
|
|
1111
|
-
await new Promise((r) => setTimeout(r, 100));
|
|
1112
|
-
|
|
1113
|
-
// Respond to the re-subscription with a result.
|
|
1114
|
-
send({
|
|
1115
|
-
type: "Transition",
|
|
1116
|
-
startVersion: { querySet: 0, identity: 1, ts: Long.fromNumber(100) },
|
|
1117
|
-
endVersion: { querySet: 1, identity: 1, ts: Long.fromNumber(200) },
|
|
1118
|
-
modifications: [
|
|
1119
|
-
{
|
|
1120
|
-
type: "QueryUpdated",
|
|
1121
|
-
queryId: 0,
|
|
1122
|
-
value: "updated result",
|
|
1123
|
-
logLines: [],
|
|
1124
|
-
journal: null,
|
|
1125
|
-
},
|
|
1126
|
-
],
|
|
1127
|
-
});
|
|
1128
|
-
|
|
1129
|
-
for (let i = 0; i < 20; i++) {
|
|
1130
|
-
if (client.localQueryResult("queries:myQuery", {}) === "updated result")
|
|
1131
|
-
break;
|
|
1132
|
-
await new Promise((r) => setTimeout(r, 50));
|
|
1133
|
-
}
|
|
1134
|
-
// Verify the client gets the subscription result.
|
|
1135
|
-
expect(client.localQueryResult("queries:myQuery", {})).toEqual(
|
|
1136
|
-
"updated result",
|
|
1137
|
-
);
|
|
1138
|
-
|
|
1139
|
-
// Client has resynced - should be at 0 retries
|
|
1140
|
-
expect(client.connectionState().connectionRetries).toBe(0);
|
|
1141
|
-
});
|
|
1142
|
-
});
|
|
1143
|
-
|
|
1144
|
-
// https://github.com/get-convex/convex-js/issues/148
|
|
1145
|
-
// When using expectAuth, the socket starts paused. Once the WebSocket connects
|
|
1146
|
-
// (while still paused), the paused state becomes "uninitialized". When auth
|
|
1147
|
-
// completes and resume() is called, hasEverConnected should become true.
|
|
1148
|
-
test("hasEverConnected is true after expectAuth resume", async () => {
|
|
1149
|
-
await withInMemoryWebSocket(async ({ address, receive, send }) => {
|
|
1150
|
-
// expectAuth causes the socket to start in paused state.
|
|
1151
|
-
const client = new BaseConvexClient(address, () => null, {
|
|
1152
|
-
webSocketConstructor: nodeWebSocket,
|
|
1153
|
-
unsavedChangesWarning: false,
|
|
1154
|
-
expectAuth: true,
|
|
1155
|
-
});
|
|
1156
|
-
|
|
1157
|
-
// Before auth, socket is paused so hasEverConnected should be false.
|
|
1158
|
-
expect(client.connectionState().hasEverConnected).toBe(false);
|
|
1159
|
-
|
|
1160
|
-
// Set auth with a delayed token fetch. The delay ensures the WebSocket
|
|
1161
|
-
// connects while the token is being fetched, causing the socket to enter
|
|
1162
|
-
// the ready+uninitialized state (the buggy path).
|
|
1163
|
-
const iat = Math.floor(Date.now() / 1000);
|
|
1164
|
-
const exp = iat + 3600;
|
|
1165
|
-
const token = encodeJwt({ sub: "user_123", exp, iat }, "test-secret");
|
|
1166
|
-
client.setAuth(
|
|
1167
|
-
async () => {
|
|
1168
|
-
await new Promise((r) => setTimeout(r, 100));
|
|
1169
|
-
return token;
|
|
1170
|
-
},
|
|
1171
|
-
(_) => {},
|
|
1172
|
-
);
|
|
1173
|
-
|
|
1174
|
-
// After resume, the deferred onOpen fires and sends Connect + auth messages.
|
|
1175
|
-
expect((await receive()).type).toEqual("Connect");
|
|
1176
|
-
expect((await receive()).type).toEqual("Authenticate");
|
|
1177
|
-
expect((await receive()).type).toEqual("ModifyQuerySet");
|
|
1178
|
-
|
|
1179
|
-
// Respond to the handshake noting that the identity was accepted.
|
|
1180
|
-
send({
|
|
1181
|
-
type: "Transition",
|
|
1182
|
-
startVersion: { querySet: 0, identity: 0, ts: Long.fromNumber(0) },
|
|
1183
|
-
endVersion: { querySet: 0, identity: 1, ts: Long.fromNumber(100) },
|
|
1184
|
-
modifications: [],
|
|
1185
|
-
});
|
|
1186
|
-
|
|
1187
|
-
// Let the client process the transition.
|
|
1188
|
-
await new Promise((r) => setTimeout(r, 100));
|
|
1189
|
-
|
|
1190
|
-
// After auth completes and socket is resumed, hasEverConnected should be true.
|
|
1191
|
-
expect(client.connectionState().isWebSocketConnected).toBe(true);
|
|
1192
|
-
expect(client.connectionState().hasEverConnected).toBe(true);
|
|
1193
|
-
|
|
1194
|
-
await client.close();
|
|
1195
|
-
});
|
|
1196
|
-
});
|
|
1197
|
-
|
|
1198
|
-
function encodeJwt(payload: object, secret: string): string {
|
|
1199
|
-
const header = Buffer.from(
|
|
1200
|
-
JSON.stringify({ alg: "HS256", typ: "JWT" }),
|
|
1201
|
-
).toString("base64url");
|
|
1202
|
-
const body = Buffer.from(JSON.stringify(payload)).toString("base64url");
|
|
1203
|
-
const sig = createHmac("sha256", secret)
|
|
1204
|
-
.update(`${header}.${body}`)
|
|
1205
|
-
.digest("base64url");
|
|
1206
|
-
return `${header}.${body}.${sig}`;
|
|
1207
|
-
}
|