convex 1.26.0-alpha.2 → 1.26.0-alpha.4
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 +43 -0
- package/dist/browser.bundle.js +102 -25
- package/dist/browser.bundle.js.map +2 -2
- package/dist/cjs/browser/http_client.js +2 -0
- package/dist/cjs/browser/http_client.js.map +2 -2
- package/dist/cjs/browser/logging.js +4 -4
- package/dist/cjs/browser/logging.js.map +2 -2
- package/dist/cjs/browser/simple_client.js +25 -0
- package/dist/cjs/browser/simple_client.js.map +2 -2
- package/dist/cjs/browser/sync/client.js +41 -2
- package/dist/cjs/browser/sync/client.js.map +2 -2
- package/dist/cjs/browser/sync/remote_query_set.js.map +2 -2
- package/dist/cjs/browser/sync/request_manager.js +8 -1
- package/dist/cjs/browser/sync/request_manager.js.map +2 -2
- package/dist/cjs/browser/sync/web_socket_manager.js +5 -1
- package/dist/cjs/browser/sync/web_socket_manager.js.map +2 -2
- package/dist/cjs/bundler/context.js.map +1 -1
- package/dist/cjs/bundler/debugBundle.js +31 -6
- package/dist/cjs/bundler/debugBundle.js.map +2 -2
- package/dist/cjs/bundler/depgraph.js +24 -26
- package/dist/cjs/bundler/depgraph.js.map +3 -3
- package/dist/cjs/cli/codegen_templates/api.js +51 -0
- package/dist/cjs/cli/codegen_templates/api.js.map +2 -2
- package/dist/cjs/cli/codegen_templates/readme.js +4 -4
- package/dist/cjs/cli/codegen_templates/readme.js.map +1 -1
- package/dist/cjs/cli/configure.js +11 -6
- package/dist/cjs/cli/configure.js.map +2 -2
- package/dist/cjs/cli/dev.js +5 -0
- package/dist/cjs/cli/dev.js.map +2 -2
- package/dist/cjs/cli/index.js +7 -3
- package/dist/cjs/cli/index.js.map +3 -3
- package/dist/cjs/cli/lib/codegen.js +33 -24
- package/dist/cjs/cli/lib/codegen.js.map +3 -3
- package/dist/cjs/cli/lib/deploymentSelection.js.map +2 -2
- package/dist/cjs/cli/lib/envvars.js +29 -0
- package/dist/cjs/cli/lib/envvars.js.map +2 -2
- package/dist/cjs/cli/lib/localDeployment/anonymous.js +21 -7
- package/dist/cjs/cli/lib/localDeployment/anonymous.js.map +2 -2
- package/dist/cjs/cli/lib/mcp/tools/run.js +1 -1
- package/dist/cjs/cli/lib/mcp/tools/run.js.map +2 -2
- package/dist/cjs/cli/lib/networkTest.js +8 -2
- package/dist/cjs/cli/lib/networkTest.js.map +2 -2
- package/dist/cjs/cli/lib/usage.js +4 -4
- package/dist/cjs/cli/lib/usage.js.map +1 -1
- package/dist/cjs/cli/lib/utils/prompts.js +4 -4
- package/dist/cjs/cli/lib/utils/prompts.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 +9 -1
- package/dist/cjs/nextjs/index.js.map +2 -2
- package/dist/cjs/react/client.js +37 -0
- package/dist/cjs/react/client.js.map +2 -2
- package/dist/cjs/react/index.js +1 -0
- package/dist/cjs/react/index.js.map +2 -2
- package/dist/cjs/server/database.js.map +1 -1
- package/dist/cjs/server/impl/database_impl.js +26 -20
- package/dist/cjs/server/impl/database_impl.js.map +2 -2
- package/dist/cjs/server/impl/registration_impl.js +10 -2
- package/dist/cjs/server/impl/registration_impl.js.map +2 -2
- package/dist/cjs/values/validators.js +19 -0
- package/dist/cjs/values/validators.js.map +2 -2
- package/dist/cjs-types/browser/http_client.d.ts +2 -0
- package/dist/cjs-types/browser/http_client.d.ts.map +1 -1
- package/dist/cjs-types/browser/logging.d.ts +7 -1
- package/dist/cjs-types/browser/logging.d.ts.map +1 -1
- package/dist/cjs-types/browser/simple_client.d.ts +19 -0
- package/dist/cjs-types/browser/simple_client.d.ts.map +1 -1
- package/dist/cjs-types/browser/sync/client.d.ts +21 -0
- package/dist/cjs-types/browser/sync/client.d.ts.map +1 -1
- package/dist/cjs-types/browser/sync/client_node_test_helpers.d.ts +5 -0
- package/dist/cjs-types/browser/sync/client_node_test_helpers.d.ts.map +1 -1
- package/dist/cjs-types/browser/sync/remote_query_set.d.ts +2 -0
- package/dist/cjs-types/browser/sync/remote_query_set.d.ts.map +1 -1
- package/dist/cjs-types/browser/sync/request_manager.d.ts +2 -1
- package/dist/cjs-types/browser/sync/request_manager.d.ts.map +1 -1
- package/dist/cjs-types/browser/sync/web_socket_manager.d.ts +2 -1
- package/dist/cjs-types/browser/sync/web_socket_manager.d.ts.map +1 -1
- package/dist/cjs-types/bundler/debugBundle.d.ts +4 -2
- package/dist/cjs-types/bundler/debugBundle.d.ts.map +1 -1
- package/dist/cjs-types/bundler/depgraph.d.ts +5 -4
- package/dist/cjs-types/bundler/depgraph.d.ts.map +1 -1
- package/dist/cjs-types/cli/codegen.d.ts +1 -1
- package/dist/cjs-types/cli/codegen_templates/api.d.ts.map +1 -1
- package/dist/cjs-types/cli/configure.d.ts.map +1 -1
- package/dist/cjs-types/cli/deploy.d.ts +1 -1
- package/dist/cjs-types/cli/dev.d.ts +1 -1
- package/dist/cjs-types/cli/dev.d.ts.map +1 -1
- 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/deploymentSelection.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/envvars.d.ts +1 -0
- package/dist/cjs-types/cli/lib/envvars.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/localDeployment/anonymous.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/networkTest.d.ts.map +1 -1
- package/dist/cjs-types/cli/run.d.ts +1 -1
- package/dist/cjs-types/index.d.ts +1 -1
- package/dist/cjs-types/nextjs/index.d.ts +2 -2
- package/dist/cjs-types/react/client.d.ts +30 -0
- package/dist/cjs-types/react/client.d.ts.map +1 -1
- package/dist/cjs-types/react/index.d.ts +1 -1
- package/dist/cjs-types/react/index.d.ts.map +1 -1
- package/dist/cjs-types/server/database.d.ts.map +1 -1
- package/dist/cjs-types/server/database_api.test.d.ts +2 -0
- package/dist/cjs-types/server/database_api.test.d.ts.map +1 -0
- package/dist/cjs-types/server/impl/database_impl.d.ts.map +1 -1
- package/dist/cjs-types/server/impl/registration_impl.d.ts.map +1 -1
- package/dist/cjs-types/values/validators.d.ts.map +1 -1
- package/dist/cli.bundle.cjs +291 -97
- package/dist/cli.bundle.cjs.map +3 -3
- package/dist/esm/browser/http_client.js +2 -0
- package/dist/esm/browser/http_client.js.map +2 -2
- package/dist/esm/browser/logging.js +3 -3
- package/dist/esm/browser/logging.js.map +2 -2
- package/dist/esm/browser/simple_client.js +25 -0
- package/dist/esm/browser/simple_client.js.map +2 -2
- package/dist/esm/browser/sync/client.js +41 -2
- package/dist/esm/browser/sync/client.js.map +2 -2
- package/dist/esm/browser/sync/remote_query_set.js.map +2 -2
- package/dist/esm/browser/sync/request_manager.js +8 -1
- package/dist/esm/browser/sync/request_manager.js.map +2 -2
- package/dist/esm/browser/sync/web_socket_manager.js +5 -1
- package/dist/esm/browser/sync/web_socket_manager.js.map +2 -2
- package/dist/esm/bundler/context.js.map +1 -1
- package/dist/esm/bundler/debugBundle.js +33 -7
- package/dist/esm/bundler/debugBundle.js.map +2 -2
- package/dist/esm/bundler/depgraph.js +24 -26
- package/dist/esm/bundler/depgraph.js.map +3 -3
- package/dist/esm/cli/codegen_templates/api.js +51 -0
- package/dist/esm/cli/codegen_templates/api.js.map +2 -2
- package/dist/esm/cli/codegen_templates/readme.js +4 -4
- package/dist/esm/cli/codegen_templates/readme.js.map +1 -1
- package/dist/esm/cli/configure.js +12 -8
- package/dist/esm/cli/configure.js.map +2 -2
- package/dist/esm/cli/dev.js +5 -0
- package/dist/esm/cli/dev.js.map +2 -2
- package/dist/esm/cli/index.js +7 -3
- package/dist/esm/cli/index.js.map +2 -2
- package/dist/esm/cli/lib/codegen.js +33 -25
- package/dist/esm/cli/lib/codegen.js.map +3 -3
- package/dist/esm/cli/lib/deploymentSelection.js.map +2 -2
- package/dist/esm/cli/lib/envvars.js +28 -0
- package/dist/esm/cli/lib/envvars.js.map +2 -2
- package/dist/esm/cli/lib/localDeployment/anonymous.js +21 -7
- package/dist/esm/cli/lib/localDeployment/anonymous.js.map +2 -2
- package/dist/esm/cli/lib/mcp/tools/run.js +2 -2
- package/dist/esm/cli/lib/mcp/tools/run.js.map +2 -2
- package/dist/esm/cli/lib/networkTest.js +9 -3
- package/dist/esm/cli/lib/networkTest.js.map +2 -2
- package/dist/esm/cli/lib/usage.js +4 -4
- package/dist/esm/cli/lib/usage.js.map +1 -1
- package/dist/esm/cli/lib/utils/prompts.js +4 -4
- package/dist/esm/cli/lib/utils/prompts.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 +9 -1
- package/dist/esm/nextjs/index.js.map +2 -2
- package/dist/esm/react/client.js +37 -1
- package/dist/esm/react/client.js.map +2 -2
- package/dist/esm/react/index.js +2 -1
- package/dist/esm/react/index.js.map +2 -2
- package/dist/esm/server/impl/database_impl.js +26 -20
- package/dist/esm/server/impl/database_impl.js.map +2 -2
- package/dist/esm/server/impl/registration_impl.js +10 -2
- package/dist/esm/server/impl/registration_impl.js.map +2 -2
- package/dist/esm/values/validators.js +19 -0
- package/dist/esm/values/validators.js.map +2 -2
- package/dist/esm-types/browser/http_client.d.ts +2 -0
- package/dist/esm-types/browser/http_client.d.ts.map +1 -1
- package/dist/esm-types/browser/logging.d.ts +7 -1
- package/dist/esm-types/browser/logging.d.ts.map +1 -1
- package/dist/esm-types/browser/simple_client.d.ts +19 -0
- package/dist/esm-types/browser/simple_client.d.ts.map +1 -1
- package/dist/esm-types/browser/sync/client.d.ts +21 -0
- package/dist/esm-types/browser/sync/client.d.ts.map +1 -1
- package/dist/esm-types/browser/sync/client_node_test_helpers.d.ts +5 -0
- package/dist/esm-types/browser/sync/client_node_test_helpers.d.ts.map +1 -1
- package/dist/esm-types/browser/sync/remote_query_set.d.ts +2 -0
- package/dist/esm-types/browser/sync/remote_query_set.d.ts.map +1 -1
- package/dist/esm-types/browser/sync/request_manager.d.ts +2 -1
- package/dist/esm-types/browser/sync/request_manager.d.ts.map +1 -1
- package/dist/esm-types/browser/sync/web_socket_manager.d.ts +2 -1
- package/dist/esm-types/browser/sync/web_socket_manager.d.ts.map +1 -1
- package/dist/esm-types/bundler/debugBundle.d.ts +4 -2
- package/dist/esm-types/bundler/debugBundle.d.ts.map +1 -1
- package/dist/esm-types/bundler/depgraph.d.ts +5 -4
- package/dist/esm-types/bundler/depgraph.d.ts.map +1 -1
- package/dist/esm-types/cli/codegen.d.ts +1 -1
- package/dist/esm-types/cli/codegen_templates/api.d.ts.map +1 -1
- package/dist/esm-types/cli/configure.d.ts.map +1 -1
- package/dist/esm-types/cli/deploy.d.ts +1 -1
- package/dist/esm-types/cli/dev.d.ts +1 -1
- package/dist/esm-types/cli/dev.d.ts.map +1 -1
- 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/deploymentSelection.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/envvars.d.ts +1 -0
- package/dist/esm-types/cli/lib/envvars.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/localDeployment/anonymous.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/networkTest.d.ts.map +1 -1
- package/dist/esm-types/cli/run.d.ts +1 -1
- package/dist/esm-types/index.d.ts +1 -1
- package/dist/esm-types/nextjs/index.d.ts +2 -2
- package/dist/esm-types/react/client.d.ts +30 -0
- package/dist/esm-types/react/client.d.ts.map +1 -1
- package/dist/esm-types/react/index.d.ts +1 -1
- package/dist/esm-types/react/index.d.ts.map +1 -1
- package/dist/esm-types/server/database.d.ts.map +1 -1
- package/dist/esm-types/server/database_api.test.d.ts +2 -0
- package/dist/esm-types/server/database_api.test.d.ts.map +1 -0
- package/dist/esm-types/server/impl/database_impl.d.ts.map +1 -1
- package/dist/esm-types/server/impl/registration_impl.d.ts.map +1 -1
- package/dist/esm-types/values/validators.d.ts.map +1 -1
- package/dist/react.bundle.js +172 -84
- package/dist/react.bundle.js.map +4 -4
- package/package.json +3 -3
- package/src/browser/.claude/settings.local.json +1 -1
- package/src/browser/http_client.ts +2 -0
- package/src/browser/logging.ts +10 -3
- package/src/browser/simple_client.ts +29 -0
- package/src/browser/sync/client.ts +54 -1
- package/src/browser/sync/client_node.test.ts +415 -0
- package/src/browser/sync/client_node_test_helpers.ts +19 -0
- package/src/browser/sync/remote_query_set.ts +2 -0
- package/src/browser/sync/request_manager.test.ts +59 -1
- package/src/browser/sync/request_manager.ts +10 -1
- package/src/browser/sync/web_socket_manager.ts +4 -0
- package/src/bundler/context.ts +1 -1
- package/src/bundler/debugBundle.ts +32 -4
- package/src/bundler/depgraph.ts +39 -41
- package/src/cli/codegen_templates/api.ts +54 -0
- package/src/cli/codegen_templates/readme.ts +4 -4
- package/src/cli/configure.ts +27 -21
- package/src/cli/dev.ts +6 -0
- package/src/cli/index.ts +12 -3
- package/src/cli/lib/codegen.ts +11 -1
- package/src/cli/lib/deploymentSelection.ts +2 -0
- package/src/cli/lib/envvars.ts +42 -0
- package/src/cli/lib/localDeployment/anonymous.ts +25 -7
- package/src/cli/lib/mcp/tools/run.ts +2 -2
- package/src/cli/lib/networkTest.ts +10 -3
- package/src/cli/lib/usage.ts +4 -4
- package/src/cli/lib/utils/prompts.ts +4 -4
- package/src/index.ts +1 -1
- package/src/nextjs/index.ts +21 -3
- package/src/react/client.ts +62 -1
- package/src/react/index.ts +1 -0
- package/src/server/database.ts +71 -0
- package/src/server/database_api.test.ts +360 -0
- package/src/server/impl/database_impl.ts +37 -17
- package/src/server/impl/registration_impl.ts +10 -2
- package/src/values/validator.test.ts +71 -0
- package/src/values/validators.ts +24 -0
|
@@ -52,6 +52,8 @@ class ConvexHttpClient {
|
|
|
52
52
|
* - `logger` - A logger or a boolean. If not provided, logs to the console.
|
|
53
53
|
* You can construct your own logger to customize logging to log elsewhere
|
|
54
54
|
* or not log at all, or use `false` as a shorthand for a no-op logger.
|
|
55
|
+
* A logger is an object with 4 methods: log(), warn(), error(), and logVerbose().
|
|
56
|
+
* These methods can receive multiple arguments of any types, like console.log().
|
|
55
57
|
* - `auth` - A JWT containing identity claims accessible in Convex functions.
|
|
56
58
|
* This identity may expire so it may be necessary to call `setAuth()` later,
|
|
57
59
|
* but for short-lived clients it's convenient to specify this value here.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/browser/http_client.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n FunctionReference,\n FunctionReturnType,\n OptionalRestArgs,\n getFunctionName,\n} from \"../server/api.js\";\nimport { parseArgs, validateDeploymentUrl } from \"../common/index.js\";\nimport { version } from \"../index.js\";\nimport {\n ConvexError,\n JSONValue,\n convexToJson,\n jsonToConvex,\n} from \"../values/index.js\";\nimport {\n instantiateDefaultLogger,\n instantiateNoopLogger,\n logForFunction,\n Logger,\n} from \"./logging.js\";\nimport {\n ArgsAndOptions,\n FunctionArgs,\n UserIdentityAttributes,\n} from \"../server/index.js\";\n\nexport const STATUS_CODE_OK = 200;\nexport const STATUS_CODE_BAD_REQUEST = 400;\n// Special custom 5xx HTTP status code to mean that the UDF returned an error.\n//\n// Must match the constant of the same name in the backend.\nexport const STATUS_CODE_UDF_FAILED = 560;\n\n// Allow fetch to be shimmed in for Node.js < 18\nlet specifiedFetch: typeof globalThis.fetch | undefined = undefined;\nexport function setFetch(f: typeof globalThis.fetch) {\n specifiedFetch = f;\n}\n\nexport type HttpMutationOptions = {\n /**\n * Skip the default queue of mutations and run this immediately.\n *\n * This allows the same HttpConvexClient to be used to request multiple\n * mutations in parallel, something not possible with WebSocket-based clients.\n */\n skipQueue: boolean;\n};\n\n/**\n * A Convex client that runs queries and mutations over HTTP.\n *\n * This client is stateful (it has user credentials and queues mutations)\n * so take care to avoid sharing it between requests in a server.\n *\n * This is appropriate for server-side code (like Netlify Lambdas) or non-reactive\n * webapps.\n *\n * @public\n */\nexport class ConvexHttpClient {\n private readonly address: string;\n private auth?: string;\n private adminAuth?: string;\n private encodedTsPromise?: Promise<string>;\n private debug: boolean;\n private fetchOptions?: FetchOptions;\n private logger: Logger;\n private mutationQueue: Array<{\n mutation: FunctionReference<\"mutation\">;\n args: FunctionArgs<any>;\n resolve: (value: any) => void;\n reject: (error: any) => void;\n }> = [];\n private isProcessingQueue: boolean = false;\n\n /**\n * Create a new {@link ConvexHttpClient}.\n *\n * @param address - The url of your Convex deployment, often provided\n * by an environment variable. E.g. `https://small-mouse-123.convex.cloud`.\n * @param options - An object of options.\n * - `skipConvexDeploymentUrlCheck` - Skip validating that the Convex deployment URL looks like\n * `https://happy-animal-123.convex.cloud` or localhost. This can be useful if running a self-hosted\n * Convex backend that uses a different URL.\n * - `logger` - A logger or a boolean. If not provided, logs to the console.\n * You can construct your own logger to customize logging to log elsewhere\n * or not log at all, or use `false` as a shorthand for a no-op logger.\n * - `auth` - A JWT containing identity claims accessible in Convex functions.\n * This identity may expire so it may be necessary to call `setAuth()` later,\n * but for short-lived clients it's convenient to specify this value here.\n */\n constructor(\n address: string,\n options?: {\n skipConvexDeploymentUrlCheck?: boolean;\n logger?: Logger | boolean;\n auth?: string;\n },\n ) {\n if (typeof options === \"boolean\") {\n throw new Error(\n \"skipConvexDeploymentUrlCheck as the second argument is no longer supported. Please pass an options object, `{ skipConvexDeploymentUrlCheck: true }`.\",\n );\n }\n const opts = options ?? {};\n if (opts.skipConvexDeploymentUrlCheck !== true) {\n validateDeploymentUrl(address);\n }\n this.logger =\n options?.logger === false\n ? instantiateNoopLogger({ verbose: false })\n : options?.logger !== true && options?.logger\n ? options.logger\n : instantiateDefaultLogger({ verbose: false });\n this.address = address;\n this.debug = true;\n }\n\n /**\n * Obtain the {@link ConvexHttpClient}'s URL to its backend.\n * @deprecated Use url, which returns the url without /api at the end.\n *\n * @returns The URL to the Convex backend, including the client's API version.\n */\n backendUrl(): string {\n return `${this.address}/api`;\n }\n\n /**\n * Return the address for this client, useful for creating a new client.\n *\n * Not guaranteed to match the address with which this client was constructed:\n * it may be canonicalized.\n */\n get url() {\n return this.address;\n }\n\n /**\n * Set the authentication token to be used for subsequent queries and mutations.\n *\n * Should be called whenever the token changes (i.e. due to expiration and refresh).\n *\n * @param value - JWT-encoded OpenID Connect identity token.\n */\n setAuth(value: string) {\n this.clearAuth();\n this.auth = value;\n }\n\n /**\n * Set admin auth token to allow calling internal queries, mutations, and actions\n * and acting as an identity.\n *\n * @internal\n */\n setAdminAuth(token: string, actingAsIdentity?: UserIdentityAttributes) {\n this.clearAuth();\n if (actingAsIdentity !== undefined) {\n // Encode the identity to a base64 string\n const bytes = new TextEncoder().encode(JSON.stringify(actingAsIdentity));\n const actingAsIdentityEncoded = btoa(String.fromCodePoint(...bytes));\n this.adminAuth = `${token}:${actingAsIdentityEncoded}`;\n } else {\n this.adminAuth = token;\n }\n }\n\n /**\n * Clear the current authentication token if set.\n */\n clearAuth() {\n this.auth = undefined;\n this.adminAuth = undefined;\n }\n\n /**\n * Sets whether the result log lines should be printed on the console or not.\n *\n * @internal\n */\n setDebug(debug: boolean) {\n this.debug = debug;\n }\n\n /**\n * Used to customize the fetch behavior in some runtimes.\n *\n * @internal\n */\n setFetchOptions(fetchOptions: FetchOptions) {\n this.fetchOptions = fetchOptions;\n }\n\n /**\n * This API is experimental: it may change or disappear.\n *\n * Execute a Convex query function at the same timestamp as every other\n * consistent query execution run by this HTTP client.\n *\n * This doesn't make sense for long-lived ConvexHttpClients as Convex\n * backends can read a limited amount into the past: beyond 30 seconds\n * in the past may not be available.\n *\n * Create a new client to use a consistent time.\n *\n * @param name - The name of the query.\n * @param args - The arguments object for the query. If this is omitted,\n * the arguments will be `{}`.\n * @returns A promise of the query's result.\n *\n * @deprecated This API is experimental: it may change or disappear.\n */\n async consistentQuery<Query extends FunctionReference<\"query\">>(\n query: Query,\n ...args: OptionalRestArgs<Query>\n ): Promise<FunctionReturnType<Query>> {\n const queryArgs = parseArgs(args[0]);\n\n const timestampPromise = this.getTimestamp();\n return await this.queryInner(query, queryArgs, { timestampPromise });\n }\n\n private async getTimestamp() {\n if (this.encodedTsPromise) {\n return this.encodedTsPromise;\n }\n return (this.encodedTsPromise = this.getTimestampInner());\n }\n\n private async getTimestampInner() {\n const localFetch = specifiedFetch || fetch;\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"Convex-Client\": `npm-${version}`,\n };\n const response = await localFetch(`${this.address}/api/query_ts`, {\n ...this.fetchOptions,\n method: \"POST\",\n headers: headers,\n });\n if (!response.ok) {\n throw new Error(await response.text());\n }\n const { ts } = (await response.json()) as { ts: string };\n return ts;\n }\n\n /**\n * Execute a Convex query function.\n *\n * @param name - The name of the query.\n * @param args - The arguments object for the query. If this is omitted,\n * the arguments will be `{}`.\n * @returns A promise of the query's result.\n */\n async query<Query extends FunctionReference<\"query\">>(\n query: Query,\n ...args: OptionalRestArgs<Query>\n ): Promise<FunctionReturnType<Query>> {\n const queryArgs = parseArgs(args[0]);\n return await this.queryInner(query, queryArgs, {});\n }\n\n private async queryInner<Query extends FunctionReference<\"query\">>(\n query: Query,\n queryArgs: FunctionArgs<Query>,\n options: { timestampPromise?: Promise<string> },\n ): Promise<FunctionReturnType<Query>> {\n const name = getFunctionName(query);\n const args = [convexToJson(queryArgs)];\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"Convex-Client\": `npm-${version}`,\n };\n if (this.adminAuth) {\n headers[\"Authorization\"] = `Convex ${this.adminAuth}`;\n } else if (this.auth) {\n headers[\"Authorization\"] = `Bearer ${this.auth}`;\n }\n const localFetch = specifiedFetch || fetch;\n\n const timestamp = options.timestampPromise\n ? await options.timestampPromise\n : undefined;\n\n const body = JSON.stringify({\n path: name,\n format: \"convex_encoded_json\",\n args,\n ...(timestamp ? { ts: timestamp } : {}),\n });\n const endpoint = timestamp\n ? `${this.address}/api/query_at_ts`\n : `${this.address}/api/query`;\n\n const response = await localFetch(endpoint, {\n ...this.fetchOptions,\n body,\n method: \"POST\",\n headers: headers,\n });\n if (!response.ok && response.status !== STATUS_CODE_UDF_FAILED) {\n throw new Error(await response.text());\n }\n const respJSON = await response.json();\n\n if (this.debug) {\n for (const line of respJSON.logLines ?? []) {\n logForFunction(this.logger, \"info\", \"query\", name, line);\n }\n }\n switch (respJSON.status) {\n case \"success\":\n return jsonToConvex(respJSON.value);\n case \"error\":\n if (respJSON.errorData !== undefined) {\n throw forwardErrorData(\n respJSON.errorData,\n new ConvexError(respJSON.errorMessage),\n );\n }\n throw new Error(respJSON.errorMessage);\n default:\n throw new Error(`Invalid response: ${JSON.stringify(respJSON)}`);\n }\n }\n\n private async mutationInner<Mutation extends FunctionReference<\"mutation\">>(\n mutation: Mutation,\n mutationArgs: FunctionArgs<Mutation>,\n ): Promise<FunctionReturnType<Mutation>> {\n const name = getFunctionName(mutation);\n const body = JSON.stringify({\n path: name,\n format: \"convex_encoded_json\",\n args: [convexToJson(mutationArgs)],\n });\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"Convex-Client\": `npm-${version}`,\n };\n if (this.adminAuth) {\n headers[\"Authorization\"] = `Convex ${this.adminAuth}`;\n } else if (this.auth) {\n headers[\"Authorization\"] = `Bearer ${this.auth}`;\n }\n const localFetch = specifiedFetch || fetch;\n const response = await localFetch(`${this.address}/api/mutation`, {\n ...this.fetchOptions,\n body,\n method: \"POST\",\n headers: headers,\n });\n if (!response.ok && response.status !== STATUS_CODE_UDF_FAILED) {\n throw new Error(await response.text());\n }\n const respJSON = await response.json();\n if (this.debug) {\n for (const line of respJSON.logLines ?? []) {\n logForFunction(this.logger, \"info\", \"mutation\", name, line);\n }\n }\n switch (respJSON.status) {\n case \"success\":\n return jsonToConvex(respJSON.value);\n case \"error\":\n if (respJSON.errorData !== undefined) {\n throw forwardErrorData(\n respJSON.errorData,\n new ConvexError(respJSON.errorMessage),\n );\n }\n throw new Error(respJSON.errorMessage);\n default:\n throw new Error(`Invalid response: ${JSON.stringify(respJSON)}`);\n }\n }\n\n private async processMutationQueue() {\n if (this.isProcessingQueue) {\n return;\n }\n\n this.isProcessingQueue = true;\n while (this.mutationQueue.length > 0) {\n const { mutation, args, resolve, reject } = this.mutationQueue.shift()!;\n try {\n const result = await this.mutationInner(mutation, args);\n resolve(result);\n } catch (error) {\n reject(error);\n }\n }\n this.isProcessingQueue = false;\n }\n\n private enqueueMutation<Mutation extends FunctionReference<\"mutation\">>(\n mutation: Mutation,\n args: FunctionArgs<Mutation>,\n ): Promise<FunctionReturnType<Mutation>> {\n return new Promise((resolve, reject) => {\n this.mutationQueue.push({ mutation, args, resolve, reject });\n void this.processMutationQueue();\n });\n }\n\n /**\n * Execute a Convex mutation function. Mutations are queued by default.\n *\n * @param name - The name of the mutation.\n * @param args - The arguments object for the mutation. If this is omitted,\n * the arguments will be `{}`.\n * @param options - An optional object containing\n * @returns A promise of the mutation's result.\n */\n async mutation<Mutation extends FunctionReference<\"mutation\">>(\n mutation: Mutation,\n ...args: ArgsAndOptions<Mutation, HttpMutationOptions>\n ): Promise<FunctionReturnType<Mutation>> {\n const [fnArgs, options] = args;\n const mutationArgs = parseArgs(fnArgs);\n const queued = !options?.skipQueue;\n\n if (queued) {\n return await this.enqueueMutation(mutation, mutationArgs);\n } else {\n return await this.mutationInner(mutation, mutationArgs);\n }\n }\n\n /**\n * Execute a Convex action function. Actions are not queued.\n *\n * @param name - The name of the action.\n * @param args - The arguments object for the action. If this is omitted,\n * the arguments will be `{}`.\n * @returns A promise of the action's result.\n */\n async action<Action extends FunctionReference<\"action\">>(\n action: Action,\n ...args: OptionalRestArgs<Action>\n ): Promise<FunctionReturnType<Action>> {\n const actionArgs = parseArgs(args[0]);\n const name = getFunctionName(action);\n const body = JSON.stringify({\n path: name,\n format: \"convex_encoded_json\",\n args: [convexToJson(actionArgs)],\n });\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"Convex-Client\": `npm-${version}`,\n };\n if (this.adminAuth) {\n headers[\"Authorization\"] = `Convex ${this.adminAuth}`;\n } else if (this.auth) {\n headers[\"Authorization\"] = `Bearer ${this.auth}`;\n }\n const localFetch = specifiedFetch || fetch;\n const response = await localFetch(`${this.address}/api/action`, {\n ...this.fetchOptions,\n body,\n method: \"POST\",\n headers: headers,\n });\n if (!response.ok && response.status !== STATUS_CODE_UDF_FAILED) {\n throw new Error(await response.text());\n }\n const respJSON = await response.json();\n if (this.debug) {\n for (const line of respJSON.logLines ?? []) {\n logForFunction(this.logger, \"info\", \"action\", name, line);\n }\n }\n switch (respJSON.status) {\n case \"success\":\n return jsonToConvex(respJSON.value);\n case \"error\":\n if (respJSON.errorData !== undefined) {\n throw forwardErrorData(\n respJSON.errorData,\n new ConvexError(respJSON.errorMessage),\n );\n }\n throw new Error(respJSON.errorMessage);\n default:\n throw new Error(`Invalid response: ${JSON.stringify(respJSON)}`);\n }\n }\n\n /**\n * Execute a Convex function of an unknown type. These function calls are not queued.\n *\n * @param name - The name of the function.\n * @param args - The arguments object for the function. If this is omitted,\n * the arguments will be `{}`.\n * @returns A promise of the function's result.\n *\n * @internal\n */\n async function<\n AnyFunction extends FunctionReference<\"query\" | \"mutation\" | \"action\">,\n >(\n anyFunction: AnyFunction | string,\n componentPath?: string,\n ...args: OptionalRestArgs<AnyFunction>\n ): Promise<FunctionReturnType<AnyFunction>> {\n const functionArgs = parseArgs(args[0]);\n const name =\n typeof anyFunction === \"string\"\n ? anyFunction\n : getFunctionName(anyFunction);\n const body = JSON.stringify({\n componentPath: componentPath,\n path: name,\n format: \"convex_encoded_json\",\n args: convexToJson(functionArgs),\n });\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"Convex-Client\": `npm-${version}`,\n };\n if (this.adminAuth) {\n headers[\"Authorization\"] = `Convex ${this.adminAuth}`;\n } else if (this.auth) {\n headers[\"Authorization\"] = `Bearer ${this.auth}`;\n }\n const localFetch = specifiedFetch || fetch;\n const response = await localFetch(`${this.address}/api/function`, {\n ...this.fetchOptions,\n body,\n method: \"POST\",\n headers: headers,\n });\n if (!response.ok && response.status !== STATUS_CODE_UDF_FAILED) {\n throw new Error(await response.text());\n }\n const respJSON = await response.json();\n if (this.debug) {\n for (const line of respJSON.logLines ?? []) {\n logForFunction(this.logger, \"info\", \"any\", name, line);\n }\n }\n switch (respJSON.status) {\n case \"success\":\n return jsonToConvex(respJSON.value);\n case \"error\":\n if (respJSON.errorData !== undefined) {\n throw forwardErrorData(\n respJSON.errorData,\n new ConvexError(respJSON.errorMessage),\n );\n }\n throw new Error(respJSON.errorMessage);\n default:\n throw new Error(`Invalid response: ${JSON.stringify(respJSON)}`);\n }\n }\n}\n\nfunction forwardErrorData(errorData: JSONValue, error: ConvexError<string>) {\n (error as ConvexError<any>).data = jsonToConvex(errorData);\n return error;\n}\n\n/**\n * @internal\n */\ntype FetchOptions = { cache: \"force-cache\" | \"no-store\" };\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAKO;AACP,oBAAiD;AACjD,eAAwB;AACxB,oBAKO;AACP,qBAKO;AAOA,MAAM,iBAAiB;AACvB,MAAM,0BAA0B;AAIhC,MAAM,yBAAyB;AAGtC,IAAI,iBAAsD;AACnD,SAAS,SAAS,GAA4B;AACnD,mBAAiB;AACnB;AAuBO,MAAM,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,
|
|
4
|
+
"sourcesContent": ["import {\n FunctionReference,\n FunctionReturnType,\n OptionalRestArgs,\n getFunctionName,\n} from \"../server/api.js\";\nimport { parseArgs, validateDeploymentUrl } from \"../common/index.js\";\nimport { version } from \"../index.js\";\nimport {\n ConvexError,\n JSONValue,\n convexToJson,\n jsonToConvex,\n} from \"../values/index.js\";\nimport {\n instantiateDefaultLogger,\n instantiateNoopLogger,\n logForFunction,\n Logger,\n} from \"./logging.js\";\nimport {\n ArgsAndOptions,\n FunctionArgs,\n UserIdentityAttributes,\n} from \"../server/index.js\";\n\nexport const STATUS_CODE_OK = 200;\nexport const STATUS_CODE_BAD_REQUEST = 400;\n// Special custom 5xx HTTP status code to mean that the UDF returned an error.\n//\n// Must match the constant of the same name in the backend.\nexport const STATUS_CODE_UDF_FAILED = 560;\n\n// Allow fetch to be shimmed in for Node.js < 18\nlet specifiedFetch: typeof globalThis.fetch | undefined = undefined;\nexport function setFetch(f: typeof globalThis.fetch) {\n specifiedFetch = f;\n}\n\nexport type HttpMutationOptions = {\n /**\n * Skip the default queue of mutations and run this immediately.\n *\n * This allows the same HttpConvexClient to be used to request multiple\n * mutations in parallel, something not possible with WebSocket-based clients.\n */\n skipQueue: boolean;\n};\n\n/**\n * A Convex client that runs queries and mutations over HTTP.\n *\n * This client is stateful (it has user credentials and queues mutations)\n * so take care to avoid sharing it between requests in a server.\n *\n * This is appropriate for server-side code (like Netlify Lambdas) or non-reactive\n * webapps.\n *\n * @public\n */\nexport class ConvexHttpClient {\n private readonly address: string;\n private auth?: string;\n private adminAuth?: string;\n private encodedTsPromise?: Promise<string>;\n private debug: boolean;\n private fetchOptions?: FetchOptions;\n private logger: Logger;\n private mutationQueue: Array<{\n mutation: FunctionReference<\"mutation\">;\n args: FunctionArgs<any>;\n resolve: (value: any) => void;\n reject: (error: any) => void;\n }> = [];\n private isProcessingQueue: boolean = false;\n\n /**\n * Create a new {@link ConvexHttpClient}.\n *\n * @param address - The url of your Convex deployment, often provided\n * by an environment variable. E.g. `https://small-mouse-123.convex.cloud`.\n * @param options - An object of options.\n * - `skipConvexDeploymentUrlCheck` - Skip validating that the Convex deployment URL looks like\n * `https://happy-animal-123.convex.cloud` or localhost. This can be useful if running a self-hosted\n * Convex backend that uses a different URL.\n * - `logger` - A logger or a boolean. If not provided, logs to the console.\n * You can construct your own logger to customize logging to log elsewhere\n * or not log at all, or use `false` as a shorthand for a no-op logger.\n * A logger is an object with 4 methods: log(), warn(), error(), and logVerbose().\n * These methods can receive multiple arguments of any types, like console.log().\n * - `auth` - A JWT containing identity claims accessible in Convex functions.\n * This identity may expire so it may be necessary to call `setAuth()` later,\n * but for short-lived clients it's convenient to specify this value here.\n */\n constructor(\n address: string,\n options?: {\n skipConvexDeploymentUrlCheck?: boolean;\n logger?: Logger | boolean;\n auth?: string;\n },\n ) {\n if (typeof options === \"boolean\") {\n throw new Error(\n \"skipConvexDeploymentUrlCheck as the second argument is no longer supported. Please pass an options object, `{ skipConvexDeploymentUrlCheck: true }`.\",\n );\n }\n const opts = options ?? {};\n if (opts.skipConvexDeploymentUrlCheck !== true) {\n validateDeploymentUrl(address);\n }\n this.logger =\n options?.logger === false\n ? instantiateNoopLogger({ verbose: false })\n : options?.logger !== true && options?.logger\n ? options.logger\n : instantiateDefaultLogger({ verbose: false });\n this.address = address;\n this.debug = true;\n }\n\n /**\n * Obtain the {@link ConvexHttpClient}'s URL to its backend.\n * @deprecated Use url, which returns the url without /api at the end.\n *\n * @returns The URL to the Convex backend, including the client's API version.\n */\n backendUrl(): string {\n return `${this.address}/api`;\n }\n\n /**\n * Return the address for this client, useful for creating a new client.\n *\n * Not guaranteed to match the address with which this client was constructed:\n * it may be canonicalized.\n */\n get url() {\n return this.address;\n }\n\n /**\n * Set the authentication token to be used for subsequent queries and mutations.\n *\n * Should be called whenever the token changes (i.e. due to expiration and refresh).\n *\n * @param value - JWT-encoded OpenID Connect identity token.\n */\n setAuth(value: string) {\n this.clearAuth();\n this.auth = value;\n }\n\n /**\n * Set admin auth token to allow calling internal queries, mutations, and actions\n * and acting as an identity.\n *\n * @internal\n */\n setAdminAuth(token: string, actingAsIdentity?: UserIdentityAttributes) {\n this.clearAuth();\n if (actingAsIdentity !== undefined) {\n // Encode the identity to a base64 string\n const bytes = new TextEncoder().encode(JSON.stringify(actingAsIdentity));\n const actingAsIdentityEncoded = btoa(String.fromCodePoint(...bytes));\n this.adminAuth = `${token}:${actingAsIdentityEncoded}`;\n } else {\n this.adminAuth = token;\n }\n }\n\n /**\n * Clear the current authentication token if set.\n */\n clearAuth() {\n this.auth = undefined;\n this.adminAuth = undefined;\n }\n\n /**\n * Sets whether the result log lines should be printed on the console or not.\n *\n * @internal\n */\n setDebug(debug: boolean) {\n this.debug = debug;\n }\n\n /**\n * Used to customize the fetch behavior in some runtimes.\n *\n * @internal\n */\n setFetchOptions(fetchOptions: FetchOptions) {\n this.fetchOptions = fetchOptions;\n }\n\n /**\n * This API is experimental: it may change or disappear.\n *\n * Execute a Convex query function at the same timestamp as every other\n * consistent query execution run by this HTTP client.\n *\n * This doesn't make sense for long-lived ConvexHttpClients as Convex\n * backends can read a limited amount into the past: beyond 30 seconds\n * in the past may not be available.\n *\n * Create a new client to use a consistent time.\n *\n * @param name - The name of the query.\n * @param args - The arguments object for the query. If this is omitted,\n * the arguments will be `{}`.\n * @returns A promise of the query's result.\n *\n * @deprecated This API is experimental: it may change or disappear.\n */\n async consistentQuery<Query extends FunctionReference<\"query\">>(\n query: Query,\n ...args: OptionalRestArgs<Query>\n ): Promise<FunctionReturnType<Query>> {\n const queryArgs = parseArgs(args[0]);\n\n const timestampPromise = this.getTimestamp();\n return await this.queryInner(query, queryArgs, { timestampPromise });\n }\n\n private async getTimestamp() {\n if (this.encodedTsPromise) {\n return this.encodedTsPromise;\n }\n return (this.encodedTsPromise = this.getTimestampInner());\n }\n\n private async getTimestampInner() {\n const localFetch = specifiedFetch || fetch;\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"Convex-Client\": `npm-${version}`,\n };\n const response = await localFetch(`${this.address}/api/query_ts`, {\n ...this.fetchOptions,\n method: \"POST\",\n headers: headers,\n });\n if (!response.ok) {\n throw new Error(await response.text());\n }\n const { ts } = (await response.json()) as { ts: string };\n return ts;\n }\n\n /**\n * Execute a Convex query function.\n *\n * @param name - The name of the query.\n * @param args - The arguments object for the query. If this is omitted,\n * the arguments will be `{}`.\n * @returns A promise of the query's result.\n */\n async query<Query extends FunctionReference<\"query\">>(\n query: Query,\n ...args: OptionalRestArgs<Query>\n ): Promise<FunctionReturnType<Query>> {\n const queryArgs = parseArgs(args[0]);\n return await this.queryInner(query, queryArgs, {});\n }\n\n private async queryInner<Query extends FunctionReference<\"query\">>(\n query: Query,\n queryArgs: FunctionArgs<Query>,\n options: { timestampPromise?: Promise<string> },\n ): Promise<FunctionReturnType<Query>> {\n const name = getFunctionName(query);\n const args = [convexToJson(queryArgs)];\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"Convex-Client\": `npm-${version}`,\n };\n if (this.adminAuth) {\n headers[\"Authorization\"] = `Convex ${this.adminAuth}`;\n } else if (this.auth) {\n headers[\"Authorization\"] = `Bearer ${this.auth}`;\n }\n const localFetch = specifiedFetch || fetch;\n\n const timestamp = options.timestampPromise\n ? await options.timestampPromise\n : undefined;\n\n const body = JSON.stringify({\n path: name,\n format: \"convex_encoded_json\",\n args,\n ...(timestamp ? { ts: timestamp } : {}),\n });\n const endpoint = timestamp\n ? `${this.address}/api/query_at_ts`\n : `${this.address}/api/query`;\n\n const response = await localFetch(endpoint, {\n ...this.fetchOptions,\n body,\n method: \"POST\",\n headers: headers,\n });\n if (!response.ok && response.status !== STATUS_CODE_UDF_FAILED) {\n throw new Error(await response.text());\n }\n const respJSON = await response.json();\n\n if (this.debug) {\n for (const line of respJSON.logLines ?? []) {\n logForFunction(this.logger, \"info\", \"query\", name, line);\n }\n }\n switch (respJSON.status) {\n case \"success\":\n return jsonToConvex(respJSON.value);\n case \"error\":\n if (respJSON.errorData !== undefined) {\n throw forwardErrorData(\n respJSON.errorData,\n new ConvexError(respJSON.errorMessage),\n );\n }\n throw new Error(respJSON.errorMessage);\n default:\n throw new Error(`Invalid response: ${JSON.stringify(respJSON)}`);\n }\n }\n\n private async mutationInner<Mutation extends FunctionReference<\"mutation\">>(\n mutation: Mutation,\n mutationArgs: FunctionArgs<Mutation>,\n ): Promise<FunctionReturnType<Mutation>> {\n const name = getFunctionName(mutation);\n const body = JSON.stringify({\n path: name,\n format: \"convex_encoded_json\",\n args: [convexToJson(mutationArgs)],\n });\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"Convex-Client\": `npm-${version}`,\n };\n if (this.adminAuth) {\n headers[\"Authorization\"] = `Convex ${this.adminAuth}`;\n } else if (this.auth) {\n headers[\"Authorization\"] = `Bearer ${this.auth}`;\n }\n const localFetch = specifiedFetch || fetch;\n const response = await localFetch(`${this.address}/api/mutation`, {\n ...this.fetchOptions,\n body,\n method: \"POST\",\n headers: headers,\n });\n if (!response.ok && response.status !== STATUS_CODE_UDF_FAILED) {\n throw new Error(await response.text());\n }\n const respJSON = await response.json();\n if (this.debug) {\n for (const line of respJSON.logLines ?? []) {\n logForFunction(this.logger, \"info\", \"mutation\", name, line);\n }\n }\n switch (respJSON.status) {\n case \"success\":\n return jsonToConvex(respJSON.value);\n case \"error\":\n if (respJSON.errorData !== undefined) {\n throw forwardErrorData(\n respJSON.errorData,\n new ConvexError(respJSON.errorMessage),\n );\n }\n throw new Error(respJSON.errorMessage);\n default:\n throw new Error(`Invalid response: ${JSON.stringify(respJSON)}`);\n }\n }\n\n private async processMutationQueue() {\n if (this.isProcessingQueue) {\n return;\n }\n\n this.isProcessingQueue = true;\n while (this.mutationQueue.length > 0) {\n const { mutation, args, resolve, reject } = this.mutationQueue.shift()!;\n try {\n const result = await this.mutationInner(mutation, args);\n resolve(result);\n } catch (error) {\n reject(error);\n }\n }\n this.isProcessingQueue = false;\n }\n\n private enqueueMutation<Mutation extends FunctionReference<\"mutation\">>(\n mutation: Mutation,\n args: FunctionArgs<Mutation>,\n ): Promise<FunctionReturnType<Mutation>> {\n return new Promise((resolve, reject) => {\n this.mutationQueue.push({ mutation, args, resolve, reject });\n void this.processMutationQueue();\n });\n }\n\n /**\n * Execute a Convex mutation function. Mutations are queued by default.\n *\n * @param name - The name of the mutation.\n * @param args - The arguments object for the mutation. If this is omitted,\n * the arguments will be `{}`.\n * @param options - An optional object containing\n * @returns A promise of the mutation's result.\n */\n async mutation<Mutation extends FunctionReference<\"mutation\">>(\n mutation: Mutation,\n ...args: ArgsAndOptions<Mutation, HttpMutationOptions>\n ): Promise<FunctionReturnType<Mutation>> {\n const [fnArgs, options] = args;\n const mutationArgs = parseArgs(fnArgs);\n const queued = !options?.skipQueue;\n\n if (queued) {\n return await this.enqueueMutation(mutation, mutationArgs);\n } else {\n return await this.mutationInner(mutation, mutationArgs);\n }\n }\n\n /**\n * Execute a Convex action function. Actions are not queued.\n *\n * @param name - The name of the action.\n * @param args - The arguments object for the action. If this is omitted,\n * the arguments will be `{}`.\n * @returns A promise of the action's result.\n */\n async action<Action extends FunctionReference<\"action\">>(\n action: Action,\n ...args: OptionalRestArgs<Action>\n ): Promise<FunctionReturnType<Action>> {\n const actionArgs = parseArgs(args[0]);\n const name = getFunctionName(action);\n const body = JSON.stringify({\n path: name,\n format: \"convex_encoded_json\",\n args: [convexToJson(actionArgs)],\n });\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"Convex-Client\": `npm-${version}`,\n };\n if (this.adminAuth) {\n headers[\"Authorization\"] = `Convex ${this.adminAuth}`;\n } else if (this.auth) {\n headers[\"Authorization\"] = `Bearer ${this.auth}`;\n }\n const localFetch = specifiedFetch || fetch;\n const response = await localFetch(`${this.address}/api/action`, {\n ...this.fetchOptions,\n body,\n method: \"POST\",\n headers: headers,\n });\n if (!response.ok && response.status !== STATUS_CODE_UDF_FAILED) {\n throw new Error(await response.text());\n }\n const respJSON = await response.json();\n if (this.debug) {\n for (const line of respJSON.logLines ?? []) {\n logForFunction(this.logger, \"info\", \"action\", name, line);\n }\n }\n switch (respJSON.status) {\n case \"success\":\n return jsonToConvex(respJSON.value);\n case \"error\":\n if (respJSON.errorData !== undefined) {\n throw forwardErrorData(\n respJSON.errorData,\n new ConvexError(respJSON.errorMessage),\n );\n }\n throw new Error(respJSON.errorMessage);\n default:\n throw new Error(`Invalid response: ${JSON.stringify(respJSON)}`);\n }\n }\n\n /**\n * Execute a Convex function of an unknown type. These function calls are not queued.\n *\n * @param name - The name of the function.\n * @param args - The arguments object for the function. If this is omitted,\n * the arguments will be `{}`.\n * @returns A promise of the function's result.\n *\n * @internal\n */\n async function<\n AnyFunction extends FunctionReference<\"query\" | \"mutation\" | \"action\">,\n >(\n anyFunction: AnyFunction | string,\n componentPath?: string,\n ...args: OptionalRestArgs<AnyFunction>\n ): Promise<FunctionReturnType<AnyFunction>> {\n const functionArgs = parseArgs(args[0]);\n const name =\n typeof anyFunction === \"string\"\n ? anyFunction\n : getFunctionName(anyFunction);\n const body = JSON.stringify({\n componentPath: componentPath,\n path: name,\n format: \"convex_encoded_json\",\n args: convexToJson(functionArgs),\n });\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"Convex-Client\": `npm-${version}`,\n };\n if (this.adminAuth) {\n headers[\"Authorization\"] = `Convex ${this.adminAuth}`;\n } else if (this.auth) {\n headers[\"Authorization\"] = `Bearer ${this.auth}`;\n }\n const localFetch = specifiedFetch || fetch;\n const response = await localFetch(`${this.address}/api/function`, {\n ...this.fetchOptions,\n body,\n method: \"POST\",\n headers: headers,\n });\n if (!response.ok && response.status !== STATUS_CODE_UDF_FAILED) {\n throw new Error(await response.text());\n }\n const respJSON = await response.json();\n if (this.debug) {\n for (const line of respJSON.logLines ?? []) {\n logForFunction(this.logger, \"info\", \"any\", name, line);\n }\n }\n switch (respJSON.status) {\n case \"success\":\n return jsonToConvex(respJSON.value);\n case \"error\":\n if (respJSON.errorData !== undefined) {\n throw forwardErrorData(\n respJSON.errorData,\n new ConvexError(respJSON.errorMessage),\n );\n }\n throw new Error(respJSON.errorMessage);\n default:\n throw new Error(`Invalid response: ${JSON.stringify(respJSON)}`);\n }\n }\n}\n\nfunction forwardErrorData(errorData: JSONValue, error: ConvexError<string>) {\n (error as ConvexError<any>).data = jsonToConvex(errorData);\n return error;\n}\n\n/**\n * @internal\n */\ntype FetchOptions = { cache: \"force-cache\" | \"no-store\" };\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -20,7 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
21
21
|
var logging_exports = {};
|
|
22
22
|
__export(logging_exports, {
|
|
23
|
-
|
|
23
|
+
DefaultLogger: () => DefaultLogger,
|
|
24
24
|
createHybridErrorStacktrace: () => createHybridErrorStacktrace,
|
|
25
25
|
forwardData: () => forwardData,
|
|
26
26
|
instantiateDefaultLogger: () => instantiateDefaultLogger,
|
|
@@ -42,7 +42,7 @@ function prefix_for_source(source) {
|
|
|
42
42
|
return "?";
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
|
-
class
|
|
45
|
+
class DefaultLogger {
|
|
46
46
|
constructor(options) {
|
|
47
47
|
__publicField(this, "_onLogLineFuncs");
|
|
48
48
|
__publicField(this, "_verbose");
|
|
@@ -86,7 +86,7 @@ class Logger {
|
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
88
|
function instantiateDefaultLogger(options) {
|
|
89
|
-
const logger = new
|
|
89
|
+
const logger = new DefaultLogger(options);
|
|
90
90
|
logger.addLogLineListener((level, ...args) => {
|
|
91
91
|
switch (level) {
|
|
92
92
|
case "debug":
|
|
@@ -110,7 +110,7 @@ function instantiateDefaultLogger(options) {
|
|
|
110
110
|
return logger;
|
|
111
111
|
}
|
|
112
112
|
function instantiateNoopLogger(options) {
|
|
113
|
-
return new
|
|
113
|
+
return new DefaultLogger(options);
|
|
114
114
|
}
|
|
115
115
|
function logForFunction(logger, type, source, udfPath, message) {
|
|
116
116
|
const prefix = prefix_for_source(source);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/browser/logging.ts"],
|
|
4
|
-
"sourcesContent": ["/* eslint-disable no-console */ // This is the one file where we can `console.log` for the default logger implementation.\nimport { ConvexError, Value } from \"../values/index.js\";\nimport { FunctionFailure } from \"./sync/function_result.js\";\n\n// This is blue #9 from https://www.radix-ui.com/docs/colors/palette-composition/the-scales\n// It must look good in both light and dark mode.\nconst INFO_COLOR = \"color:rgb(0, 145, 255)\";\n\nexport type UdfType = \"query\" | \"mutation\" | \"action\" | \"any\";\n\nfunction prefix_for_source(source: UdfType) {\n switch (source) {\n case \"query\":\n return \"Q\";\n case \"mutation\":\n return \"M\";\n case \"action\":\n return \"A\";\n case \"any\":\n return \"?\";\n }\n}\n\nexport type LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\";\n\n/**\n * A logger that can be used to log messages. By default, this is a wrapper\n * around `console`, but can be configured to not log at all or to log somewhere\n * else.\n */\nexport class Logger {\n private _onLogLineFuncs: Record<\n string,\n (level: LogLevel, ...args: any[]) => void\n >;\n private _verbose: boolean;\n\n constructor(options: { verbose: boolean }) {\n this._onLogLineFuncs = {};\n this._verbose = options.verbose;\n }\n\n addLogLineListener(\n func: (level: LogLevel, ...args: any[]) => void,\n ): () => void {\n let id = Math.random().toString(36).substring(2, 15);\n for (let i = 0; i < 10; i++) {\n if (this._onLogLineFuncs[id] === undefined) {\n break;\n }\n id = Math.random().toString(36).substring(2, 15);\n }\n this._onLogLineFuncs[id] = func;\n return () => {\n delete this._onLogLineFuncs[id];\n };\n }\n\n logVerbose(...args: any[]) {\n if (this._verbose) {\n for (const func of Object.values(this._onLogLineFuncs)) {\n func(\"debug\", `${new Date().toISOString()}`, ...args);\n }\n }\n }\n\n log(...args: any[]) {\n for (const func of Object.values(this._onLogLineFuncs)) {\n func(\"info\", ...args);\n }\n }\n\n warn(...args: any[]) {\n for (const func of Object.values(this._onLogLineFuncs)) {\n func(\"warn\", ...args);\n }\n }\n\n error(...args: any[]) {\n for (const func of Object.values(this._onLogLineFuncs)) {\n func(\"error\", ...args);\n }\n }\n}\n\nexport function instantiateDefaultLogger(options: {\n verbose: boolean;\n}): Logger {\n const logger = new
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAMA,MAAM,aAAa;AAInB,SAAS,kBAAkB,QAAiB;AAC1C,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,EACX;AACF;
|
|
4
|
+
"sourcesContent": ["/* eslint-disable no-console */ // This is the one file where we can `console.log` for the default logger implementation.\nimport { ConvexError, Value } from \"../values/index.js\";\nimport { FunctionFailure } from \"./sync/function_result.js\";\n\n// This is blue #9 from https://www.radix-ui.com/docs/colors/palette-composition/the-scales\n// It must look good in both light and dark mode.\nconst INFO_COLOR = \"color:rgb(0, 145, 255)\";\n\nexport type UdfType = \"query\" | \"mutation\" | \"action\" | \"any\";\n\nfunction prefix_for_source(source: UdfType) {\n switch (source) {\n case \"query\":\n return \"Q\";\n case \"mutation\":\n return \"M\";\n case \"action\":\n return \"A\";\n case \"any\":\n return \"?\";\n }\n}\n\nexport type LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\";\n\n/**\n * A logger that can be used to log messages. By default, this is a wrapper\n * around `console`, but can be configured to not log at all or to log somewhere\n * else.\n */\nexport type Logger = {\n logVerbose(...args: any[]): void;\n log(...args: any[]): void;\n warn(...args: any[]): void;\n error(...args: any[]): void;\n};\n\nexport class DefaultLogger implements Logger {\n private _onLogLineFuncs: Record<\n string,\n (level: LogLevel, ...args: any[]) => void\n >;\n private _verbose: boolean;\n\n constructor(options: { verbose: boolean }) {\n this._onLogLineFuncs = {};\n this._verbose = options.verbose;\n }\n\n addLogLineListener(\n func: (level: LogLevel, ...args: any[]) => void,\n ): () => void {\n let id = Math.random().toString(36).substring(2, 15);\n for (let i = 0; i < 10; i++) {\n if (this._onLogLineFuncs[id] === undefined) {\n break;\n }\n id = Math.random().toString(36).substring(2, 15);\n }\n this._onLogLineFuncs[id] = func;\n return () => {\n delete this._onLogLineFuncs[id];\n };\n }\n\n logVerbose(...args: any[]) {\n if (this._verbose) {\n for (const func of Object.values(this._onLogLineFuncs)) {\n func(\"debug\", `${new Date().toISOString()}`, ...args);\n }\n }\n }\n\n log(...args: any[]) {\n for (const func of Object.values(this._onLogLineFuncs)) {\n func(\"info\", ...args);\n }\n }\n\n warn(...args: any[]) {\n for (const func of Object.values(this._onLogLineFuncs)) {\n func(\"warn\", ...args);\n }\n }\n\n error(...args: any[]) {\n for (const func of Object.values(this._onLogLineFuncs)) {\n func(\"error\", ...args);\n }\n }\n}\n\nexport function instantiateDefaultLogger(options: {\n verbose: boolean;\n}): Logger {\n const logger = new DefaultLogger(options);\n logger.addLogLineListener((level, ...args) => {\n switch (level) {\n case \"debug\":\n console.debug(...args);\n break;\n case \"info\":\n console.log(...args);\n break;\n case \"warn\":\n console.warn(...args);\n break;\n case \"error\":\n console.error(...args);\n break;\n default: {\n const _typecheck: never = level;\n console.log(...args);\n }\n }\n });\n return logger;\n}\n\nexport function instantiateNoopLogger(options: { verbose: boolean }): Logger {\n return new DefaultLogger(options);\n}\n\nexport function logForFunction(\n logger: Logger,\n type: \"info\" | \"error\",\n source: UdfType,\n udfPath: string,\n message: string | { errorData: Value },\n) {\n const prefix = prefix_for_source(source);\n\n if (typeof message === \"object\") {\n message = `ConvexError ${JSON.stringify(message.errorData, null, 2)}`;\n }\n if (type === \"info\") {\n const match = message.match(/^\\[.*?\\] /);\n if (match === null) {\n logger.error(\n `[CONVEX ${prefix}(${udfPath})] Could not parse console.log`,\n );\n return;\n }\n const level = message.slice(1, match[0].length - 2);\n const args = message.slice(match[0].length);\n\n logger.log(`%c[CONVEX ${prefix}(${udfPath})] [${level}]`, INFO_COLOR, args);\n } else {\n logger.error(`[CONVEX ${prefix}(${udfPath})] ${message}`);\n }\n}\n\nexport function logFatalError(logger: Logger, message: string): Error {\n const errorMessage = `[CONVEX FATAL ERROR] ${message}`;\n logger.error(errorMessage);\n return new Error(errorMessage);\n}\n\nexport function createHybridErrorStacktrace(\n source: UdfType,\n udfPath: string,\n result: FunctionFailure,\n): string {\n const prefix = prefix_for_source(source);\n return `[CONVEX ${prefix}(${udfPath})] ${result.errorMessage}\\n Called by client`;\n}\n\nexport function forwardData(\n result: FunctionFailure,\n error: ConvexError<string>,\n) {\n (error as ConvexError<any>).data = result.errorData;\n return error;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -280,5 +280,30 @@ class ConvexClient {
|
|
|
280
280
|
);
|
|
281
281
|
});
|
|
282
282
|
}
|
|
283
|
+
/**
|
|
284
|
+
* Get the current {@link ConnectionState} between the client and the Convex
|
|
285
|
+
* backend.
|
|
286
|
+
*
|
|
287
|
+
* @returns The {@link ConnectionState} with the Convex backend.
|
|
288
|
+
*/
|
|
289
|
+
connectionState() {
|
|
290
|
+
if (this.disabled) throw new Error("ConvexClient is disabled");
|
|
291
|
+
return this.client.connectionState();
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Subscribe to the {@link ConnectionState} between the client and the Convex
|
|
295
|
+
* backend, calling a callback each time it changes.
|
|
296
|
+
*
|
|
297
|
+
* Subscribed callbacks will be called when any part of ConnectionState changes.
|
|
298
|
+
* ConnectionState may grow in future versions (e.g. to provide a array of
|
|
299
|
+
* inflight requests) in which case callbacks would be called more frequently.
|
|
300
|
+
*
|
|
301
|
+
* @returns An unsubscribe function to stop listening.
|
|
302
|
+
*/
|
|
303
|
+
subscribeToConnectionState(cb) {
|
|
304
|
+
if (this.disabled) return () => {
|
|
305
|
+
};
|
|
306
|
+
return this.client.subscribeToConnectionState(cb);
|
|
307
|
+
}
|
|
283
308
|
}
|
|
284
309
|
//# sourceMappingURL=simple_client.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/browser/simple_client.ts"],
|
|
4
|
-
"sourcesContent": ["import { validateDeploymentUrl } from \"../common/index.js\";\nimport {\n BaseConvexClient,\n BaseConvexClientOptions,\n MutationOptions,\n QueryToken,\n UserIdentityAttributes,\n} from \"./index.js\";\nimport {\n FunctionArgs,\n FunctionReference,\n FunctionReturnType,\n} from \"../server/index.js\";\nimport { getFunctionName } from \"../server/api.js\";\nimport { AuthTokenFetcher } from \"./sync/authentication_manager.js\";\n\n// In Node.js builds this points to a bundled WebSocket implementation. If no\n// WebSocket implementation is manually specified or globally available,\n// this one is used.\nlet defaultWebSocketConstructor: typeof WebSocket | undefined;\n\n/** internal */\nexport function setDefaultWebSocketConstructor(ws: typeof WebSocket) {\n defaultWebSocketConstructor = ws;\n}\n\nexport type ConvexClientOptions = BaseConvexClientOptions & {\n /**\n * `disabled` makes onUpdate callback registration a no-op and actions,\n * mutations and one-shot queries throw. Setting disabled to true may be\n * useful for server-side rendering, where subscriptions don't make sense.\n */\n disabled?: boolean;\n /**\n * Whether to prompt users in browsers about queued or in-flight mutations.\n * This only works in environments where `window.onbeforeunload` is available.\n *\n * Defaults to true when `window` is defined, otherwise false.\n */\n unsavedChangesWarning?: boolean;\n};\n\n/**\n * Stops callbacks from running.\n *\n * @public\n */\nexport type Unsubscribe<T> = {\n /** Stop calling callback when query results changes. If this is the last listener on this query, stop received updates. */\n (): void;\n /** Stop calling callback when query results changes. If this is the last listener on this query, stop received updates. */\n unsubscribe(): void;\n /** Get the last known value, possibly with local optimistic updates applied. */\n getCurrentValue(): T | undefined;\n /** @internal */\n getQueryLogs(): string[] | undefined;\n};\n\n/**\n * Subscribes to Convex query functions and executes mutations and actions over a WebSocket.\n *\n * Optimistic updates for mutations are not provided for this client.\n * Third party clients may choose to wrap {@link browser.BaseConvexClient} for additional control.\n *\n * ```ts\n * const client = new ConvexClient(\"https://happy-otter-123.convex.cloud\");\n * const unsubscribe = client.onUpdate(api.messages.list, (messages) => {\n * console.log(messages[0].body);\n * });\n * ```\n *\n * @public\n */\nexport class ConvexClient {\n private listeners: Set<QueryInfo>;\n private _client: BaseConvexClient | undefined;\n // A synthetic server event to run callbacks the first time\n private callNewListenersWithCurrentValuesTimer:\n | ReturnType<typeof setTimeout>\n | undefined;\n private _closed: boolean;\n private _disabled: boolean;\n /**\n * Once closed no registered callbacks will fire again.\n */\n get closed(): boolean {\n return this._closed;\n }\n get client(): BaseConvexClient {\n if (this._client) return this._client;\n throw new Error(\"ConvexClient is disabled\");\n }\n get disabled(): boolean {\n return this._disabled;\n }\n\n /**\n * Construct a client and immediately initiate a WebSocket connection to the passed address.\n *\n * @public\n */\n constructor(address: string, options: ConvexClientOptions = {}) {\n if (options.skipConvexDeploymentUrlCheck !== true) {\n validateDeploymentUrl(address);\n }\n const { disabled, ...baseOptions } = options;\n this._closed = false;\n this._disabled = !!disabled;\n if (\n defaultWebSocketConstructor &&\n !(\"webSocketConstructor\" in baseOptions) &&\n typeof WebSocket === \"undefined\"\n ) {\n baseOptions.webSocketConstructor = defaultWebSocketConstructor;\n }\n if (\n typeof window === \"undefined\" &&\n !(\"unsavedChangesWarning\" in baseOptions)\n ) {\n baseOptions.unsavedChangesWarning = false;\n }\n if (!this.disabled) {\n this._client = new BaseConvexClient(\n address,\n (updatedQueries) => this._transition(updatedQueries),\n baseOptions,\n );\n }\n this.listeners = new Set();\n }\n\n /**\n * Call a callback whenever a new result for a query is received. The callback\n * will run soon after being registered if a result for the query is already\n * in memory.\n *\n * The return value is an {@link Unsubscribe} object which is both a function\n * an an object with properties. Both of the patterns below work with this object:\n *\n *```ts\n * // call the return value as a function\n * const unsubscribe = client.onUpdate(api.messages.list, {}, (messages) => {\n * console.log(messages);\n * });\n * unsubscribe();\n *\n * // unpack the return value into its properties\n * const {\n * getCurrentValue,\n * unsubscribe,\n * } = client.onUpdate(api.messages.list, {}, (messages) => {\n * console.log(messages);\n * });\n *```\n *\n * @param query - A {@link server.FunctionReference} for the public query to run.\n * @param args - The arguments to run the query with.\n * @param callback - Function to call when the query result updates.\n * @param onError - Function to call when the query result updates with an error.\n * If not provided, errors will be thrown instead of calling the callback.\n *\n * @return an {@link Unsubscribe} function to stop calling the onUpdate function.\n */\n onUpdate<Query extends FunctionReference<\"query\">>(\n query: Query,\n args: FunctionArgs<Query>,\n callback: (result: FunctionReturnType<Query>) => unknown,\n onError?: (e: Error) => unknown,\n ): Unsubscribe<Query[\"_returnType\"]> {\n if (this.disabled) {\n const disabledUnsubscribe = (() => {}) as Unsubscribe<\n Query[\"_returnType\"]\n >;\n const unsubscribeProps: RemoveCallSignature<\n Unsubscribe<Query[\"_returnType\"]>\n > = {\n unsubscribe: disabledUnsubscribe,\n getCurrentValue: () => undefined,\n getQueryLogs: () => undefined,\n };\n Object.assign(disabledUnsubscribe, unsubscribeProps);\n return disabledUnsubscribe;\n }\n\n // BaseConvexClient takes care of deduplicating queries subscriptions...\n const { queryToken, unsubscribe } = this.client.subscribe(\n getFunctionName(query),\n args,\n );\n\n // ...but we still need to bookkeep callbacks to actually call them.\n const queryInfo: QueryInfo = {\n queryToken,\n callback,\n onError,\n unsubscribe,\n hasEverRun: false,\n query,\n args,\n };\n this.listeners.add(queryInfo);\n\n // If the callback is registered for a query with a result immediately available\n // schedule a fake transition to call the callback soon instead of waiting for\n // a new server update (which could take seconds or days).\n if (\n this.queryResultReady(queryToken) &&\n this.callNewListenersWithCurrentValuesTimer === undefined\n ) {\n this.callNewListenersWithCurrentValuesTimer = setTimeout(\n () => this.callNewListenersWithCurrentValues(),\n 0,\n );\n }\n\n const unsubscribeProps: RemoveCallSignature<\n Unsubscribe<Query[\"_returnType\"]>\n > = {\n unsubscribe: () => {\n if (this.closed) {\n // all unsubscribes already ran\n return;\n }\n this.listeners.delete(queryInfo);\n unsubscribe();\n },\n getCurrentValue: () => this.client.localQueryResultByToken(queryToken),\n getQueryLogs: () => this.client.localQueryLogs(queryToken),\n };\n const ret = unsubscribeProps.unsubscribe as Unsubscribe<\n Query[\"_returnType\"]\n >;\n Object.assign(ret, unsubscribeProps);\n return ret;\n }\n\n // Run all callbacks that have never been run before if they have a query\n // result available now.\n private callNewListenersWithCurrentValues() {\n this.callNewListenersWithCurrentValuesTimer = undefined;\n this._transition([], true);\n }\n\n private queryResultReady(queryToken: QueryToken): boolean {\n return this.client.hasLocalQueryResultByToken(queryToken);\n }\n\n async close() {\n if (this.disabled) return;\n // prevent pending updates\n this.listeners.clear();\n this._closed = true;\n return this.client.close();\n }\n\n /**\n * Set the authentication token to be used for subsequent queries and mutations.\n * `fetchToken` will be called automatically again if a token expires.\n * `fetchToken` should return `null` if the token cannot be retrieved, for example\n * when the user's rights were permanently revoked.\n * @param fetchToken - an async function returning the JWT (typically an OpenID Connect Identity Token)\n * @param onChange - a callback that will be called when the authentication status changes\n */\n setAuth(\n fetchToken: AuthTokenFetcher,\n onChange?: (isAuthenticated: boolean) => void,\n ) {\n if (this.disabled) return;\n this.client.setAuth(\n fetchToken,\n onChange ??\n (() => {\n // Do nothing\n }),\n );\n }\n\n /**\n * @internal\n */\n setAdminAuth(token: string, identity?: UserIdentityAttributes) {\n if (this.closed) {\n throw new Error(\"ConvexClient has already been closed.\");\n }\n if (this.disabled) return;\n this.client.setAdminAuth(token, identity);\n }\n\n /**\n * @internal\n */\n _transition(updatedQueries: QueryToken[], callNewListeners = false) {\n // Deduping subscriptions happens in the BaseConvexClient, so not much to do here.\n\n // Call all callbacks in the order they were registered\n for (const queryInfo of this.listeners) {\n const { callback, queryToken, onError, hasEverRun } = queryInfo;\n if (\n updatedQueries.includes(queryToken) ||\n (callNewListeners &&\n !hasEverRun &&\n this.client.hasLocalQueryResultByToken(queryToken))\n ) {\n queryInfo.hasEverRun = true;\n let newValue;\n try {\n newValue = this.client.localQueryResultByToken(queryToken);\n } catch (error) {\n if (!(error instanceof Error)) throw error;\n if (onError) {\n onError(\n error,\n \"Second argument to onUpdate onError is reserved for later use\",\n );\n } else {\n // Make some noise without unsubscribing or failing to call other callbacks.\n void Promise.reject(error);\n }\n continue;\n }\n callback(\n newValue,\n \"Second argument to onUpdate callback is reserved for later use\",\n );\n }\n }\n }\n\n /**\n * Execute a mutation function.\n *\n * @param mutation - A {@link server.FunctionReference} for the public mutation\n * to run.\n * @param args - An arguments object for the mutation.\n * @param options - A {@link MutationOptions} options object for the mutation.\n * @returns A promise of the mutation's result.\n */\n async mutation<Mutation extends FunctionReference<\"mutation\">>(\n mutation: Mutation,\n args: FunctionArgs<Mutation>,\n options?: MutationOptions,\n ): Promise<Awaited<FunctionReturnType<Mutation>>> {\n if (this.disabled) throw new Error(\"ConvexClient is disabled\");\n return await this.client.mutation(getFunctionName(mutation), args, options);\n }\n\n /**\n * Execute an action function.\n *\n * @param action - A {@link server.FunctionReference} for the public action\n * to run.\n * @param args - An arguments object for the action.\n * @returns A promise of the action's result.\n */\n async action<Action extends FunctionReference<\"action\">>(\n action: Action,\n args: FunctionArgs<Action>,\n ): Promise<Awaited<FunctionReturnType<Action>>> {\n if (this.disabled) throw new Error(\"ConvexClient is disabled\");\n return await this.client.action(getFunctionName(action), args);\n }\n\n /**\n * Fetch a query result once.\n *\n * @param query - A {@link server.FunctionReference} for the public query\n * to run.\n * @param args - An arguments object for the query.\n * @returns A promise of the query's result.\n */\n async query<Query extends FunctionReference<\"query\">>(\n query: Query,\n args: Query[\"_args\"],\n ): Promise<Awaited<Query[\"_returnType\"]>> {\n if (this.disabled) throw new Error(\"ConvexClient is disabled\");\n const value = this.client.localQueryResult(getFunctionName(query), args) as\n | Awaited<Query[\"_returnType\"]>\n | undefined;\n if (value !== undefined) return Promise.resolve(value);\n\n return new Promise((resolve, reject) => {\n const { unsubscribe } = this.onUpdate(\n query,\n args,\n (value) => {\n unsubscribe();\n resolve(value);\n },\n (e: Error) => {\n unsubscribe();\n reject(e);\n },\n );\n });\n }\n}\n\n// internal information tracked about each registered callback\ntype QueryInfo = {\n callback: (result: any, meta: unknown) => unknown;\n onError: ((e: Error, meta: unknown) => unknown) | undefined;\n unsubscribe: () => void;\n queryToken: QueryToken;\n hasEverRun: boolean;\n // query and args are just here for debugging, the queryToken is authoritative\n query: FunctionReference<\"query\">;\n args: any;\n};\n\ntype RemoveCallSignature<T> = Omit<T, never>;\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAAsC;AACtC,mBAMO;AAMP,iBAAgC;
|
|
4
|
+
"sourcesContent": ["import { validateDeploymentUrl } from \"../common/index.js\";\nimport {\n BaseConvexClient,\n BaseConvexClientOptions,\n MutationOptions,\n QueryToken,\n UserIdentityAttributes,\n} from \"./index.js\";\nimport {\n FunctionArgs,\n FunctionReference,\n FunctionReturnType,\n} from \"../server/index.js\";\nimport { getFunctionName } from \"../server/api.js\";\nimport { AuthTokenFetcher } from \"./sync/authentication_manager.js\";\nimport { ConnectionState } from \"./sync/client.js\";\n\n// In Node.js builds this points to a bundled WebSocket implementation. If no\n// WebSocket implementation is manually specified or globally available,\n// this one is used.\nlet defaultWebSocketConstructor: typeof WebSocket | undefined;\n\n/** internal */\nexport function setDefaultWebSocketConstructor(ws: typeof WebSocket) {\n defaultWebSocketConstructor = ws;\n}\n\nexport type ConvexClientOptions = BaseConvexClientOptions & {\n /**\n * `disabled` makes onUpdate callback registration a no-op and actions,\n * mutations and one-shot queries throw. Setting disabled to true may be\n * useful for server-side rendering, where subscriptions don't make sense.\n */\n disabled?: boolean;\n /**\n * Whether to prompt users in browsers about queued or in-flight mutations.\n * This only works in environments where `window.onbeforeunload` is available.\n *\n * Defaults to true when `window` is defined, otherwise false.\n */\n unsavedChangesWarning?: boolean;\n};\n\n/**\n * Stops callbacks from running.\n *\n * @public\n */\nexport type Unsubscribe<T> = {\n /** Stop calling callback when query results changes. If this is the last listener on this query, stop received updates. */\n (): void;\n /** Stop calling callback when query results changes. If this is the last listener on this query, stop received updates. */\n unsubscribe(): void;\n /** Get the last known value, possibly with local optimistic updates applied. */\n getCurrentValue(): T | undefined;\n /** @internal */\n getQueryLogs(): string[] | undefined;\n};\n\n/**\n * Subscribes to Convex query functions and executes mutations and actions over a WebSocket.\n *\n * Optimistic updates for mutations are not provided for this client.\n * Third party clients may choose to wrap {@link browser.BaseConvexClient} for additional control.\n *\n * ```ts\n * const client = new ConvexClient(\"https://happy-otter-123.convex.cloud\");\n * const unsubscribe = client.onUpdate(api.messages.list, (messages) => {\n * console.log(messages[0].body);\n * });\n * ```\n *\n * @public\n */\nexport class ConvexClient {\n private listeners: Set<QueryInfo>;\n private _client: BaseConvexClient | undefined;\n // A synthetic server event to run callbacks the first time\n private callNewListenersWithCurrentValuesTimer:\n | ReturnType<typeof setTimeout>\n | undefined;\n private _closed: boolean;\n private _disabled: boolean;\n /**\n * Once closed no registered callbacks will fire again.\n */\n get closed(): boolean {\n return this._closed;\n }\n get client(): BaseConvexClient {\n if (this._client) return this._client;\n throw new Error(\"ConvexClient is disabled\");\n }\n get disabled(): boolean {\n return this._disabled;\n }\n\n /**\n * Construct a client and immediately initiate a WebSocket connection to the passed address.\n *\n * @public\n */\n constructor(address: string, options: ConvexClientOptions = {}) {\n if (options.skipConvexDeploymentUrlCheck !== true) {\n validateDeploymentUrl(address);\n }\n const { disabled, ...baseOptions } = options;\n this._closed = false;\n this._disabled = !!disabled;\n if (\n defaultWebSocketConstructor &&\n !(\"webSocketConstructor\" in baseOptions) &&\n typeof WebSocket === \"undefined\"\n ) {\n baseOptions.webSocketConstructor = defaultWebSocketConstructor;\n }\n if (\n typeof window === \"undefined\" &&\n !(\"unsavedChangesWarning\" in baseOptions)\n ) {\n baseOptions.unsavedChangesWarning = false;\n }\n if (!this.disabled) {\n this._client = new BaseConvexClient(\n address,\n (updatedQueries) => this._transition(updatedQueries),\n baseOptions,\n );\n }\n this.listeners = new Set();\n }\n\n /**\n * Call a callback whenever a new result for a query is received. The callback\n * will run soon after being registered if a result for the query is already\n * in memory.\n *\n * The return value is an {@link Unsubscribe} object which is both a function\n * an an object with properties. Both of the patterns below work with this object:\n *\n *```ts\n * // call the return value as a function\n * const unsubscribe = client.onUpdate(api.messages.list, {}, (messages) => {\n * console.log(messages);\n * });\n * unsubscribe();\n *\n * // unpack the return value into its properties\n * const {\n * getCurrentValue,\n * unsubscribe,\n * } = client.onUpdate(api.messages.list, {}, (messages) => {\n * console.log(messages);\n * });\n *```\n *\n * @param query - A {@link server.FunctionReference} for the public query to run.\n * @param args - The arguments to run the query with.\n * @param callback - Function to call when the query result updates.\n * @param onError - Function to call when the query result updates with an error.\n * If not provided, errors will be thrown instead of calling the callback.\n *\n * @return an {@link Unsubscribe} function to stop calling the onUpdate function.\n */\n onUpdate<Query extends FunctionReference<\"query\">>(\n query: Query,\n args: FunctionArgs<Query>,\n callback: (result: FunctionReturnType<Query>) => unknown,\n onError?: (e: Error) => unknown,\n ): Unsubscribe<Query[\"_returnType\"]> {\n if (this.disabled) {\n const disabledUnsubscribe = (() => {}) as Unsubscribe<\n Query[\"_returnType\"]\n >;\n const unsubscribeProps: RemoveCallSignature<\n Unsubscribe<Query[\"_returnType\"]>\n > = {\n unsubscribe: disabledUnsubscribe,\n getCurrentValue: () => undefined,\n getQueryLogs: () => undefined,\n };\n Object.assign(disabledUnsubscribe, unsubscribeProps);\n return disabledUnsubscribe;\n }\n\n // BaseConvexClient takes care of deduplicating queries subscriptions...\n const { queryToken, unsubscribe } = this.client.subscribe(\n getFunctionName(query),\n args,\n );\n\n // ...but we still need to bookkeep callbacks to actually call them.\n const queryInfo: QueryInfo = {\n queryToken,\n callback,\n onError,\n unsubscribe,\n hasEverRun: false,\n query,\n args,\n };\n this.listeners.add(queryInfo);\n\n // If the callback is registered for a query with a result immediately available\n // schedule a fake transition to call the callback soon instead of waiting for\n // a new server update (which could take seconds or days).\n if (\n this.queryResultReady(queryToken) &&\n this.callNewListenersWithCurrentValuesTimer === undefined\n ) {\n this.callNewListenersWithCurrentValuesTimer = setTimeout(\n () => this.callNewListenersWithCurrentValues(),\n 0,\n );\n }\n\n const unsubscribeProps: RemoveCallSignature<\n Unsubscribe<Query[\"_returnType\"]>\n > = {\n unsubscribe: () => {\n if (this.closed) {\n // all unsubscribes already ran\n return;\n }\n this.listeners.delete(queryInfo);\n unsubscribe();\n },\n getCurrentValue: () => this.client.localQueryResultByToken(queryToken),\n getQueryLogs: () => this.client.localQueryLogs(queryToken),\n };\n const ret = unsubscribeProps.unsubscribe as Unsubscribe<\n Query[\"_returnType\"]\n >;\n Object.assign(ret, unsubscribeProps);\n return ret;\n }\n\n // Run all callbacks that have never been run before if they have a query\n // result available now.\n private callNewListenersWithCurrentValues() {\n this.callNewListenersWithCurrentValuesTimer = undefined;\n this._transition([], true);\n }\n\n private queryResultReady(queryToken: QueryToken): boolean {\n return this.client.hasLocalQueryResultByToken(queryToken);\n }\n\n async close() {\n if (this.disabled) return;\n // prevent pending updates\n this.listeners.clear();\n this._closed = true;\n return this.client.close();\n }\n\n /**\n * Set the authentication token to be used for subsequent queries and mutations.\n * `fetchToken` will be called automatically again if a token expires.\n * `fetchToken` should return `null` if the token cannot be retrieved, for example\n * when the user's rights were permanently revoked.\n * @param fetchToken - an async function returning the JWT (typically an OpenID Connect Identity Token)\n * @param onChange - a callback that will be called when the authentication status changes\n */\n setAuth(\n fetchToken: AuthTokenFetcher,\n onChange?: (isAuthenticated: boolean) => void,\n ) {\n if (this.disabled) return;\n this.client.setAuth(\n fetchToken,\n onChange ??\n (() => {\n // Do nothing\n }),\n );\n }\n\n /**\n * @internal\n */\n setAdminAuth(token: string, identity?: UserIdentityAttributes) {\n if (this.closed) {\n throw new Error(\"ConvexClient has already been closed.\");\n }\n if (this.disabled) return;\n this.client.setAdminAuth(token, identity);\n }\n\n /**\n * @internal\n */\n _transition(updatedQueries: QueryToken[], callNewListeners = false) {\n // Deduping subscriptions happens in the BaseConvexClient, so not much to do here.\n\n // Call all callbacks in the order they were registered\n for (const queryInfo of this.listeners) {\n const { callback, queryToken, onError, hasEverRun } = queryInfo;\n if (\n updatedQueries.includes(queryToken) ||\n (callNewListeners &&\n !hasEverRun &&\n this.client.hasLocalQueryResultByToken(queryToken))\n ) {\n queryInfo.hasEverRun = true;\n let newValue;\n try {\n newValue = this.client.localQueryResultByToken(queryToken);\n } catch (error) {\n if (!(error instanceof Error)) throw error;\n if (onError) {\n onError(\n error,\n \"Second argument to onUpdate onError is reserved for later use\",\n );\n } else {\n // Make some noise without unsubscribing or failing to call other callbacks.\n void Promise.reject(error);\n }\n continue;\n }\n callback(\n newValue,\n \"Second argument to onUpdate callback is reserved for later use\",\n );\n }\n }\n }\n\n /**\n * Execute a mutation function.\n *\n * @param mutation - A {@link server.FunctionReference} for the public mutation\n * to run.\n * @param args - An arguments object for the mutation.\n * @param options - A {@link MutationOptions} options object for the mutation.\n * @returns A promise of the mutation's result.\n */\n async mutation<Mutation extends FunctionReference<\"mutation\">>(\n mutation: Mutation,\n args: FunctionArgs<Mutation>,\n options?: MutationOptions,\n ): Promise<Awaited<FunctionReturnType<Mutation>>> {\n if (this.disabled) throw new Error(\"ConvexClient is disabled\");\n return await this.client.mutation(getFunctionName(mutation), args, options);\n }\n\n /**\n * Execute an action function.\n *\n * @param action - A {@link server.FunctionReference} for the public action\n * to run.\n * @param args - An arguments object for the action.\n * @returns A promise of the action's result.\n */\n async action<Action extends FunctionReference<\"action\">>(\n action: Action,\n args: FunctionArgs<Action>,\n ): Promise<Awaited<FunctionReturnType<Action>>> {\n if (this.disabled) throw new Error(\"ConvexClient is disabled\");\n return await this.client.action(getFunctionName(action), args);\n }\n\n /**\n * Fetch a query result once.\n *\n * @param query - A {@link server.FunctionReference} for the public query\n * to run.\n * @param args - An arguments object for the query.\n * @returns A promise of the query's result.\n */\n async query<Query extends FunctionReference<\"query\">>(\n query: Query,\n args: Query[\"_args\"],\n ): Promise<Awaited<Query[\"_returnType\"]>> {\n if (this.disabled) throw new Error(\"ConvexClient is disabled\");\n const value = this.client.localQueryResult(getFunctionName(query), args) as\n | Awaited<Query[\"_returnType\"]>\n | undefined;\n if (value !== undefined) return Promise.resolve(value);\n\n return new Promise((resolve, reject) => {\n const { unsubscribe } = this.onUpdate(\n query,\n args,\n (value) => {\n unsubscribe();\n resolve(value);\n },\n (e: Error) => {\n unsubscribe();\n reject(e);\n },\n );\n });\n }\n\n /**\n * Get the current {@link ConnectionState} between the client and the Convex\n * backend.\n *\n * @returns The {@link ConnectionState} with the Convex backend.\n */\n connectionState(): ConnectionState {\n if (this.disabled) throw new Error(\"ConvexClient is disabled\");\n return this.client.connectionState();\n }\n\n /**\n * Subscribe to the {@link ConnectionState} between the client and the Convex\n * backend, calling a callback each time it changes.\n *\n * Subscribed callbacks will be called when any part of ConnectionState changes.\n * ConnectionState may grow in future versions (e.g. to provide a array of\n * inflight requests) in which case callbacks would be called more frequently.\n *\n * @returns An unsubscribe function to stop listening.\n */\n subscribeToConnectionState(\n cb: (connectionState: ConnectionState) => void,\n ): () => void {\n if (this.disabled) return () => {};\n return this.client.subscribeToConnectionState(cb);\n }\n}\n\n// internal information tracked about each registered callback\ntype QueryInfo = {\n callback: (result: any, meta: unknown) => unknown;\n onError: ((e: Error, meta: unknown) => unknown) | undefined;\n unsubscribe: () => void;\n queryToken: QueryToken;\n hasEverRun: boolean;\n // query and args are just here for debugging, the queryToken is authoritative\n query: FunctionReference<\"query\">;\n args: any;\n};\n\ntype RemoveCallSignature<T> = Omit<T, never>;\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAAsC;AACtC,mBAMO;AAMP,iBAAgC;AAOhC,IAAI;AAGG,SAAS,+BAA+B,IAAsB;AACnE,gCAA8B;AAChC;AAiDO,MAAM,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA4BxB,YAAY,SAAiB,UAA+B,CAAC,GAAG;AA3BhE,wBAAQ;AACR,wBAAQ;AAER;AAAA,wBAAQ;AAGR,wBAAQ;AACR,wBAAQ;AAqBN,QAAI,QAAQ,iCAAiC,MAAM;AACjD,+CAAsB,OAAO;AAAA,IAC/B;AACA,UAAM,EAAE,UAAU,GAAG,YAAY,IAAI;AACrC,SAAK,UAAU;AACf,SAAK,YAAY,CAAC,CAAC;AACnB,QACE,+BACA,EAAE,0BAA0B,gBAC5B,OAAO,cAAc,aACrB;AACA,kBAAY,uBAAuB;AAAA,IACrC;AACA,QACE,OAAO,WAAW,eAClB,EAAE,2BAA2B,cAC7B;AACA,kBAAY,wBAAwB;AAAA,IACtC;AACA,QAAI,CAAC,KAAK,UAAU;AAClB,WAAK,UAAU,IAAI;AAAA,QACjB;AAAA,QACA,CAAC,mBAAmB,KAAK,YAAY,cAAc;AAAA,QACnD;AAAA,MACF;AAAA,IACF;AACA,SAAK,YAAY,oBAAI,IAAI;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA,EA5CA,IAAI,SAAkB;AACpB,WAAO,KAAK;AAAA,EACd;AAAA,EACA,IAAI,SAA2B;AAC7B,QAAI,KAAK,QAAS,QAAO,KAAK;AAC9B,UAAM,IAAI,MAAM,0BAA0B;AAAA,EAC5C;AAAA,EACA,IAAI,WAAoB;AACtB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAqEA,SACE,OACA,MACA,UACA,SACmC;AACnC,QAAI,KAAK,UAAU;AACjB,YAAM,sBAAuB,MAAM;AAAA,MAAC;AAGpC,YAAMA,oBAEF;AAAA,QACF,aAAa;AAAA,QACb,iBAAiB,MAAM;AAAA,QACvB,cAAc,MAAM;AAAA,MACtB;AACA,aAAO,OAAO,qBAAqBA,iBAAgB;AACnD,aAAO;AAAA,IACT;AAGA,UAAM,EAAE,YAAY,YAAY,IAAI,KAAK,OAAO;AAAA,UAC9C,4BAAgB,KAAK;AAAA,MACrB;AAAA,IACF;AAGA,UAAM,YAAuB;AAAA,MAC3B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,YAAY;AAAA,MACZ;AAAA,MACA;AAAA,IACF;AACA,SAAK,UAAU,IAAI,SAAS;AAK5B,QACE,KAAK,iBAAiB,UAAU,KAChC,KAAK,2CAA2C,QAChD;AACA,WAAK,yCAAyC;AAAA,QAC5C,MAAM,KAAK,kCAAkC;AAAA,QAC7C;AAAA,MACF;AAAA,IACF;AAEA,UAAM,mBAEF;AAAA,MACF,aAAa,MAAM;AACjB,YAAI,KAAK,QAAQ;AAEf;AAAA,QACF;AACA,aAAK,UAAU,OAAO,SAAS;AAC/B,oBAAY;AAAA,MACd;AAAA,MACA,iBAAiB,MAAM,KAAK,OAAO,wBAAwB,UAAU;AAAA,MACrE,cAAc,MAAM,KAAK,OAAO,eAAe,UAAU;AAAA,IAC3D;AACA,UAAM,MAAM,iBAAiB;AAG7B,WAAO,OAAO,KAAK,gBAAgB;AACnC,WAAO;AAAA,EACT;AAAA;AAAA;AAAA,EAIQ,oCAAoC;AAC1C,SAAK,yCAAyC;AAC9C,SAAK,YAAY,CAAC,GAAG,IAAI;AAAA,EAC3B;AAAA,EAEQ,iBAAiB,YAAiC;AACxD,WAAO,KAAK,OAAO,2BAA2B,UAAU;AAAA,EAC1D;AAAA,EAEA,MAAM,QAAQ;AACZ,QAAI,KAAK,SAAU;AAEnB,SAAK,UAAU,MAAM;AACrB,SAAK,UAAU;AACf,WAAO,KAAK,OAAO,MAAM;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,QACE,YACA,UACA;AACA,QAAI,KAAK,SAAU;AACnB,SAAK,OAAO;AAAA,MACV;AAAA,MACA,aACG,MAAM;AAAA,MAEP;AAAA,IACJ;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,OAAe,UAAmC;AAC7D,QAAI,KAAK,QAAQ;AACf,YAAM,IAAI,MAAM,uCAAuC;AAAA,IACzD;AACA,QAAI,KAAK,SAAU;AACnB,SAAK,OAAO,aAAa,OAAO,QAAQ;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA,EAKA,YAAY,gBAA8B,mBAAmB,OAAO;AAIlE,eAAW,aAAa,KAAK,WAAW;AACtC,YAAM,EAAE,UAAU,YAAY,SAAS,WAAW,IAAI;AACtD,UACE,eAAe,SAAS,UAAU,KACjC,oBACC,CAAC,cACD,KAAK,OAAO,2BAA2B,UAAU,GACnD;AACA,kBAAU,aAAa;AACvB,YAAI;AACJ,YAAI;AACF,qBAAW,KAAK,OAAO,wBAAwB,UAAU;AAAA,QAC3D,SAAS,OAAO;AACd,cAAI,EAAE,iBAAiB,OAAQ,OAAM;AACrC,cAAI,SAAS;AACX;AAAA,cACE;AAAA,cACA;AAAA,YACF;AAAA,UACF,OAAO;AAEL,iBAAK,QAAQ,OAAO,KAAK;AAAA,UAC3B;AACA;AAAA,QACF;AACA;AAAA,UACE;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,SACJ,UACA,MACA,SACgD;AAChD,QAAI,KAAK,SAAU,OAAM,IAAI,MAAM,0BAA0B;AAC7D,WAAO,MAAM,KAAK,OAAO,aAAS,4BAAgB,QAAQ,GAAG,MAAM,OAAO;AAAA,EAC5E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,OACJ,QACA,MAC8C;AAC9C,QAAI,KAAK,SAAU,OAAM,IAAI,MAAM,0BAA0B;AAC7D,WAAO,MAAM,KAAK,OAAO,WAAO,4BAAgB,MAAM,GAAG,IAAI;AAAA,EAC/D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,MACJ,OACA,MACwC;AACxC,QAAI,KAAK,SAAU,OAAM,IAAI,MAAM,0BAA0B;AAC7D,UAAM,QAAQ,KAAK,OAAO,qBAAiB,4BAAgB,KAAK,GAAG,IAAI;AAGvE,QAAI,UAAU,OAAW,QAAO,QAAQ,QAAQ,KAAK;AAErD,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,YAAM,EAAE,YAAY,IAAI,KAAK;AAAA,QAC3B;AAAA,QACA;AAAA,QACA,CAACC,WAAU;AACT,sBAAY;AACZ,kBAAQA,MAAK;AAAA,QACf;AAAA,QACA,CAAC,MAAa;AACZ,sBAAY;AACZ,iBAAO,CAAC;AAAA,QACV;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,kBAAmC;AACjC,QAAI,KAAK,SAAU,OAAM,IAAI,MAAM,0BAA0B;AAC7D,WAAO,KAAK,OAAO,gBAAgB;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,2BACE,IACY;AACZ,QAAI,KAAK,SAAU,QAAO,MAAM;AAAA,IAAC;AACjC,WAAO,KAAK,OAAO,2BAA2B,EAAE;AAAA,EAClD;AACF;",
|
|
6
6
|
"names": ["unsubscribeProps", "value"]
|
|
7
7
|
}
|
|
@@ -62,6 +62,24 @@ class BaseConvexClient {
|
|
|
62
62
|
__publicField(this, "debug");
|
|
63
63
|
__publicField(this, "logger");
|
|
64
64
|
__publicField(this, "maxObservedTimestamp");
|
|
65
|
+
__publicField(this, "connectionStateSubscribers", /* @__PURE__ */ new Map());
|
|
66
|
+
__publicField(this, "nextConnectionStateSubscriberId", 0);
|
|
67
|
+
__publicField(this, "_lastPublishedConnectionState");
|
|
68
|
+
/**
|
|
69
|
+
* Call this whenever the connection state may have changed in a way that could
|
|
70
|
+
* require publishing it. Schedules a possibly update.
|
|
71
|
+
*/
|
|
72
|
+
__publicField(this, "markConnectionStateDirty", () => {
|
|
73
|
+
void Promise.resolve().then(() => {
|
|
74
|
+
const curConnectionState = this.connectionState();
|
|
75
|
+
if (JSON.stringify(curConnectionState) !== JSON.stringify(this._lastPublishedConnectionState)) {
|
|
76
|
+
this._lastPublishedConnectionState = curConnectionState;
|
|
77
|
+
for (const cb of this.connectionStateSubscribers.values()) {
|
|
78
|
+
cb(curConnectionState);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
});
|
|
65
83
|
// Instance property so that `mark()` doesn't need to be called as a method.
|
|
66
84
|
__publicField(this, "mark", (name) => {
|
|
67
85
|
if (this.debug) {
|
|
@@ -108,7 +126,10 @@ class BaseConvexClient {
|
|
|
108
126
|
(queryId) => this.state.queryPath(queryId),
|
|
109
127
|
this.logger
|
|
110
128
|
);
|
|
111
|
-
this.requestManager = new import_request_manager.RequestManager(
|
|
129
|
+
this.requestManager = new import_request_manager.RequestManager(
|
|
130
|
+
this.logger,
|
|
131
|
+
this.markConnectionStateDirty
|
|
132
|
+
);
|
|
112
133
|
this.authenticationManager = new import_authentication_manager.AuthenticationManager(
|
|
113
134
|
this.state,
|
|
114
135
|
{
|
|
@@ -259,7 +280,8 @@ class BaseConvexClient {
|
|
|
259
280
|
onServerDisconnectError: options.onServerDisconnectError
|
|
260
281
|
},
|
|
261
282
|
webSocketConstructor,
|
|
262
|
-
this.logger
|
|
283
|
+
this.logger,
|
|
284
|
+
this.markConnectionStateDirty
|
|
263
285
|
);
|
|
264
286
|
this.mark("convexClientConstructed");
|
|
265
287
|
}
|
|
@@ -476,6 +498,23 @@ class BaseConvexClient {
|
|
|
476
498
|
inflightActions: this.requestManager.inflightActions()
|
|
477
499
|
};
|
|
478
500
|
}
|
|
501
|
+
/**
|
|
502
|
+
* Subscribe to the {@link ConnectionState} between the client and the Convex
|
|
503
|
+
* backend, calling a callback each time it changes.
|
|
504
|
+
*
|
|
505
|
+
* Subscribed callbacks will be called when any part of ConnectionState changes.
|
|
506
|
+
* ConnectionState may grow in future versions (e.g. to provide a array of
|
|
507
|
+
* inflight requests) in which case callbacks would be called more frequently.
|
|
508
|
+
*
|
|
509
|
+
* @returns An unsubscribe function to stop listening.
|
|
510
|
+
*/
|
|
511
|
+
subscribeToConnectionState(cb) {
|
|
512
|
+
const id = this.nextConnectionStateSubscriberId++;
|
|
513
|
+
this.connectionStateSubscribers.set(id, cb);
|
|
514
|
+
return () => {
|
|
515
|
+
this.connectionStateSubscribers.delete(id);
|
|
516
|
+
};
|
|
517
|
+
}
|
|
479
518
|
/**
|
|
480
519
|
* Execute a mutation function.
|
|
481
520
|
*
|